os/textandloc/textrendering/textformatting/test/src/TGraphemeIterator.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/textandloc/textrendering/textformatting/test/src/TGraphemeIterator.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1339 @@
     1.4 +/*
     1.5 +* Copyright (c) 2003-2010 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +* All rights reserved.
     1.7 +* This component and the accompanying materials are made available
     1.8 +* under the terms of "Eclipse Public License v1.0"
     1.9 +* which accompanies this distribution, and is available
    1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +*
    1.12 +* Initial Contributors:
    1.13 +* Nokia Corporation - initial contribution.
    1.14 +*
    1.15 +* Contributors:
    1.16 +*
    1.17 +* Description: 
    1.18 +* TGraphemeIterator.cpp unit tests for RTmGraphemeEdgeIterator
    1.19 +*
    1.20 +*/
    1.21 +
    1.22 +
    1.23 +#include "TestLayout.h"
    1.24 +#include "TGraphicsContext.h"
    1.25 +#include "TMINTERP.H"
    1.26 +
    1.27 +#include "tgraphemeiterator.h"
    1.28 +
    1.29 +namespace LocalToTGraphemeIterator
    1.30 +{
    1.31 +CTGraphemeIteratorStep* TestStep;
    1.32 +#define TESTPOINT(p) TestStep->testpoint(p,(TText8*)__FILE__,__LINE__)
    1.33 +#define TESTPRINT(p) TestStep->print(p,(TText8*)__FILE__,__LINE__)
    1.34 +
    1.35 +struct TTransliteration
    1.36 +    {
    1.37 +    const TText* iString;
    1.38 +    TInt iChar;
    1.39 +    };
    1.40 +static const TTransliteration KArabicTransliteration[] =
    1.41 +    {
    1.42 +    { reinterpret_cast<const TText*>(L"?"), 0x61F },
    1.43 +    { reinterpret_cast<const TText*>(L"`"), 0x621 },    // in-line hamza
    1.44 +    { reinterpret_cast<const TText*>(L"a"), 0x627 },    // alif
    1.45 +    { reinterpret_cast<const TText*>(L"b"), 0x628 },
    1.46 +    { reinterpret_cast<const TText*>(L"A"), 0x629 },    // teh marbuta
    1.47 +    { reinterpret_cast<const TText*>(L"t"), 0x62A },
    1.48 +    { reinterpret_cast<const TText*>(L"th"), 0x62B },
    1.49 +    { reinterpret_cast<const TText*>(L"j"), 0x62C },
    1.50 +    { reinterpret_cast<const TText*>(L"H"), 0x62D },    // hah
    1.51 +    { reinterpret_cast<const TText*>(L"kh"), 0x62E },
    1.52 +    { reinterpret_cast<const TText*>(L"d"), 0x62F },
    1.53 +    { reinterpret_cast<const TText*>(L"dh"), 0x630 },
    1.54 +    { reinterpret_cast<const TText*>(L"r"), 0x631 },
    1.55 +    { reinterpret_cast<const TText*>(L"z"), 0x632 },
    1.56 +    { reinterpret_cast<const TText*>(L"s"), 0x633 },
    1.57 +    { reinterpret_cast<const TText*>(L"sh"), 0x634 },
    1.58 +    { reinterpret_cast<const TText*>(L"S"), 0x635 },
    1.59 +    { reinterpret_cast<const TText*>(L"D"), 0x636 },
    1.60 +    { reinterpret_cast<const TText*>(L"T"), 0x637 },
    1.61 +    { reinterpret_cast<const TText*>(L"Z"), 0x638 },    // zah
    1.62 +    { reinterpret_cast<const TText*>(L"'"), 0x639 },    // ain
    1.63 +    { reinterpret_cast<const TText*>(L"g"), 0x63A },
    1.64 +    { reinterpret_cast<const TText*>(L"_"), 0x640 },    // kashida
    1.65 +    { reinterpret_cast<const TText*>(L"f"), 0x641 },
    1.66 +    { reinterpret_cast<const TText*>(L"q"), 0x642 },
    1.67 +    { reinterpret_cast<const TText*>(L"k"), 0x643 },
    1.68 +    { reinterpret_cast<const TText*>(L"l"), 0x644 },    // lam
    1.69 +    { reinterpret_cast<const TText*>(L"m"), 0x645 },
    1.70 +    { reinterpret_cast<const TText*>(L"n"), 0x646 },
    1.71 +    { reinterpret_cast<const TText*>(L"h"), 0x647 },    // heh
    1.72 +    { reinterpret_cast<const TText*>(L"w"), 0x648 },
    1.73 +    { reinterpret_cast<const TText*>(L"y"), 0x64A },
    1.74 +    { reinterpret_cast<const TText*>(L"^F"), 0x64B },   // fathatan
    1.75 +    { reinterpret_cast<const TText*>(L"^D"), 0x64C },   // dammatan
    1.76 +    { reinterpret_cast<const TText*>(L"^K"), 0x64D },   // kasratan
    1.77 +    { reinterpret_cast<const TText*>(L"^f"), 0x64E },   // fatha
    1.78 +    { reinterpret_cast<const TText*>(L"^d"), 0x64F },   // damma
    1.79 +    { reinterpret_cast<const TText*>(L"^k"), 0x650 },   // kasra
    1.80 +    { reinterpret_cast<const TText*>(L"^s"), 0x651 },   // shadda
    1.81 +    { reinterpret_cast<const TText*>(L"^h"), 0x652 },   // sukun
    1.82 +    { reinterpret_cast<const TText*>(L"^~"), 0x653 },   // maddah
    1.83 +    { reinterpret_cast<const TText*>(L"^`"), 0x654 },   // hamza above
    1.84 +    { reinterpret_cast<const TText*>(L"_`"), 0x653 },   // hamza below
    1.85 +    { reinterpret_cast<const TText*>(L"0"), 0x660 },
    1.86 +    { reinterpret_cast<const TText*>(L"1"), 0x661 },
    1.87 +    { reinterpret_cast<const TText*>(L"2"), 0x662 },
    1.88 +    { reinterpret_cast<const TText*>(L"3"), 0x663 },
    1.89 +    { reinterpret_cast<const TText*>(L"4"), 0x664 },
    1.90 +    { reinterpret_cast<const TText*>(L"5"), 0x665 },
    1.91 +    { reinterpret_cast<const TText*>(L"6"), 0x666 },
    1.92 +    { reinterpret_cast<const TText*>(L"7"), 0x667 },
    1.93 +    { reinterpret_cast<const TText*>(L"8"), 0x668 },
    1.94 +    { reinterpret_cast<const TText*>(L"9"), 0x669 }
    1.95 +    };
    1.96 +}
    1.97 +using namespace LocalToTGraphemeIterator;
    1.98 +
    1.99 +TText TransliterateSingle(const TText*& aInput, const TText* aEnd)
   1.100 +	{
   1.101 +	const TInt tableSize =
   1.102 +		sizeof(KArabicTransliteration)/sizeof(KArabicTransliteration[0]);
   1.103 +	for (TInt i = 0; i != tableSize; ++i)
   1.104 +		{
   1.105 +		const TText* p = KArabicTransliteration[i].iString;
   1.106 +		const TText* q = aInput;
   1.107 +		while (q != aEnd && *q == *p)
   1.108 +			{
   1.109 +			++q;
   1.110 +			++p;
   1.111 +			if (*p == '\0')
   1.112 +				{
   1.113 +				aInput = q;
   1.114 +				return static_cast<TText>(KArabicTransliteration[i].iChar);
   1.115 +				}
   1.116 +			}
   1.117 +		}
   1.118 +	TText result = *aInput;
   1.119 +	++aInput;
   1.120 +	return result;
   1.121 +	}
   1.122 +
   1.123 +// transliteration is turned on with { and off with }.
   1.124 +// use }{ to split digraphs.
   1.125 +void Transliterate(const TDesC& aIn, TDes& aOut)
   1.126 +	{
   1.127 +	const TText KTransliterationOn = '{';
   1.128 +	const TText KTransliterationOff = '}';
   1.129 +	TBool transliterating = EFalse;
   1.130 +	const TText* p = &aIn[0];
   1.131 +	const TText* pEnd = p + aIn.Length();
   1.132 +	while (p != pEnd)
   1.133 +		{
   1.134 +		if (!transliterating)
   1.135 +			{
   1.136 +			if (*p == KTransliterationOn)
   1.137 +				{
   1.138 +				transliterating = ETrue;
   1.139 +				++p;
   1.140 +				}
   1.141 +			else
   1.142 +				aOut.Append(*p++);
   1.143 +			}
   1.144 +		else
   1.145 +			{
   1.146 +			if (*p == KTransliterationOff)
   1.147 +				{
   1.148 +				transliterating = EFalse;
   1.149 +				++p;
   1.150 +				}
   1.151 +			else
   1.152 +				aOut.Append(TransliterateSingle(p, pEnd));
   1.153 +			}
   1.154 +		}
   1.155 +	}
   1.156 +
   1.157 +/**
   1.158 +Tests RTmGraphemeEdgeIterator::DocPosMatches for this document position and
   1.159 +edge.
   1.160 +*/
   1.161 +void TestDocPosMatchesCase(const TTmGraphemeEdgeInfo& aEdgeInfo,
   1.162 +	TTmDocPosSpec& aPosSpec,
   1.163 +	RTmGraphemeEdgeIterator::TGraphemeMatch aExpectedMatchType)
   1.164 +	{
   1.165 +	TInt start = aEdgeInfo.iPos.iDocPos.iPos;
   1.166 +	TInt end = start;
   1.167 +	if (aEdgeInfo.iPos.iDocPos.iLeadingEdge)
   1.168 +		end += aEdgeInfo.iCodePoints;
   1.169 +	else
   1.170 +		{
   1.171 +		start -= aEdgeInfo.iCodePoints - 1;
   1.172 +		++end;
   1.173 +		}
   1.174 +	aPosSpec.iPos = start - 1;
   1.175 +	TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
   1.176 +		== RTmGraphemeEdgeIterator::ENoMatch);
   1.177 +	for (TInt i = start; i != end; ++i)
   1.178 +		{
   1.179 +		aPosSpec.iPos = i;
   1.180 +		TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
   1.181 +			== aExpectedMatchType);
   1.182 +		}
   1.183 +	aPosSpec.iPos = end;
   1.184 +	TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
   1.185 +		== RTmGraphemeEdgeIterator::ENoMatch);
   1.186 +	}
   1.187 +
   1.188 +/**
   1.189 +Tests RTmGraphemeEdgeIterator::DocPosMatches for this edge and all relevant
   1.190 +document position specifications.
   1.191 +*/
   1.192 +void TestDocPosMatchesAllSpecs(const TTmGraphemeEdgeInfo& aEdgeInfo)
   1.193 +	{
   1.194 +	TTmDocPosSpec posSpec;
   1.195 +	RTmGraphemeEdgeIterator::TGraphemeMatch expected;
   1.196 +	posSpec.iType = TTmDocPosSpec::ELeftToRight;
   1.197 +	expected = aEdgeInfo.iPos.iRightToLeft?
   1.198 +		RTmGraphemeEdgeIterator::EPositionOnly
   1.199 +		: RTmGraphemeEdgeIterator::ETotalMatch;
   1.200 +	TestDocPosMatchesCase(aEdgeInfo, posSpec, expected);
   1.201 +	posSpec.iType = TTmDocPosSpec::ERightToLeft;
   1.202 +	expected = aEdgeInfo.iPos.iRightToLeft?
   1.203 +		RTmGraphemeEdgeIterator::ETotalMatch
   1.204 +		: RTmGraphemeEdgeIterator::EPositionOnly;
   1.205 +	TestDocPosMatchesCase(aEdgeInfo, posSpec, expected);
   1.206 +	posSpec.iType = TTmDocPosSpec::ETrailing;
   1.207 +	expected = aEdgeInfo.iPos.iDocPos.iLeadingEdge?
   1.208 +		RTmGraphemeEdgeIterator::ENoMatch
   1.209 +		: RTmGraphemeEdgeIterator::ETotalMatch;
   1.210 +	TestDocPosMatchesCase(aEdgeInfo, posSpec, expected);
   1.211 +	posSpec.iType = TTmDocPosSpec::ELeading;
   1.212 +	expected = aEdgeInfo.iPos.iDocPos.iLeadingEdge?
   1.213 +		RTmGraphemeEdgeIterator::ETotalMatch
   1.214 +		: RTmGraphemeEdgeIterator::ENoMatch;
   1.215 +	TestDocPosMatchesCase(aEdgeInfo, posSpec, expected);
   1.216 +	}
   1.217 +
   1.218 +/**
   1.219 +Tests RTmGraphemeEdgeIterator::DocPosMatches for a variety of edges and
   1.220 +positions.
   1.221 +*/
   1.222 +void TestDocPosMatches()
   1.223 +	{
   1.224 +	TTmGraphemeEdgeInfo edgeInfo;
   1.225 +	edgeInfo.iPos.iDocPos.iPos = 5;
   1.226 +	for (edgeInfo.iCodePoints = 1; edgeInfo.iCodePoints <= 3;
   1.227 +		++edgeInfo.iCodePoints)
   1.228 +		{
   1.229 +		edgeInfo.iPos.iDocPos.iLeadingEdge = ETrue;
   1.230 +		edgeInfo.iPos.iRightToLeft = EFalse;
   1.231 +		TestDocPosMatchesAllSpecs(edgeInfo);
   1.232 +		edgeInfo.iPos.iDocPos.iLeadingEdge = EFalse;
   1.233 +		TestDocPosMatchesAllSpecs(edgeInfo);
   1.234 +		edgeInfo.iPos.iRightToLeft = ETrue;
   1.235 +		TestDocPosMatchesAllSpecs(edgeInfo);
   1.236 +		edgeInfo.iPos.iDocPos.iLeadingEdge = ETrue;
   1.237 +		TestDocPosMatchesAllSpecs(edgeInfo);
   1.238 +		}
   1.239 +	}
   1.240 +
   1.241 +enum TEdgeType { ETrail, ELead };
   1.242 +enum TEdgeRelationship { EEdgeDifferent, EEdgeSame, EEdgeNewline };
   1.243 +enum TAmbiguity { EUnamb = 0, EAmb = 1 };
   1.244 +enum TDirectionality { EL2R = 0, ER2L = 1 };
   1.245 +struct TEdge
   1.246 +	{
   1.247 +	TInt iPos;
   1.248 +	TEdgeType iLeading;
   1.249 +	TEdgeRelationship iNext;
   1.250 +	TAmbiguity iAmbiguity;
   1.251 +	TDirectionality iRightToLeft;
   1.252 +	};
   1.253 +
   1.254 +_LIT(KLatin1, "Latin text\x2029Latin text over three          lines.");
   1.255 +static const TEdge KLatin1Edges[] =
   1.256 +	{
   1.257 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.258 +	{1, ETrail, EEdgeSame, EUnamb, EL2R}, {1, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.259 +	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {2, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.260 +	{3, ETrail, EEdgeSame, EUnamb, EL2R}, {3, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.261 +	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.262 +	{5, ETrail, EEdgeSame, EUnamb, EL2R}, {5, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.263 +	{6, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.264 +	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.265 +	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {8, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.266 +	{9, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.267 +	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeNewline, EUnamb, EL2R},
   1.268 +	{11, ETrail, EEdgeSame, EUnamb, EL2R}, {11, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.269 +	{12, ETrail, EEdgeSame, EUnamb, EL2R}, {12, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.270 +	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.271 +	{14, ETrail, EEdgeSame, EUnamb, EL2R}, {14, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.272 +	{15, ETrail, EEdgeSame, EUnamb, EL2R}, {15, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.273 +	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.274 +	{17, ETrail, EEdgeSame, EUnamb, EL2R}, {17, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.275 +	{18, ETrail, EEdgeSame, EUnamb, EL2R}, {18, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.276 +	{19, ETrail, EEdgeSame, EUnamb, EL2R}, {19, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.277 +	{20, ETrail, EEdgeSame, EUnamb, EL2R}, {20, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.278 +// This change tests the change made for DEF059214 which makes
   1.279 +// the trailing edges of line breaks over unambiguous text move to
   1.280 +// the start of the next line rather than hanging onto the end of
   1.281 +// the breaking line.
   1.282 +//	{21, ETrail, EEdgeSame, EUnamb, EL2R}, {21, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.283 +//	{22, ETrail, EEdgeNewline, EUnamb, EL2R}, {22, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.284 +	{21, ETrail, EEdgeSame, EUnamb, EL2R}, {21, ELead, EEdgeNewline, EUnamb, EL2R},
   1.285 +	{22, ETrail, EEdgeSame, EUnamb, EL2R}, {22, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.286 +	{23, ETrail, EEdgeSame, EUnamb, EL2R}, {23, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.287 +	{24, ETrail, EEdgeSame, EUnamb, EL2R}, {24, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.288 +	{25, ETrail, EEdgeSame, EUnamb, EL2R}, {25, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.289 +	{26, ETrail, EEdgeSame, EUnamb, EL2R}, {26, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.290 +	{27, ETrail, EEdgeSame, EUnamb, EL2R}, {27, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.291 +	{28, ETrail, EEdgeSame, EUnamb, EL2R}, {28, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.292 +	{29, ETrail, EEdgeSame, EUnamb, EL2R}, {29, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.293 +	{30, ETrail, EEdgeSame, EUnamb, EL2R}, {30, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.294 +	{31, ETrail, EEdgeSame, EUnamb, EL2R}, {31, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.295 +	{32, ETrail, EEdgeSame, EUnamb, EL2R}, {32, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.296 +	{33, ETrail, EEdgeSame, EUnamb, EL2R}, {33, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.297 +	{34, ETrail, EEdgeSame, EUnamb, EL2R}, {34, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.298 +	{35, ETrail, EEdgeSame, EUnamb, EL2R}, {35, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.299 +	{36, ETrail, EEdgeSame, EUnamb, EL2R}, {36, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.300 +	{37, ETrail, EEdgeSame, EUnamb, EL2R}, {37, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.301 +	{38, ETrail, EEdgeSame, EUnamb, EL2R}, {38, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.302 +	{39, ETrail, EEdgeSame, EUnamb, EL2R}, {39, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.303 +	{40, ETrail, EEdgeSame, EUnamb, EL2R}, {40, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.304 +// This change tests the change made for DEF059214
   1.305 +//	{41, ETrail, EEdgeSame, EUnamb, EL2R}, {41, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.306 +//	{42, ETrail, EEdgeNewline, EUnamb, EL2R}, {42, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.307 +// similar changes have been made to other tests.
   1.308 +	{41, ETrail, EEdgeSame, EUnamb, EL2R}, {41, ELead, EEdgeNewline, EUnamb, EL2R},
   1.309 +	{42, ETrail, EEdgeSame, EUnamb, EL2R}, {42, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.310 +	{43, ETrail, EEdgeSame, EUnamb, EL2R}, {43, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.311 +	{44, ETrail, EEdgeSame, EUnamb, EL2R}, {44, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.312 +	{45, ETrail, EEdgeSame, EUnamb, EL2R}, {45, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.313 +	{46, ETrail, EEdgeSame, EUnamb, EL2R}, {46, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.314 +	{47, ETrail, EEdgeSame, EUnamb, EL2R}, {47, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.315 +	{48, ETrail, EEdgeSame, EUnamb, EL2R}, {48, ELead, EEdgeNewline, EUnamb, EL2R},
   1.316 +	};
   1.317 +
   1.318 +_LIT(KArabic1, "{al'rbyA}\x2029{al'rbyA kf Sayd almwstfa}\x2029{lala lala}.");
   1.319 +static const TEdge KArabic1Edges[] =
   1.320 +	{
   1.321 +	{7, ELead, EEdgeSame, EUnamb, ER2L}, {7, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.322 +	{6, ELead, EEdgeSame, EUnamb, ER2L}, {6, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.323 +	{5, ELead, EEdgeSame, EUnamb, ER2L}, {5, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.324 +	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.325 +	{3, ELead, EEdgeSame, EUnamb, ER2L}, {3, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.326 +	{2, ELead, EEdgeSame, EUnamb, ER2L}, {2, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.327 +	{1, ELead, EEdgeSame, EUnamb, ER2L}, {1, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.328 +	{0, ELead, EEdgeSame, EUnamb, ER2L}, {0, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.329 +	{18, ELead, EEdgeSame, EUnamb, ER2L}, {18, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.330 +	{17, ELead, EEdgeSame, EUnamb, ER2L}, {17, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.331 +	{16, ELead, EEdgeSame, EUnamb, ER2L}, {16, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.332 +	{15, ELead, EEdgeSame, EUnamb, ER2L}, {15, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.333 +	{14, ELead, EEdgeSame, EUnamb, ER2L}, {14, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.334 +	{13, ELead, EEdgeSame, EUnamb, ER2L}, {13, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.335 +	{12, ELead, EEdgeSame, EUnamb, ER2L}, {12, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.336 +	{11, ELead, EEdgeSame, EUnamb, ER2L}, {11, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.337 +	{10, ELead, EEdgeSame, EUnamb, ER2L}, {10, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.338 +	{9, ELead, EEdgeSame, EUnamb, ER2L}, {9, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.339 +	{8, ELead, EEdgeSame, EUnamb, ER2L}, {8, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.340 +	{23, ELead, EEdgeSame, EUnamb, ER2L}, {23, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.341 +	{22, ELead, EEdgeSame, EUnamb, ER2L}, {22, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.342 +	{21, ELead, EEdgeSame, EUnamb, ER2L}, {21, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.343 +	{20, ELead, EEdgeSame, EUnamb, ER2L}, {20, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.344 +	{19, ELead, EEdgeSame, EUnamb, ER2L}, {19, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.345 +	{32, ELead, EEdgeSame, EUnamb, ER2L}, {32, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.346 +	{31, ELead, EEdgeSame, EUnamb, ER2L}, {31, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.347 +	{30, ELead, EEdgeSame, EUnamb, ER2L}, {30, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.348 +	{29, ELead, EEdgeSame, EUnamb, ER2L}, {29, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.349 +	{28, ELead, EEdgeSame, EUnamb, ER2L}, {28, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.350 +	{27, ELead, EEdgeSame, EUnamb, ER2L}, {27, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.351 +	{26, ELead, EEdgeSame, EUnamb, ER2L}, {26, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.352 +	{25, ELead, EEdgeSame, EUnamb, ER2L}, {25, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.353 +	{24, ELead, EEdgeSame, EUnamb, ER2L}, {24, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.354 +	{43, ELead, EEdgeSame, EUnamb, ER2L}, {43, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.355 +	{42, ELead, EEdgeSame, EUnamb, ER2L}, {42, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.356 +	{40, ELead, EEdgeSame, EUnamb, ER2L}, {40, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.357 +	{38, ELead, EEdgeSame, EUnamb, ER2L}, {38, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.358 +	{37, ELead, EEdgeSame, EUnamb, ER2L}, {37, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.359 +	{35, ELead, EEdgeSame, EUnamb, ER2L}, {35, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.360 +	{33, ELead, EEdgeSame, EUnamb, ER2L}, {33, ETrail, EEdgeNewline, EUnamb, ER2L}
   1.361 +	};
   1.362 +
   1.363 +// Add another example including combining marks and zero-width characters
   1.364 +_LIT(KCombiners1, "z\x300\x301\x302y\x300\x301\x302\x2029z\x300\x301\x302(\xFEFF)");
   1.365 +static const TEdge KCombiners1Edges[] =
   1.366 +	{
   1.367 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.368 +	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.369 +	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {8, ELead, EEdgeNewline, EUnamb, EL2R},
   1.370 +	{9, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ELead, EEdgeNewline, EUnamb, EL2R},
   1.371 +	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.372 +	{14, ETrail, EEdgeSame, EUnamb, EL2R}, {14, ELead, EEdgeSame, EUnamb, EL2R},
   1.373 +	{15, ETrail, EEdgeSame, EUnamb, EL2R}, {15, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.374 +	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeNewline, EUnamb, EL2R}
   1.375 +	};
   1.376 +
   1.377 +// Add another example including bidirectional text
   1.378 +_LIT(KBidi1, "A\x301{b^ft^k}12\x200FZ\x301");
   1.379 +static const TEdge KBidi1Edges[] =
   1.380 +	{
   1.381 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.382 +	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ETrail, EEdgeSame, EAmb, ER2L},
   1.383 +	{8, ELead, EEdgeSame, EUnamb, ER2L}, {6, ELead, EEdgeDifferent, EAmb, EL2R},
   1.384 +	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.385 +	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.386 +	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.387 +	{2, ELead, EEdgeSame, EUnamb, ER2L}, {9, ELead, EEdgeDifferent, EAmb, EL2R},
   1.388 +	{11, ETrail, EEdgeSame, EUnamb, EL2R}, {11, ELead, EEdgeNewline, EUnamb, EL2R}
   1.389 +	};
   1.390 +
   1.391 +// This example contains the "amtriguous" case where numbers
   1.392 +// are embedded within Arabic but are next to Latin.
   1.393 +_LIT(KBidi2, "A\x301{b^ft^k}12Z\x301");
   1.394 +static const TEdge KBidi2Edges[] =
   1.395 +	{
   1.396 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.397 +	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ELead, EEdgeDifferent, EAmb, EL2R},
   1.398 +	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.399 +	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.400 +	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.401 +	{2, ELead, EEdgeSame, EUnamb, ER2L}, {8, ELead, EEdgeDifferent, EAmb, EL2R},
   1.402 +	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeNewline, EUnamb, EL2R}
   1.403 +	};
   1.404 +
   1.405 +_LIT(KParagraphs1, "z\x2029{b}\x2029z");
   1.406 +static const TEdge KParagraphs1Edges[] =
   1.407 +	{
   1.408 +	// First line:
   1.409 +	// 0T 0L (Z) 1T 1L (ParagraphDelimiter)
   1.410 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.411 +	{1, ETrail, EEdgeSame, EUnamb, EL2R}, {1, ELead, EEdgeNewline, EUnamb, EL2R},
   1.412 +	// Second line:
   1.413 +	// (PD) 3L< 3T< (Beh) 2L< 2T<
   1.414 +	{3, ELead, EEdgeSame, EUnamb, ER2L}, {3, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.415 +	{2, ELead, EEdgeSame, EUnamb, ER2L}, {2, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.416 +	// Third line:
   1.417 +	// 4T 4L (Z) 5T 5L (NominalPD)
   1.418 +	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.419 +	{5, ETrail, EEdgeSame, EUnamb, EL2R}, {5, ELead, EEdgeNewline, EUnamb, EL2R}
   1.420 +	};
   1.421 +
   1.422 +// 2 characters per line
   1.423 +_LIT(KEmbedded1, "z{bb}z\x2029{b}zz{b}\x2029z{b}zz{b}z\x2029{b}z{bb}z{b}");
   1.424 +// T=trailing, L=leading, !=Ambiguous, <=Right-to-left
   1.425 +static const TEdge KEmbedded1Edges[] =
   1.426 +	{
   1.427 +	// First line:
   1.428 +	// 0T 0L (0Z) 1T! 2T!< (1Beh) 1L<
   1.429 +	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.430 +	{1, ETrail, EEdgeSame, EAmb, EL2R}, {2, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.431 +	{1, ELead, EEdgeNewline, EUnamb, ER2L},
   1.432 +	// Second line:
   1.433 +	// 3T< (2Beh) 2L!< 3L! (3Z) 4T 4L (4ParagraphDelimiter)
   1.434 +	{3, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.435 +	{2, ELead, EEdgeSame, EAmb, ER2L}, {3, ELead, EEdgeDifferent, EAmb, EL2R},
   1.436 +	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeNewline, EUnamb, EL2R},
   1.437 +	// Third line:
   1.438 +	// 6L (6Z) 7T! 6T!< (5Beh) 5L< 5T<
   1.439 +	{6, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.440 +	{7, ETrail, EEdgeSame, EAmb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.441 +	{5, ELead, EEdgeSame, EUnamb, ER2L}, {5, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.442 +	// Fourth line:
   1.443 +	// (9PD) 9L< 9T< (8Beh) 8L!< 7L! (7Z) 8T
   1.444 +	{9, ELead, EEdgeSame, EUnamb, ER2L}, {9, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.445 +	{8, ELead, EEdgeSame, EAmb, ER2L}, {7, ELead, EEdgeDifferent, EAmb, EL2R},
   1.446 +	{8, ETrail, EEdgeNewline, EUnamb, EL2R},
   1.447 +	// Fifth line:
   1.448 +	// 10T 10L (10Z) 11T! 12T!< (11Beh) 11L<
   1.449 +	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.450 +	{11, ETrail, EEdgeSame, EAmb, EL2R}, {12, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.451 +	{11, ELead, EEdgeNewline, EUnamb, ER2L},
   1.452 +	// Sixth line:
   1.453 +	// 12L (12Z) 13T 13L (13Z) 14T
   1.454 +	{12, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.455 +	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.456 +	{14, ETrail, EEdgeNewline, EUnamb, EL2R},
   1.457 +	// Seventh line:
   1.458 +	// 15T< (14Beh) 14L!< 15L! (15Z) 16T 16L (16PD)
   1.459 +	{15, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.460 +	{14, ELead, EEdgeSame, EAmb, ER2L}, {15, ELead, EEdgeDifferent, EAmb, EL2R},
   1.461 +	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeNewline, EUnamb, EL2R},
   1.462 +	// Eighth line:
   1.463 +	// 18L (18Z) 19T! 18T!< (17Beh) 17L< 17T<
   1.464 +	{18, ELead, EEdgeDifferent, EUnamb, EL2R},
   1.465 +	{19, ETrail, EEdgeSame, EAmb, EL2R}, {18, ETrail, EEdgeDifferent, EAmb, ER2L},
   1.466 +	{17, ELead, EEdgeSame, EUnamb, ER2L}, {17, ETrail, EEdgeNewline, EUnamb, ER2L},
   1.467 +	// Ninth line:
   1.468 +	// 21T< (20Beh) 20L< 20T< (19Beh) 19L<
   1.469 +	{21, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.470 +	{20, ELead, EEdgeSame, EUnamb, ER2L}, {20, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.471 +	{19, ELead, EEdgeNewline, EUnamb, ER2L},
   1.472 +	// Tenth line:
   1.473 +	// (23NominalPD) 23L< 23T< (22Beh) 22L!< 21L! (21Z) 22T
   1.474 +	{23, ELead, EEdgeSame, EUnamb, ER2L}, {23, ETrail, EEdgeDifferent, EUnamb, ER2L},
   1.475 +	{22, ELead, EEdgeSame, EAmb, ER2L}, {21, ELead, EEdgeDifferent, EAmb, EL2R},
   1.476 +	{22, ETrail, EEdgeNewline, EUnamb, EL2R},
   1.477 +	};
   1.478 +
   1.479 +/**
   1.480 +Returns which portion of the text is in the specified line.
   1.481 +*/
   1.482 +void LineExtent(TInt aLine, CTestTmTextLayout& aLayout,
   1.483 +	TInt& aLineStart, TInt& aLineEnd)
   1.484 +	{
   1.485 +	CTmTextLayout& layout = aLayout.Layout();
   1.486 +	TTmInterpreterParam interpParam(layout);
   1.487 +	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.488 +	interp.LineNumberToLine(aLine);
   1.489 +	aLineStart = interp.LineInfo().iStart;
   1.490 +	aLineEnd = interp.LineInfo().iEnd;
   1.491 +	}
   1.492 +
   1.493 +/**
   1.494 +Finds an edge in the expected edges list that matches a document position
   1.495 +specification.
   1.496 +*/
   1.497 +const TEdge* FindExpectedEdge(const TTmDocPosSpec& aPos,
   1.498 +	const TEdge* aExpected, TInt aNumExpected)
   1.499 +	{
   1.500 +	const TEdge* nearestTrailing = 0;
   1.501 +	TInt distanceTrailing = KMaxTInt;
   1.502 +	const TEdge* nearestLeading = 0;
   1.503 +	TInt distanceLeading = KMinTInt;
   1.504 +	for (const TEdge* e = aExpected; e != aExpected + aNumExpected; ++e)
   1.505 +		{
   1.506 +		TInt distance = e->iPos - aPos.iPos;
   1.507 +		if (!e->iLeading && 0 <= distance && distance < distanceTrailing)
   1.508 +			{
   1.509 +			distanceTrailing = distance;
   1.510 +			nearestTrailing = e;
   1.511 +			}
   1.512 +		if (e->iLeading && distanceLeading < distance && distance <= 0)
   1.513 +			{
   1.514 +			distanceLeading = distance;
   1.515 +			nearestLeading = e;
   1.516 +			}
   1.517 +		}
   1.518 +	if (aPos.iType == TTmDocPosSpec::ELeading || !nearestTrailing)
   1.519 +		{
   1.520 +		return nearestLeading;
   1.521 +		}
   1.522 +	if (aPos.iType == TTmDocPosSpec::ETrailing || !nearestLeading)
   1.523 +		{
   1.524 +		return nearestTrailing;
   1.525 +		}
   1.526 +	// Differences in iPos might be because pos is within a grapheme cluster,
   1.527 +	// or might be that the leading or trailing edge is not on that line.
   1.528 +	// Grapheme cluster differences are OK, not on the line differences will mean
   1.529 +	// that the one that does not match the input position is wrong.
   1.530 +	if (nearestLeading->iPos == aPos.iPos && nearestTrailing->iPos != aPos.iPos)
   1.531 +		return nearestLeading;
   1.532 +	if (nearestTrailing->iPos == aPos.iPos && nearestLeading->iPos != aPos.iPos)
   1.533 +		return nearestTrailing;
   1.534 +	TBool directionalitiesMatch = nearestTrailing->iRightToLeft?
   1.535 +		nearestLeading->iRightToLeft : !nearestLeading->iRightToLeft;
   1.536 +	if (directionalitiesMatch)
   1.537 +		return nearestLeading;
   1.538 +	TBool leadingIsCorrect = aPos.iType == TTmDocPosSpec::ERightToLeft?
   1.539 +		nearestLeading->iRightToLeft : !nearestLeading->iRightToLeft;
   1.540 +	return leadingIsCorrect? nearestLeading : nearestTrailing;
   1.541 +	}
   1.542 +
   1.543 +/**
   1.544 +Returns ETrue if and only if the two edges specified are expected to be
   1.545 +coincident.
   1.546 +*/
   1.547 +TBool ExpectedEdgesCoincide(const TEdge* aA, const TEdge* aB)
   1.548 +	{
   1.549 +	const TEdge* a = aA < aB? aA : aB;
   1.550 +	const TEdge* b = aA < aB? aB : aA;
   1.551 +	while (a != b)
   1.552 +		{
   1.553 +		if (a->iNext != EEdgeSame)
   1.554 +			return EFalse;
   1.555 +		++a;
   1.556 +		}
   1.557 +	return ETrue;
   1.558 +	}
   1.559 +
   1.560 +/**
   1.561 +Tests that the edge information matches the expected edge.
   1.562 +*/
   1.563 +void TestExpectedEdge(const TTmPosInfo2& aEdgeInfo,
   1.564 +	const TEdge* aExpected)
   1.565 +	{
   1.566 +	TESTPOINT(aEdgeInfo.iRightToLeft?
   1.567 +		aExpected->iRightToLeft : !aExpected->iRightToLeft);
   1.568 +	TESTPOINT(aEdgeInfo.iDocPos.iPos == aExpected->iPos);
   1.569 +	TESTPOINT(aEdgeInfo.iDocPos.iLeadingEdge?
   1.570 +		aExpected->iLeading : !aExpected->iLeading);
   1.571 +	}
   1.572 +
   1.573 +/**
   1.574 +Tests that the edge information matches one of the expected edges.
   1.575 +*/
   1.576 +void TestEdgeExists(const TTmPosInfo2& aEdgeInfo,
   1.577 +	const TEdge* aExpected, TInt aNumExpected)
   1.578 +	{
   1.579 +	TTmDocPos pos(aEdgeInfo.iDocPos);
   1.580 +	const TEdge* edge = FindExpectedEdge(pos, aExpected, aNumExpected);
   1.581 +	TESTPOINT(edge != 0);
   1.582 +	TestExpectedEdge(aEdgeInfo, edge);
   1.583 +	}
   1.584 +
   1.585 +/**
   1.586 +Tests that the visual position matches one of the expected edges.
   1.587 +*/
   1.588 +void TestVisualPositionExists(const TTmVisualDocPos& aPos,
   1.589 +	const TEdge* aExpected, TInt aNumExpected)
   1.590 +	{
   1.591 +    TESTPOINT(aPos.Ambiguity() != TTmVisualDocPos::ENotFound);
   1.592 +	TTmDocPos posLeft(aPos.LeftEdge().iDocPos);
   1.593 +	const TEdge* left = FindExpectedEdge(posLeft, aExpected, aNumExpected);
   1.594 +	TestExpectedEdge(aPos.LeftEdge(), left);
   1.595 +	TTmDocPos posRight(aPos.RightEdge().iDocPos);
   1.596 +	const TEdge* right = FindExpectedEdge(posRight, aExpected, aNumExpected);
   1.597 +	TestExpectedEdge(aPos.RightEdge(), right);
   1.598 +	TESTPOINT( (aPos.Ambiguity() == TTmVisualDocPos::EAmbiguous
   1.599 +			&& left->iAmbiguity && right->iAmbiguity)
   1.600 +		|| (aPos.Ambiguity() != TTmVisualDocPos::EAmbiguous
   1.601 +			&& !left->iAmbiguity && !right->iAmbiguity) );
   1.602 +	TESTPOINT(ExpectedEdgesCoincide(left, right));
   1.603 +	}
   1.604 +
   1.605 +/**
   1.606 +Tests that a RTmGraphemeEdgeIterator iterates through all the positions in a
   1.607 +line from left to right.
   1.608 +*/
   1.609 +void TestLayoutSimplePass(CTestTmTextLayout& aLayout,
   1.610 +	const TEdge* aExpected, TInt aNumExpected)
   1.611 +	{
   1.612 +	CTmTextLayout& layout = aLayout.Layout();
   1.613 +	TTmInterpreterParam interpParam(layout);
   1.614 +	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.615 +	interp.LineNumberToLine(0);
   1.616 +	RTmGraphemeEdgeIterator it;
   1.617 +	it.Begin(interp);
   1.618 +	TTmPosInfo2 last = it.GetInfo();
   1.619 +	for (TInt i = 0; i != aNumExpected; ++i)
   1.620 +		{
   1.621 +		const TEdge& expected = aExpected[i];
   1.622 +		TESTPOINT(expected.iPos == last.iDocPos.iPos);
   1.623 +		TESTPOINT(expected.iLeading == last.iDocPos.iLeadingEdge);
   1.624 +		it.Next();
   1.625 +		if (it.AtEnd())
   1.626 +			{
   1.627 +            TESTPOINT(expected.iNext == EEdgeNewline);
   1.628 +			while (interp.Op() != TTmInterpreter::EOpLine && interp.Next())
   1.629 +				{}
   1.630 +			if (i + 1 != aNumExpected)
   1.631 +				{
   1.632 +				it.Begin(interp);
   1.633 +				last = it.GetInfo();
   1.634 +				}
   1.635 +			}
   1.636 +		else
   1.637 +			{
   1.638 +			TTmPosInfo2 thisOne = it.GetInfo();
   1.639 +			TestEdgeExists(thisOne, aExpected, aNumExpected);
   1.640 +			TESTPOINT(expected.iNext != EEdgeNewline);
   1.641 +			if (expected.iNext == EEdgeSame)
   1.642 +			    TESTPOINT(last.iEdge.iX == thisOne.iEdge.iX);
   1.643 +			else if (expected.iNext == EEdgeDifferent)
   1.644 +			    TESTPOINT(last.iEdge.iX != thisOne.iEdge.iX);
   1.645 +			last = thisOne;
   1.646 +			}
   1.647 +		}
   1.648 +	it.Close();
   1.649 +	interp.Close();
   1.650 +	}
   1.651 +
   1.652 +/**
   1.653 +Tests that FindXPos returns the edge 'closest' to the input co-ordinate
   1.654 +where there is no ambiguity.
   1.655 +*/
   1.656 +void TestLayoutFindXPosEdges(TInt aLine,
   1.657 +	CTestTmTextLayout& aLayout,
   1.658 +	const TEdge* aExpected, TInt aNumExpected)
   1.659 +	{
   1.660 +	CTmTextLayout& layout = aLayout.Layout();
   1.661 +	TTmInterpreterParam interpParam(layout);
   1.662 +	TTmPosInfo2 posInfo;
   1.663 +	TTmDocPosSpec posSpec;
   1.664 +	TTmLineInfo lineInfo;
   1.665 +	TTmVisualDocPos visPos;
   1.666 +	for (TInt i = 0; i != aNumExpected - 1; ++i)
   1.667 +		{
   1.668 +		const TEdge& expectedL = aExpected[i];
   1.669 +		const TEdge& expectedR = aExpected[i + 1];
   1.670 +		if (expectedL.iNext == EEdgeDifferent)
   1.671 +			{
   1.672 +			// This code assumes that no character has a width of exactly 1 pixel.
   1.673 +			if (!expectedL.iAmbiguity)
   1.674 +				{
   1.675 +				posSpec.iPos = expectedL.iPos;
   1.676 +				posSpec.iType = expectedL.iLeading?
   1.677 +					TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing;
   1.678 +				layout.FindDocPos(posSpec, posInfo, lineInfo);
   1.679 +				RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.680 +				interp.LineNumberToLine(aLine);
   1.681 +				RTmGraphemeEdgeIterator it;
   1.682 +				it.Begin(interp);
   1.683 +				it.FindXPos(posInfo.iEdge.iX, visPos);
   1.684 +				TESTPOINT(visPos.Ambiguity() != TTmVisualDocPos::EAmbiguous);
   1.685 +				TESTPOINT(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
   1.686 +				TESTPOINT(visPos.LeftEdge().iDocPos.iPos == expectedL.iPos);
   1.687 +				TESTPOINT(visPos.LeftEdge().iDocPos.iLeadingEdge?
   1.688 +					expectedL.iLeading : !expectedL.iLeading);
   1.689 +				it.Close();
   1.690 +				interp.Close();
   1.691 +				}
   1.692 +			if (!expectedR.iAmbiguity)
   1.693 +				{
   1.694 +				posSpec.iPos = expectedR.iPos;
   1.695 +				posSpec.iType = expectedR.iLeading?
   1.696 +					TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing;
   1.697 +				layout.FindDocPos(posSpec, posInfo, lineInfo);
   1.698 +				RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.699 +				interp.LineNumberToLine(aLine);
   1.700 +				RTmGraphemeEdgeIterator it;
   1.701 +				it.Begin(interp);
   1.702 +				it.FindXPos(posInfo.iEdge.iX - 1, visPos);
   1.703 +				TESTPOINT(visPos.Ambiguity() != TTmVisualDocPos::EAmbiguous);
   1.704 +				TESTPOINT(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
   1.705 +				TESTPOINT(visPos.LeftEdge().iDocPos.iPos == expectedR.iPos);
   1.706 +				TESTPOINT(visPos.LeftEdge().iDocPos.iLeadingEdge?
   1.707 +					expectedR.iLeading : !expectedR.iLeading);
   1.708 +				it.Close();
   1.709 +				interp.Close();
   1.710 +				}
   1.711 +			}
   1.712 +		}
   1.713 +	}
   1.714 +
   1.715 +/**
   1.716 +Tests that RTmGraphemeEdgeIterator::FindXPos finds document positions that
   1.717 +match the positions they are supposed to be in.
   1.718 +*/
   1.719 +void TestLayoutFindXPos(TInt aLine,
   1.720 +	CTestTmTextLayout& aLayout,
   1.721 +	const TEdge* aExpected, TInt aNumExpected)
   1.722 +	{
   1.723 +	TInt lastLeftX = KMinTInt;
   1.724 +	TInt lastRightX = KMinTInt;
   1.725 +	TTmVisualDocPos visPos;
   1.726 +	TBool finished = EFalse;
   1.727 +	for (TInt x = -10; !finished; ++x)
   1.728 +		{
   1.729 +		CTmTextLayout& layout = aLayout.Layout();
   1.730 +		TTmInterpreterParam interpParam(layout);
   1.731 +		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.732 +		interp.LineNumberToLine(aLine);
   1.733 +		RTmGraphemeEdgeIterator it;
   1.734 +		it.Begin(interp);
   1.735 +		it.FindXPos(x, visPos);
   1.736 +		TestVisualPositionExists(visPos, aExpected, aNumExpected);
   1.737 +		TESTPOINT(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
   1.738 +		TESTPOINT(visPos.LeftEdge().iEdge.iX <= visPos.RightEdge().iEdge.iX);
   1.739 +		TESTPOINT(visPos.Ambiguity() == TTmVisualDocPos::EAmbiguous
   1.740 +			|| visPos.LeftEdge().iEdge.iX == visPos.RightEdge().iEdge.iX);
   1.741 +		TESTPOINT(lastLeftX <= visPos.LeftEdge().iEdge.iX);
   1.742 +		if (lastLeftX == visPos.LeftEdge().iEdge.iX)
   1.743 +			{
   1.744 +            TESTPOINT(lastRightX == visPos.RightEdge().iEdge.iX);
   1.745 +			while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
   1.746 +				|| aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
   1.747 +				{
   1.748 +                TESTPOINT(aExpected->iNext == EEdgeSame);
   1.749 +                TESTPOINT(0 < aNumExpected);
   1.750 +				++aExpected;
   1.751 +				--aNumExpected;
   1.752 +				}
   1.753 +			}
   1.754 +		else
   1.755 +			{
   1.756 +            TESTPOINT(lastRightX <= visPos.LeftEdge().iEdge.iX);
   1.757 +			while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
   1.758 +				|| aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
   1.759 +				{
   1.760 +                TESTPOINT(0 < aNumExpected);
   1.761 +				++aExpected;
   1.762 +				--aNumExpected;
   1.763 +				}
   1.764 +			}
   1.765 +		if (interp.LineInfo().iInnerRect.iBr.iX + 120 < x)
   1.766 +			finished = ETrue;
   1.767 +		it.Close();
   1.768 +		interp.Close();
   1.769 +		}
   1.770 +	while (aExpected->iNext != EEdgeNewline)
   1.771 +		{
   1.772 +        TESTPOINT(aExpected->iNext == EEdgeSame);
   1.773 +        TESTPOINT(0 < aNumExpected);
   1.774 +		++aExpected;
   1.775 +		--aNumExpected;
   1.776 +		}
   1.777 +	}
   1.778 +
   1.779 +/**
   1.780 +Uses RTmGraphemeEdgeIterator::FindEdge to find a document position in a
   1.781 +CTestTmTextLayout.
   1.782 +*/
   1.783 +TBool FindEdgeFromLayout(CTestTmTextLayout& aLayout, TInt aLine,
   1.784 +	const TTmDocPosSpec& aDocPos, TTmPosInfo2& aInfo)
   1.785 +	{
   1.786 +	CTmTextLayout& layout = aLayout.Layout();
   1.787 +	TTmInterpreterParam interpParam(layout);
   1.788 +	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.789 +	interp.LineNumberToLine(aLine);
   1.790 +	RTmGraphemeEdgeIterator it;
   1.791 +	it.Begin(interp);
   1.792 +	TBool result = it.FindEdge(aDocPos, aInfo);
   1.793 +	it.Close();
   1.794 +	interp.Close();
   1.795 +	return result;
   1.796 +	}
   1.797 +
   1.798 +/**
   1.799 +Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
   1.800 +specifications of leading or trailing edges.
   1.801 +*/
   1.802 +void TestLayoutFindEdgesInVisualOrder(TInt aLine,
   1.803 +	CTestTmTextLayout& aLayout,
   1.804 +	const TEdge* aExpected, TInt aNumExpected)
   1.805 +	{
   1.806 +	TInt lastX = KMinTInt;
   1.807 +	TBool sameExpected = EFalse;
   1.808 +	TTmPosInfo2 posInfo;
   1.809 +	while (aNumExpected != 0)
   1.810 +		{
   1.811 +		TTmDocPosSpec posSpec(aExpected->iPos, aExpected->iLeading?
   1.812 +			TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing);
   1.813 +		FindEdgeFromLayout(aLayout, aLine, posSpec, posInfo);
   1.814 +		TestEdgeExists(posInfo, aExpected, aNumExpected);
   1.815 +		TESTPOINT(aExpected->iLeading?
   1.816 +			posInfo.iDocPos.iLeadingEdge : !posInfo.iDocPos.iLeadingEdge);
   1.817 +		TESTPOINT(aExpected->iPos == posInfo.iDocPos.iPos);
   1.818 +		TESTPOINT(sameExpected || posInfo.iEdge.iX != lastX);
   1.819 +		TESTPOINT(!sameExpected || posInfo.iEdge.iX == lastX);
   1.820 +		lastX = posInfo.iEdge.iX;
   1.821 +		sameExpected = aExpected->iNext == EEdgeSame? ETrue : EFalse;
   1.822 +		++aExpected;
   1.823 +		--aNumExpected;
   1.824 +		}
   1.825 +	}
   1.826 +
   1.827 +/**
   1.828 +Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
   1.829 +specifications of directionality.
   1.830 +*/
   1.831 +void TestLayoutFindEdgesByDirectionality(TInt aLine,
   1.832 +	CTestTmTextLayout& aLayout,
   1.833 +	const TEdge* aExpected, TInt aNumExpected)
   1.834 +	{
   1.835 +	TInt lineStart;
   1.836 +	TInt lineEnd;
   1.837 +	LineExtent(aLine, aLayout, lineStart, lineEnd);
   1.838 +	TTmPosInfo2 lToRPosInfo;
   1.839 +	TTmPosInfo2 rToLPosInfo;
   1.840 +	for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
   1.841 +		{
   1.842 +		TTmDocPosSpec rToLPosSpec(pos, TTmDocPosSpec::ERightToLeft);
   1.843 +		TBool rToLFound = FindEdgeFromLayout(aLayout, aLine, rToLPosSpec, rToLPosInfo);
   1.844 +		TTmDocPosSpec lToRPosSpec(pos, TTmDocPosSpec::ELeftToRight);
   1.845 +		TBool lToRFound = FindEdgeFromLayout(aLayout, aLine, lToRPosSpec, lToRPosInfo);
   1.846 +		if (!lToRFound)
   1.847 +			{
   1.848 +            TESTPOINT(!rToLFound);
   1.849 +            TESTPOINT(pos < lineStart || lineEnd <= pos);
   1.850 +			}
   1.851 +		else
   1.852 +			{
   1.853 +            TESTPOINT(rToLFound);
   1.854 +			TestEdgeExists(rToLPosInfo, aExpected, aNumExpected);
   1.855 +			TestEdgeExists(lToRPosInfo, aExpected, aNumExpected);
   1.856 +			// Now find the nearest edges in the expected range
   1.857 +			TTmDocPosSpec trailingPosSpec(pos, TTmDocPosSpec::ETrailing);
   1.858 +			const TEdge* trailingExpected
   1.859 +				= FindExpectedEdge(trailingPosSpec, aExpected, aNumExpected);
   1.860 +			TTmDocPosSpec leadingPosSpec(pos, TTmDocPosSpec::ELeading);
   1.861 +			const TEdge* leadingExpected
   1.862 +				= FindExpectedEdge(leadingPosSpec, aExpected, aNumExpected);
   1.863 +			if (!trailingExpected)
   1.864 +				trailingExpected = leadingExpected;
   1.865 +			if (!leadingExpected)
   1.866 +				leadingExpected = trailingExpected;
   1.867 +			const TEdge* rToLPosEdge
   1.868 +				= FindExpectedEdge(rToLPosInfo.iDocPos, aExpected, aNumExpected);
   1.869 +			const TEdge* lToRPosEdge
   1.870 +				= FindExpectedEdge(lToRPosInfo.iDocPos, aExpected, aNumExpected);
   1.871 +			TESTPOINT(leadingExpected != 0);
   1.872 +			TESTPOINT(trailingExpected != 0);
   1.873 +			TESTPOINT(ExpectedEdgesCoincide(leadingExpected, rToLPosEdge)
   1.874 +				|| ExpectedEdgesCoincide(trailingExpected, rToLPosEdge));
   1.875 +			TESTPOINT(ExpectedEdgesCoincide(leadingExpected, lToRPosEdge)
   1.876 +				|| ExpectedEdgesCoincide(trailingExpected, lToRPosEdge));
   1.877 +			// Also check that the "found" ones are at least as good as the
   1.878 +			// "expected" ones.
   1.879 +			TESTPOINT(rToLPosInfo.iRightToLeft
   1.880 +				|| (!leadingExpected->iRightToLeft && !trailingExpected->iRightToLeft));
   1.881 +			TESTPOINT(!lToRPosInfo.iRightToLeft
   1.882 +				|| (leadingExpected->iRightToLeft && trailingExpected->iRightToLeft));
   1.883 +			}
   1.884 +		}
   1.885 +	}
   1.886 +
   1.887 +/**
   1.888 +Tests RTmGraphemeEdgeIterator::FindEdgeRightwards or
   1.889 +RTmGraphemeEdgeIterator::FindEdgeLeftwards.
   1.890 +*/
   1.891 +void TestLayoutFindEdgesLeftRight(TInt aLine,
   1.892 +	CTestTmTextLayout& aLayout, TBool aRightwards,
   1.893 +	const TEdge* aExpected, TInt aNumExpected)
   1.894 +	{
   1.895 +	TInt lineStart;
   1.896 +	TInt lineEnd;
   1.897 +	LineExtent(aLine, aLayout, lineStart, lineEnd);
   1.898 +	TTmPosInfo2 nearest;
   1.899 +	TTmVisualDocPos next;
   1.900 +	const TTmDocPosSpec::TType types[4]
   1.901 +		= {TTmDocPosSpec::ETrailing,
   1.902 +		TTmDocPosSpec::ELeading,
   1.903 +		TTmDocPosSpec::ELeftToRight,
   1.904 +		TTmDocPosSpec::ERightToLeft};
   1.905 +
   1.906 +	for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
   1.907 +		{
   1.908 +		for (TInt type = 0; type != 4; ++type)
   1.909 +			{
   1.910 +			TTmDocPosSpec posSpec(pos, types[type]);
   1.911 +
   1.912 +			// What do we expect the nearest to be?
   1.913 +			TTmDocPosSpec leadingPosSpec(pos, TTmDocPosSpec::ELeading);
   1.914 +			TTmDocPosSpec trailingPosSpec(pos, TTmDocPosSpec::ETrailing);
   1.915 +
   1.916 +			const TEdge* leadingExpected
   1.917 +				= FindExpectedEdge(leadingPosSpec, aExpected, aNumExpected);
   1.918 +			const TEdge* trailingExpected
   1.919 +				= FindExpectedEdge(trailingPosSpec, aExpected, aNumExpected);
   1.920 +
   1.921 +			// but should we expect anything at all?
   1.922 +			if (pos < lineStart || lineEnd < pos)
   1.923 +				leadingExpected = trailingExpected = 0;
   1.924 +			if (posSpec.iType == TTmDocPosSpec::ELeading
   1.925 +				&& (!leadingExpected || !leadingExpected->iLeading))
   1.926 +				leadingExpected = trailingExpected = 0;
   1.927 +			if (posSpec.iType == TTmDocPosSpec::ETrailing
   1.928 +				&& (!trailingExpected || trailingExpected->iLeading))
   1.929 +				leadingExpected = trailingExpected = 0;
   1.930 +
   1.931 +			// <lineEnd, trailing> is the only element that may be present
   1.932 +			// at position lineEnd.
   1.933 +			if (pos == lineEnd)
   1.934 +				{
   1.935 +				// If we are looking for a leading edge, we won't find
   1.936 +				// the trailing even if it is there.
   1.937 +				if (posSpec.iType == TTmDocPosSpec::ELeading
   1.938 +					|| !trailingExpected
   1.939 +					|| trailingExpected->iPos != pos)
   1.940 +					leadingExpected = trailingExpected = 0;
   1.941 +				}
   1.942 +			// <lineStart, trailing> may not be in the line.
   1.943 +			// We must check explicitly.
   1.944 +			if (pos == lineStart && posSpec.iType == TTmDocPosSpec::ETrailing)
   1.945 +				{
   1.946 +				// If there is no trailing edge at the start of the line
   1.947 +				// and we are looking for one, we
   1.948 +				// do not expect to have a nearest match there.
   1.949 +				if (!trailingExpected || trailingExpected->iPos != pos)
   1.950 +					leadingExpected = trailingExpected = 0;
   1.951 +				}
   1.952 +
   1.953 +			if (!leadingExpected)
   1.954 +				leadingExpected = trailingExpected;
   1.955 +			if (!trailingExpected)
   1.956 +				trailingExpected = leadingExpected;
   1.957 +
   1.958 +			const TEdge* nextExpected = 0;
   1.959 +
   1.960 +			CTmTextLayout& layout = aLayout.Layout();
   1.961 +			TTmInterpreterParam interpParam(layout);
   1.962 +			RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
   1.963 +			interp.LineNumberToLine(aLine);
   1.964 +			RTmGraphemeEdgeIterator it;
   1.965 +			it.Begin(interp);
   1.966 +			RTmGraphemeEdgeIterator::TEdgesFound result = aRightwards?
   1.967 +				it.FindEdgeRightwards(posSpec, nearest, next)
   1.968 +				: it.FindEdgeLeftwards(posSpec, nearest, next);
   1.969 +			interp.Close();
   1.970 +
   1.971 +			// Does what we got match what we expect?
   1.972 +			if (!leadingExpected)
   1.973 +				{
   1.974 +                TESTPOINT(result == RTmGraphemeEdgeIterator::ENone);
   1.975 +				}
   1.976 +			else
   1.977 +				{
   1.978 +                TESTPOINT(result == RTmGraphemeEdgeIterator::ENearestOnly
   1.979 +					|| result == RTmGraphemeEdgeIterator::ENearestAndNext);
   1.980 +				TTmDocPosSpec nearestPos(nearest.iDocPos);
   1.981 +				const TEdge* nearestEdge
   1.982 +					= FindExpectedEdge(nearestPos, aExpected, aNumExpected);
   1.983 +				TestExpectedEdge(nearest, nearestEdge);
   1.984 +				const TEdge* matchingEdge = leadingExpected;
   1.985 +				if (posSpec.iType == TTmDocPosSpec::ELeading)
   1.986 +				    TESTPOINT(ExpectedEdgesCoincide(leadingExpected, nearestEdge));
   1.987 +				else if (posSpec.iType == TTmDocPosSpec::ETrailing)
   1.988 +					{
   1.989 +                    TESTPOINT(ExpectedEdgesCoincide(trailingExpected, nearestEdge));
   1.990 +					matchingEdge = trailingExpected;
   1.991 +					}
   1.992 +				else
   1.993 +					{
   1.994 +                    TESTPOINT(ExpectedEdgesCoincide(leadingExpected, nearestEdge)
   1.995 +						|| ExpectedEdgesCoincide(trailingExpected, nearestEdge));
   1.996 +					if (ExpectedEdgesCoincide(trailingExpected, nearestEdge))
   1.997 +						matchingEdge = trailingExpected;
   1.998 +					TBool directionalitiesMatch = leadingExpected->iRightToLeft?
   1.999 +						trailingExpected->iRightToLeft : !trailingExpected->iRightToLeft;
  1.1000 +					TBool foundCorrectDirectionality
  1.1001 +						= posSpec.iType == TTmDocPosSpec::ERightToLeft?
  1.1002 +							nearest.iRightToLeft : !nearest.iRightToLeft;
  1.1003 +					TESTPOINT(foundCorrectDirectionality || directionalitiesMatch);
  1.1004 +					}
  1.1005 +
  1.1006 +				// Find next edge in expected list
  1.1007 +				const TEdge* e = matchingEdge;
  1.1008 +				const TEdge* end = aRightwards?
  1.1009 +					aExpected + aNumExpected - 1
  1.1010 +					: aExpected;
  1.1011 +				TInt direction = aRightwards? 1 : -1;
  1.1012 +				while (nextExpected == 0 && e != end)
  1.1013 +					{
  1.1014 +					e += direction;
  1.1015 +					if (!ExpectedEdgesCoincide(e, matchingEdge))
  1.1016 +						nextExpected = e;
  1.1017 +					}
  1.1018 +				}
  1.1019 +			if (!nextExpected)
  1.1020 +			    TESTPOINT(result == RTmGraphemeEdgeIterator::ENone
  1.1021 +					|| result == RTmGraphemeEdgeIterator::ENearestOnly);
  1.1022 +			else
  1.1023 +				{
  1.1024 +                TESTPOINT(result == RTmGraphemeEdgeIterator::ENearestAndNext);
  1.1025 +				TestVisualPositionExists(next, aExpected, aNumExpected);
  1.1026 +				TESTPOINT(next.Ambiguity() != TTmVisualDocPos::ENotFound);
  1.1027 +				TTmDocPosSpec nextPosLeft(next.LeftEdge().iDocPos);
  1.1028 +				TESTPOINT(ExpectedEdgesCoincide(nextExpected,
  1.1029 +					FindExpectedEdge(nextPosLeft, aExpected, aNumExpected)));
  1.1030 +				TTmDocPosSpec nextPosRight(next.RightEdge().iDocPos);
  1.1031 +				TESTPOINT(ExpectedEdgesCoincide(nextExpected,
  1.1032 +					FindExpectedEdge(nextPosRight, aExpected, aNumExpected)));
  1.1033 +				}
  1.1034 +			it.Close();
  1.1035 +			}
  1.1036 +		}
  1.1037 +	}
  1.1038 +
  1.1039 +/**
  1.1040 +Tests RTmGraphemeEdgeIterator::FindEdgeRightwards.
  1.1041 +*/
  1.1042 +void TestLayoutFindEdgesRightwards(TInt aLine,
  1.1043 +	CTestTmTextLayout& aLayout,
  1.1044 +	const TEdge* aExpected, TInt aNumExpected)
  1.1045 +	{
  1.1046 +	TestLayoutFindEdgesLeftRight(aLine, aLayout, ETrue,
  1.1047 +		aExpected, aNumExpected);
  1.1048 +	}
  1.1049 +
  1.1050 +/**
  1.1051 +Tests RTmGraphemeEdgeIterator::FindEdgeLeftwards.
  1.1052 +*/
  1.1053 +void TestLayoutFindEdgesLeftwards(TInt aLine,
  1.1054 +	CTestTmTextLayout& aLayout,
  1.1055 +	const TEdge* aExpected, TInt aNumExpected)
  1.1056 +	{
  1.1057 +	TestLayoutFindEdgesLeftRight(aLine, aLayout, EFalse,
  1.1058 +		aExpected, aNumExpected);
  1.1059 +	}
  1.1060 +
  1.1061 +/**
  1.1062 +Tests RTmGraphemeEdgeIterator::NextPosition. Expected behaviour is to find the
  1.1063 +smallest number 'n' that is a position in the same line greater than the input 'i',
  1.1064 +where the positions <i, leading> and <n, trailing> are not coincident.
  1.1065 +*/
  1.1066 +void TestLayoutFindEdgesForwards(TInt aLine,
  1.1067 +	CTestTmTextLayout& aLayout,
  1.1068 +	const TEdge* aExpected, TInt aNumExpected)
  1.1069 +	{
  1.1070 +	TInt lineStart;
  1.1071 +	TInt lineEnd;
  1.1072 +	LineExtent(aLine, aLayout, lineStart, lineEnd);
  1.1073 +	for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
  1.1074 +		{
  1.1075 +		CTmTextLayout& layout = aLayout.Layout();
  1.1076 +		TTmInterpreterParam interpParam(layout);
  1.1077 +		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
  1.1078 +		interp.LineNumberToLine(aLine);
  1.1079 +		RTmGraphemeEdgeIterator it;
  1.1080 +		it.Begin(interp);
  1.1081 +		TInt result = it.NextPosition(i);
  1.1082 +		interp.Close();
  1.1083 +
  1.1084 +		if (result == KErrNotFound)
  1.1085 +			{
  1.1086 +			// Must be at or after the line's end.
  1.1087 +			// Try to find a later edge in the line...
  1.1088 +			TTmDocPosSpec in(i, TTmDocPosSpec::ELeading);
  1.1089 +			const TEdge* inEdge = FindExpectedEdge(in,
  1.1090 +				aExpected, aNumExpected);
  1.1091 +			TTmDocPosSpec out(result, TTmDocPosSpec::ETrailing);
  1.1092 +			const TEdge* outEdge = FindExpectedEdge(out,
  1.1093 +				aExpected, aNumExpected);
  1.1094 +			// ...and test that we failed.
  1.1095 +			TESTPOINT(!inEdge || inEdge->iPos <= i);
  1.1096 +			TESTPOINT(!outEdge || outEdge->iPos <= i);
  1.1097 +			}
  1.1098 +		else
  1.1099 +			{
  1.1100 +            TESTPOINT(i < result);
  1.1101 +			TTmDocPosSpec in(i, TTmDocPosSpec::ELeading);
  1.1102 +			const TEdge* inEdge = FindExpectedEdge(in,
  1.1103 +				aExpected, aNumExpected);
  1.1104 +			TTmDocPosSpec out(result, TTmDocPosSpec::ETrailing);
  1.1105 +			const TEdge* outEdge = FindExpectedEdge(out,
  1.1106 +				aExpected, aNumExpected);
  1.1107 +			TESTPOINT(outEdge != 0);
  1.1108 +			if (inEdge)
  1.1109 +				{
  1.1110 +                TESTPOINT(lineStart <= i);
  1.1111 +                TESTPOINT(!ExpectedEdgesCoincide(inEdge, outEdge));
  1.1112 +				for (TInt j = i + 1; j != result; ++j)
  1.1113 +					{
  1.1114 +					TTmDocPosSpec between(j, TTmDocPosSpec::ETrailing);
  1.1115 +					const TEdge* betweenEdge = FindExpectedEdge(between,
  1.1116 +						aExpected, aNumExpected);
  1.1117 +					TESTPOINT(betweenEdge != 0);
  1.1118 +					// Test that, if there actually is a <j, trailing> edge, it is
  1.1119 +					// coincident with <i, leading>. If the edge does not exist
  1.1120 +					// it does not matter. We can find out if it exists by checking
  1.1121 +					// whether the returned expected edge has the same position
  1.1122 +					// we asked for.
  1.1123 +					TESTPOINT(ExpectedEdgesCoincide(inEdge, betweenEdge)
  1.1124 +						|| j != betweenEdge->iPos);
  1.1125 +					}
  1.1126 +				}
  1.1127 +			else
  1.1128 +				{
  1.1129 +				// before the start means finding the first trailing edge
  1.1130 +				TESTPOINT (i < lineStart);
  1.1131 +				TInt leastTrailingEdge = KMaxTInt;
  1.1132 +				for (const TEdge* e = aExpected; e != aExpected + aNumExpected;
  1.1133 +					++e)
  1.1134 +					{
  1.1135 +					if (!e->iLeading && e->iPos < leastTrailingEdge)
  1.1136 +						leastTrailingEdge = e->iPos;
  1.1137 +					}
  1.1138 +				TESTPOINT(leastTrailingEdge == result);
  1.1139 +				}
  1.1140 +			}
  1.1141 +		it.Close();
  1.1142 +		}
  1.1143 +	}
  1.1144 +
  1.1145 +/**
  1.1146 +Tests RTmGraphemeEdgeIterator::PreviousPosition. Expected behaviour is to find the
  1.1147 +largest number 'n' that is a position in the same line smaller than the input 'i',
  1.1148 +where the positions <i, trailing> and <n, leading> are not coincident.
  1.1149 +*/
  1.1150 +void TestLayoutFindEdgesBackwards(TInt aLine,
  1.1151 +	CTestTmTextLayout& aLayout,
  1.1152 +	const TEdge* aExpected, TInt aNumExpected)
  1.1153 +	{
  1.1154 +	TInt lineStart;
  1.1155 +	TInt lineEnd;
  1.1156 +	LineExtent(aLine, aLayout, lineStart, lineEnd);
  1.1157 +	for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
  1.1158 +		{
  1.1159 +		CTmTextLayout& layout = aLayout.Layout();
  1.1160 +		TTmInterpreterParam interpParam(layout);
  1.1161 +		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
  1.1162 +		interp.LineNumberToLine(aLine);
  1.1163 +		RTmGraphemeEdgeIterator it;
  1.1164 +		it.Begin(interp);
  1.1165 +		TInt result = it.PreviousPosition(i);
  1.1166 +		interp.Close();
  1.1167 +
  1.1168 +		if (result == KErrNotFound)
  1.1169 +			{
  1.1170 +			// Must be at or before the line's beginning.
  1.1171 +			// Could possibly be that there are no leading edges in the line, but
  1.1172 +			// we'll ignore that possibility.
  1.1173 +			TESTPOINT(i <= lineStart);
  1.1174 +			}
  1.1175 +		else
  1.1176 +			{
  1.1177 +			TESTPOINT(result < i);
  1.1178 +			TTmDocPosSpec out(result, TTmDocPosSpec::ELeading);
  1.1179 +			const TEdge* outEdge = FindExpectedEdge(out,
  1.1180 +				aExpected, aNumExpected);
  1.1181 +			TESTPOINT(outEdge != 0);
  1.1182 +			TTmDocPosSpec in(i, TTmDocPosSpec::ETrailing);
  1.1183 +			const TEdge* inEdge = FindExpectedEdge(in,
  1.1184 +				aExpected, aNumExpected);
  1.1185 +			// if we could not find a trailing edge at this number, then we
  1.1186 +			// were beyond the end of the line.
  1.1187 +			if (inEdge && !inEdge->iLeading)
  1.1188 +				{
  1.1189 +				TESTPOINT(inEdge != 0);
  1.1190 +				TESTPOINT(!ExpectedEdgesCoincide(inEdge, outEdge));
  1.1191 +				for (TInt j = result + 1; j != i; ++j)
  1.1192 +					{
  1.1193 +					TTmDocPosSpec between(j, TTmDocPosSpec::ELeading);
  1.1194 +					const TEdge* betweenEdge = FindExpectedEdge(between,
  1.1195 +						aExpected, aNumExpected);
  1.1196 +					TESTPOINT(betweenEdge != 0);
  1.1197 +					// Test that, if there actually is a <j, trailing> edge, it is
  1.1198 +					// coincident with <i, leading>. If the edge does not exist
  1.1199 +					// it does not matter. We can find out if it exists by checking
  1.1200 +					// whether the returned expected edge has the same position
  1.1201 +					// we asked for.
  1.1202 +					TESTPOINT(ExpectedEdgesCoincide(inEdge, betweenEdge)
  1.1203 +						|| j != betweenEdge->iPos);
  1.1204 +					}
  1.1205 +				}
  1.1206 +			else
  1.1207 +				{
  1.1208 +				// after the end means finding the last leading edge
  1.1209 +				TInt greatestLeadingEdge = KMinTInt;
  1.1210 +				for (const TEdge* e = aExpected; e != aExpected + aNumExpected;
  1.1211 +					++e)
  1.1212 +					{
  1.1213 +					if (e->iLeading && greatestLeadingEdge < e->iPos)
  1.1214 +						greatestLeadingEdge = e->iPos;
  1.1215 +					}
  1.1216 +				TESTPOINT(greatestLeadingEdge == result);
  1.1217 +				}
  1.1218 +			}
  1.1219 +		it.Close();
  1.1220 +		}
  1.1221 +	}
  1.1222 +
  1.1223 +typedef void FTestLine(TInt aLine,
  1.1224 +	CTestTmTextLayout& aLayout,
  1.1225 +	const TEdge* aExpected, TInt aNumExpected);
  1.1226 +
  1.1227 +/**
  1.1228 +Runs a particular test for each line in the input data.
  1.1229 +*/
  1.1230 +void TestEachLine(FTestLine* aFn,
  1.1231 +	CTestTmTextLayout& aLayout, const TEdge* aExpected, TInt aNumExpected)
  1.1232 +	{
  1.1233 +	TInt line = 0;
  1.1234 +	TInt start = 0;
  1.1235 +	for (TInt end = 1; end != aNumExpected; ++end)
  1.1236 +		{
  1.1237 +		if (aExpected[end - 1].iNext == EEdgeNewline)
  1.1238 +			{
  1.1239 +			aFn(line, aLayout, aExpected + start, end - start);
  1.1240 +			start = end;
  1.1241 +			++line;
  1.1242 +			}
  1.1243 +		}
  1.1244 +	}
  1.1245 +
  1.1246 +/**
  1.1247 +Tests TTmGraphemeIterator and supporting functionality for the specified
  1.1248 +layout.
  1.1249 +*/
  1.1250 +void TestLayoutL(CTestTmTextLayout& aLayout,
  1.1251 +	const TEdge* aExpected, TInt aNumExpected)
  1.1252 +	{
  1.1253 +	TESTPRINT(_L("Simple iteration"));
  1.1254 +	TestLayoutSimplePass(aLayout, aExpected, aNumExpected);
  1.1255 +	TESTPRINT(_L("FindXPos"));
  1.1256 +	TestEachLine(TestLayoutFindXPos,
  1.1257 +		aLayout, aExpected, aNumExpected);
  1.1258 +	TESTPRINT(_L("FindXPos (unambiguous edges)"));
  1.1259 +	TestEachLine(TestLayoutFindXPosEdges,
  1.1260 +		aLayout, aExpected, aNumExpected);
  1.1261 +	TESTPRINT(_L("FindEdge"));
  1.1262 +	TestEachLine(TestLayoutFindEdgesInVisualOrder,
  1.1263 +		aLayout, aExpected, aNumExpected);
  1.1264 +	TestEachLine(TestLayoutFindEdgesByDirectionality,
  1.1265 +		aLayout, aExpected, aNumExpected);
  1.1266 +	TESTPRINT(_L("FindEdgeRightwards"));
  1.1267 +	TestEachLine(TestLayoutFindEdgesRightwards,
  1.1268 +		aLayout, aExpected, aNumExpected);
  1.1269 +	TESTPRINT(_L("FindEdgeLeftwards"));
  1.1270 +	TestEachLine(TestLayoutFindEdgesLeftwards,
  1.1271 +		aLayout, aExpected, aNumExpected);
  1.1272 +	TESTPRINT(_L("NextPosition"));
  1.1273 +	TestEachLine(TestLayoutFindEdgesForwards,
  1.1274 +		aLayout, aExpected, aNumExpected);
  1.1275 +	TESTPRINT(_L("PreviousPosition"));
  1.1276 +	TestEachLine(TestLayoutFindEdgesBackwards,
  1.1277 +		aLayout, aExpected, aNumExpected);
  1.1278 +	}
  1.1279 +
  1.1280 +/**
  1.1281 +Tests TTmGraphemeIterator and supporting functionality for each piece of text.
  1.1282 +*/
  1.1283 +TVerdict CTGraphemeIteratorStep::doTestStepL()
  1.1284 +	{
  1.1285 +    SetTestStepResult(EPass);
  1.1286 +    TestStep = this;
  1.1287 +    TESTPRINT(_L("RTmGraphemeEdgeIterator unit"));
  1.1288 +    
  1.1289 +    TESTPRINT(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-GRAPHEMEITERATOR-0001 DocPosMatches "));
  1.1290 +	TestDocPosMatches();
  1.1291 +	TESTPRINT(_L("Simple Latin"));
  1.1292 +	CTestTmTextLayout* latin1 = CTestTmTextLayout::NewLC(
  1.1293 +		KLatin1, 100, Transliterate);
  1.1294 +	TestLayoutL( *latin1, KLatin1Edges,
  1.1295 +		sizeof(KLatin1Edges)/sizeof(KLatin1Edges[0]));
  1.1296 +	CleanupStack::PopAndDestroy(latin1);
  1.1297 +
  1.1298 +	TESTPRINT(_L("Simple Arabic"));
  1.1299 +	CTestTmTextLayout* arabic1 = CTestTmTextLayout::NewLC(
  1.1300 +		KArabic1, 100, Transliterate);
  1.1301 +	TestLayoutL(*arabic1, KArabic1Edges,
  1.1302 +		sizeof(KArabic1Edges)/sizeof(KArabic1Edges[0]));
  1.1303 +	CleanupStack::PopAndDestroy(arabic1);
  1.1304 +
  1.1305 +	TESTPRINT(_L("Latin with combining marks and zero width characters"));
  1.1306 +	CTestTmTextLayout* combiners1 = CTestTmTextLayout::NewLC(
  1.1307 +		KCombiners1, 20, Transliterate);
  1.1308 +	TestLayoutL(*combiners1, KCombiners1Edges,
  1.1309 +		sizeof(KCombiners1Edges)/sizeof(KCombiners1Edges[0]));
  1.1310 +	CleanupStack::PopAndDestroy(combiners1);
  1.1311 +
  1.1312 +	TESTPRINT(_L("Bidirectional text with combining marks"));
  1.1313 +	CTestTmTextLayout* bidi1 = CTestTmTextLayout::NewLC(
  1.1314 +		KBidi1, 60, Transliterate);
  1.1315 +	TestLayoutL( *bidi1, KBidi1Edges,
  1.1316 +		sizeof(KBidi1Edges)/sizeof(KBidi1Edges[0]));
  1.1317 +	CleanupStack::PopAndDestroy(bidi1);
  1.1318 +
  1.1319 +	TESTPRINT(_L("Bidirectional text with combining marks and 'amtriguity'"));
  1.1320 +	CTestTmTextLayout* bidi2 = CTestTmTextLayout::NewLC(
  1.1321 +		KBidi2, 60, Transliterate);
  1.1322 +	TestLayoutL(*bidi2, KBidi2Edges,
  1.1323 +		sizeof(KBidi2Edges)/sizeof(KBidi2Edges[0]));
  1.1324 +	CleanupStack::PopAndDestroy(bidi2);
  1.1325 +
  1.1326 +	TESTPRINT(_L("Small paragraphs of alternating directionality"));
  1.1327 +	CTestTmTextLayout* paragraphs1 = CTestTmTextLayout::NewLC(
  1.1328 +		KParagraphs1, 20, Transliterate);
  1.1329 +	TestLayoutL(*paragraphs1, KParagraphs1Edges,
  1.1330 +		sizeof(KParagraphs1Edges)/sizeof(KParagraphs1Edges[0]));
  1.1331 +	CleanupStack::PopAndDestroy(paragraphs1);
  1.1332 +
  1.1333 +	TESTPRINT(_L("Lines ending over or next to embedded runs"));
  1.1334 +	CTestTmTextLayout* embedded1 = CTestTmTextLayout::NewLC(
  1.1335 +		KEmbedded1, 20, Transliterate);
  1.1336 +	TestLayoutL( *embedded1, KEmbedded1Edges,
  1.1337 +		sizeof(KEmbedded1Edges)/sizeof(KEmbedded1Edges[0]));
  1.1338 +	CleanupStack::PopAndDestroy(embedded1);
  1.1339 +
  1.1340 +	return TestStepResult();
  1.1341 +	}
  1.1342 +