textrendering/textformatting/test/src/TTmSource.cpp
changeset 0 1fb32624e06b
child 51 a7c938434754
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 /*
       
     2 * Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 * Test code for MTmSource functionality
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "TAGMA.H"
       
    21 #include <e32test.h>
       
    22 
       
    23 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    24 #include "TAGMA_INTERNAL.H"
       
    25 #endif
       
    26 
       
    27 #define UNUSED_VAR(a) a = a
       
    28 
       
    29 CTrapCleanup* TrapCleanup;
       
    30 RTest test(_L("TTmSource - MTmSource tests"));
       
    31 
       
    32 class TTestGraphicsDeviceMap : public MGraphicsDeviceMap
       
    33 	{
       
    34 public:
       
    35 	TInt HorizontalTwipsToPixels(TInt a) const { return a; }
       
    36 	TInt VerticalTwipsToPixels(TInt a) const { return a; }
       
    37 	TInt HorizontalPixelsToTwips(TInt a) const { return a; }
       
    38 	TInt VerticalPixelsToTwips(TInt a) const { return a; }
       
    39 	TInt GetNearestFontInTwips(CFont*&,const TFontSpec&)
       
    40 		{
       
    41 		return KErrGeneral;
       
    42 		}
       
    43 	void ReleaseFont(CFont*) {}
       
    44 	};
       
    45 
       
    46 class CTestPicture : public CPicture
       
    47 	{
       
    48 public:
       
    49 	CTestPicture() {}
       
    50 	virtual void Draw(CGraphicsContext&, const TPoint&, const TRect&, MGraphicsDeviceMap*) const {}
       
    51 	virtual void ExternalizeL(RWriteStream&) const {}
       
    52 	virtual void GetOriginalSizeInTwips(TSize&) const {}
       
    53 	virtual TBool LineBreakPossible(TUint aClass,TBool aBeforePicture,TBool aHaveSpaces) const
       
    54 		{
       
    55 		++iRequestCount;
       
    56 		if (aBeforePicture)
       
    57 			{
       
    58 			test(aClass == iClassBefore);
       
    59 			test(aHaveSpaces == iSpacesBefore);
       
    60 			return iResultBefore;
       
    61 			}
       
    62 		test(aClass == iClassAfter);
       
    63 		test(aHaveSpaces == iSpacesAfter);
       
    64 		return iResultAfter;
       
    65 		}
       
    66 	// expected parameters for LineBreakPossible
       
    67 	TUint iClassBefore;
       
    68 	TUint iClassAfter;
       
    69 	TBool iSpacesBefore;
       
    70 	TBool iSpacesAfter;
       
    71 	// Results for breaking before/breaking after
       
    72 	TBool iResultBefore;
       
    73 	TBool iResultAfter;
       
    74 	mutable TInt iRequestCount;
       
    75 	};
       
    76 
       
    77 class TTestSource : public MTmSource
       
    78 	{
       
    79 public:
       
    80 	TTestSource() : iPicturePos(-1) {}
       
    81 	virtual ~TTestSource() {}
       
    82 	MGraphicsDeviceMap& FormatDevice() const { return iGDM; }
       
    83 	MGraphicsDeviceMap& InterpretDevice() const { return iGDM; }
       
    84 	TInt DocumentLength() const
       
    85 		{
       
    86 		return iText->Length();
       
    87 		}
       
    88 	void GetText(TInt aPos,TPtrC& aText, TTmCharFormat& aFormat) const
       
    89 		{
       
    90 		TTmCharFormat f;
       
    91 		aFormat = f;
       
    92 		aText.Set(iText->Mid(aPos));
       
    93 		}
       
    94 	void GetParagraphFormatL(TInt, RTmParFormat& aFormat) const
       
    95 		{
       
    96 		RTmParFormat p;
       
    97 		aFormat.CopyL(p);
       
    98 		}
       
    99 	CPicture* PictureL(TInt aPos) const
       
   100 		{
       
   101 		return aPos == iPicturePos? iPicture : 0;
       
   102 		}
       
   103 	TInt ParagraphStart(TInt) const { return 0; }
       
   104 
       
   105 	virtual TUint LineBreakClass(TUint aCode, TUint& aRangeStart,
       
   106 		TUint& aRangeEnd) const
       
   107 		{
       
   108 		if ('@' == aCode)
       
   109 			{
       
   110 			aRangeStart = aRangeEnd = aCode;
       
   111 			return ESaLineBreakClass;
       
   112 			}
       
   113 		if ('0' <= aCode && aCode <= '9')
       
   114 			{
       
   115 			aRangeStart = aRangeEnd = aCode;
       
   116 			return ELineBreakClasses + aCode - '0';
       
   117 			}
       
   118 		return MTmSource::LineBreakClass(aCode, aRangeStart, aRangeEnd);
       
   119 		}
       
   120 
       
   121 	virtual TBool LineBreakPossible(TUint aPrevClass, TUint aNextClass,
       
   122 		TBool aHaveSpaces) const
       
   123 		{
       
   124 		TInt first = static_cast<TInt>(aPrevClass);
       
   125 		TInt second = static_cast<TInt>(aNextClass);
       
   126 		TInt customCount = 0;
       
   127 		if (iDirection < 0)
       
   128 			{
       
   129 			first = aNextClass;
       
   130 			second = aPrevClass;
       
   131 			}
       
   132 		if (ELineBreakClasses <= first && first < ELineBreakClasses + 10)
       
   133 			{
       
   134 			++customCount;
       
   135 			test(first - ELineBreakClasses + '0' == FindNextCustomClass());
       
   136 			TInt countSpaces = CountSpaces();
       
   137 			test(!aHaveSpaces == !countSpaces);
       
   138 			}
       
   139 		if (ELineBreakClasses <= second && second < ELineBreakClasses + 10)
       
   140 			{
       
   141 			++customCount;
       
   142 			TInt c = FindNextCustomClass();
       
   143 			test(second - ELineBreakClasses + '0' == c);
       
   144 			}
       
   145 		if (0 == customCount)
       
   146 			return MTmSource::LineBreakPossible(aPrevClass, aNextClass, aHaveSpaces);
       
   147 		// Between custom and non-custom classes, allow a break only with spaces
       
   148 		// or between @ and 5
       
   149 		if (1 == customCount)
       
   150 			return aHaveSpaces
       
   151 				|| (first == ESaLineBreakClass && second == ELineBreakClasses + 5)
       
   152 				|| (second == ESaLineBreakClass && first == ELineBreakClasses + 5);
       
   153 		// Allow a break with spaces except after '0' or before '9'
       
   154 		if (aHaveSpaces)
       
   155 			return aPrevClass != ELineBreakClasses && aNextClass != ELineBreakClasses + 9;
       
   156 		// Allow a break only between a class and the class one more than it.
       
   157 		return aPrevClass + 1 == aNextClass;
       
   158 		}
       
   159 
       
   160 	virtual TBool GetLineBreakInContext(
       
   161 		const TDesC& aText, TInt aMinBreakPos, TInt aMaxBreakPos,
       
   162 		TBool aForwards,TInt& aBreakPos) const
       
   163 		{
       
   164 		test (iDirection == (aForwards? 1 : -1));
       
   165 		// The allowable break-points should not include the first
       
   166 		// and last characters of the run.
       
   167 		test (aMinBreakPos != 0);
       
   168 		for (TInt i = aMinBreakPos - 1; i <= aMaxBreakPos; ++i)
       
   169 			test('@' == aText[i]);
       
   170 		++iSaRequestCount;
       
   171 		aBreakPos = iText->Ptr() + iSaBreakpoint - aText.Ptr();
       
   172 		return aMinBreakPos <= aBreakPos && aBreakPos <= aMaxBreakPos;
       
   173 		}
       
   174 
       
   175 	virtual TBool IsHangingCharacter(TUint aChar) const
       
   176 		{
       
   177 		++iHangingCharRequestCount;
       
   178 		test(aChar == (*iText)[iMaxBreakPos]);
       
   179 		if (!iHangingChar)
       
   180 			return EFalse;
       
   181 		if (iDirection < 0)
       
   182 			++iCurrentPos;
       
   183 		return ETrue;
       
   184 		}
       
   185 
       
   186 	// non-virtual
       
   187 	TBool GetLineBreakL(const TDesC& aText, TInt aDocPos,
       
   188 		TInt aMinBreakPos, TInt aMaxBreakPos, TBool aForwards,
       
   189 		TInt& aBreakPos, TInt& aHangingChars, TInt& aBreakPosAfterSpaces) const
       
   190 		{
       
   191 		iText = &aText;
       
   192 		iMaxBreakPos = aMaxBreakPos;
       
   193 		iMinBreakPos = aMinBreakPos;
       
   194 		iHangingCharRequestCount = 0;
       
   195 		iSaRequestCount = 0;
       
   196 		iDirection = aForwards? 1 : -1;
       
   197 		iCurrentPos = aForwards? aMinBreakPos : aMaxBreakPos - 1;
       
   198 		TBool r = MTmSource::GetLineBreakL(aText, aDocPos,
       
   199 			aMinBreakPos, aMaxBreakPos, aForwards,
       
   200 			aBreakPos, aHangingChars, aBreakPosAfterSpaces);
       
   201 		if (r)
       
   202 			{
       
   203 			test(aMinBreakPos <= aBreakPos);
       
   204 			test(0 < aBreakPos);
       
   205 			test(aBreakPos <= aHangingChars);
       
   206 			test(aHangingChars <= aBreakPosAfterSpaces);
       
   207 			test(aBreakPos <= aMaxBreakPos);
       
   208 			test(aHangingChars == aBreakPos || iHangingChar);
       
   209 			// If the direction was backwards, the algorithm should have
       
   210 			// checked if a hanging character was allowed.
       
   211 			// This condition could be relaxed to allow it not to be checked
       
   212 			// if there is no break allowed between the possible hanging
       
   213 			// character and the previous character.
       
   214 			test(!aForwards || aText.Length() == aMaxBreakPos
       
   215 				|| 0 < iHangingCharRequestCount);
       
   216 			// If the maximum break point was chosen or exceeded, the algorithm
       
   217 			// should have checked to find out whether a hanging character is
       
   218 			// allowed.
       
   219 			test(aHangingChars < aMaxBreakPos
       
   220 				|| 0 < iHangingCharRequestCount);
       
   221 			// Check that only spaces exist between aHangingChars and
       
   222 			// aMaxBreakPos
       
   223 			for (TInt i = aHangingChars; i != aBreakPosAfterSpaces; ++i)
       
   224 				{
       
   225 				TUint n;
       
   226 				test(ESpLineBreakClass == LineBreakClass(aText[i], n, n));
       
   227 				}
       
   228 			// Check that all the spaces were counted
       
   229 			test(aBreakPosAfterSpaces == aText.Length()
       
   230 				|| aText[aBreakPosAfterSpaces] != ' ');
       
   231 			}
       
   232 		// Find out how many runs of two or more Sa there are, and check that
       
   233 		// this matches the number of times that it was requested.
       
   234 		TInt minChecked = aMinBreakPos - 1;
       
   235 		TInt maxChecked = aMaxBreakPos + 2;
       
   236 		if (r)
       
   237 			{
       
   238 			if (aForwards)
       
   239 				maxChecked = aBreakPos + 1;
       
   240 			else
       
   241 				minChecked = aBreakPos - 1;
       
   242 			}
       
   243 		if (minChecked < 0)
       
   244 			minChecked = 0;
       
   245 		if (aText.Length() < maxChecked)
       
   246 			maxChecked = aText.Length();
       
   247 		TInt runs = 0;
       
   248 		TInt sasSoFar = 0;
       
   249 		test (maxChecked - minChecked < 2
       
   250 			|| aText[minChecked] != '@'
       
   251 			|| aText[minChecked + 1] != '@'
       
   252 			|| !aForwards
       
   253 			|| aHangingChars == iSaBreakpoint);
       
   254 		for (; minChecked != maxChecked; ++minChecked)
       
   255 			{
       
   256 			if (aText[minChecked] == '@')
       
   257 				++sasSoFar;
       
   258 			else
       
   259 				{
       
   260 				if (1 < sasSoFar)
       
   261 					++runs;
       
   262 				sasSoFar = 0;
       
   263 				}
       
   264 			}
       
   265 		if (1 < sasSoFar)
       
   266 			++runs;
       
   267 		test(sasSoFar < 2 || aForwards || aHangingChars == iSaBreakpoint);
       
   268 		test(runs == iSaRequestCount);
       
   269 		return r;
       
   270 		}
       
   271 
       
   272 	TInt FindNextCustomClass() const
       
   273 		{
       
   274 		TInt end = iDirection < 0? -1 : iText->Length();
       
   275 		for (; iCurrentPos != end; iCurrentPos += iDirection)
       
   276 			{
       
   277 			TInt c = (*iText)[iCurrentPos];
       
   278 			if ('0' <= c && c <= '9')
       
   279 				return c;
       
   280 			}
       
   281 		return -1;
       
   282 		}
       
   283 	TInt CountSpaces() const
       
   284 		{
       
   285 		TInt end = iDirection < 0? -1 : iText->Length();
       
   286 		TInt count = 0;
       
   287 		if (iCurrentPos == end)
       
   288 			return 0;
       
   289 		iCurrentPos += iDirection;
       
   290 		for (; iCurrentPos != end; iCurrentPos += iDirection, ++count)
       
   291 			{
       
   292 			TInt c = (*iText)[iCurrentPos];
       
   293 			if (' ' != c)
       
   294 				return count;
       
   295 			}
       
   296 		return count;
       
   297 		}
       
   298 
       
   299 private:
       
   300 	mutable TTestGraphicsDeviceMap iGDM;
       
   301 	mutable const TDesC* iText;
       
   302 	mutable TInt iMaxBreakPos;
       
   303 	mutable TInt iMinBreakPos;
       
   304 
       
   305 	mutable TInt iDirection;
       
   306 	mutable TInt iCurrentPos;
       
   307 	mutable TInt iHangingCharRequestCount;
       
   308 	mutable TInt iSaRequestCount;
       
   309 
       
   310 public:
       
   311 	TInt iPicturePos;
       
   312 	CPicture* iPicture;
       
   313 
       
   314 	TBool iHangingChar;
       
   315 
       
   316 	TInt iSaBreakpoint;
       
   317 	};
       
   318 
       
   319 TInt TestLineBreak(const TDesC& aText, TInt aSaBreak, TBool aHangingChar,
       
   320 	TInt aMin, TInt aMax, TBool aForwards)
       
   321 	{
       
   322 	if (aMax == 0)
       
   323 		aMax = aText.Length();
       
   324 	TTestSource t;
       
   325 	t.iHangingChar = aHangingChar;
       
   326 	t.iSaBreakpoint = aSaBreak;
       
   327 	TInt b0, b1, b2;
       
   328 	b0 = KMaxTInt;
       
   329 	b1 = KMaxTInt;
       
   330 	b2 = KMaxTInt;
       
   331 	return t.GetLineBreakL(aText, 0, aMin, aMax, aForwards, b0, b1, b2)?
       
   332 		b1 : -1;
       
   333 	}
       
   334 
       
   335 void RunTests()
       
   336 	{
       
   337 	test.Title();
       
   338 	test.Start(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-TTMSOURCE-0001 Line-Break Tests: "));
       
   339 
       
   340 	test(-1 == TestLineBreak(_L(""), 0, 0, 0, 0, 0));
       
   341 	test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 0));
       
   342 	test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 1));
       
   343 	test(-1 == TestLineBreak(_L("@"), 1, 0, 0, 0, 0));
       
   344 	test(1 == TestLineBreak(_L("a   b"), 0, 0, 0, 0, 0));
       
   345 	test(-1 == TestLineBreak(_L("0 0 0 9    9"), 0, 0, 0, 0, 0));
       
   346 	test(-1 == TestLineBreak(_L("0 0 0 9    9"), 0, 0, 0, 0, 1));
       
   347 	test(9 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 0));
       
   348 	test(5 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 1));
       
   349 	test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 0));
       
   350 	test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 1));
       
   351 	test(-1 == TestLineBreak(_L("hel  the re"), 0, 0, 5, 7, 0));
       
   352 	test(-1 == TestLineBreak(_L("hel  the re"), 0, 0, 5, 7, 1));
       
   353 	test(8 == TestLineBreak(_L("hel  the re"), 0, 1, 5, 7, 0));
       
   354 	test(8 == TestLineBreak(_L("hel  the re"), 0, 1, 6, 7, 1));
       
   355 	test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 0));
       
   356 	test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 1));
       
   357 	test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 0));
       
   358 	test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 1));
       
   359 	test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 0));
       
   360 	test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 1));
       
   361 	test(5 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 0));
       
   362 	test(2 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 1));
       
   363 	test(3 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 0));
       
   364 	test(2 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 1));
       
   365 
       
   366 	// Test for DEF046468, which was caused by the TLineBreakIterator constructor accessing past the end of a string
       
   367 	test.Next(_L("Line-Break DEF046468 Test:"));
       
   368 	// Create a string of 16 chars with a picture code at the 17th position
       
   369 	_LIT(KLarsString, "dolor sit amet, \xFFFC");
       
   370 	// Create a TPtrC for the 16 character string ( with the picture code after the string in memory )
       
   371 	TBufC<20> KTestBuffer(KLarsString);
       
   372 	TPtrC KTestString( reinterpret_cast<const TUint16*>(KTestBuffer.Ptr()), 16);
       
   373 	// Test the iterator overrun. If iterator accesses past the end of the array, it'll get picture code and crash
       
   374 	test(9 == TestLineBreak(KTestString,0,0,1,15,0));
       
   375 
       
   376 	test.End();
       
   377 	test.Close();
       
   378 
       
   379 	}
       
   380 
       
   381 TInt E32Main()
       
   382 	{
       
   383 	TrapCleanup = CTrapCleanup::New();
       
   384 	TRAPD(err, RunTests());
       
   385     test(err == KErrNone);
       
   386 	delete TrapCleanup;
       
   387 	return 0;
       
   388 	}