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.
     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 	}