os/graphics/graphicsdeviceinterface/gdi/sgdi/BidiCopy.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "BidiCopy.h"
sl@0
    17
#include <e32std.h>
sl@0
    18
#include "mglyphs.inl"
sl@0
    19
sl@0
    20
TInt BidiCopy::Mirror(TInt a)
sl@0
    21
/**
sl@0
    22
Find the mirror image of a character.
sl@0
    23
@internalComponent
sl@0
    24
*/
sl@0
    25
	{
sl@0
    26
	TInt current = MirrorStart(a);
sl@0
    27
	unsigned long v = mGlyphArray[current];
sl@0
    28
	TInt key = v >> 16;
sl@0
    29
	// 1st easy-out: no steps at all for any at this key
sl@0
    30
	if (key == 0)
sl@0
    31
		return a;
sl@0
    32
	// 2nd easy-out: no steps at all but we have found it
sl@0
    33
	if (key == a)
sl@0
    34
		return v & 0xFFFF;
sl@0
    35
	TInt step = MirrorStep(a);
sl@0
    36
	do	{
sl@0
    37
		current += step;
sl@0
    38
		current &= (KMirrorTableSize-1);
sl@0
    39
		key = mGlyphArray[current] >> 16;
sl@0
    40
		if (key == a)
sl@0
    41
			return mGlyphArray[current] & 0xFFFF;
sl@0
    42
		} while (key != 0);
sl@0
    43
	return a;
sl@0
    44
	}
sl@0
    45
sl@0
    46
void BidiCopy::ReverseCodes(TText* aText, TInt aLength)
sl@0
    47
/**
sl@0
    48
Reverse the contents of aText[0..aLength], so that aText[0] holds the
sl@0
    49
value previously found in aText[aLength - 1], aText[1] holds the value
sl@0
    50
previously held in aText[aLength - 2] and so on.
sl@0
    51
@internalComponent
sl@0
    52
*/
sl@0
    53
	{
sl@0
    54
	TText *text = aText;	// backup
sl@0
    55
sl@0
    56
	// reverse int16 by int16 (note: high surrogate + low surrogate will be reverse to low surrogate + high surrogate)
sl@0
    57
	TText* end = aText + aLength - 1;
sl@0
    58
	while (aText < end)
sl@0
    59
		{
sl@0
    60
		TText t = *aText;
sl@0
    61
		*aText = *end;
sl@0
    62
		*end = t;
sl@0
    63
		++aText;
sl@0
    64
		--end;
sl@0
    65
		}
sl@0
    66
sl@0
    67
	CorrectSurrogatePairs(text, aLength);
sl@0
    68
	}
sl@0
    69
sl@0
    70
void BidiCopy::DeleteUnreversedSurrogates(TText* aText, TInt aLength)
sl@0
    71
/**
sl@0
    72
Replaces all surrogates with 0xFFFF that are not paired up the wrong
sl@0
    73
way round.
sl@0
    74
@internalComponent
sl@0
    75
*/
sl@0
    76
	{
sl@0
    77
	if (aLength < 1)
sl@0
    78
		return;
sl@0
    79
	TText* end = aText + aLength;
sl@0
    80
	while (aText < end)
sl@0
    81
		{
sl@0
    82
		if ((aText[0] & 0xF800) == 0xD800)
sl@0
    83
			{
sl@0
    84
			if ((aText[0] & 0xFC00) == 0xD800
sl@0
    85
				&& aText + 1 != end
sl@0
    86
				&& (aText[1] & 0xFC00) == 0xDC00)
sl@0
    87
				++aText;
sl@0
    88
			else
sl@0
    89
				aText[0] = 0xFFFF;
sl@0
    90
			}
sl@0
    91
		++aText;
sl@0
    92
		}
sl@0
    93
	}
sl@0
    94
sl@0
    95
void BidiCopy::CorrectSurrogatePairs(TText* aText, TInt aLength)
sl@0
    96
/**
sl@0
    97
Corrects all reversed surrogate pairs. Assumes that no unpaired
sl@0
    98
surrogates are present.
sl@0
    99
@internalComponent
sl@0
   100
*/
sl@0
   101
	{
sl@0
   102
	TText* end = aText + aLength;
sl@0
   103
	while (aText < end)
sl@0
   104
		{
sl@0
   105
		if ((aText[0] & 0xF800) == 0xD800)
sl@0
   106
			{
sl@0
   107
			// Surrogate pair discovered.
sl@0
   108
			// Do we need to swap it?
sl@0
   109
			ASSERT(aText + 1 < end);
sl@0
   110
			ASSERT((aText[1] & 0xF800) == 0xD800);
sl@0
   111
			if ((aText[0] & 0xFC00) == 0xDC00)
sl@0
   112
				{
sl@0
   113
				ASSERT((aText[1] & 0xFC00) == 0xD800);
sl@0
   114
				TText t = aText[0];
sl@0
   115
				aText[0] = aText[1];
sl@0
   116
				aText[1] = t;
sl@0
   117
				}
sl@0
   118
			++aText;
sl@0
   119
			}
sl@0
   120
		++aText;
sl@0
   121
		}
sl@0
   122
	}
sl@0
   123
sl@0
   124
void BidiCopy::CorrectGroups(TText* aText, TInt aLength)
sl@0
   125
/**
sl@0
   126
Correct all reversed groups (non-combiner followed by combining
sl@0
   127
characters). Surrogate pairs may be reversed by this operation.
sl@0
   128
Assumes that no unpaired surrogates are present.
sl@0
   129
Leading and trailing 0xFFFFs are left alone.
sl@0
   130
@internalComponent
sl@0
   131
*/
sl@0
   132
	{
sl@0
   133
	TText *end = aText + aLength;
sl@0
   134
	// Ignore leading 0xFFFFs. This helps Tagma's
sl@0
   135
	// RTmTextCache::GetDisplayedText with its sentinels.
sl@0
   136
	while (aText < end && *aText == 0xFFFF)
sl@0
   137
		++aText;
sl@0
   138
	TText* groupStart = aText;
sl@0
   139
	while (aText < end)
sl@0
   140
		{
sl@0
   141
		TText* next = aText + 1;
sl@0
   142
		TInt c = aText[0];
sl@0
   143
		if ((c & 0xFC00) == 0xD800)
sl@0
   144
			{
sl@0
   145
			ASSERT(aText + 1 < end);
sl@0
   146
			ASSERT((aText[1] & 0xFC00) == 0xDC00);
sl@0
   147
			c = (c << 10) + (aText[1] & 0x3FF)
sl@0
   148
				+ (0x10000 - 0xD800*0x400);
sl@0
   149
			++next;
sl@0
   150
			}
sl@0
   151
		// ignore non-characters
sl@0
   152
		if ((c & 0xFFFE) != 0xFFFE)
sl@0
   153
			{
sl@0
   154
			// non-marks represent the end of groups that may need to
sl@0
   155
			// be reversed
sl@0
   156
			TChar ch = c;
sl@0
   157
			if ((ch.GetCategory() & 0xFFFFFFF0) != TChar::EMarkGroup)
sl@0
   158
				{
sl@0
   159
				if (aText != groupStart)
sl@0
   160
					ReverseCodes(groupStart, aText - groupStart + 1);
sl@0
   161
				groupStart = next;
sl@0
   162
				}
sl@0
   163
			}
sl@0
   164
		aText = next;
sl@0
   165
		}
sl@0
   166
	}
sl@0
   167
sl@0
   168
void BidiCopy::SubstituteMirrorImages(TText* aText, TInt aLength)
sl@0
   169
/**
sl@0
   170
Reverse all mirror image characters. Will not change characters
sl@0
   171
in the basic multilingual plane for surrogate pairs. Assumes
sl@0
   172
that no unpaired surrogates are present.
sl@0
   173
@internalComponent
sl@0
   174
*/
sl@0
   175
	{
sl@0
   176
	TText *end = aText + aLength;
sl@0
   177
	while (aText < end)
sl@0
   178
		{
sl@0
   179
		TText* next = aText + 1;
sl@0
   180
		TInt c = aText[0];
sl@0
   181
		if ((c & 0xFC00) == 0xD800)
sl@0
   182
			{
sl@0
   183
			ASSERT(aText + 1 < end);
sl@0
   184
			ASSERT((aText[1] & 0xFC00) == 0xDC00);
sl@0
   185
			c = (c << 10) + (aText[1] & 0x3FF)
sl@0
   186
				+ (0x10000 - 0xD800*0x400);
sl@0
   187
			++next;
sl@0
   188
			}
sl@0
   189
		TInt m = Mirror(c);
sl@0
   190
		if (m != c)
sl@0
   191
			{
sl@0
   192
			if (m <= 0xFFFF)
sl@0
   193
				{
sl@0
   194
				aText[0] = static_cast<TText>(m);
sl@0
   195
				if (0xFFFF < c)
sl@0
   196
					aText[1] = 0xFFFF;
sl@0
   197
				}
sl@0
   198
			else if (0xFFFF < c)
sl@0
   199
				{
sl@0
   200
				aText[0] = static_cast<TText>((c >> 10) + 0xD760);
sl@0
   201
				aText[1] = static_cast<TText>((c & 0x3FF) + 0xDC00);
sl@0
   202
				}
sl@0
   203
			}
sl@0
   204
		aText = next;
sl@0
   205
		}
sl@0
   206
	}
sl@0
   207
sl@0
   208
TText* BidiCopy::CopyMirror(TText* aDestination, const TText* aSource, TInt length)
sl@0
   209
/**
sl@0
   210
Copy some text, substituting mirrored characters.
sl@0
   211
sl@0
   212
@return aDestination + number of TText codes output.
sl@0
   213
@internalComponent
sl@0
   214
*/
sl@0
   215
	{
sl@0
   216
	for (; length; --length, ++aDestination, ++aSource)
sl@0
   217
		*aDestination = static_cast<TText>(Mirror(*aSource));
sl@0
   218
	return aDestination;
sl@0
   219
	}
sl@0
   220
sl@0
   221
TText* BidiCopy::OutputTChar(TText* aDestination, TInt aToOutput)
sl@0
   222
/**
sl@0
   223
Write out the input character as UTF16.
sl@0
   224
sl@0
   225
@return aDestination + number of TText codes output.
sl@0
   226
@internalComponent
sl@0
   227
*/
sl@0
   228
	{
sl@0
   229
	if (aToOutput > 0xFFFF)
sl@0
   230
		{
sl@0
   231
		TInt c = aToOutput;
sl@0
   232
		aDestination[0] = static_cast<TText>((c >> 10) + 0xD760);
sl@0
   233
		aDestination[1] = static_cast<TText>((c & 0x3FF) + 0xDC00);
sl@0
   234
		return aDestination + 2;
sl@0
   235
		}
sl@0
   236
	*aDestination = static_cast<TText>(aToOutput);
sl@0
   237
	return aDestination + 1;
sl@0
   238
	}
sl@0
   239
sl@0
   240
TText* BidiCopy::CopyBackwards(TText* aDestination,
sl@0
   241
	const TText* aSource, TInt aLength)
sl@0
   242
/**
sl@0
   243
Copy the text backwards without substituting mirrored characters,
sl@0
   244
checking for surrogate pairs or combining characters.
sl@0
   245
sl@0
   246
@return aDestination + number of TText codes output.
sl@0
   247
@internalComponent
sl@0
   248
*/
sl@0
   249
	{
sl@0
   250
	TText *end = aDestination + aLength;
sl@0
   251
	while (aDestination != end)
sl@0
   252
		{
sl@0
   253
		*--end = *aSource++;
sl@0
   254
		}
sl@0
   255
	return aDestination + aLength;
sl@0
   256
	}
sl@0
   257
sl@0
   258
TText* BidiCopy::CopyBackwardsWithMirroring(TText* aDestination,
sl@0
   259
	const TText* aSource, TInt aLength)
sl@0
   260
/**
sl@0
   261
Copy the text backwards to the output without checking for surrogate
sl@0
   262
pairs or combining characters, substituting mirrored characters.
sl@0
   263
sl@0
   264
@return aDestination + number of TText codes output.
sl@0
   265
@internalComponent
sl@0
   266
*/
sl@0
   267
	{
sl@0
   268
	TText *end = aDestination + aLength;
sl@0
   269
	while (aDestination != end)
sl@0
   270
		{
sl@0
   271
		*--end = static_cast<TText>(Mirror(*aSource++));
sl@0
   272
		}
sl@0
   273
	return aDestination + aLength;
sl@0
   274
	}
sl@0
   275
sl@0
   276
TText* BidiCopy::CopyGroupsBackwards(TText* aDestination,
sl@0
   277
	const TText* aSource, TInt aLength)
sl@0
   278
/**
sl@0
   279
Copy the text backwards, substituting mirrored characters and correctly
sl@0
   280
handling all surrogate pairs and combining characters.
sl@0
   281
sl@0
   282
@return aDestination + number of TText codes output.
sl@0
   283
@internalComponent
sl@0
   284
*/
sl@0
   285
	{
sl@0
   286
	TText* retval = CopyBackwards(aDestination, aSource, aLength);
sl@0
   287
	DeleteUnreversedSurrogates(aDestination, aLength);
sl@0
   288
	SubstituteMirrorImages(aDestination, aLength);
sl@0
   289
	CorrectGroups(aDestination, aLength);
sl@0
   290
	CorrectSurrogatePairs(aDestination, aLength);
sl@0
   291
	return retval;
sl@0
   292
	}
sl@0
   293
sl@0
   294
TBool BidiCopy::ImplicitDirectionalityIsRightToLeft(
sl@0
   295
	const TText* aText, TInt aLength, TBool* aFound)
sl@0
   296
/**
sl@0
   297
Find out if the implicit directionality of a piece of text is right to
sl@0
   298
left.
sl@0
   299
sl@0
   300
@param aText Text to be examined, or the first portion of text to be examined.
sl@0
   301
@param aLength Length of the text.
sl@0
   302
@param aFound If non-null, returns ETrue if the directionality could be
sl@0
   303
determined from aText. If not, and there is more text beyond, the function 
sl@0
   304
should be called with the next portion of text until aFound returns ETrue 
sl@0
   305
or there is no more text.
sl@0
   306
@return	ETrue if the directionality is right to left. If the directionality
sl@0
   307
cannot be determined solely from this text, EFalse is returned.	This is the 
sl@0
   308
implicit directionality of text that is composed entirely of neutrals.
sl@0
   309
@internalComponent
sl@0
   310
*/
sl@0
   311
	{
sl@0
   312
	if (aFound)
sl@0
   313
		*aFound = ETrue;
sl@0
   314
	const TText* end = aText + aLength;
sl@0
   315
	TInt lastUtf16 = 0;
sl@0
   316
	while (aText != end)
sl@0
   317
		{
sl@0
   318
		TInt code = *aText++;
sl@0
   319
		if ((code & 0xFFFFFC00) == 0xD800
sl@0
   320
			&& (lastUtf16 & 0xFFFFFC00) == 0xDC00)
sl@0
   321
			{
sl@0
   322
			code = (code << 10) + (lastUtf16 & 0x3FF)
sl@0
   323
				+ (0x10000 - 0xD800*0x400);
sl@0
   324
			}
sl@0
   325
		lastUtf16 = code;
sl@0
   326
		TChar c = code;
sl@0
   327
		switch(c.GetBdCategory())
sl@0
   328
			{
sl@0
   329
		case TChar::ELeftToRight:
sl@0
   330
			return EFalse;
sl@0
   331
		case TChar::ERightToLeft:
sl@0
   332
		case TChar::ERightToLeftArabic:
sl@0
   333
			return ETrue;
sl@0
   334
		default:
sl@0
   335
			break;
sl@0
   336
			}
sl@0
   337
		}
sl@0
   338
	if (aFound)
sl@0
   339
		*aFound = EFalse;
sl@0
   340
	return EFalse;
sl@0
   341
	}