1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/textbase/sgdi/BidiCompact.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,269 @@
1.4 +// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "BidiCompact.h"
1.20 +#include "BidiCopy.h"
1.21 +#include <textbase.h>
1.22 +
1.23 +static const TInt KZeroWidthJoiner = 0x200D;
1.24 +// This gets round the compiler warning about converting
1.25 +// EFRightToLeft to unsigned long.
1.26 +inline TUint FRightToLeft() { return static_cast<TUint>(TRunInfoCompact::EFRightToLeft); }
1.27 +
1.28 +/**
1.29 +Constructs a run description without considering optimisations based
1.30 +on the text itself.
1.31 +@param aStart Index of the start of the run.
1.32 +@param aLength Length of the run.
1.33 +@param aReverse ETrue if the run is right-to-left.
1.34 +@internalTechnology
1.35 +*/
1.36 +TRunInfoCompact::TRunInfoCompact(TInt aStart, TInt aLength,
1.37 + TBool aReverse)
1.38 + : iStart(aStart), iLengthAndType(aLength)
1.39 + {
1.40 + if (aReverse)
1.41 + iLengthAndType |= FRightToLeft();
1.42 + }
1.43 +
1.44 +/**
1.45 +Constructs a run description.
1.46 +
1.47 +@param aStart Index of the start of the run.
1.48 +@param aLength Length of the run.
1.49 +@param aReverse ETrue if the run is right-to-left.
1.50 +@param aText The text that this run refers to (starting at index 0, not
1.51 +the start of the run). This is required only to determine if optimisations
1.52 +to the re-ordering are possible.
1.53 +@internalTechnology
1.54 +*/
1.55 +TRunInfoCompact::TRunInfoCompact(TInt aStart, TInt aLength,
1.56 + TBool aReverse, const TText* aText)
1.57 + : iStart(aStart), iLengthAndType(aLength)
1.58 + {
1.59 + ASSERT(0 <= aLength);
1.60 + ASSERT(aLength < 0x10000000);
1.61 + ASSERT(0 <= aStart);
1.62 + if (!aReverse)
1.63 + return;
1.64 + iLengthAndType |= FRightToLeft();
1.65 + TUint32 flags = EFNoPairsNoCombiners | EFNoMirroredCharacters;
1.66 + aText += aStart;
1.67 +
1.68 + for (const TText* end = aText + aLength; aText < end && flags; ++aText)
1.69 + {
1.70 + TInt code = *aText;
1.71 + if ((code & 0xF800) == 0xD800)
1.72 + {
1.73 + flags &= ~EFNoPairsNoCombiners;
1.74 + if ((code & 0xFC00) == 0xDC00
1.75 + && aText + 1 < end
1.76 + && (aText[1] & 0xFC00) == 0xD800)
1.77 + {
1.78 + code = (aText[1] << 10) + (code & 0x3FF)
1.79 + + (0x10000 - 0xD800*0x400);
1.80 + ++aText;
1.81 + }
1.82 + }
1.83 + TChar c = code;
1.84 + if (c.GetCombiningClass() != 0)
1.85 + flags &= ~EFNoPairsNoCombiners;
1.86 + if (BidiCopy::Mirror(code) != code)
1.87 + flags &= ~EFNoMirroredCharacters;
1.88 + }
1.89 + iLengthAndType |= flags;
1.90 + }
1.91 +
1.92 +/**
1.93 +Attempts to extend a run.
1.94 +
1.95 +@param aToBeAdded The run to be merged.
1.96 +@return ETrue if extension succeeded, EFalse if not.
1.97 +@internalTechnology
1.98 +*/
1.99 +TBool TRunInfoCompact::AddRun(const TRunInfoCompact& aToBeAdded)
1.100 + {
1.101 + TInt length = Length();
1.102 + if (length == 0)
1.103 + {
1.104 + *this = aToBeAdded;
1.105 + return ETrue;
1.106 + }
1.107 +
1.108 + // Are both runs in the same direction?
1.109 + if ((iLengthAndType ^ aToBeAdded.iLengthAndType) & FRightToLeft())
1.110 + return EFalse;
1.111 +
1.112 + TBool rightToLeft = TypeFlags() & EFRightToLeft;
1.113 + TInt end = rightToLeft?
1.114 + Start() - Length() : Start() + Length();
1.115 +
1.116 + if (end != aToBeAdded.Start())
1.117 + return EFalse;
1.118 +
1.119 + length += aToBeAdded.Length();
1.120 +
1.121 + iLengthAndType = length | (TypeFlags() & aToBeAdded.TypeFlags());
1.122 +
1.123 + if (rightToLeft)
1.124 + iStart -= aToBeAdded.Length();
1.125 +
1.126 + return ETrue;
1.127 + }
1.128 +
1.129 +/**
1.130 +Reorders text described by this run according to aContext. Allow 6 extra
1.131 +bytes for a truncation.
1.132 +@param aDestination Where to write this run of visually-ordered text to.
1.133 +@param aContext The source of the text to be ordered.
1.134 +@return The first byte not written to: in other words, what aDestination
1.135 +should be updated to.
1.136 +@internalTechnology
1.137 +*/
1.138 +TText* TRunInfoCompact::Reorder(TText* aDestination,
1.139 + const TRunInfoCompact::TReorderingContext& aContext) const
1.140 + {
1.141 + TInt start = Start();
1.142 + if (aContext.iEnd < start)
1.143 + // does not overlap
1.144 + return aDestination;
1.145 + TInt end = Start() + Length();
1.146 + if (end <= aContext.iStart)
1.147 + // does not overlap
1.148 + return aDestination;
1.149 + TBool startJoins = EFalse;
1.150 + if (start <= aContext.iStart)
1.151 + {
1.152 + start = aContext.iStart;
1.153 + startJoins = aContext.iJoinsAtStart;
1.154 + }
1.155 + TBool truncated = EFalse;
1.156 + TBool endJoins = EFalse;
1.157 + if (aContext.iEnd <= end)
1.158 + {
1.159 + if (aContext.iEnd < end
1.160 + && aContext.iTruncation != 0xFFFF)
1.161 + truncated = ETrue;
1.162 + end = aContext.iEnd;
1.163 + endJoins = aContext.iJoinsAtEnd;
1.164 + }
1.165 + TInt length = end - start;
1.166 + if (length == 0 && !truncated)
1.167 + return aDestination;
1.168 + ASSERT(0 <= length);
1.169 + const TText* source = aContext.iSource + start;
1.170 + if (TypeFlags() & FRightToLeft())
1.171 + {
1.172 + // Right-to-left
1.173 + if (truncated)
1.174 + aDestination = BidiCopy::OutputTChar(aDestination, aContext.iTruncation);
1.175 + if (endJoins)
1.176 + *(aDestination++) = KZeroWidthJoiner;
1.177 + if (TypeFlags() & EFNoPairsNoCombiners)
1.178 + {
1.179 + // Simple
1.180 + aDestination = TypeFlags() & EFNoMirroredCharacters?
1.181 + BidiCopy::CopyBackwards(aDestination, source, length)
1.182 + : BidiCopy::CopyBackwardsWithMirroring(aDestination, source, length);
1.183 + }
1.184 + else
1.185 + // Respect groups
1.186 + aDestination = BidiCopy::CopyGroupsBackwards(aDestination, source, length);
1.187 + if (startJoins)
1.188 + *aDestination++ = KZeroWidthJoiner;
1.189 + return aDestination;
1.190 + }
1.191 + // Left-to-right
1.192 + if (startJoins)
1.193 + *aDestination++ = KZeroWidthJoiner;
1.194 + Mem::Copy(aDestination, source, length * sizeof(TText));
1.195 + aDestination += length;
1.196 + if (endJoins)
1.197 + *aDestination++ = KZeroWidthJoiner;
1.198 + if (truncated)
1.199 + aDestination = BidiCopy::OutputTChar(aDestination, aContext.iTruncation);
1.200 + return aDestination;
1.201 + }
1.202 +
1.203 +/**
1.204 +Converts an array of aArraySize TBidirectionalState::TRunInfos into a
1.205 +compact form.
1.206 +
1.207 +@param aBuffer Memory to output to, or null just to find out how large the output
1.208 +array will need to be.
1.209 +@param aText The text that aRunArray refers to.
1.210 +@param aRunArray The array to be converted.
1.211 +@param aArraySize The length of aRunArray.
1.212 +@return The length of the output array.
1.213 +@internalTechnology
1.214 +*/
1.215 +TInt TRunInfoCompact::Convert(TRunInfoCompact* aBuffer, const TDesC& aText,
1.216 + const TBidirectionalState::TRunInfo* aRunArray, TInt aArraySize)
1.217 + {
1.218 + const TText* text = aText.Ptr();
1.219 + TInt outputSize = 0;
1.220 +
1.221 + TRunInfoCompact currentRun;
1.222 + while (aArraySize)
1.223 + {
1.224 + TRunInfoCompact newRun(aRunArray->iStart, aRunArray->iLength,
1.225 + aRunArray->iDirection, text);
1.226 + --aArraySize;
1.227 + if (!currentRun.AddRun(newRun))
1.228 + {
1.229 + if (aBuffer)
1.230 + *aBuffer++ = currentRun;
1.231 + ++outputSize;
1.232 + currentRun = newRun;
1.233 + }
1.234 + ++aRunArray; //point to next run
1.235 + }
1.236 + if (0 < currentRun.Length())
1.237 + {
1.238 + if (aBuffer)
1.239 + *aBuffer++ = currentRun;
1.240 + ++outputSize;
1.241 + }
1.242 +
1.243 + return outputSize;
1.244 + }
1.245 +
1.246 +/**
1.247 +Utility tells whether a character will form a join with the previous
1.248 +base character.
1.249 +
1.250 +@param aText The text.
1.251 +@param aIndex The index into aText of the character to test.
1.252 +@return ETrue if there is a join before the character.
1.253 +*/
1.254 +TBool TRunInfoCompact::JoinBefore(const TText* aText, TInt aIndex)
1.255 + {
1.256 + TInt charUnderTest = aText[aIndex];
1.257 + if (!CFont::CharactersJoin(charUnderTest, KZeroWidthJoiner))
1.258 + // Character does not join with anything, so we
1.259 + // will not do any more work.
1.260 + return EFalse;
1.261 + while (aIndex != 0)
1.262 + {
1.263 + --aIndex;
1.264 + TInt c = aText[aIndex];
1.265 + // If it is an Arabic point, we will skip it.
1.266 + if (0x64B <= c && c < 0x671
1.267 + && !(0x656 <= c && c < 0x670))
1.268 + continue;
1.269 + return CFont::CharactersJoin(charUnderTest, c);
1.270 + }
1.271 + return EFalse;
1.272 + }