fontservices/textbase/sgdi/BidiCompact.cpp
changeset 51 a7c938434754
equal deleted inserted replaced
44:601ab138ba0b 51:a7c938434754
       
     1 // Copyright (c) 2002-2010 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 "BidiCompact.h"
       
    17 #include "BidiCopy.h"
       
    18 #include <textbase.h>
       
    19 
       
    20 static const TInt KZeroWidthJoiner = 0x200D;
       
    21 // This gets round the compiler warning about converting
       
    22 // EFRightToLeft to unsigned long.
       
    23 inline TUint FRightToLeft() { return static_cast<TUint>(TRunInfoCompact::EFRightToLeft); }
       
    24 
       
    25 /**
       
    26 Constructs a run description without considering optimisations based
       
    27 on the text itself.
       
    28 @param aStart Index of the start of the run.
       
    29 @param aLength Length of the run.
       
    30 @param aReverse ETrue if the run is right-to-left.
       
    31 @internalTechnology
       
    32 */
       
    33 TRunInfoCompact::TRunInfoCompact(TInt aStart, TInt aLength,
       
    34 	TBool aReverse)
       
    35 	: iStart(aStart), iLengthAndType(aLength)
       
    36 	{
       
    37 	if (aReverse)
       
    38 		iLengthAndType |= FRightToLeft();
       
    39 	}
       
    40 
       
    41 /**
       
    42 Constructs a run description.
       
    43 
       
    44 @param aStart Index of the start of the run.
       
    45 @param aLength Length of the run.
       
    46 @param aReverse ETrue if the run is right-to-left.
       
    47 @param aText The text that this run refers to (starting at index 0, not
       
    48 the start of the run). This is required only to determine if optimisations 
       
    49 to the re-ordering are possible.
       
    50 @internalTechnology
       
    51 */
       
    52 TRunInfoCompact::TRunInfoCompact(TInt aStart, TInt aLength,
       
    53 	TBool aReverse, const TText* aText)
       
    54 	: iStart(aStart), iLengthAndType(aLength)
       
    55 	{
       
    56 	ASSERT(0 <= aLength);
       
    57 	ASSERT(aLength < 0x10000000);
       
    58 	ASSERT(0 <= aStart);
       
    59 	if (!aReverse)
       
    60 		return;
       
    61 	iLengthAndType |= FRightToLeft();
       
    62 	TUint32 flags = EFNoPairsNoCombiners | EFNoMirroredCharacters;
       
    63 	aText += aStart;
       
    64 
       
    65 	for (const TText* end = aText + aLength; aText < end && flags; ++aText)
       
    66 		{
       
    67 		TInt code = *aText;
       
    68 		if ((code & 0xF800) == 0xD800)
       
    69 			{
       
    70 			flags &= ~EFNoPairsNoCombiners;
       
    71 			if ((code & 0xFC00) == 0xDC00
       
    72 				&& aText + 1 < end
       
    73 				&& (aText[1] & 0xFC00) == 0xD800)
       
    74 				{
       
    75 				code = (aText[1] << 10) + (code & 0x3FF)
       
    76 					+ (0x10000 - 0xD800*0x400);
       
    77 				++aText;
       
    78 				}
       
    79 			}
       
    80 		TChar c = code;
       
    81 		if (c.GetCombiningClass() != 0)
       
    82 			flags &= ~EFNoPairsNoCombiners;
       
    83 		if (BidiCopy::Mirror(code) != code)
       
    84 			flags &= ~EFNoMirroredCharacters;
       
    85 		}
       
    86 	iLengthAndType |= flags;
       
    87 	}
       
    88 
       
    89 /**
       
    90 Attempts to extend a run.
       
    91 
       
    92 @param aToBeAdded The run to be merged.
       
    93 @return ETrue if extension succeeded, EFalse if not.
       
    94 @internalTechnology
       
    95 */
       
    96 TBool TRunInfoCompact::AddRun(const TRunInfoCompact& aToBeAdded)
       
    97 	{
       
    98 	TInt length = Length();
       
    99 	if (length == 0)
       
   100 		{
       
   101 		*this = aToBeAdded;
       
   102 		return ETrue;
       
   103 		}
       
   104 
       
   105 	// Are both runs in the same direction?
       
   106 	if ((iLengthAndType ^ aToBeAdded.iLengthAndType) & FRightToLeft())
       
   107 		return EFalse;
       
   108 
       
   109 	TBool rightToLeft = TypeFlags() & EFRightToLeft;
       
   110 	TInt end = rightToLeft?
       
   111 		Start() - Length() : Start() + Length();
       
   112 
       
   113 	if (end != aToBeAdded.Start())
       
   114 		return EFalse;
       
   115 
       
   116 	length += aToBeAdded.Length();
       
   117 
       
   118 	iLengthAndType = length | (TypeFlags() & aToBeAdded.TypeFlags());
       
   119 
       
   120 	if (rightToLeft)
       
   121 		iStart -= aToBeAdded.Length();
       
   122 
       
   123 	return ETrue;
       
   124 	}
       
   125 
       
   126 /**
       
   127 Reorders text described by this run according to aContext. Allow 6 extra
       
   128 bytes for a truncation.
       
   129 @param aDestination	Where to write this run of visually-ordered text to.
       
   130 @param aContext The source of the text to be ordered.
       
   131 @return	The first byte not written to: in other words, what aDestination
       
   132 should be updated to.
       
   133 @internalTechnology
       
   134 */
       
   135 TText* TRunInfoCompact::Reorder(TText* aDestination,
       
   136 	const TRunInfoCompact::TReorderingContext& aContext) const
       
   137 	{
       
   138 	TInt start = Start();
       
   139 	if (aContext.iEnd < start)
       
   140 		// does not overlap
       
   141 		return aDestination;
       
   142 	TInt end = Start() + Length();
       
   143 	if (end <= aContext.iStart)
       
   144 		// does not overlap
       
   145 		return aDestination;
       
   146 	TBool startJoins = EFalse;
       
   147 	if (start <= aContext.iStart)
       
   148 		{
       
   149 		start = aContext.iStart;
       
   150 		startJoins = aContext.iJoinsAtStart;
       
   151 		}
       
   152 	TBool truncated = EFalse;
       
   153 	TBool endJoins = EFalse;
       
   154 	if (aContext.iEnd <= end)
       
   155 		{
       
   156 		if (aContext.iEnd < end
       
   157 			&& aContext.iTruncation != 0xFFFF)
       
   158 			truncated = ETrue;
       
   159 		end = aContext.iEnd;
       
   160 		endJoins = aContext.iJoinsAtEnd;
       
   161 		}
       
   162 	TInt length = end - start;
       
   163 	if (length == 0 && !truncated)
       
   164 		return aDestination;
       
   165 	ASSERT(0 <= length);
       
   166 	const TText* source = aContext.iSource + start;
       
   167 	if (TypeFlags() & FRightToLeft())
       
   168 		{
       
   169 		// Right-to-left
       
   170 		if (truncated)
       
   171 			aDestination = BidiCopy::OutputTChar(aDestination, aContext.iTruncation);
       
   172 		if (endJoins)
       
   173 			*(aDestination++) = KZeroWidthJoiner;
       
   174 		if (TypeFlags() & EFNoPairsNoCombiners)
       
   175 			{
       
   176 			// Simple
       
   177 			aDestination = TypeFlags() & EFNoMirroredCharacters?
       
   178 				BidiCopy::CopyBackwards(aDestination, source, length)
       
   179 				: BidiCopy::CopyBackwardsWithMirroring(aDestination, source, length);
       
   180 			}
       
   181 		else
       
   182 			// Respect groups
       
   183 			aDestination = BidiCopy::CopyGroupsBackwards(aDestination, source, length);
       
   184 		if (startJoins)
       
   185 			*aDestination++ = KZeroWidthJoiner;
       
   186 		return aDestination;
       
   187 		}
       
   188 	// Left-to-right
       
   189 	if (startJoins)
       
   190 		*aDestination++ = KZeroWidthJoiner;
       
   191 	Mem::Copy(aDestination, source, length * sizeof(TText));
       
   192 	aDestination += length;
       
   193 	if (endJoins)
       
   194 		*aDestination++ = KZeroWidthJoiner;
       
   195 	if (truncated)
       
   196 		aDestination = BidiCopy::OutputTChar(aDestination, aContext.iTruncation);
       
   197 	return aDestination;
       
   198 	}
       
   199 
       
   200 /**
       
   201 Converts an array of aArraySize TBidirectionalState::TRunInfos into a
       
   202 compact form.
       
   203 
       
   204 @param aBuffer Memory to output to, or null just to find out how large the output
       
   205 array will need to be.
       
   206 @param aText The text that aRunArray refers to.
       
   207 @param aRunArray The array to be converted.
       
   208 @param aArraySize The length of aRunArray.
       
   209 @return The length of the output array.
       
   210 @internalTechnology
       
   211 */
       
   212 TInt TRunInfoCompact::Convert(TRunInfoCompact* aBuffer, const TDesC& aText,
       
   213 	const TBidirectionalState::TRunInfo* aRunArray, TInt aArraySize)
       
   214 	{
       
   215 	const TText* text = aText.Ptr();
       
   216 	TInt outputSize =  0;
       
   217 
       
   218 	TRunInfoCompact currentRun;
       
   219 	while (aArraySize)
       
   220 		{
       
   221 		TRunInfoCompact newRun(aRunArray->iStart, aRunArray->iLength,
       
   222 			aRunArray->iDirection, text);
       
   223 		--aArraySize;
       
   224 		if (!currentRun.AddRun(newRun))
       
   225 			{
       
   226 			if (aBuffer)
       
   227 				*aBuffer++ = currentRun;
       
   228 			++outputSize;
       
   229 			currentRun = newRun;
       
   230 			}
       
   231 		++aRunArray; //point to next run
       
   232 		}
       
   233 	if (0 < currentRun.Length())
       
   234 		{
       
   235 		if (aBuffer)
       
   236 			*aBuffer++ = currentRun;
       
   237 		++outputSize;
       
   238 		}
       
   239 
       
   240 	return outputSize;
       
   241 	}
       
   242 
       
   243 /**
       
   244 Utility tells whether a character will form a join with the previous
       
   245 base character.
       
   246 
       
   247 @param aText The text.
       
   248 @param aIndex The index into aText of the character to test.
       
   249 @return ETrue if there is a join before the character.
       
   250 */
       
   251 TBool TRunInfoCompact::JoinBefore(const TText* aText, TInt aIndex)
       
   252 	{
       
   253 	TInt charUnderTest = aText[aIndex];
       
   254 	if (!CFont::CharactersJoin(charUnderTest, KZeroWidthJoiner))
       
   255 		// Character does not join with anything, so we
       
   256 		// will not do any more work.
       
   257 		return EFalse;
       
   258 	while (aIndex != 0)
       
   259 		{
       
   260 		--aIndex;
       
   261 		TInt c = aText[aIndex];
       
   262 		// If it is an Arabic point, we will skip it.
       
   263 		if (0x64B <= c && c < 0x671
       
   264 			&& !(0x656 <= c && c < 0x670))
       
   265 			continue;
       
   266 		return CFont::CharactersJoin(charUnderTest, c);
       
   267 		}
       
   268 	return EFalse;
       
   269 	}