diff -r 000000000000 -r 1fb32624e06b textrendering/textformatting/test/src/TTmSource.cpp --- /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 + +#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(aPrevClass); + TInt second = static_cast(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(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; + }