--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/test/src/TTmSource.cpp Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,388 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+* Test code for MTmSource functionality
+*
+*/
+
+
+#include "TAGMA.H"
+#include <e32test.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "TAGMA_INTERNAL.H"
+#endif
+
+#define UNUSED_VAR(a) a = a
+
+CTrapCleanup* TrapCleanup;
+RTest test(_L("TTmSource - MTmSource tests"));
+
+class TTestGraphicsDeviceMap : public MGraphicsDeviceMap
+ {
+public:
+ TInt HorizontalTwipsToPixels(TInt a) const { return a; }
+ TInt VerticalTwipsToPixels(TInt a) const { return a; }
+ TInt HorizontalPixelsToTwips(TInt a) const { return a; }
+ TInt VerticalPixelsToTwips(TInt a) const { return a; }
+ TInt GetNearestFontInTwips(CFont*&,const TFontSpec&)
+ {
+ return KErrGeneral;
+ }
+ void ReleaseFont(CFont*) {}
+ };
+
+class CTestPicture : public CPicture
+ {
+public:
+ CTestPicture() {}
+ virtual void Draw(CGraphicsContext&, const TPoint&, const TRect&, MGraphicsDeviceMap*) const {}
+ virtual void ExternalizeL(RWriteStream&) const {}
+ virtual void GetOriginalSizeInTwips(TSize&) const {}
+ virtual TBool LineBreakPossible(TUint aClass,TBool aBeforePicture,TBool aHaveSpaces) const
+ {
+ ++iRequestCount;
+ if (aBeforePicture)
+ {
+ test(aClass == iClassBefore);
+ test(aHaveSpaces == iSpacesBefore);
+ return iResultBefore;
+ }
+ test(aClass == iClassAfter);
+ test(aHaveSpaces == iSpacesAfter);
+ return iResultAfter;
+ }
+ // expected parameters for LineBreakPossible
+ TUint iClassBefore;
+ TUint iClassAfter;
+ TBool iSpacesBefore;
+ TBool iSpacesAfter;
+ // Results for breaking before/breaking after
+ TBool iResultBefore;
+ TBool iResultAfter;
+ mutable TInt iRequestCount;
+ };
+
+class TTestSource : public MTmSource
+ {
+public:
+ TTestSource() : iPicturePos(-1) {}
+ virtual ~TTestSource() {}
+ MGraphicsDeviceMap& FormatDevice() const { return iGDM; }
+ MGraphicsDeviceMap& InterpretDevice() const { return iGDM; }
+ TInt DocumentLength() const
+ {
+ return iText->Length();
+ }
+ void GetText(TInt aPos,TPtrC& aText, TTmCharFormat& aFormat) const
+ {
+ TTmCharFormat f;
+ aFormat = f;
+ aText.Set(iText->Mid(aPos));
+ }
+ void GetParagraphFormatL(TInt, RTmParFormat& aFormat) const
+ {
+ RTmParFormat p;
+ aFormat.CopyL(p);
+ }
+ CPicture* PictureL(TInt aPos) const
+ {
+ return aPos == iPicturePos? iPicture : 0;
+ }
+ TInt ParagraphStart(TInt) const { return 0; }
+
+ virtual TUint LineBreakClass(TUint aCode, TUint& aRangeStart,
+ TUint& aRangeEnd) const
+ {
+ if ('@' == aCode)
+ {
+ aRangeStart = aRangeEnd = aCode;
+ return ESaLineBreakClass;
+ }
+ if ('0' <= aCode && aCode <= '9')
+ {
+ aRangeStart = aRangeEnd = aCode;
+ return ELineBreakClasses + aCode - '0';
+ }
+ return MTmSource::LineBreakClass(aCode, aRangeStart, aRangeEnd);
+ }
+
+ virtual TBool LineBreakPossible(TUint aPrevClass, TUint aNextClass,
+ TBool aHaveSpaces) const
+ {
+ TInt first = static_cast<TInt>(aPrevClass);
+ TInt second = static_cast<TInt>(aNextClass);
+ TInt customCount = 0;
+ if (iDirection < 0)
+ {
+ first = aNextClass;
+ second = aPrevClass;
+ }
+ if (ELineBreakClasses <= first && first < ELineBreakClasses + 10)
+ {
+ ++customCount;
+ test(first - ELineBreakClasses + '0' == FindNextCustomClass());
+ TInt countSpaces = CountSpaces();
+ test(!aHaveSpaces == !countSpaces);
+ }
+ if (ELineBreakClasses <= second && second < ELineBreakClasses + 10)
+ {
+ ++customCount;
+ TInt c = FindNextCustomClass();
+ test(second - ELineBreakClasses + '0' == c);
+ }
+ if (0 == customCount)
+ return MTmSource::LineBreakPossible(aPrevClass, aNextClass, aHaveSpaces);
+ // Between custom and non-custom classes, allow a break only with spaces
+ // or between @ and 5
+ if (1 == customCount)
+ return aHaveSpaces
+ || (first == ESaLineBreakClass && second == ELineBreakClasses + 5)
+ || (second == ESaLineBreakClass && first == ELineBreakClasses + 5);
+ // Allow a break with spaces except after '0' or before '9'
+ if (aHaveSpaces)
+ return aPrevClass != ELineBreakClasses && aNextClass != ELineBreakClasses + 9;
+ // Allow a break only between a class and the class one more than it.
+ return aPrevClass + 1 == aNextClass;
+ }
+
+ virtual TBool GetLineBreakInContext(
+ const TDesC& aText, TInt aMinBreakPos, TInt aMaxBreakPos,
+ TBool aForwards,TInt& aBreakPos) const
+ {
+ test (iDirection == (aForwards? 1 : -1));
+ // The allowable break-points should not include the first
+ // and last characters of the run.
+ test (aMinBreakPos != 0);
+ for (TInt i = aMinBreakPos - 1; i <= aMaxBreakPos; ++i)
+ test('@' == aText[i]);
+ ++iSaRequestCount;
+ aBreakPos = iText->Ptr() + iSaBreakpoint - aText.Ptr();
+ return aMinBreakPos <= aBreakPos && aBreakPos <= aMaxBreakPos;
+ }
+
+ virtual TBool IsHangingCharacter(TUint aChar) const
+ {
+ ++iHangingCharRequestCount;
+ test(aChar == (*iText)[iMaxBreakPos]);
+ if (!iHangingChar)
+ return EFalse;
+ if (iDirection < 0)
+ ++iCurrentPos;
+ return ETrue;
+ }
+
+ // non-virtual
+ TBool GetLineBreakL(const TDesC& aText, TInt aDocPos,
+ TInt aMinBreakPos, TInt aMaxBreakPos, TBool aForwards,
+ TInt& aBreakPos, TInt& aHangingChars, TInt& aBreakPosAfterSpaces) const
+ {
+ iText = &aText;
+ iMaxBreakPos = aMaxBreakPos;
+ iMinBreakPos = aMinBreakPos;
+ iHangingCharRequestCount = 0;
+ iSaRequestCount = 0;
+ iDirection = aForwards? 1 : -1;
+ iCurrentPos = aForwards? aMinBreakPos : aMaxBreakPos - 1;
+ TBool r = MTmSource::GetLineBreakL(aText, aDocPos,
+ aMinBreakPos, aMaxBreakPos, aForwards,
+ aBreakPos, aHangingChars, aBreakPosAfterSpaces);
+ if (r)
+ {
+ test(aMinBreakPos <= aBreakPos);
+ test(0 < aBreakPos);
+ test(aBreakPos <= aHangingChars);
+ test(aHangingChars <= aBreakPosAfterSpaces);
+ test(aBreakPos <= aMaxBreakPos);
+ test(aHangingChars == aBreakPos || iHangingChar);
+ // If the direction was backwards, the algorithm should have
+ // checked if a hanging character was allowed.
+ // This condition could be relaxed to allow it not to be checked
+ // if there is no break allowed between the possible hanging
+ // character and the previous character.
+ test(!aForwards || aText.Length() == aMaxBreakPos
+ || 0 < iHangingCharRequestCount);
+ // If the maximum break point was chosen or exceeded, the algorithm
+ // should have checked to find out whether a hanging character is
+ // allowed.
+ test(aHangingChars < aMaxBreakPos
+ || 0 < iHangingCharRequestCount);
+ // Check that only spaces exist between aHangingChars and
+ // aMaxBreakPos
+ for (TInt i = aHangingChars; i != aBreakPosAfterSpaces; ++i)
+ {
+ TUint n;
+ test(ESpLineBreakClass == LineBreakClass(aText[i], n, n));
+ }
+ // Check that all the spaces were counted
+ test(aBreakPosAfterSpaces == aText.Length()
+ || aText[aBreakPosAfterSpaces] != ' ');
+ }
+ // Find out how many runs of two or more Sa there are, and check that
+ // this matches the number of times that it was requested.
+ TInt minChecked = aMinBreakPos - 1;
+ TInt maxChecked = aMaxBreakPos + 2;
+ if (r)
+ {
+ if (aForwards)
+ maxChecked = aBreakPos + 1;
+ else
+ minChecked = aBreakPos - 1;
+ }
+ if (minChecked < 0)
+ minChecked = 0;
+ if (aText.Length() < maxChecked)
+ maxChecked = aText.Length();
+ TInt runs = 0;
+ TInt sasSoFar = 0;
+ test (maxChecked - minChecked < 2
+ || aText[minChecked] != '@'
+ || aText[minChecked + 1] != '@'
+ || !aForwards
+ || aHangingChars == iSaBreakpoint);
+ for (; minChecked != maxChecked; ++minChecked)
+ {
+ if (aText[minChecked] == '@')
+ ++sasSoFar;
+ else
+ {
+ if (1 < sasSoFar)
+ ++runs;
+ sasSoFar = 0;
+ }
+ }
+ if (1 < sasSoFar)
+ ++runs;
+ test(sasSoFar < 2 || aForwards || aHangingChars == iSaBreakpoint);
+ test(runs == iSaRequestCount);
+ return r;
+ }
+
+ TInt FindNextCustomClass() const
+ {
+ TInt end = iDirection < 0? -1 : iText->Length();
+ for (; iCurrentPos != end; iCurrentPos += iDirection)
+ {
+ TInt c = (*iText)[iCurrentPos];
+ if ('0' <= c && c <= '9')
+ return c;
+ }
+ return -1;
+ }
+ TInt CountSpaces() const
+ {
+ TInt end = iDirection < 0? -1 : iText->Length();
+ TInt count = 0;
+ if (iCurrentPos == end)
+ return 0;
+ iCurrentPos += iDirection;
+ for (; iCurrentPos != end; iCurrentPos += iDirection, ++count)
+ {
+ TInt c = (*iText)[iCurrentPos];
+ if (' ' != c)
+ return count;
+ }
+ return count;
+ }
+
+private:
+ mutable TTestGraphicsDeviceMap iGDM;
+ mutable const TDesC* iText;
+ mutable TInt iMaxBreakPos;
+ mutable TInt iMinBreakPos;
+
+ mutable TInt iDirection;
+ mutable TInt iCurrentPos;
+ mutable TInt iHangingCharRequestCount;
+ mutable TInt iSaRequestCount;
+
+public:
+ TInt iPicturePos;
+ CPicture* iPicture;
+
+ TBool iHangingChar;
+
+ TInt iSaBreakpoint;
+ };
+
+TInt TestLineBreak(const TDesC& aText, TInt aSaBreak, TBool aHangingChar,
+ TInt aMin, TInt aMax, TBool aForwards)
+ {
+ if (aMax == 0)
+ aMax = aText.Length();
+ TTestSource t;
+ t.iHangingChar = aHangingChar;
+ t.iSaBreakpoint = aSaBreak;
+ TInt b0, b1, b2;
+ b0 = KMaxTInt;
+ b1 = KMaxTInt;
+ b2 = KMaxTInt;
+ return t.GetLineBreakL(aText, 0, aMin, aMax, aForwards, b0, b1, b2)?
+ b1 : -1;
+ }
+
+void RunTests()
+ {
+ test.Title();
+ test.Start(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-TTMSOURCE-0001 Line-Break Tests: "));
+
+ test(-1 == TestLineBreak(_L(""), 0, 0, 0, 0, 0));
+ test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 0));
+ test(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 1));
+ test(-1 == TestLineBreak(_L("@"), 1, 0, 0, 0, 0));
+ test(1 == TestLineBreak(_L("a b"), 0, 0, 0, 0, 0));
+ test(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 0));
+ test(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 1));
+ test(9 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 0));
+ test(5 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 1));
+ test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 0));
+ test(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 1));
+ test(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 0));
+ test(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 1));
+ test(8 == TestLineBreak(_L("hel the re"), 0, 1, 5, 7, 0));
+ test(8 == TestLineBreak(_L("hel the re"), 0, 1, 6, 7, 1));
+ test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 0));
+ test(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 1));
+ test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 0));
+ test(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 1));
+ test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 0));
+ test(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 1));
+ test(5 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 0));
+ test(2 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 1));
+ test(3 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 0));
+ test(2 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 1));
+
+ // Test for DEF046468, which was caused by the TLineBreakIterator constructor accessing past the end of a string
+ test.Next(_L("Line-Break DEF046468 Test:"));
+ // Create a string of 16 chars with a picture code at the 17th position
+ _LIT(KLarsString, "dolor sit amet, \xFFFC");
+ // Create a TPtrC for the 16 character string ( with the picture code after the string in memory )
+ TBufC<20> KTestBuffer(KLarsString);
+ TPtrC KTestString( reinterpret_cast<const TUint16*>(KTestBuffer.Ptr()), 16);
+ // Test the iterator overrun. If iterator accesses past the end of the array, it'll get picture code and crash
+ test(9 == TestLineBreak(KTestString,0,0,1,15,0));
+
+ test.End();
+ test.Close();
+
+ }
+
+TInt E32Main()
+ {
+ TrapCleanup = CTrapCleanup::New();
+ TRAPD(err, RunTests());
+ test(err == KErrNone);
+ delete TrapCleanup;
+ return 0;
+ }