sl@0: // Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "BidiCopy.h" sl@0: #include sl@0: #include "mglyphs.inl" sl@0: sl@0: TInt BidiCopy::Mirror(TInt a) sl@0: /** sl@0: Find the mirror image of a character. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TInt current = MirrorStart(a); sl@0: unsigned long v = mGlyphArray[current]; sl@0: TInt key = v >> 16; sl@0: // 1st easy-out: no steps at all for any at this key sl@0: if (key == 0) sl@0: return a; sl@0: // 2nd easy-out: no steps at all but we have found it sl@0: if (key == a) sl@0: return v & 0xFFFF; sl@0: TInt step = MirrorStep(a); sl@0: do { sl@0: current += step; sl@0: current &= (KMirrorTableSize-1); sl@0: key = mGlyphArray[current] >> 16; sl@0: if (key == a) sl@0: return mGlyphArray[current] & 0xFFFF; sl@0: } while (key != 0); sl@0: return a; sl@0: } sl@0: sl@0: void BidiCopy::ReverseCodes(TText* aText, TInt aLength) sl@0: /** sl@0: Reverse the contents of aText[0..aLength], so that aText[0] holds the sl@0: value previously found in aText[aLength - 1], aText[1] holds the value sl@0: previously held in aText[aLength - 2] and so on. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText *text = aText; // backup sl@0: sl@0: // reverse int16 by int16 (note: high surrogate + low surrogate will be reverse to low surrogate + high surrogate) sl@0: TText* end = aText + aLength - 1; sl@0: while (aText < end) sl@0: { sl@0: TText t = *aText; sl@0: *aText = *end; sl@0: *end = t; sl@0: ++aText; sl@0: --end; sl@0: } sl@0: sl@0: CorrectSurrogatePairs(text, aLength); sl@0: } sl@0: sl@0: void BidiCopy::DeleteUnreversedSurrogates(TText* aText, TInt aLength) sl@0: /** sl@0: Replaces all surrogates with 0xFFFF that are not paired up the wrong sl@0: way round. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: if (aLength < 1) sl@0: return; sl@0: TText* end = aText + aLength; sl@0: while (aText < end) sl@0: { sl@0: if ((aText[0] & 0xF800) == 0xD800) sl@0: { sl@0: if ((aText[0] & 0xFC00) == 0xD800 sl@0: && aText + 1 != end sl@0: && (aText[1] & 0xFC00) == 0xDC00) sl@0: ++aText; sl@0: else sl@0: aText[0] = 0xFFFF; sl@0: } sl@0: ++aText; sl@0: } sl@0: } sl@0: sl@0: void BidiCopy::CorrectSurrogatePairs(TText* aText, TInt aLength) sl@0: /** sl@0: Corrects all reversed surrogate pairs. Assumes that no unpaired sl@0: surrogates are present. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText* end = aText + aLength; sl@0: while (aText < end) sl@0: { sl@0: if ((aText[0] & 0xF800) == 0xD800) sl@0: { sl@0: // Surrogate pair discovered. sl@0: // Do we need to swap it? sl@0: ASSERT(aText + 1 < end); sl@0: ASSERT((aText[1] & 0xF800) == 0xD800); sl@0: if ((aText[0] & 0xFC00) == 0xDC00) sl@0: { sl@0: ASSERT((aText[1] & 0xFC00) == 0xD800); sl@0: TText t = aText[0]; sl@0: aText[0] = aText[1]; sl@0: aText[1] = t; sl@0: } sl@0: ++aText; sl@0: } sl@0: ++aText; sl@0: } sl@0: } sl@0: sl@0: void BidiCopy::CorrectGroups(TText* aText, TInt aLength) sl@0: /** sl@0: Correct all reversed groups (non-combiner followed by combining sl@0: characters). Surrogate pairs may be reversed by this operation. sl@0: Assumes that no unpaired surrogates are present. sl@0: Leading and trailing 0xFFFFs are left alone. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText *end = aText + aLength; sl@0: // Ignore leading 0xFFFFs. This helps Tagma's sl@0: // RTmTextCache::GetDisplayedText with its sentinels. sl@0: while (aText < end && *aText == 0xFFFF) sl@0: ++aText; sl@0: TText* groupStart = aText; sl@0: while (aText < end) sl@0: { sl@0: TText* next = aText + 1; sl@0: TInt c = aText[0]; sl@0: if ((c & 0xFC00) == 0xD800) sl@0: { sl@0: ASSERT(aText + 1 < end); sl@0: ASSERT((aText[1] & 0xFC00) == 0xDC00); sl@0: c = (c << 10) + (aText[1] & 0x3FF) sl@0: + (0x10000 - 0xD800*0x400); sl@0: ++next; sl@0: } sl@0: // ignore non-characters sl@0: if ((c & 0xFFFE) != 0xFFFE) sl@0: { sl@0: // non-marks represent the end of groups that may need to sl@0: // be reversed sl@0: TChar ch = c; sl@0: if ((ch.GetCategory() & 0xFFFFFFF0) != TChar::EMarkGroup) sl@0: { sl@0: if (aText != groupStart) sl@0: ReverseCodes(groupStart, aText - groupStart + 1); sl@0: groupStart = next; sl@0: } sl@0: } sl@0: aText = next; sl@0: } sl@0: } sl@0: sl@0: void BidiCopy::SubstituteMirrorImages(TText* aText, TInt aLength) sl@0: /** sl@0: Reverse all mirror image characters. Will not change characters sl@0: in the basic multilingual plane for surrogate pairs. Assumes sl@0: that no unpaired surrogates are present. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText *end = aText + aLength; sl@0: while (aText < end) sl@0: { sl@0: TText* next = aText + 1; sl@0: TInt c = aText[0]; sl@0: if ((c & 0xFC00) == 0xD800) sl@0: { sl@0: ASSERT(aText + 1 < end); sl@0: ASSERT((aText[1] & 0xFC00) == 0xDC00); sl@0: c = (c << 10) + (aText[1] & 0x3FF) sl@0: + (0x10000 - 0xD800*0x400); sl@0: ++next; sl@0: } sl@0: TInt m = Mirror(c); sl@0: if (m != c) sl@0: { sl@0: if (m <= 0xFFFF) sl@0: { sl@0: aText[0] = static_cast(m); sl@0: if (0xFFFF < c) sl@0: aText[1] = 0xFFFF; sl@0: } sl@0: else if (0xFFFF < c) sl@0: { sl@0: aText[0] = static_cast((c >> 10) + 0xD760); sl@0: aText[1] = static_cast((c & 0x3FF) + 0xDC00); sl@0: } sl@0: } sl@0: aText = next; sl@0: } sl@0: } sl@0: sl@0: TText* BidiCopy::CopyMirror(TText* aDestination, const TText* aSource, TInt length) sl@0: /** sl@0: Copy some text, substituting mirrored characters. sl@0: sl@0: @return aDestination + number of TText codes output. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: for (; length; --length, ++aDestination, ++aSource) sl@0: *aDestination = static_cast(Mirror(*aSource)); sl@0: return aDestination; sl@0: } sl@0: sl@0: TText* BidiCopy::OutputTChar(TText* aDestination, TInt aToOutput) sl@0: /** sl@0: Write out the input character as UTF16. sl@0: sl@0: @return aDestination + number of TText codes output. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: if (aToOutput > 0xFFFF) sl@0: { sl@0: TInt c = aToOutput; sl@0: aDestination[0] = static_cast((c >> 10) + 0xD760); sl@0: aDestination[1] = static_cast((c & 0x3FF) + 0xDC00); sl@0: return aDestination + 2; sl@0: } sl@0: *aDestination = static_cast(aToOutput); sl@0: return aDestination + 1; sl@0: } sl@0: sl@0: TText* BidiCopy::CopyBackwards(TText* aDestination, sl@0: const TText* aSource, TInt aLength) sl@0: /** sl@0: Copy the text backwards without substituting mirrored characters, sl@0: checking for surrogate pairs or combining characters. sl@0: sl@0: @return aDestination + number of TText codes output. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText *end = aDestination + aLength; sl@0: while (aDestination != end) sl@0: { sl@0: *--end = *aSource++; sl@0: } sl@0: return aDestination + aLength; sl@0: } sl@0: sl@0: TText* BidiCopy::CopyBackwardsWithMirroring(TText* aDestination, sl@0: const TText* aSource, TInt aLength) sl@0: /** sl@0: Copy the text backwards to the output without checking for surrogate sl@0: pairs or combining characters, substituting mirrored characters. sl@0: sl@0: @return aDestination + number of TText codes output. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText *end = aDestination + aLength; sl@0: while (aDestination != end) sl@0: { sl@0: *--end = static_cast(Mirror(*aSource++)); sl@0: } sl@0: return aDestination + aLength; sl@0: } sl@0: sl@0: TText* BidiCopy::CopyGroupsBackwards(TText* aDestination, sl@0: const TText* aSource, TInt aLength) sl@0: /** sl@0: Copy the text backwards, substituting mirrored characters and correctly sl@0: handling all surrogate pairs and combining characters. sl@0: sl@0: @return aDestination + number of TText codes output. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: TText* retval = CopyBackwards(aDestination, aSource, aLength); sl@0: DeleteUnreversedSurrogates(aDestination, aLength); sl@0: SubstituteMirrorImages(aDestination, aLength); sl@0: CorrectGroups(aDestination, aLength); sl@0: CorrectSurrogatePairs(aDestination, aLength); sl@0: return retval; sl@0: } sl@0: sl@0: TBool BidiCopy::ImplicitDirectionalityIsRightToLeft( sl@0: const TText* aText, TInt aLength, TBool* aFound) sl@0: /** sl@0: Find out if the implicit directionality of a piece of text is right to sl@0: left. sl@0: sl@0: @param aText Text to be examined, or the first portion of text to be examined. sl@0: @param aLength Length of the text. sl@0: @param aFound If non-null, returns ETrue if the directionality could be sl@0: determined from aText. If not, and there is more text beyond, the function sl@0: should be called with the next portion of text until aFound returns ETrue sl@0: or there is no more text. sl@0: @return ETrue if the directionality is right to left. If the directionality sl@0: cannot be determined solely from this text, EFalse is returned. This is the sl@0: implicit directionality of text that is composed entirely of neutrals. sl@0: @internalComponent sl@0: */ sl@0: { sl@0: if (aFound) sl@0: *aFound = ETrue; sl@0: const TText* end = aText + aLength; sl@0: TInt lastUtf16 = 0; sl@0: while (aText != end) sl@0: { sl@0: TInt code = *aText++; sl@0: if ((code & 0xFFFFFC00) == 0xD800 sl@0: && (lastUtf16 & 0xFFFFFC00) == 0xDC00) sl@0: { sl@0: code = (code << 10) + (lastUtf16 & 0x3FF) sl@0: + (0x10000 - 0xD800*0x400); sl@0: } sl@0: lastUtf16 = code; sl@0: TChar c = code; sl@0: switch(c.GetBdCategory()) sl@0: { sl@0: case TChar::ELeftToRight: sl@0: return EFalse; sl@0: case TChar::ERightToLeft: sl@0: case TChar::ERightToLeftArabic: sl@0: return ETrue; sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: if (aFound) sl@0: *aFound = EFalse; sl@0: return EFalse; sl@0: }