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