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