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