textrendering/textformatting/test/src/TGraphemeIterator.cpp
changeset 0 1fb32624e06b
child 51 a7c938434754
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 /*
       
     2 * Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 * TGraphemeIterator.cpp unit tests for RTmGraphemeEdgeIterator
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "TestLayout.h"
       
    21 #include "TGraphicsContext.h"
       
    22 #include "TMINTERP.H"
       
    23 
       
    24 #include <e32test.h>
       
    25 
       
    26 struct TTransliteration
       
    27 	{
       
    28 	const TText* iString;
       
    29 	TInt iChar;
       
    30 	};
       
    31 static const TTransliteration KArabicTransliteration[] =
       
    32 	{
       
    33 	{ reinterpret_cast<const TText*>(L"?"), 0x61F },
       
    34 	{ reinterpret_cast<const TText*>(L"`"), 0x621 },	// in-line hamza
       
    35 	{ reinterpret_cast<const TText*>(L"a"), 0x627 },	// alif
       
    36 	{ reinterpret_cast<const TText*>(L"b"), 0x628 },
       
    37 	{ reinterpret_cast<const TText*>(L"A"), 0x629 },	// teh marbuta
       
    38 	{ reinterpret_cast<const TText*>(L"t"), 0x62A },
       
    39 	{ reinterpret_cast<const TText*>(L"th"), 0x62B },
       
    40 	{ reinterpret_cast<const TText*>(L"j"), 0x62C },
       
    41 	{ reinterpret_cast<const TText*>(L"H"), 0x62D },	// hah
       
    42 	{ reinterpret_cast<const TText*>(L"kh"), 0x62E },
       
    43 	{ reinterpret_cast<const TText*>(L"d"), 0x62F },
       
    44 	{ reinterpret_cast<const TText*>(L"dh"), 0x630 },
       
    45 	{ reinterpret_cast<const TText*>(L"r"), 0x631 },
       
    46 	{ reinterpret_cast<const TText*>(L"z"), 0x632 },
       
    47 	{ reinterpret_cast<const TText*>(L"s"), 0x633 },
       
    48 	{ reinterpret_cast<const TText*>(L"sh"), 0x634 },
       
    49 	{ reinterpret_cast<const TText*>(L"S"), 0x635 },
       
    50 	{ reinterpret_cast<const TText*>(L"D"), 0x636 },
       
    51 	{ reinterpret_cast<const TText*>(L"T"), 0x637 },
       
    52 	{ reinterpret_cast<const TText*>(L"Z"), 0x638 },	// zah
       
    53 	{ reinterpret_cast<const TText*>(L"'"), 0x639 },	// ain
       
    54 	{ reinterpret_cast<const TText*>(L"g"), 0x63A },
       
    55 	{ reinterpret_cast<const TText*>(L"_"), 0x640 },	// kashida
       
    56 	{ reinterpret_cast<const TText*>(L"f"), 0x641 },
       
    57 	{ reinterpret_cast<const TText*>(L"q"), 0x642 },
       
    58 	{ reinterpret_cast<const TText*>(L"k"), 0x643 },
       
    59 	{ reinterpret_cast<const TText*>(L"l"), 0x644 },	// lam
       
    60 	{ reinterpret_cast<const TText*>(L"m"), 0x645 },
       
    61 	{ reinterpret_cast<const TText*>(L"n"), 0x646 },
       
    62 	{ reinterpret_cast<const TText*>(L"h"), 0x647 },	// heh
       
    63 	{ reinterpret_cast<const TText*>(L"w"), 0x648 },
       
    64 	{ reinterpret_cast<const TText*>(L"y"), 0x64A },
       
    65 	{ reinterpret_cast<const TText*>(L"^F"), 0x64B },	// fathatan
       
    66 	{ reinterpret_cast<const TText*>(L"^D"), 0x64C },	// dammatan
       
    67 	{ reinterpret_cast<const TText*>(L"^K"), 0x64D },	// kasratan
       
    68 	{ reinterpret_cast<const TText*>(L"^f"), 0x64E },	// fatha
       
    69 	{ reinterpret_cast<const TText*>(L"^d"), 0x64F },	// damma
       
    70 	{ reinterpret_cast<const TText*>(L"^k"), 0x650 },	// kasra
       
    71 	{ reinterpret_cast<const TText*>(L"^s"), 0x651 },	// shadda
       
    72 	{ reinterpret_cast<const TText*>(L"^h"), 0x652 },	// sukun
       
    73 	{ reinterpret_cast<const TText*>(L"^~"), 0x653 },	// maddah
       
    74 	{ reinterpret_cast<const TText*>(L"^`"), 0x654 },	// hamza above
       
    75 	{ reinterpret_cast<const TText*>(L"_`"), 0x653 },	// hamza below
       
    76 	{ reinterpret_cast<const TText*>(L"0"), 0x660 },
       
    77 	{ reinterpret_cast<const TText*>(L"1"), 0x661 },
       
    78 	{ reinterpret_cast<const TText*>(L"2"), 0x662 },
       
    79 	{ reinterpret_cast<const TText*>(L"3"), 0x663 },
       
    80 	{ reinterpret_cast<const TText*>(L"4"), 0x664 },
       
    81 	{ reinterpret_cast<const TText*>(L"5"), 0x665 },
       
    82 	{ reinterpret_cast<const TText*>(L"6"), 0x666 },
       
    83 	{ reinterpret_cast<const TText*>(L"7"), 0x667 },
       
    84 	{ reinterpret_cast<const TText*>(L"8"), 0x668 },
       
    85 	{ reinterpret_cast<const TText*>(L"9"), 0x669 }
       
    86 	};
       
    87 
       
    88 TText TransliterateSingle(const TText*& aInput, const TText* aEnd)
       
    89 	{
       
    90 	const TInt tableSize =
       
    91 		sizeof(KArabicTransliteration)/sizeof(KArabicTransliteration[0]);
       
    92 	for (TInt i = 0; i != tableSize; ++i)
       
    93 		{
       
    94 		const TText* p = KArabicTransliteration[i].iString;
       
    95 		const TText* q = aInput;
       
    96 		while (q != aEnd && *q == *p)
       
    97 			{
       
    98 			++q;
       
    99 			++p;
       
   100 			if (*p == '\0')
       
   101 				{
       
   102 				aInput = q;
       
   103 				return static_cast<TText>(KArabicTransliteration[i].iChar);
       
   104 				}
       
   105 			}
       
   106 		}
       
   107 	TText result = *aInput;
       
   108 	++aInput;
       
   109 	return result;
       
   110 	}
       
   111 
       
   112 // transliteration is turned on with { and off with }.
       
   113 // use }{ to split digraphs.
       
   114 void Transliterate(const TDesC& aIn, TDes& aOut)
       
   115 	{
       
   116 	const TText KTransliterationOn = '{';
       
   117 	const TText KTransliterationOff = '}';
       
   118 	TBool transliterating = EFalse;
       
   119 	const TText* p = &aIn[0];
       
   120 	const TText* pEnd = p + aIn.Length();
       
   121 	while (p != pEnd)
       
   122 		{
       
   123 		if (!transliterating)
       
   124 			{
       
   125 			if (*p == KTransliterationOn)
       
   126 				{
       
   127 				transliterating = ETrue;
       
   128 				++p;
       
   129 				}
       
   130 			else
       
   131 				aOut.Append(*p++);
       
   132 			}
       
   133 		else
       
   134 			{
       
   135 			if (*p == KTransliterationOff)
       
   136 				{
       
   137 				transliterating = EFalse;
       
   138 				++p;
       
   139 				}
       
   140 			else
       
   141 				aOut.Append(TransliterateSingle(p, pEnd));
       
   142 			}
       
   143 		}
       
   144 	}
       
   145 
       
   146 /**
       
   147 Tests RTmGraphemeEdgeIterator::DocPosMatches for this document position and
       
   148 edge.
       
   149 */
       
   150 void TestDocPosMatchesCase(RTest& aTest,
       
   151 	const TTmGraphemeEdgeInfo& aEdgeInfo,
       
   152 	TTmDocPosSpec& aPosSpec,
       
   153 	RTmGraphemeEdgeIterator::TGraphemeMatch aExpectedMatchType)
       
   154 	{
       
   155 	TInt start = aEdgeInfo.iPos.iDocPos.iPos;
       
   156 	TInt end = start;
       
   157 	if (aEdgeInfo.iPos.iDocPos.iLeadingEdge)
       
   158 		end += aEdgeInfo.iCodePoints;
       
   159 	else
       
   160 		{
       
   161 		start -= aEdgeInfo.iCodePoints - 1;
       
   162 		++end;
       
   163 		}
       
   164 	aPosSpec.iPos = start - 1;
       
   165 	aTest(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
       
   166 		== RTmGraphemeEdgeIterator::ENoMatch);
       
   167 	for (TInt i = start; i != end; ++i)
       
   168 		{
       
   169 		aPosSpec.iPos = i;
       
   170 		aTest(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
       
   171 			== aExpectedMatchType);
       
   172 		}
       
   173 	aPosSpec.iPos = end;
       
   174 	aTest(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
       
   175 		== RTmGraphemeEdgeIterator::ENoMatch);
       
   176 	}
       
   177 
       
   178 /**
       
   179 Tests RTmGraphemeEdgeIterator::DocPosMatches for this edge and all relevant
       
   180 document position specifications.
       
   181 */
       
   182 void TestDocPosMatchesAllSpecs(RTest& aTest,
       
   183 	const TTmGraphemeEdgeInfo& aEdgeInfo)
       
   184 	{
       
   185 	TTmDocPosSpec posSpec;
       
   186 	RTmGraphemeEdgeIterator::TGraphemeMatch expected;
       
   187 	posSpec.iType = TTmDocPosSpec::ELeftToRight;
       
   188 	expected = aEdgeInfo.iPos.iRightToLeft?
       
   189 		RTmGraphemeEdgeIterator::EPositionOnly
       
   190 		: RTmGraphemeEdgeIterator::ETotalMatch;
       
   191 	TestDocPosMatchesCase(aTest, aEdgeInfo, posSpec, expected);
       
   192 	posSpec.iType = TTmDocPosSpec::ERightToLeft;
       
   193 	expected = aEdgeInfo.iPos.iRightToLeft?
       
   194 		RTmGraphemeEdgeIterator::ETotalMatch
       
   195 		: RTmGraphemeEdgeIterator::EPositionOnly;
       
   196 	TestDocPosMatchesCase(aTest, aEdgeInfo, posSpec, expected);
       
   197 	posSpec.iType = TTmDocPosSpec::ETrailing;
       
   198 	expected = aEdgeInfo.iPos.iDocPos.iLeadingEdge?
       
   199 		RTmGraphemeEdgeIterator::ENoMatch
       
   200 		: RTmGraphemeEdgeIterator::ETotalMatch;
       
   201 	TestDocPosMatchesCase(aTest, aEdgeInfo, posSpec, expected);
       
   202 	posSpec.iType = TTmDocPosSpec::ELeading;
       
   203 	expected = aEdgeInfo.iPos.iDocPos.iLeadingEdge?
       
   204 		RTmGraphemeEdgeIterator::ETotalMatch
       
   205 		: RTmGraphemeEdgeIterator::ENoMatch;
       
   206 	TestDocPosMatchesCase(aTest, aEdgeInfo, posSpec, expected);
       
   207 	}
       
   208 
       
   209 /**
       
   210 Tests RTmGraphemeEdgeIterator::DocPosMatches for a variety of edges and
       
   211 positions.
       
   212 */
       
   213 void TestDocPosMatches(RTest& aTest)
       
   214 	{
       
   215 	TTmGraphemeEdgeInfo edgeInfo;
       
   216 	edgeInfo.iPos.iDocPos.iPos = 5;
       
   217 	for (edgeInfo.iCodePoints = 1; edgeInfo.iCodePoints <= 3;
       
   218 		++edgeInfo.iCodePoints)
       
   219 		{
       
   220 		edgeInfo.iPos.iDocPos.iLeadingEdge = ETrue;
       
   221 		edgeInfo.iPos.iRightToLeft = EFalse;
       
   222 		TestDocPosMatchesAllSpecs(aTest, edgeInfo);
       
   223 		edgeInfo.iPos.iDocPos.iLeadingEdge = EFalse;
       
   224 		TestDocPosMatchesAllSpecs(aTest, edgeInfo);
       
   225 		edgeInfo.iPos.iRightToLeft = ETrue;
       
   226 		TestDocPosMatchesAllSpecs(aTest, edgeInfo);
       
   227 		edgeInfo.iPos.iDocPos.iLeadingEdge = ETrue;
       
   228 		TestDocPosMatchesAllSpecs(aTest, edgeInfo);
       
   229 		}
       
   230 	}
       
   231 
       
   232 enum TEdgeType { ETrail, ELead };
       
   233 enum TEdgeRelationship { EEdgeDifferent, EEdgeSame, EEdgeNewline };
       
   234 enum TAmbiguity { EUnamb = 0, EAmb = 1 };
       
   235 enum TDirectionality { EL2R = 0, ER2L = 1 };
       
   236 struct TEdge
       
   237 	{
       
   238 	TInt iPos;
       
   239 	TEdgeType iLeading;
       
   240 	TEdgeRelationship iNext;
       
   241 	TAmbiguity iAmbiguity;
       
   242 	TDirectionality iRightToLeft;
       
   243 	};
       
   244 
       
   245 _LIT(KLatin1, "Latin text\x2029Latin text over three          lines.");
       
   246 static const TEdge KLatin1Edges[] =
       
   247 	{
       
   248 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   249 	{1, ETrail, EEdgeSame, EUnamb, EL2R}, {1, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   250 	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {2, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   251 	{3, ETrail, EEdgeSame, EUnamb, EL2R}, {3, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   252 	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   253 	{5, ETrail, EEdgeSame, EUnamb, EL2R}, {5, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   254 	{6, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   255 	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   256 	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {8, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   257 	{9, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   258 	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeNewline, EUnamb, EL2R},
       
   259 	{11, ETrail, EEdgeSame, EUnamb, EL2R}, {11, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   260 	{12, ETrail, EEdgeSame, EUnamb, EL2R}, {12, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   261 	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   262 	{14, ETrail, EEdgeSame, EUnamb, EL2R}, {14, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   263 	{15, ETrail, EEdgeSame, EUnamb, EL2R}, {15, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   264 	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   265 	{17, ETrail, EEdgeSame, EUnamb, EL2R}, {17, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   266 	{18, ETrail, EEdgeSame, EUnamb, EL2R}, {18, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   267 	{19, ETrail, EEdgeSame, EUnamb, EL2R}, {19, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   268 	{20, ETrail, EEdgeSame, EUnamb, EL2R}, {20, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   269 // This change tests the change made for DEF059214 which makes
       
   270 // the trailing edges of line breaks over unambiguous text move to
       
   271 // the start of the next line rather than hanging onto the end of
       
   272 // the breaking line.
       
   273 //	{21, ETrail, EEdgeSame, EUnamb, EL2R}, {21, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   274 //	{22, ETrail, EEdgeNewline, EUnamb, EL2R}, {22, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   275 	{21, ETrail, EEdgeSame, EUnamb, EL2R}, {21, ELead, EEdgeNewline, EUnamb, EL2R},
       
   276 	{22, ETrail, EEdgeSame, EUnamb, EL2R}, {22, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   277 	{23, ETrail, EEdgeSame, EUnamb, EL2R}, {23, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   278 	{24, ETrail, EEdgeSame, EUnamb, EL2R}, {24, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   279 	{25, ETrail, EEdgeSame, EUnamb, EL2R}, {25, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   280 	{26, ETrail, EEdgeSame, EUnamb, EL2R}, {26, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   281 	{27, ETrail, EEdgeSame, EUnamb, EL2R}, {27, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   282 	{28, ETrail, EEdgeSame, EUnamb, EL2R}, {28, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   283 	{29, ETrail, EEdgeSame, EUnamb, EL2R}, {29, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   284 	{30, ETrail, EEdgeSame, EUnamb, EL2R}, {30, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   285 	{31, ETrail, EEdgeSame, EUnamb, EL2R}, {31, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   286 	{32, ETrail, EEdgeSame, EUnamb, EL2R}, {32, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   287 	{33, ETrail, EEdgeSame, EUnamb, EL2R}, {33, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   288 	{34, ETrail, EEdgeSame, EUnamb, EL2R}, {34, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   289 	{35, ETrail, EEdgeSame, EUnamb, EL2R}, {35, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   290 	{36, ETrail, EEdgeSame, EUnamb, EL2R}, {36, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   291 	{37, ETrail, EEdgeSame, EUnamb, EL2R}, {37, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   292 	{38, ETrail, EEdgeSame, EUnamb, EL2R}, {38, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   293 	{39, ETrail, EEdgeSame, EUnamb, EL2R}, {39, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   294 	{40, ETrail, EEdgeSame, EUnamb, EL2R}, {40, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   295 // This change tests the change made for DEF059214
       
   296 //	{41, ETrail, EEdgeSame, EUnamb, EL2R}, {41, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   297 //	{42, ETrail, EEdgeNewline, EUnamb, EL2R}, {42, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   298 // similar changes have been made to other tests.
       
   299 	{41, ETrail, EEdgeSame, EUnamb, EL2R}, {41, ELead, EEdgeNewline, EUnamb, EL2R},
       
   300 	{42, ETrail, EEdgeSame, EUnamb, EL2R}, {42, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   301 	{43, ETrail, EEdgeSame, EUnamb, EL2R}, {43, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   302 	{44, ETrail, EEdgeSame, EUnamb, EL2R}, {44, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   303 	{45, ETrail, EEdgeSame, EUnamb, EL2R}, {45, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   304 	{46, ETrail, EEdgeSame, EUnamb, EL2R}, {46, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   305 	{47, ETrail, EEdgeSame, EUnamb, EL2R}, {47, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   306 	{48, ETrail, EEdgeSame, EUnamb, EL2R}, {48, ELead, EEdgeNewline, EUnamb, EL2R},
       
   307 	};
       
   308 
       
   309 _LIT(KArabic1, "{al'rbyA}\x2029{al'rbyA kf Sayd almwstfa}\x2029{lala lala}.");
       
   310 static const TEdge KArabic1Edges[] =
       
   311 	{
       
   312 	{7, ELead, EEdgeSame, EUnamb, ER2L}, {7, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   313 	{6, ELead, EEdgeSame, EUnamb, ER2L}, {6, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   314 	{5, ELead, EEdgeSame, EUnamb, ER2L}, {5, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   315 	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   316 	{3, ELead, EEdgeSame, EUnamb, ER2L}, {3, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   317 	{2, ELead, EEdgeSame, EUnamb, ER2L}, {2, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   318 	{1, ELead, EEdgeSame, EUnamb, ER2L}, {1, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   319 	{0, ELead, EEdgeSame, EUnamb, ER2L}, {0, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   320 	{18, ELead, EEdgeSame, EUnamb, ER2L}, {18, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   321 	{17, ELead, EEdgeSame, EUnamb, ER2L}, {17, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   322 	{16, ELead, EEdgeSame, EUnamb, ER2L}, {16, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   323 	{15, ELead, EEdgeSame, EUnamb, ER2L}, {15, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   324 	{14, ELead, EEdgeSame, EUnamb, ER2L}, {14, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   325 	{13, ELead, EEdgeSame, EUnamb, ER2L}, {13, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   326 	{12, ELead, EEdgeSame, EUnamb, ER2L}, {12, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   327 	{11, ELead, EEdgeSame, EUnamb, ER2L}, {11, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   328 	{10, ELead, EEdgeSame, EUnamb, ER2L}, {10, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   329 	{9, ELead, EEdgeSame, EUnamb, ER2L}, {9, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   330 	{8, ELead, EEdgeSame, EUnamb, ER2L}, {8, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   331 	{23, ELead, EEdgeSame, EUnamb, ER2L}, {23, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   332 	{22, ELead, EEdgeSame, EUnamb, ER2L}, {22, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   333 	{21, ELead, EEdgeSame, EUnamb, ER2L}, {21, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   334 	{20, ELead, EEdgeSame, EUnamb, ER2L}, {20, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   335 	{19, ELead, EEdgeSame, EUnamb, ER2L}, {19, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   336 	{32, ELead, EEdgeSame, EUnamb, ER2L}, {32, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   337 	{31, ELead, EEdgeSame, EUnamb, ER2L}, {31, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   338 	{30, ELead, EEdgeSame, EUnamb, ER2L}, {30, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   339 	{29, ELead, EEdgeSame, EUnamb, ER2L}, {29, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   340 	{28, ELead, EEdgeSame, EUnamb, ER2L}, {28, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   341 	{27, ELead, EEdgeSame, EUnamb, ER2L}, {27, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   342 	{26, ELead, EEdgeSame, EUnamb, ER2L}, {26, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   343 	{25, ELead, EEdgeSame, EUnamb, ER2L}, {25, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   344 	{24, ELead, EEdgeSame, EUnamb, ER2L}, {24, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   345 	{43, ELead, EEdgeSame, EUnamb, ER2L}, {43, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   346 	{42, ELead, EEdgeSame, EUnamb, ER2L}, {42, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   347 	{40, ELead, EEdgeSame, EUnamb, ER2L}, {40, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   348 	{38, ELead, EEdgeSame, EUnamb, ER2L}, {38, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   349 	{37, ELead, EEdgeSame, EUnamb, ER2L}, {37, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   350 	{35, ELead, EEdgeSame, EUnamb, ER2L}, {35, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   351 	{33, ELead, EEdgeSame, EUnamb, ER2L}, {33, ETrail, EEdgeNewline, EUnamb, ER2L}
       
   352 	};
       
   353 
       
   354 // Add another example including combining marks and zero-width characters
       
   355 _LIT(KCombiners1, "z\x300\x301\x302y\x300\x301\x302\x2029z\x300\x301\x302(\xFEFF)");
       
   356 static const TEdge KCombiners1Edges[] =
       
   357 	{
       
   358 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   359 	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   360 	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {8, ELead, EEdgeNewline, EUnamb, EL2R},
       
   361 	{9, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ELead, EEdgeNewline, EUnamb, EL2R},
       
   362 	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   363 	{14, ETrail, EEdgeSame, EUnamb, EL2R}, {14, ELead, EEdgeSame, EUnamb, EL2R},
       
   364 	{15, ETrail, EEdgeSame, EUnamb, EL2R}, {15, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   365 	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeNewline, EUnamb, EL2R}
       
   366 	};
       
   367 
       
   368 // Add another example including bidirectional text
       
   369 _LIT(KBidi1, "A\x301{b^ft^k}12\x200FZ\x301");
       
   370 static const TEdge KBidi1Edges[] =
       
   371 	{
       
   372 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   373 	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {9, ETrail, EEdgeSame, EAmb, ER2L},
       
   374 	{8, ELead, EEdgeSame, EUnamb, ER2L}, {6, ELead, EEdgeDifferent, EAmb, EL2R},
       
   375 	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   376 	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   377 	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   378 	{2, ELead, EEdgeSame, EUnamb, ER2L}, {9, ELead, EEdgeDifferent, EAmb, EL2R},
       
   379 	{11, ETrail, EEdgeSame, EUnamb, EL2R}, {11, ELead, EEdgeNewline, EUnamb, EL2R}
       
   380 	};
       
   381 
       
   382 // This example contains the "amtriguous" case where numbers
       
   383 // are embedded within Arabic but are next to Latin.
       
   384 _LIT(KBidi2, "A\x301{b^ft^k}12Z\x301");
       
   385 static const TEdge KBidi2Edges[] =
       
   386 	{
       
   387 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   388 	{2, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ELead, EEdgeDifferent, EAmb, EL2R},
       
   389 	{7, ETrail, EEdgeSame, EUnamb, EL2R}, {7, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   390 	{8, ETrail, EEdgeSame, EUnamb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   391 	{4, ELead, EEdgeSame, EUnamb, ER2L}, {4, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   392 	{2, ELead, EEdgeSame, EUnamb, ER2L}, {8, ELead, EEdgeDifferent, EAmb, EL2R},
       
   393 	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeNewline, EUnamb, EL2R}
       
   394 	};
       
   395 
       
   396 _LIT(KParagraphs1, "z\x2029{b}\x2029z");
       
   397 static const TEdge KParagraphs1Edges[] =
       
   398 	{
       
   399 	// First line:
       
   400 	// 0T 0L (Z) 1T 1L (ParagraphDelimiter)
       
   401 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   402 	{1, ETrail, EEdgeSame, EUnamb, EL2R}, {1, ELead, EEdgeNewline, EUnamb, EL2R},
       
   403 	// Second line:
       
   404 	// (PD) 3L< 3T< (Beh) 2L< 2T<
       
   405 	{3, ELead, EEdgeSame, EUnamb, ER2L}, {3, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   406 	{2, ELead, EEdgeSame, EUnamb, ER2L}, {2, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   407 	// Third line:
       
   408 	// 4T 4L (Z) 5T 5L (NominalPD)
       
   409 	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   410 	{5, ETrail, EEdgeSame, EUnamb, EL2R}, {5, ELead, EEdgeNewline, EUnamb, EL2R}
       
   411 	};
       
   412 
       
   413 // 2 characters per line
       
   414 _LIT(KEmbedded1, "z{bb}z\x2029{b}zz{b}\x2029z{b}zz{b}z\x2029{b}z{bb}z{b}");
       
   415 // T=trailing, L=leading, !=Ambiguous, <=Right-to-left
       
   416 static const TEdge KEmbedded1Edges[] =
       
   417 	{
       
   418 	// First line:
       
   419 	// 0T 0L (0Z) 1T! 2T!< (1Beh) 1L<
       
   420 	{0, ETrail, EEdgeSame, EUnamb, EL2R}, {0, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   421 	{1, ETrail, EEdgeSame, EAmb, EL2R}, {2, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   422 	{1, ELead, EEdgeNewline, EUnamb, ER2L},
       
   423 	// Second line:
       
   424 	// 3T< (2Beh) 2L!< 3L! (3Z) 4T 4L (4ParagraphDelimiter)
       
   425 	{3, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   426 	{2, ELead, EEdgeSame, EAmb, ER2L}, {3, ELead, EEdgeDifferent, EAmb, EL2R},
       
   427 	{4, ETrail, EEdgeSame, EUnamb, EL2R}, {4, ELead, EEdgeNewline, EUnamb, EL2R},
       
   428 	// Third line:
       
   429 	// 6L (6Z) 7T! 6T!< (5Beh) 5L< 5T<
       
   430 	{6, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   431 	{7, ETrail, EEdgeSame, EAmb, EL2R}, {6, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   432 	{5, ELead, EEdgeSame, EUnamb, ER2L}, {5, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   433 	// Fourth line:
       
   434 	// (9PD) 9L< 9T< (8Beh) 8L!< 7L! (7Z) 8T
       
   435 	{9, ELead, EEdgeSame, EUnamb, ER2L}, {9, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   436 	{8, ELead, EEdgeSame, EAmb, ER2L}, {7, ELead, EEdgeDifferent, EAmb, EL2R},
       
   437 	{8, ETrail, EEdgeNewline, EUnamb, EL2R},
       
   438 	// Fifth line:
       
   439 	// 10T 10L (10Z) 11T! 12T!< (11Beh) 11L<
       
   440 	{10, ETrail, EEdgeSame, EUnamb, EL2R}, {10, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   441 	{11, ETrail, EEdgeSame, EAmb, EL2R}, {12, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   442 	{11, ELead, EEdgeNewline, EUnamb, ER2L},
       
   443 	// Sixth line:
       
   444 	// 12L (12Z) 13T 13L (13Z) 14T
       
   445 	{12, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   446 	{13, ETrail, EEdgeSame, EUnamb, EL2R}, {13, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   447 	{14, ETrail, EEdgeNewline, EUnamb, EL2R},
       
   448 	// Seventh line:
       
   449 	// 15T< (14Beh) 14L!< 15L! (15Z) 16T 16L (16PD)
       
   450 	{15, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   451 	{14, ELead, EEdgeSame, EAmb, ER2L}, {15, ELead, EEdgeDifferent, EAmb, EL2R},
       
   452 	{16, ETrail, EEdgeSame, EUnamb, EL2R}, {16, ELead, EEdgeNewline, EUnamb, EL2R},
       
   453 	// Eighth line:
       
   454 	// 18L (18Z) 19T! 18T!< (17Beh) 17L< 17T<
       
   455 	{18, ELead, EEdgeDifferent, EUnamb, EL2R},
       
   456 	{19, ETrail, EEdgeSame, EAmb, EL2R}, {18, ETrail, EEdgeDifferent, EAmb, ER2L},
       
   457 	{17, ELead, EEdgeSame, EUnamb, ER2L}, {17, ETrail, EEdgeNewline, EUnamb, ER2L},
       
   458 	// Ninth line:
       
   459 	// 21T< (20Beh) 20L< 20T< (19Beh) 19L<
       
   460 	{21, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   461 	{20, ELead, EEdgeSame, EUnamb, ER2L}, {20, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   462 	{19, ELead, EEdgeNewline, EUnamb, ER2L},
       
   463 	// Tenth line:
       
   464 	// (23NominalPD) 23L< 23T< (22Beh) 22L!< 21L! (21Z) 22T
       
   465 	{23, ELead, EEdgeSame, EUnamb, ER2L}, {23, ETrail, EEdgeDifferent, EUnamb, ER2L},
       
   466 	{22, ELead, EEdgeSame, EAmb, ER2L}, {21, ELead, EEdgeDifferent, EAmb, EL2R},
       
   467 	{22, ETrail, EEdgeNewline, EUnamb, EL2R},
       
   468 	};
       
   469 
       
   470 /**
       
   471 Returns which portion of the text is in the specified line.
       
   472 */
       
   473 void LineExtent(TInt aLine, CTestTmTextLayout& aLayout,
       
   474 	TInt& aLineStart, TInt& aLineEnd)
       
   475 	{
       
   476 	CTmTextLayout& layout = aLayout.Layout();
       
   477 	TTmInterpreterParam interpParam(layout);
       
   478 	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   479 	interp.LineNumberToLine(aLine);
       
   480 	aLineStart = interp.LineInfo().iStart;
       
   481 	aLineEnd = interp.LineInfo().iEnd;
       
   482 	}
       
   483 
       
   484 /**
       
   485 Finds an edge in the expected edges list that matches a document position
       
   486 specification.
       
   487 */
       
   488 const TEdge* FindExpectedEdge(const TTmDocPosSpec& aPos,
       
   489 	const TEdge* aExpected, TInt aNumExpected)
       
   490 	{
       
   491 	const TEdge* nearestTrailing = 0;
       
   492 	TInt distanceTrailing = KMaxTInt;
       
   493 	const TEdge* nearestLeading = 0;
       
   494 	TInt distanceLeading = KMinTInt;
       
   495 	for (const TEdge* e = aExpected; e != aExpected + aNumExpected; ++e)
       
   496 		{
       
   497 		TInt distance = e->iPos - aPos.iPos;
       
   498 		if (!e->iLeading && 0 <= distance && distance < distanceTrailing)
       
   499 			{
       
   500 			distanceTrailing = distance;
       
   501 			nearestTrailing = e;
       
   502 			}
       
   503 		if (e->iLeading && distanceLeading < distance && distance <= 0)
       
   504 			{
       
   505 			distanceLeading = distance;
       
   506 			nearestLeading = e;
       
   507 			}
       
   508 		}
       
   509 	if (aPos.iType == TTmDocPosSpec::ELeading || !nearestTrailing)
       
   510 		{
       
   511 		return nearestLeading;
       
   512 		}
       
   513 	if (aPos.iType == TTmDocPosSpec::ETrailing || !nearestLeading)
       
   514 		{
       
   515 		return nearestTrailing;
       
   516 		}
       
   517 	// Differences in iPos might be because pos is within a grapheme cluster,
       
   518 	// or might be that the leading or trailing edge is not on that line.
       
   519 	// Grapheme cluster differences are OK, not on the line differences will mean
       
   520 	// that the one that does not match the input position is wrong.
       
   521 	if (nearestLeading->iPos == aPos.iPos && nearestTrailing->iPos != aPos.iPos)
       
   522 		return nearestLeading;
       
   523 	if (nearestTrailing->iPos == aPos.iPos && nearestLeading->iPos != aPos.iPos)
       
   524 		return nearestTrailing;
       
   525 	TBool directionalitiesMatch = nearestTrailing->iRightToLeft?
       
   526 		nearestLeading->iRightToLeft : !nearestLeading->iRightToLeft;
       
   527 	if (directionalitiesMatch)
       
   528 		return nearestLeading;
       
   529 	TBool leadingIsCorrect = aPos.iType == TTmDocPosSpec::ERightToLeft?
       
   530 		nearestLeading->iRightToLeft : !nearestLeading->iRightToLeft;
       
   531 	return leadingIsCorrect? nearestLeading : nearestTrailing;
       
   532 	}
       
   533 
       
   534 /**
       
   535 Returns ETrue if and only if the two edges specified are expected to be
       
   536 coincident.
       
   537 */
       
   538 TBool ExpectedEdgesCoincide(const TEdge* aA, const TEdge* aB)
       
   539 	{
       
   540 	const TEdge* a = aA < aB? aA : aB;
       
   541 	const TEdge* b = aA < aB? aB : aA;
       
   542 	while (a != b)
       
   543 		{
       
   544 		if (a->iNext != EEdgeSame)
       
   545 			return EFalse;
       
   546 		++a;
       
   547 		}
       
   548 	return ETrue;
       
   549 	}
       
   550 
       
   551 /**
       
   552 Tests that the edge information matches the expected edge.
       
   553 */
       
   554 void TestExpectedEdge(RTest& aTest, const TTmPosInfo2& aEdgeInfo,
       
   555 	const TEdge* aExpected)
       
   556 	{
       
   557 	aTest(aEdgeInfo.iRightToLeft?
       
   558 		aExpected->iRightToLeft : !aExpected->iRightToLeft);
       
   559 	aTest(aEdgeInfo.iDocPos.iPos == aExpected->iPos);
       
   560 	aTest(aEdgeInfo.iDocPos.iLeadingEdge?
       
   561 		aExpected->iLeading : !aExpected->iLeading);
       
   562 	}
       
   563 
       
   564 /**
       
   565 Tests that the edge information matches one of the expected edges.
       
   566 */
       
   567 void TestEdgeExists(RTest& aTest, const TTmPosInfo2& aEdgeInfo,
       
   568 	const TEdge* aExpected, TInt aNumExpected)
       
   569 	{
       
   570 	TTmDocPos pos(aEdgeInfo.iDocPos);
       
   571 	const TEdge* edge = FindExpectedEdge(pos, aExpected, aNumExpected);
       
   572 	aTest(edge != 0);
       
   573 	TestExpectedEdge(aTest, aEdgeInfo, edge);
       
   574 	}
       
   575 
       
   576 /**
       
   577 Tests that the visual position matches one of the expected edges.
       
   578 */
       
   579 void TestVisualPositionExists(RTest& aTest, const TTmVisualDocPos& aPos,
       
   580 	const TEdge* aExpected, TInt aNumExpected)
       
   581 	{
       
   582 	aTest(aPos.Ambiguity() != TTmVisualDocPos::ENotFound);
       
   583 	TTmDocPos posLeft(aPos.LeftEdge().iDocPos);
       
   584 	const TEdge* left = FindExpectedEdge(posLeft, aExpected, aNumExpected);
       
   585 	TestExpectedEdge(aTest, aPos.LeftEdge(), left);
       
   586 	TTmDocPos posRight(aPos.RightEdge().iDocPos);
       
   587 	const TEdge* right = FindExpectedEdge(posRight, aExpected, aNumExpected);
       
   588 	TestExpectedEdge(aTest, aPos.RightEdge(), right);
       
   589 	aTest( (aPos.Ambiguity() == TTmVisualDocPos::EAmbiguous
       
   590 			&& left->iAmbiguity && right->iAmbiguity)
       
   591 		|| (aPos.Ambiguity() != TTmVisualDocPos::EAmbiguous
       
   592 			&& !left->iAmbiguity && !right->iAmbiguity) );
       
   593 	aTest(ExpectedEdgesCoincide(left, right));
       
   594 	}
       
   595 
       
   596 /**
       
   597 Tests that a RTmGraphemeEdgeIterator iterates through all the positions in a
       
   598 line from left to right.
       
   599 */
       
   600 void TestLayoutSimplePass(RTest& aTest, CTestTmTextLayout& aLayout,
       
   601 	const TEdge* aExpected, TInt aNumExpected)
       
   602 	{
       
   603 	CTmTextLayout& layout = aLayout.Layout();
       
   604 	TTmInterpreterParam interpParam(layout);
       
   605 	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   606 	interp.LineNumberToLine(0);
       
   607 	RTmGraphemeEdgeIterator it;
       
   608 	it.Begin(interp);
       
   609 	TTmPosInfo2 last = it.GetInfo();
       
   610 	for (TInt i = 0; i != aNumExpected; ++i)
       
   611 		{
       
   612 		const TEdge& expected = aExpected[i];
       
   613 		aTest(expected.iPos == last.iDocPos.iPos);
       
   614 		aTest(expected.iLeading == last.iDocPos.iLeadingEdge);
       
   615 		it.Next();
       
   616 		if (it.AtEnd())
       
   617 			{
       
   618 			aTest(expected.iNext == EEdgeNewline);
       
   619 			while (interp.Op() != TTmInterpreter::EOpLine && interp.Next())
       
   620 				{}
       
   621 			if (i + 1 != aNumExpected)
       
   622 				{
       
   623 				it.Begin(interp);
       
   624 				last = it.GetInfo();
       
   625 				}
       
   626 			}
       
   627 		else
       
   628 			{
       
   629 			TTmPosInfo2 thisOne = it.GetInfo();
       
   630 			TestEdgeExists(aTest, thisOne, aExpected, aNumExpected);
       
   631 			aTest(expected.iNext != EEdgeNewline);
       
   632 			if (expected.iNext == EEdgeSame)
       
   633 				aTest(last.iEdge.iX == thisOne.iEdge.iX);
       
   634 			else if (expected.iNext == EEdgeDifferent)
       
   635 				aTest(last.iEdge.iX != thisOne.iEdge.iX);
       
   636 			last = thisOne;
       
   637 			}
       
   638 		}
       
   639 	it.Close();
       
   640 	interp.Close();
       
   641 	}
       
   642 
       
   643 /**
       
   644 Tests that FindXPos returns the edge 'closest' to the input co-ordinate
       
   645 where there is no ambiguity.
       
   646 */
       
   647 void TestLayoutFindXPosEdges(RTest& aTest, TInt aLine,
       
   648 	CTestTmTextLayout& aLayout,
       
   649 	const TEdge* aExpected, TInt aNumExpected)
       
   650 	{
       
   651 	CTmTextLayout& layout = aLayout.Layout();
       
   652 	TTmInterpreterParam interpParam(layout);
       
   653 	TTmPosInfo2 posInfo;
       
   654 	TTmDocPosSpec posSpec;
       
   655 	TTmLineInfo lineInfo;
       
   656 	TTmVisualDocPos visPos;
       
   657 	for (TInt i = 0; i != aNumExpected - 1; ++i)
       
   658 		{
       
   659 		const TEdge& expectedL = aExpected[i];
       
   660 		const TEdge& expectedR = aExpected[i + 1];
       
   661 		if (expectedL.iNext == EEdgeDifferent)
       
   662 			{
       
   663 			// This code assumes that no character has a width of exactly 1 pixel.
       
   664 			if (!expectedL.iAmbiguity)
       
   665 				{
       
   666 				posSpec.iPos = expectedL.iPos;
       
   667 				posSpec.iType = expectedL.iLeading?
       
   668 					TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing;
       
   669 				layout.FindDocPos(posSpec, posInfo, lineInfo);
       
   670 				RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   671 				interp.LineNumberToLine(aLine);
       
   672 				RTmGraphemeEdgeIterator it;
       
   673 				it.Begin(interp);
       
   674 				it.FindXPos(posInfo.iEdge.iX, visPos);
       
   675 				aTest(visPos.Ambiguity() != TTmVisualDocPos::EAmbiguous);
       
   676 				aTest(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
       
   677 				aTest(visPos.LeftEdge().iDocPos.iPos == expectedL.iPos);
       
   678 				aTest(visPos.LeftEdge().iDocPos.iLeadingEdge?
       
   679 					expectedL.iLeading : !expectedL.iLeading);
       
   680 				it.Close();
       
   681 				interp.Close();
       
   682 				}
       
   683 			if (!expectedR.iAmbiguity)
       
   684 				{
       
   685 				posSpec.iPos = expectedR.iPos;
       
   686 				posSpec.iType = expectedR.iLeading?
       
   687 					TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing;
       
   688 				layout.FindDocPos(posSpec, posInfo, lineInfo);
       
   689 				RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   690 				interp.LineNumberToLine(aLine);
       
   691 				RTmGraphemeEdgeIterator it;
       
   692 				it.Begin(interp);
       
   693 				it.FindXPos(posInfo.iEdge.iX - 1, visPos);
       
   694 				aTest(visPos.Ambiguity() != TTmVisualDocPos::EAmbiguous);
       
   695 				aTest(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
       
   696 				aTest(visPos.LeftEdge().iDocPos.iPos == expectedR.iPos);
       
   697 				aTest(visPos.LeftEdge().iDocPos.iLeadingEdge?
       
   698 					expectedR.iLeading : !expectedR.iLeading);
       
   699 				it.Close();
       
   700 				interp.Close();
       
   701 				}
       
   702 			}
       
   703 		}
       
   704 	}
       
   705 
       
   706 /**
       
   707 Tests that RTmGraphemeEdgeIterator::FindXPos finds document positions that
       
   708 match the positions they are supposed to be in.
       
   709 */
       
   710 void TestLayoutFindXPos(RTest& aTest, TInt aLine,
       
   711 	CTestTmTextLayout& aLayout,
       
   712 	const TEdge* aExpected, TInt aNumExpected)
       
   713 	{
       
   714 	TInt lastLeftX = KMinTInt;
       
   715 	TInt lastRightX = KMinTInt;
       
   716 	TTmVisualDocPos visPos;
       
   717 	TBool finished = EFalse;
       
   718 	for (TInt x = -10; !finished; ++x)
       
   719 		{
       
   720 		CTmTextLayout& layout = aLayout.Layout();
       
   721 		TTmInterpreterParam interpParam(layout);
       
   722 		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   723 		interp.LineNumberToLine(aLine);
       
   724 		RTmGraphemeEdgeIterator it;
       
   725 		it.Begin(interp);
       
   726 		it.FindXPos(x, visPos);
       
   727 		TestVisualPositionExists(aTest, visPos, aExpected, aNumExpected);
       
   728 		aTest(visPos.Ambiguity() != TTmVisualDocPos::ENotFound);
       
   729 		aTest(visPos.LeftEdge().iEdge.iX <= visPos.RightEdge().iEdge.iX);
       
   730 		aTest(visPos.Ambiguity() == TTmVisualDocPos::EAmbiguous
       
   731 			|| visPos.LeftEdge().iEdge.iX == visPos.RightEdge().iEdge.iX);
       
   732 		aTest(lastLeftX <= visPos.LeftEdge().iEdge.iX);
       
   733 		if (lastLeftX == visPos.LeftEdge().iEdge.iX)
       
   734 			{
       
   735 			aTest(lastRightX == visPos.RightEdge().iEdge.iX);
       
   736 			while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
       
   737 				|| aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
       
   738 				{
       
   739 				aTest(aExpected->iNext == EEdgeSame);
       
   740 				aTest(0 < aNumExpected);
       
   741 				++aExpected;
       
   742 				--aNumExpected;
       
   743 				}
       
   744 			}
       
   745 		else
       
   746 			{
       
   747 			aTest(lastRightX <= visPos.LeftEdge().iEdge.iX);
       
   748 			while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
       
   749 				|| aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
       
   750 				{
       
   751 				aTest(0 < aNumExpected);
       
   752 				++aExpected;
       
   753 				--aNumExpected;
       
   754 				}
       
   755 			}
       
   756 		if (interp.LineInfo().iInnerRect.iBr.iX + 120 < x)
       
   757 			finished = ETrue;
       
   758 		it.Close();
       
   759 		interp.Close();
       
   760 		}
       
   761 	while (aExpected->iNext != EEdgeNewline)
       
   762 		{
       
   763 		aTest(aExpected->iNext == EEdgeSame);
       
   764 		aTest(0 < aNumExpected);
       
   765 		++aExpected;
       
   766 		--aNumExpected;
       
   767 		}
       
   768 	}
       
   769 
       
   770 /**
       
   771 Uses RTmGraphemeEdgeIterator::FindEdge to find a document position in a
       
   772 CTestTmTextLayout.
       
   773 */
       
   774 TBool FindEdgeFromLayout(CTestTmTextLayout& aLayout, TInt aLine,
       
   775 	const TTmDocPosSpec& aDocPos, TTmPosInfo2& aInfo)
       
   776 	{
       
   777 	CTmTextLayout& layout = aLayout.Layout();
       
   778 	TTmInterpreterParam interpParam(layout);
       
   779 	RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   780 	interp.LineNumberToLine(aLine);
       
   781 	RTmGraphemeEdgeIterator it;
       
   782 	it.Begin(interp);
       
   783 	TBool result = it.FindEdge(aDocPos, aInfo);
       
   784 	it.Close();
       
   785 	interp.Close();
       
   786 	return result;
       
   787 	}
       
   788 
       
   789 /**
       
   790 Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
       
   791 specifications of leading or trailing edges.
       
   792 */
       
   793 void TestLayoutFindEdgesInVisualOrder(RTest& aTest, TInt aLine,
       
   794 	CTestTmTextLayout& aLayout,
       
   795 	const TEdge* aExpected, TInt aNumExpected)
       
   796 	{
       
   797 	TInt lastX = KMinTInt;
       
   798 	TBool sameExpected = EFalse;
       
   799 	TTmPosInfo2 posInfo;
       
   800 	while (aNumExpected != 0)
       
   801 		{
       
   802 		TTmDocPosSpec posSpec(aExpected->iPos, aExpected->iLeading?
       
   803 			TTmDocPosSpec::ELeading : TTmDocPosSpec::ETrailing);
       
   804 		FindEdgeFromLayout(aLayout, aLine, posSpec, posInfo);
       
   805 		TestEdgeExists(aTest, posInfo, aExpected, aNumExpected);
       
   806 		aTest(aExpected->iLeading?
       
   807 			posInfo.iDocPos.iLeadingEdge : !posInfo.iDocPos.iLeadingEdge);
       
   808 		aTest(aExpected->iPos == posInfo.iDocPos.iPos);
       
   809 		aTest(sameExpected || posInfo.iEdge.iX != lastX);
       
   810 		aTest(!sameExpected || posInfo.iEdge.iX == lastX);
       
   811 		lastX = posInfo.iEdge.iX;
       
   812 		sameExpected = aExpected->iNext == EEdgeSame? ETrue : EFalse;
       
   813 		++aExpected;
       
   814 		--aNumExpected;
       
   815 		}
       
   816 	}
       
   817 
       
   818 /**
       
   819 Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
       
   820 specifications of directionality.
       
   821 */
       
   822 void TestLayoutFindEdgesByDirectionality(RTest& aTest, TInt aLine,
       
   823 	CTestTmTextLayout& aLayout,
       
   824 	const TEdge* aExpected, TInt aNumExpected)
       
   825 	{
       
   826 	TInt lineStart;
       
   827 	TInt lineEnd;
       
   828 	LineExtent(aLine, aLayout, lineStart, lineEnd);
       
   829 	TTmPosInfo2 lToRPosInfo;
       
   830 	TTmPosInfo2 rToLPosInfo;
       
   831 	for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
       
   832 		{
       
   833 		TTmDocPosSpec rToLPosSpec(pos, TTmDocPosSpec::ERightToLeft);
       
   834 		TBool rToLFound = FindEdgeFromLayout(aLayout, aLine, rToLPosSpec, rToLPosInfo);
       
   835 		TTmDocPosSpec lToRPosSpec(pos, TTmDocPosSpec::ELeftToRight);
       
   836 		TBool lToRFound = FindEdgeFromLayout(aLayout, aLine, lToRPosSpec, lToRPosInfo);
       
   837 		if (!lToRFound)
       
   838 			{
       
   839 			aTest(!rToLFound);
       
   840 			aTest(pos < lineStart || lineEnd <= pos);
       
   841 			}
       
   842 		else
       
   843 			{
       
   844 			aTest(rToLFound);
       
   845 			TestEdgeExists(aTest, rToLPosInfo, aExpected, aNumExpected);
       
   846 			TestEdgeExists(aTest, lToRPosInfo, aExpected, aNumExpected);
       
   847 			// Now find the nearest edges in the expected range
       
   848 			TTmDocPosSpec trailingPosSpec(pos, TTmDocPosSpec::ETrailing);
       
   849 			const TEdge* trailingExpected
       
   850 				= FindExpectedEdge(trailingPosSpec, aExpected, aNumExpected);
       
   851 			TTmDocPosSpec leadingPosSpec(pos, TTmDocPosSpec::ELeading);
       
   852 			const TEdge* leadingExpected
       
   853 				= FindExpectedEdge(leadingPosSpec, aExpected, aNumExpected);
       
   854 			if (!trailingExpected)
       
   855 				trailingExpected = leadingExpected;
       
   856 			if (!leadingExpected)
       
   857 				leadingExpected = trailingExpected;
       
   858 			const TEdge* rToLPosEdge
       
   859 				= FindExpectedEdge(rToLPosInfo.iDocPos, aExpected, aNumExpected);
       
   860 			const TEdge* lToRPosEdge
       
   861 				= FindExpectedEdge(lToRPosInfo.iDocPos, aExpected, aNumExpected);
       
   862 			aTest(leadingExpected != 0);
       
   863 			aTest(trailingExpected != 0);
       
   864 			aTest(ExpectedEdgesCoincide(leadingExpected, rToLPosEdge)
       
   865 				|| ExpectedEdgesCoincide(trailingExpected, rToLPosEdge));
       
   866 			aTest(ExpectedEdgesCoincide(leadingExpected, lToRPosEdge)
       
   867 				|| ExpectedEdgesCoincide(trailingExpected, lToRPosEdge));
       
   868 			// Also check that the "found" ones are at least as good as the
       
   869 			// "expected" ones.
       
   870 			aTest(rToLPosInfo.iRightToLeft
       
   871 				|| (!leadingExpected->iRightToLeft && !trailingExpected->iRightToLeft));
       
   872 			aTest(!lToRPosInfo.iRightToLeft
       
   873 				|| (leadingExpected->iRightToLeft && trailingExpected->iRightToLeft));
       
   874 			}
       
   875 		}
       
   876 	}
       
   877 
       
   878 /**
       
   879 Tests RTmGraphemeEdgeIterator::FindEdgeRightwards or
       
   880 RTmGraphemeEdgeIterator::FindEdgeLeftwards.
       
   881 */
       
   882 void TestLayoutFindEdgesLeftRight(RTest& aTest, TInt aLine,
       
   883 	CTestTmTextLayout& aLayout, TBool aRightwards,
       
   884 	const TEdge* aExpected, TInt aNumExpected)
       
   885 	{
       
   886 	TInt lineStart;
       
   887 	TInt lineEnd;
       
   888 	LineExtent(aLine, aLayout, lineStart, lineEnd);
       
   889 	TTmPosInfo2 nearest;
       
   890 	TTmVisualDocPos next;
       
   891 	const TTmDocPosSpec::TType types[4]
       
   892 		= {TTmDocPosSpec::ETrailing,
       
   893 		TTmDocPosSpec::ELeading,
       
   894 		TTmDocPosSpec::ELeftToRight,
       
   895 		TTmDocPosSpec::ERightToLeft};
       
   896 
       
   897 	for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
       
   898 		{
       
   899 		for (TInt type = 0; type != 4; ++type)
       
   900 			{
       
   901 			TTmDocPosSpec posSpec(pos, types[type]);
       
   902 
       
   903 			// What do we expect the nearest to be?
       
   904 			TTmDocPosSpec leadingPosSpec(pos, TTmDocPosSpec::ELeading);
       
   905 			TTmDocPosSpec trailingPosSpec(pos, TTmDocPosSpec::ETrailing);
       
   906 
       
   907 			const TEdge* leadingExpected
       
   908 				= FindExpectedEdge(leadingPosSpec, aExpected, aNumExpected);
       
   909 			const TEdge* trailingExpected
       
   910 				= FindExpectedEdge(trailingPosSpec, aExpected, aNumExpected);
       
   911 
       
   912 			// but should we expect anything at all?
       
   913 			if (pos < lineStart || lineEnd < pos)
       
   914 				leadingExpected = trailingExpected = 0;
       
   915 			if (posSpec.iType == TTmDocPosSpec::ELeading
       
   916 				&& (!leadingExpected || !leadingExpected->iLeading))
       
   917 				leadingExpected = trailingExpected = 0;
       
   918 			if (posSpec.iType == TTmDocPosSpec::ETrailing
       
   919 				&& (!trailingExpected || trailingExpected->iLeading))
       
   920 				leadingExpected = trailingExpected = 0;
       
   921 
       
   922 			// <lineEnd, trailing> is the only element that may be present
       
   923 			// at position lineEnd.
       
   924 			if (pos == lineEnd)
       
   925 				{
       
   926 				// If we are looking for a leading edge, we won't find
       
   927 				// the trailing even if it is there.
       
   928 				if (posSpec.iType == TTmDocPosSpec::ELeading
       
   929 					|| !trailingExpected
       
   930 					|| trailingExpected->iPos != pos)
       
   931 					leadingExpected = trailingExpected = 0;
       
   932 				}
       
   933 			// <lineStart, trailing> may not be in the line.
       
   934 			// We must check explicitly.
       
   935 			if (pos == lineStart && posSpec.iType == TTmDocPosSpec::ETrailing)
       
   936 				{
       
   937 				// If there is no trailing edge at the start of the line
       
   938 				// and we are looking for one, we
       
   939 				// do not expect to have a nearest match there.
       
   940 				if (!trailingExpected || trailingExpected->iPos != pos)
       
   941 					leadingExpected = trailingExpected = 0;
       
   942 				}
       
   943 
       
   944 			if (!leadingExpected)
       
   945 				leadingExpected = trailingExpected;
       
   946 			if (!trailingExpected)
       
   947 				trailingExpected = leadingExpected;
       
   948 
       
   949 			const TEdge* nextExpected = 0;
       
   950 
       
   951 			CTmTextLayout& layout = aLayout.Layout();
       
   952 			TTmInterpreterParam interpParam(layout);
       
   953 			RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
   954 			interp.LineNumberToLine(aLine);
       
   955 			RTmGraphemeEdgeIterator it;
       
   956 			it.Begin(interp);
       
   957 			RTmGraphemeEdgeIterator::TEdgesFound result = aRightwards?
       
   958 				it.FindEdgeRightwards(posSpec, nearest, next)
       
   959 				: it.FindEdgeLeftwards(posSpec, nearest, next);
       
   960 			interp.Close();
       
   961 
       
   962 			// Does what we got match what we expect?
       
   963 			if (!leadingExpected)
       
   964 				{
       
   965 				aTest(result == RTmGraphemeEdgeIterator::ENone);
       
   966 				}
       
   967 			else
       
   968 				{
       
   969 				aTest(result == RTmGraphemeEdgeIterator::ENearestOnly
       
   970 					|| result == RTmGraphemeEdgeIterator::ENearestAndNext);
       
   971 				TTmDocPosSpec nearestPos(nearest.iDocPos);
       
   972 				const TEdge* nearestEdge
       
   973 					= FindExpectedEdge(nearestPos, aExpected, aNumExpected);
       
   974 				TestExpectedEdge(aTest, nearest, nearestEdge);
       
   975 				const TEdge* matchingEdge = leadingExpected;
       
   976 				if (posSpec.iType == TTmDocPosSpec::ELeading)
       
   977 					aTest(ExpectedEdgesCoincide(leadingExpected, nearestEdge));
       
   978 				else if (posSpec.iType == TTmDocPosSpec::ETrailing)
       
   979 					{
       
   980 					aTest(ExpectedEdgesCoincide(trailingExpected, nearestEdge));
       
   981 					matchingEdge = trailingExpected;
       
   982 					}
       
   983 				else
       
   984 					{
       
   985 					aTest(ExpectedEdgesCoincide(leadingExpected, nearestEdge)
       
   986 						|| ExpectedEdgesCoincide(trailingExpected, nearestEdge));
       
   987 					if (ExpectedEdgesCoincide(trailingExpected, nearestEdge))
       
   988 						matchingEdge = trailingExpected;
       
   989 					TBool directionalitiesMatch = leadingExpected->iRightToLeft?
       
   990 						trailingExpected->iRightToLeft : !trailingExpected->iRightToLeft;
       
   991 					TBool foundCorrectDirectionality
       
   992 						= posSpec.iType == TTmDocPosSpec::ERightToLeft?
       
   993 							nearest.iRightToLeft : !nearest.iRightToLeft;
       
   994 					aTest(foundCorrectDirectionality || directionalitiesMatch);
       
   995 					}
       
   996 
       
   997 				// Find next edge in expected list
       
   998 				const TEdge* e = matchingEdge;
       
   999 				const TEdge* end = aRightwards?
       
  1000 					aExpected + aNumExpected - 1
       
  1001 					: aExpected;
       
  1002 				TInt direction = aRightwards? 1 : -1;
       
  1003 				while (nextExpected == 0 && e != end)
       
  1004 					{
       
  1005 					e += direction;
       
  1006 					if (!ExpectedEdgesCoincide(e, matchingEdge))
       
  1007 						nextExpected = e;
       
  1008 					}
       
  1009 				}
       
  1010 			if (!nextExpected)
       
  1011 				aTest(result == RTmGraphemeEdgeIterator::ENone
       
  1012 					|| result == RTmGraphemeEdgeIterator::ENearestOnly);
       
  1013 			else
       
  1014 				{
       
  1015 				aTest(result == RTmGraphemeEdgeIterator::ENearestAndNext);
       
  1016 				TestVisualPositionExists(aTest, next, aExpected, aNumExpected);
       
  1017 				aTest(next.Ambiguity() != TTmVisualDocPos::ENotFound);
       
  1018 				TTmDocPosSpec nextPosLeft(next.LeftEdge().iDocPos);
       
  1019 				aTest(ExpectedEdgesCoincide(nextExpected,
       
  1020 					FindExpectedEdge(nextPosLeft, aExpected, aNumExpected)));
       
  1021 				TTmDocPosSpec nextPosRight(next.RightEdge().iDocPos);
       
  1022 				aTest(ExpectedEdgesCoincide(nextExpected,
       
  1023 					FindExpectedEdge(nextPosRight, aExpected, aNumExpected)));
       
  1024 				}
       
  1025 			it.Close();
       
  1026 			}
       
  1027 		}
       
  1028 	}
       
  1029 
       
  1030 /**
       
  1031 Tests RTmGraphemeEdgeIterator::FindEdgeRightwards.
       
  1032 */
       
  1033 void TestLayoutFindEdgesRightwards(RTest& aTest, TInt aLine,
       
  1034 	CTestTmTextLayout& aLayout,
       
  1035 	const TEdge* aExpected, TInt aNumExpected)
       
  1036 	{
       
  1037 	TestLayoutFindEdgesLeftRight(aTest, aLine, aLayout, ETrue,
       
  1038 		aExpected, aNumExpected);
       
  1039 	}
       
  1040 
       
  1041 /**
       
  1042 Tests RTmGraphemeEdgeIterator::FindEdgeLeftwards.
       
  1043 */
       
  1044 void TestLayoutFindEdgesLeftwards(RTest& aTest, TInt aLine,
       
  1045 	CTestTmTextLayout& aLayout,
       
  1046 	const TEdge* aExpected, TInt aNumExpected)
       
  1047 	{
       
  1048 	TestLayoutFindEdgesLeftRight(aTest, aLine, aLayout, EFalse,
       
  1049 		aExpected, aNumExpected);
       
  1050 	}
       
  1051 
       
  1052 /**
       
  1053 Tests RTmGraphemeEdgeIterator::NextPosition. Expected behaviour is to find the
       
  1054 smallest number 'n' that is a position in the same line greater than the input 'i',
       
  1055 where the positions <i, leading> and <n, trailing> are not coincident.
       
  1056 */
       
  1057 void TestLayoutFindEdgesForwards(RTest& aTest, TInt aLine,
       
  1058 	CTestTmTextLayout& aLayout,
       
  1059 	const TEdge* aExpected, TInt aNumExpected)
       
  1060 	{
       
  1061 	TInt lineStart;
       
  1062 	TInt lineEnd;
       
  1063 	LineExtent(aLine, aLayout, lineStart, lineEnd);
       
  1064 	for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
       
  1065 		{
       
  1066 		CTmTextLayout& layout = aLayout.Layout();
       
  1067 		TTmInterpreterParam interpParam(layout);
       
  1068 		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
  1069 		interp.LineNumberToLine(aLine);
       
  1070 		RTmGraphemeEdgeIterator it;
       
  1071 		it.Begin(interp);
       
  1072 		TInt result = it.NextPosition(i);
       
  1073 		interp.Close();
       
  1074 
       
  1075 		if (result == KErrNotFound)
       
  1076 			{
       
  1077 			// Must be at or after the line's end.
       
  1078 			// Try to find a later edge in the line...
       
  1079 			TTmDocPosSpec in(i, TTmDocPosSpec::ELeading);
       
  1080 			const TEdge* inEdge = FindExpectedEdge(in,
       
  1081 				aExpected, aNumExpected);
       
  1082 			TTmDocPosSpec out(result, TTmDocPosSpec::ETrailing);
       
  1083 			const TEdge* outEdge = FindExpectedEdge(out,
       
  1084 				aExpected, aNumExpected);
       
  1085 			// ...and test that we failed.
       
  1086 			aTest(!inEdge || inEdge->iPos <= i);
       
  1087 			aTest(!outEdge || outEdge->iPos <= i);
       
  1088 			}
       
  1089 		else
       
  1090 			{
       
  1091 			aTest(i < result);
       
  1092 			TTmDocPosSpec in(i, TTmDocPosSpec::ELeading);
       
  1093 			const TEdge* inEdge = FindExpectedEdge(in,
       
  1094 				aExpected, aNumExpected);
       
  1095 			TTmDocPosSpec out(result, TTmDocPosSpec::ETrailing);
       
  1096 			const TEdge* outEdge = FindExpectedEdge(out,
       
  1097 				aExpected, aNumExpected);
       
  1098 			aTest(outEdge != 0);
       
  1099 			if (inEdge)
       
  1100 				{
       
  1101 				aTest(lineStart <= i);
       
  1102 				aTest(!ExpectedEdgesCoincide(inEdge, outEdge));
       
  1103 				for (TInt j = i + 1; j != result; ++j)
       
  1104 					{
       
  1105 					TTmDocPosSpec between(j, TTmDocPosSpec::ETrailing);
       
  1106 					const TEdge* betweenEdge = FindExpectedEdge(between,
       
  1107 						aExpected, aNumExpected);
       
  1108 					aTest(betweenEdge != 0);
       
  1109 					// Test that, if there actually is a <j, trailing> edge, it is
       
  1110 					// coincident with <i, leading>. If the edge does not exist
       
  1111 					// it does not matter. We can find out if it exists by checking
       
  1112 					// whether the returned expected edge has the same position
       
  1113 					// we asked for.
       
  1114 					aTest(ExpectedEdgesCoincide(inEdge, betweenEdge)
       
  1115 						|| j != betweenEdge->iPos);
       
  1116 					}
       
  1117 				}
       
  1118 			else
       
  1119 				{
       
  1120 				// before the start means finding the first trailing edge
       
  1121 				aTest (i < lineStart);
       
  1122 				TInt leastTrailingEdge = KMaxTInt;
       
  1123 				for (const TEdge* e = aExpected; e != aExpected + aNumExpected;
       
  1124 					++e)
       
  1125 					{
       
  1126 					if (!e->iLeading && e->iPos < leastTrailingEdge)
       
  1127 						leastTrailingEdge = e->iPos;
       
  1128 					}
       
  1129 				aTest(leastTrailingEdge == result);
       
  1130 				}
       
  1131 			}
       
  1132 		it.Close();
       
  1133 		}
       
  1134 	}
       
  1135 
       
  1136 /**
       
  1137 Tests RTmGraphemeEdgeIterator::PreviousPosition. Expected behaviour is to find the
       
  1138 largest number 'n' that is a position in the same line smaller than the input 'i',
       
  1139 where the positions <i, trailing> and <n, leading> are not coincident.
       
  1140 */
       
  1141 void TestLayoutFindEdgesBackwards(RTest& aTest, TInt aLine,
       
  1142 	CTestTmTextLayout& aLayout,
       
  1143 	const TEdge* aExpected, TInt aNumExpected)
       
  1144 	{
       
  1145 	TInt lineStart;
       
  1146 	TInt lineEnd;
       
  1147 	LineExtent(aLine, aLayout, lineStart, lineEnd);
       
  1148 	for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
       
  1149 		{
       
  1150 		CTmTextLayout& layout = aLayout.Layout();
       
  1151 		TTmInterpreterParam interpParam(layout);
       
  1152 		RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
       
  1153 		interp.LineNumberToLine(aLine);
       
  1154 		RTmGraphemeEdgeIterator it;
       
  1155 		it.Begin(interp);
       
  1156 		TInt result = it.PreviousPosition(i);
       
  1157 		interp.Close();
       
  1158 
       
  1159 		if (result == KErrNotFound)
       
  1160 			{
       
  1161 			// Must be at or before the line's beginning.
       
  1162 			// Could possibly be that there are no leading edges in the line, but
       
  1163 			// we'll ignore that possibility.
       
  1164 			aTest(i <= lineStart);
       
  1165 			}
       
  1166 		else
       
  1167 			{
       
  1168 			aTest(result < i);
       
  1169 			TTmDocPosSpec out(result, TTmDocPosSpec::ELeading);
       
  1170 			const TEdge* outEdge = FindExpectedEdge(out,
       
  1171 				aExpected, aNumExpected);
       
  1172 			aTest(outEdge != 0);
       
  1173 			TTmDocPosSpec in(i, TTmDocPosSpec::ETrailing);
       
  1174 			const TEdge* inEdge = FindExpectedEdge(in,
       
  1175 				aExpected, aNumExpected);
       
  1176 			// if we could not find a trailing edge at this number, then we
       
  1177 			// were beyond the end of the line.
       
  1178 			if (inEdge && !inEdge->iLeading)
       
  1179 				{
       
  1180 				aTest(inEdge != 0);
       
  1181 				aTest(!ExpectedEdgesCoincide(inEdge, outEdge));
       
  1182 				for (TInt j = result + 1; j != i; ++j)
       
  1183 					{
       
  1184 					TTmDocPosSpec between(j, TTmDocPosSpec::ELeading);
       
  1185 					const TEdge* betweenEdge = FindExpectedEdge(between,
       
  1186 						aExpected, aNumExpected);
       
  1187 					aTest(betweenEdge != 0);
       
  1188 					// Test that, if there actually is a <j, trailing> edge, it is
       
  1189 					// coincident with <i, leading>. If the edge does not exist
       
  1190 					// it does not matter. We can find out if it exists by checking
       
  1191 					// whether the returned expected edge has the same position
       
  1192 					// we asked for.
       
  1193 					aTest(ExpectedEdgesCoincide(inEdge, betweenEdge)
       
  1194 						|| j != betweenEdge->iPos);
       
  1195 					}
       
  1196 				}
       
  1197 			else
       
  1198 				{
       
  1199 				// after the end means finding the last leading edge
       
  1200 				TInt greatestLeadingEdge = KMinTInt;
       
  1201 				for (const TEdge* e = aExpected; e != aExpected + aNumExpected;
       
  1202 					++e)
       
  1203 					{
       
  1204 					if (e->iLeading && greatestLeadingEdge < e->iPos)
       
  1205 						greatestLeadingEdge = e->iPos;
       
  1206 					}
       
  1207 				aTest(greatestLeadingEdge == result);
       
  1208 				}
       
  1209 			}
       
  1210 		it.Close();
       
  1211 		}
       
  1212 	}
       
  1213 
       
  1214 typedef void FTestLine(RTest& aTest, TInt aLine,
       
  1215 	CTestTmTextLayout& aLayout,
       
  1216 	const TEdge* aExpected, TInt aNumExpected);
       
  1217 
       
  1218 /**
       
  1219 Runs a particular test for each line in the input data.
       
  1220 */
       
  1221 void TestEachLine(RTest& aTest, FTestLine* aFn,
       
  1222 	CTestTmTextLayout& aLayout, const TEdge* aExpected, TInt aNumExpected)
       
  1223 	{
       
  1224 	TInt line = 0;
       
  1225 	TInt start = 0;
       
  1226 	for (TInt end = 1; end != aNumExpected; ++end)
       
  1227 		{
       
  1228 		if (aExpected[end - 1].iNext == EEdgeNewline)
       
  1229 			{
       
  1230 			aFn(aTest, line, aLayout, aExpected + start, end - start);
       
  1231 			start = end;
       
  1232 			++line;
       
  1233 			}
       
  1234 		}
       
  1235 	}
       
  1236 
       
  1237 /**
       
  1238 Tests TTmGraphemeIterator and supporting functionality for the specified
       
  1239 layout.
       
  1240 */
       
  1241 void TestLayoutL(RTest& aTest, CTestTmTextLayout& aLayout,
       
  1242 	const TEdge* aExpected, TInt aNumExpected)
       
  1243 	{
       
  1244 	aTest.Start(_L("Simple iteration"));
       
  1245 	TestLayoutSimplePass(aTest, aLayout, aExpected, aNumExpected);
       
  1246 	aTest.Next(_L("FindXPos"));
       
  1247 	TestEachLine(aTest, TestLayoutFindXPos,
       
  1248 		aLayout, aExpected, aNumExpected);
       
  1249 	aTest.Next(_L("FindXPos (unambiguous edges)"));
       
  1250 	TestEachLine(aTest, TestLayoutFindXPosEdges,
       
  1251 		aLayout, aExpected, aNumExpected);
       
  1252 	aTest.Next(_L("FindEdge"));
       
  1253 	TestEachLine(aTest, TestLayoutFindEdgesInVisualOrder,
       
  1254 		aLayout, aExpected, aNumExpected);
       
  1255 	TestEachLine(aTest, TestLayoutFindEdgesByDirectionality,
       
  1256 		aLayout, aExpected, aNumExpected);
       
  1257 	aTest.Next(_L("FindEdgeRightwards"));
       
  1258 	TestEachLine(aTest, TestLayoutFindEdgesRightwards,
       
  1259 		aLayout, aExpected, aNumExpected);
       
  1260 	aTest.Next(_L("FindEdgeLeftwards"));
       
  1261 	TestEachLine(aTest, TestLayoutFindEdgesLeftwards,
       
  1262 		aLayout, aExpected, aNumExpected);
       
  1263 	aTest.Next(_L("NextPosition"));
       
  1264 	TestEachLine(aTest, TestLayoutFindEdgesForwards,
       
  1265 		aLayout, aExpected, aNumExpected);
       
  1266 	aTest.Next(_L("PreviousPosition"));
       
  1267 	TestEachLine(aTest, TestLayoutFindEdgesBackwards,
       
  1268 		aLayout, aExpected, aNumExpected);
       
  1269 	aTest.End();
       
  1270 	}
       
  1271 
       
  1272 /**
       
  1273 Tests TTmGraphemeIterator and supporting functionality for each piece of text.
       
  1274 */
       
  1275 void RunTestsL(RTest& aTest)
       
  1276 	{
       
  1277 	aTest.Start(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-GRAPHEMEITERATOR-0001 DocPosMatches "));
       
  1278 	TestDocPosMatches(aTest);
       
  1279 	aTest.Next(_L("Simple Latin"));
       
  1280 	CTestTmTextLayout* latin1 = CTestTmTextLayout::NewLC(
       
  1281 		KLatin1, 100, Transliterate);
       
  1282 	TestLayoutL(aTest, *latin1, KLatin1Edges,
       
  1283 		sizeof(KLatin1Edges)/sizeof(KLatin1Edges[0]));
       
  1284 	CleanupStack::PopAndDestroy(latin1);
       
  1285 
       
  1286 	aTest.Next(_L("Simple Arabic"));
       
  1287 	CTestTmTextLayout* arabic1 = CTestTmTextLayout::NewLC(
       
  1288 		KArabic1, 100, Transliterate);
       
  1289 	TestLayoutL(aTest, *arabic1, KArabic1Edges,
       
  1290 		sizeof(KArabic1Edges)/sizeof(KArabic1Edges[0]));
       
  1291 	CleanupStack::PopAndDestroy(arabic1);
       
  1292 
       
  1293 	aTest.Next(_L("Latin with combining marks and zero width characters"));
       
  1294 	CTestTmTextLayout* combiners1 = CTestTmTextLayout::NewLC(
       
  1295 		KCombiners1, 20, Transliterate);
       
  1296 	TestLayoutL(aTest, *combiners1, KCombiners1Edges,
       
  1297 		sizeof(KCombiners1Edges)/sizeof(KCombiners1Edges[0]));
       
  1298 	CleanupStack::PopAndDestroy(combiners1);
       
  1299 
       
  1300 	aTest.Next(_L("Bidirectional text with combining marks"));
       
  1301 	CTestTmTextLayout* bidi1 = CTestTmTextLayout::NewLC(
       
  1302 		KBidi1, 60, Transliterate);
       
  1303 	TestLayoutL(aTest, *bidi1, KBidi1Edges,
       
  1304 		sizeof(KBidi1Edges)/sizeof(KBidi1Edges[0]));
       
  1305 	CleanupStack::PopAndDestroy(bidi1);
       
  1306 
       
  1307 	aTest.Next(_L("Bidirectional text with combining marks and 'amtriguity'"));
       
  1308 	CTestTmTextLayout* bidi2 = CTestTmTextLayout::NewLC(
       
  1309 		KBidi2, 60, Transliterate);
       
  1310 	TestLayoutL(aTest, *bidi2, KBidi2Edges,
       
  1311 		sizeof(KBidi2Edges)/sizeof(KBidi2Edges[0]));
       
  1312 	CleanupStack::PopAndDestroy(bidi2);
       
  1313 
       
  1314 	aTest.Next(_L("Small paragraphs of alternating directionality"));
       
  1315 	CTestTmTextLayout* paragraphs1 = CTestTmTextLayout::NewLC(
       
  1316 		KParagraphs1, 20, Transliterate);
       
  1317 	TestLayoutL(aTest, *paragraphs1, KParagraphs1Edges,
       
  1318 		sizeof(KParagraphs1Edges)/sizeof(KParagraphs1Edges[0]));
       
  1319 	CleanupStack::PopAndDestroy(paragraphs1);
       
  1320 
       
  1321 	aTest.Next(_L("Lines ending over or next to embedded runs"));
       
  1322 	CTestTmTextLayout* embedded1 = CTestTmTextLayout::NewLC(
       
  1323 		KEmbedded1, 20, Transliterate);
       
  1324 	TestLayoutL(aTest, *embedded1, KEmbedded1Edges,
       
  1325 		sizeof(KEmbedded1Edges)/sizeof(KEmbedded1Edges[0]));
       
  1326 	CleanupStack::PopAndDestroy(embedded1);
       
  1327 
       
  1328 	aTest.End();
       
  1329 	}
       
  1330 
       
  1331 /**
       
  1332 Tests TTmGraphemeIterator and supporting functionality.
       
  1333 */
       
  1334 TInt E32Main()
       
  1335 	{
       
  1336 	RTest rtest(_L("RTmGraphemeEdgeIterator unit"));
       
  1337 	CTrapCleanup* TrapCleanup = CTrapCleanup::New();
       
  1338 	rtest.Title();
       
  1339 	TRAPD(err, RunTestsL(rtest));
       
  1340 	rtest.Close();
       
  1341 	delete TrapCleanup;
       
  1342 	return err;
       
  1343 	}
       
  1344