Update contrib.
2 * Copyright (c) 2003-2010 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
15 * TGraphemeIterator.cpp unit tests for RTmGraphemeEdgeIterator
20 #include "TestLayout.h"
21 #include "TGraphicsContext.h"
24 #include "tgraphemeiterator.h"
26 namespace LocalToTGraphemeIterator
28 CTGraphemeIteratorStep* TestStep;
29 #define TESTPOINT(p) TestStep->testpoint(p,(TText8*)__FILE__,__LINE__)
30 #define TESTPRINT(p) TestStep->print(p,(TText8*)__FILE__,__LINE__)
32 struct TTransliteration
37 static const TTransliteration KArabicTransliteration[] =
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 }
94 using namespace LocalToTGraphemeIterator;
96 TText TransliterateSingle(const TText*& aInput, const TText* aEnd)
98 const TInt tableSize =
99 sizeof(KArabicTransliteration)/sizeof(KArabicTransliteration[0]);
100 for (TInt i = 0; i != tableSize; ++i)
102 const TText* p = KArabicTransliteration[i].iString;
103 const TText* q = aInput;
104 while (q != aEnd && *q == *p)
111 return static_cast<TText>(KArabicTransliteration[i].iChar);
115 TText result = *aInput;
120 // transliteration is turned on with { and off with }.
121 // use }{ to split digraphs.
122 void Transliterate(const TDesC& aIn, TDes& aOut)
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();
131 if (!transliterating)
133 if (*p == KTransliterationOn)
135 transliterating = ETrue;
143 if (*p == KTransliterationOff)
145 transliterating = EFalse;
149 aOut.Append(TransliterateSingle(p, pEnd));
155 Tests RTmGraphemeEdgeIterator::DocPosMatches for this document position and
158 void TestDocPosMatchesCase(const TTmGraphemeEdgeInfo& aEdgeInfo,
159 TTmDocPosSpec& aPosSpec,
160 RTmGraphemeEdgeIterator::TGraphemeMatch aExpectedMatchType)
162 TInt start = aEdgeInfo.iPos.iDocPos.iPos;
164 if (aEdgeInfo.iPos.iDocPos.iLeadingEdge)
165 end += aEdgeInfo.iCodePoints;
168 start -= aEdgeInfo.iCodePoints - 1;
171 aPosSpec.iPos = start - 1;
172 TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
173 == RTmGraphemeEdgeIterator::ENoMatch);
174 for (TInt i = start; i != end; ++i)
177 TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
178 == aExpectedMatchType);
181 TESTPOINT(RTmGraphemeEdgeIterator::DocPosMatches(aPosSpec, aEdgeInfo)
182 == RTmGraphemeEdgeIterator::ENoMatch);
186 Tests RTmGraphemeEdgeIterator::DocPosMatches for this edge and all relevant
187 document position specifications.
189 void TestDocPosMatchesAllSpecs(const TTmGraphemeEdgeInfo& aEdgeInfo)
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);
216 Tests RTmGraphemeEdgeIterator::DocPosMatches for a variety of edges and
219 void TestDocPosMatches()
221 TTmGraphemeEdgeInfo edgeInfo;
222 edgeInfo.iPos.iDocPos.iPos = 5;
223 for (edgeInfo.iCodePoints = 1; edgeInfo.iCodePoints <= 3;
224 ++edgeInfo.iCodePoints)
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);
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 };
246 TEdgeRelationship iNext;
247 TAmbiguity iAmbiguity;
248 TDirectionality iRightToLeft;
251 _LIT(KLatin1, "Latin text\x2029Latin text over three lines.");
252 static const TEdge KLatin1Edges[] =
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},
315 _LIT(KArabic1, "{al'rbyA}\x2029{al'rbyA kf Sayd almwstfa}\x2029{lala lala}.");
316 static const TEdge KArabic1Edges[] =
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}
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[] =
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}
374 // Add another example including bidirectional text
375 _LIT(KBidi1, "A\x301{b^ft^k}12\x200FZ\x301");
376 static const TEdge KBidi1Edges[] =
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}
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[] =
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}
402 _LIT(KParagraphs1, "z\x2029{b}\x2029z");
403 static const TEdge KParagraphs1Edges[] =
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},
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},
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}
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[] =
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},
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},
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},
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},
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},
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},
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},
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},
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},
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},
477 Returns which portion of the text is in the specified line.
479 void LineExtent(TInt aLine, CTestTmTextLayout& aLayout,
480 TInt& aLineStart, TInt& aLineEnd)
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;
491 Finds an edge in the expected edges list that matches a document position
494 const TEdge* FindExpectedEdge(const TTmDocPosSpec& aPos,
495 const TEdge* aExpected, TInt aNumExpected)
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)
503 TInt distance = e->iPos - aPos.iPos;
504 if (!e->iLeading && 0 <= distance && distance < distanceTrailing)
506 distanceTrailing = distance;
509 if (e->iLeading && distanceLeading < distance && distance <= 0)
511 distanceLeading = distance;
515 if (aPos.iType == TTmDocPosSpec::ELeading || !nearestTrailing)
517 return nearestLeading;
519 if (aPos.iType == TTmDocPosSpec::ETrailing || !nearestLeading)
521 return nearestTrailing;
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;
541 Returns ETrue if and only if the two edges specified are expected to be
544 TBool ExpectedEdgesCoincide(const TEdge* aA, const TEdge* aB)
546 const TEdge* a = aA < aB? aA : aB;
547 const TEdge* b = aA < aB? aB : aA;
550 if (a->iNext != EEdgeSame)
558 Tests that the edge information matches the expected edge.
560 void TestExpectedEdge(const TTmPosInfo2& aEdgeInfo,
561 const TEdge* aExpected)
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);
571 Tests that the edge information matches one of the expected edges.
573 void TestEdgeExists(const TTmPosInfo2& aEdgeInfo,
574 const TEdge* aExpected, TInt aNumExpected)
576 TTmDocPos pos(aEdgeInfo.iDocPos);
577 const TEdge* edge = FindExpectedEdge(pos, aExpected, aNumExpected);
578 TESTPOINT(edge != 0);
579 TestExpectedEdge(aEdgeInfo, edge);
583 Tests that the visual position matches one of the expected edges.
585 void TestVisualPositionExists(const TTmVisualDocPos& aPos,
586 const TEdge* aExpected, TInt aNumExpected)
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));
603 Tests that a RTmGraphemeEdgeIterator iterates through all the positions in a
604 line from left to right.
606 void TestLayoutSimplePass(CTestTmTextLayout& aLayout,
607 const TEdge* aExpected, TInt aNumExpected)
609 CTmTextLayout& layout = aLayout.Layout();
610 TTmInterpreterParam interpParam(layout);
611 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
612 interp.LineNumberToLine(0);
613 RTmGraphemeEdgeIterator it;
615 TTmPosInfo2 last = it.GetInfo();
616 for (TInt i = 0; i != aNumExpected; ++i)
618 const TEdge& expected = aExpected[i];
619 TESTPOINT(expected.iPos == last.iDocPos.iPos);
620 TESTPOINT(expected.iLeading == last.iDocPos.iLeadingEdge);
624 TESTPOINT(expected.iNext == EEdgeNewline);
625 while (interp.Op() != TTmInterpreter::EOpLine && interp.Next())
627 if (i + 1 != aNumExpected)
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);
650 Tests that FindXPos returns the edge 'closest' to the input co-ordinate
651 where there is no ambiguity.
653 void TestLayoutFindXPosEdges(TInt aLine,
654 CTestTmTextLayout& aLayout,
655 const TEdge* aExpected, TInt aNumExpected)
657 CTmTextLayout& layout = aLayout.Layout();
658 TTmInterpreterParam interpParam(layout);
660 TTmDocPosSpec posSpec;
661 TTmLineInfo lineInfo;
662 TTmVisualDocPos visPos;
663 for (TInt i = 0; i != aNumExpected - 1; ++i)
665 const TEdge& expectedL = aExpected[i];
666 const TEdge& expectedR = aExpected[i + 1];
667 if (expectedL.iNext == EEdgeDifferent)
669 // This code assumes that no character has a width of exactly 1 pixel.
670 if (!expectedL.iAmbiguity)
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;
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);
689 if (!expectedR.iAmbiguity)
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;
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);
713 Tests that RTmGraphemeEdgeIterator::FindXPos finds document positions that
714 match the positions they are supposed to be in.
716 void TestLayoutFindXPos(TInt aLine,
717 CTestTmTextLayout& aLayout,
718 const TEdge* aExpected, TInt aNumExpected)
720 TInt lastLeftX = KMinTInt;
721 TInt lastRightX = KMinTInt;
722 TTmVisualDocPos visPos;
723 TBool finished = EFalse;
724 for (TInt x = -10; !finished; ++x)
726 CTmTextLayout& layout = aLayout.Layout();
727 TTmInterpreterParam interpParam(layout);
728 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
729 interp.LineNumberToLine(aLine);
730 RTmGraphemeEdgeIterator it;
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)
741 TESTPOINT(lastRightX == visPos.RightEdge().iEdge.iX);
742 while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
743 || aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
745 TESTPOINT(aExpected->iNext == EEdgeSame);
746 TESTPOINT(0 < aNumExpected);
753 TESTPOINT(lastRightX <= visPos.LeftEdge().iEdge.iX);
754 while (aExpected->iPos != visPos.LeftEdge().iDocPos.iPos
755 || aExpected->iLeading != visPos.LeftEdge().iDocPos.iLeadingEdge)
757 TESTPOINT(0 < aNumExpected);
762 if (interp.LineInfo().iInnerRect.iBr.iX + 120 < x)
767 while (aExpected->iNext != EEdgeNewline)
769 TESTPOINT(aExpected->iNext == EEdgeSame);
770 TESTPOINT(0 < aNumExpected);
777 Uses RTmGraphemeEdgeIterator::FindEdge to find a document position in a
780 TBool FindEdgeFromLayout(CTestTmTextLayout& aLayout, TInt aLine,
781 const TTmDocPosSpec& aDocPos, TTmPosInfo2& aInfo)
783 CTmTextLayout& layout = aLayout.Layout();
784 TTmInterpreterParam interpParam(layout);
785 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
786 interp.LineNumberToLine(aLine);
787 RTmGraphemeEdgeIterator it;
789 TBool result = it.FindEdge(aDocPos, aInfo);
796 Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
797 specifications of leading or trailing edges.
799 void TestLayoutFindEdgesInVisualOrder(TInt aLine,
800 CTestTmTextLayout& aLayout,
801 const TEdge* aExpected, TInt aNumExpected)
803 TInt lastX = KMinTInt;
804 TBool sameExpected = EFalse;
806 while (aNumExpected != 0)
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;
825 Tests that RTmGraphemeEdgeIterator::FindEdge finds the edges in the layout with
826 specifications of directionality.
828 void TestLayoutFindEdgesByDirectionality(TInt aLine,
829 CTestTmTextLayout& aLayout,
830 const TEdge* aExpected, TInt aNumExpected)
834 LineExtent(aLine, aLayout, lineStart, lineEnd);
835 TTmPosInfo2 lToRPosInfo;
836 TTmPosInfo2 rToLPosInfo;
837 for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
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);
845 TESTPOINT(!rToLFound);
846 TESTPOINT(pos < lineStart || lineEnd <= pos);
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
876 TESTPOINT(rToLPosInfo.iRightToLeft
877 || (!leadingExpected->iRightToLeft && !trailingExpected->iRightToLeft));
878 TESTPOINT(!lToRPosInfo.iRightToLeft
879 || (leadingExpected->iRightToLeft && trailingExpected->iRightToLeft));
885 Tests RTmGraphemeEdgeIterator::FindEdgeRightwards or
886 RTmGraphemeEdgeIterator::FindEdgeLeftwards.
888 void TestLayoutFindEdgesLeftRight(TInt aLine,
889 CTestTmTextLayout& aLayout, TBool aRightwards,
890 const TEdge* aExpected, TInt aNumExpected)
894 LineExtent(aLine, aLayout, lineStart, lineEnd);
896 TTmVisualDocPos next;
897 const TTmDocPosSpec::TType types[4]
898 = {TTmDocPosSpec::ETrailing,
899 TTmDocPosSpec::ELeading,
900 TTmDocPosSpec::ELeftToRight,
901 TTmDocPosSpec::ERightToLeft};
903 for (TInt pos = lineStart - 1; pos != lineEnd + 1; ++pos)
905 for (TInt type = 0; type != 4; ++type)
907 TTmDocPosSpec posSpec(pos, types[type]);
909 // What do we expect the nearest to be?
910 TTmDocPosSpec leadingPosSpec(pos, TTmDocPosSpec::ELeading);
911 TTmDocPosSpec trailingPosSpec(pos, TTmDocPosSpec::ETrailing);
913 const TEdge* leadingExpected
914 = FindExpectedEdge(leadingPosSpec, aExpected, aNumExpected);
915 const TEdge* trailingExpected
916 = FindExpectedEdge(trailingPosSpec, aExpected, aNumExpected);
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;
928 // <lineEnd, trailing> is the only element that may be present
929 // at position lineEnd.
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
936 || trailingExpected->iPos != pos)
937 leadingExpected = trailingExpected = 0;
939 // <lineStart, trailing> may not be in the line.
940 // We must check explicitly.
941 if (pos == lineStart && posSpec.iType == TTmDocPosSpec::ETrailing)
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;
950 if (!leadingExpected)
951 leadingExpected = trailingExpected;
952 if (!trailingExpected)
953 trailingExpected = leadingExpected;
955 const TEdge* nextExpected = 0;
957 CTmTextLayout& layout = aLayout.Layout();
958 TTmInterpreterParam interpParam(layout);
959 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
960 interp.LineNumberToLine(aLine);
961 RTmGraphemeEdgeIterator it;
963 RTmGraphemeEdgeIterator::TEdgesFound result = aRightwards?
964 it.FindEdgeRightwards(posSpec, nearest, next)
965 : it.FindEdgeLeftwards(posSpec, nearest, next);
968 // Does what we got match what we expect?
969 if (!leadingExpected)
971 TESTPOINT(result == RTmGraphemeEdgeIterator::ENone);
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)
986 TESTPOINT(ExpectedEdgesCoincide(trailingExpected, nearestEdge));
987 matchingEdge = trailingExpected;
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);
1003 // Find next edge in expected list
1004 const TEdge* e = matchingEdge;
1005 const TEdge* end = aRightwards?
1006 aExpected + aNumExpected - 1
1008 TInt direction = aRightwards? 1 : -1;
1009 while (nextExpected == 0 && e != end)
1012 if (!ExpectedEdgesCoincide(e, matchingEdge))
1017 TESTPOINT(result == RTmGraphemeEdgeIterator::ENone
1018 || result == RTmGraphemeEdgeIterator::ENearestOnly);
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)));
1037 Tests RTmGraphemeEdgeIterator::FindEdgeRightwards.
1039 void TestLayoutFindEdgesRightwards(TInt aLine,
1040 CTestTmTextLayout& aLayout,
1041 const TEdge* aExpected, TInt aNumExpected)
1043 TestLayoutFindEdgesLeftRight(aLine, aLayout, ETrue,
1044 aExpected, aNumExpected);
1048 Tests RTmGraphemeEdgeIterator::FindEdgeLeftwards.
1050 void TestLayoutFindEdgesLeftwards(TInt aLine,
1051 CTestTmTextLayout& aLayout,
1052 const TEdge* aExpected, TInt aNumExpected)
1054 TestLayoutFindEdgesLeftRight(aLine, aLayout, EFalse,
1055 aExpected, aNumExpected);
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.
1063 void TestLayoutFindEdgesForwards(TInt aLine,
1064 CTestTmTextLayout& aLayout,
1065 const TEdge* aExpected, TInt aNumExpected)
1069 LineExtent(aLine, aLayout, lineStart, lineEnd);
1070 for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
1072 CTmTextLayout& layout = aLayout.Layout();
1073 TTmInterpreterParam interpParam(layout);
1074 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
1075 interp.LineNumberToLine(aLine);
1076 RTmGraphemeEdgeIterator it;
1078 TInt result = it.NextPosition(i);
1081 if (result == KErrNotFound)
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);
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);
1107 TESTPOINT(lineStart <= i);
1108 TESTPOINT(!ExpectedEdgesCoincide(inEdge, outEdge));
1109 for (TInt j = i + 1; j != result; ++j)
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
1120 TESTPOINT(ExpectedEdgesCoincide(inEdge, betweenEdge)
1121 || j != betweenEdge->iPos);
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;
1132 if (!e->iLeading && e->iPos < leastTrailingEdge)
1133 leastTrailingEdge = e->iPos;
1135 TESTPOINT(leastTrailingEdge == result);
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.
1147 void TestLayoutFindEdgesBackwards(TInt aLine,
1148 CTestTmTextLayout& aLayout,
1149 const TEdge* aExpected, TInt aNumExpected)
1153 LineExtent(aLine, aLayout, lineStart, lineEnd);
1154 for (TInt i = lineStart - 1; i != lineEnd + 1; ++i)
1156 CTmTextLayout& layout = aLayout.Layout();
1157 TTmInterpreterParam interpParam(layout);
1158 RTmGeneralInterpreter interp(aLayout.Source(), interpParam);
1159 interp.LineNumberToLine(aLine);
1160 RTmGraphemeEdgeIterator it;
1162 TInt result = it.PreviousPosition(i);
1165 if (result == KErrNotFound)
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);
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)
1186 TESTPOINT(inEdge != 0);
1187 TESTPOINT(!ExpectedEdgesCoincide(inEdge, outEdge));
1188 for (TInt j = result + 1; j != i; ++j)
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
1199 TESTPOINT(ExpectedEdgesCoincide(inEdge, betweenEdge)
1200 || j != betweenEdge->iPos);
1205 // after the end means finding the last leading edge
1206 TInt greatestLeadingEdge = KMinTInt;
1207 for (const TEdge* e = aExpected; e != aExpected + aNumExpected;
1210 if (e->iLeading && greatestLeadingEdge < e->iPos)
1211 greatestLeadingEdge = e->iPos;
1213 TESTPOINT(greatestLeadingEdge == result);
1220 typedef void FTestLine(TInt aLine,
1221 CTestTmTextLayout& aLayout,
1222 const TEdge* aExpected, TInt aNumExpected);
1225 Runs a particular test for each line in the input data.
1227 void TestEachLine(FTestLine* aFn,
1228 CTestTmTextLayout& aLayout, const TEdge* aExpected, TInt aNumExpected)
1232 for (TInt end = 1; end != aNumExpected; ++end)
1234 if (aExpected[end - 1].iNext == EEdgeNewline)
1236 aFn(line, aLayout, aExpected + start, end - start);
1244 Tests TTmGraphemeIterator and supporting functionality for the specified
1247 void TestLayoutL(CTestTmTextLayout& aLayout,
1248 const TEdge* aExpected, TInt aNumExpected)
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);
1278 Tests TTmGraphemeIterator and supporting functionality for each piece of text.
1280 TVerdict CTGraphemeIteratorStep::doTestStepL()
1282 SetTestStepResult(EPass);
1284 TESTPRINT(_L("RTmGraphemeEdgeIterator unit"));
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);
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);
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);
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);
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);
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);
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);
1337 return TestStepResult();