1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/textrendering/textformatting/test/src/TTmSource.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,393 @@
1.4 +/*
1.5 +* Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +* Test code for MTmSource functionality
1.19 +*
1.20 +*/
1.21 +
1.22 +
1.23 +#include "TAGMA.H"
1.24 +#include <e32test.h>
1.25 +
1.26 +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
1.27 +#include "TAGMA_INTERNAL.H"
1.28 +#endif
1.29 +
1.30 +#include "ttmsource.h"
1.31 +
1.32 +
1.33 +#define UNUSED_VAR(a) a = a
1.34 +
1.35 +namespace LocalToTTmSource
1.36 +{
1.37 +CTTmSourceStep* TestStep = NULL;
1.38 +#define TESTPOINT(p) TestStep->testpoint(p,(TText8*)__FILE__,__LINE__)
1.39 +#define TESTPRINT(p) TestStep->print(p,(TText8*)__FILE__,__LINE__)
1.40 +}
1.41 +using namespace LocalToTTmSource;
1.42 +
1.43 +class TTestGraphicsDeviceMap : public MGraphicsDeviceMap
1.44 + {
1.45 +public:
1.46 + TInt HorizontalTwipsToPixels(TInt a) const { return a; }
1.47 + TInt VerticalTwipsToPixels(TInt a) const { return a; }
1.48 + TInt HorizontalPixelsToTwips(TInt a) const { return a; }
1.49 + TInt VerticalPixelsToTwips(TInt a) const { return a; }
1.50 + TInt GetNearestFontInTwips(CFont*&,const TFontSpec&)
1.51 + {
1.52 + return KErrGeneral;
1.53 + }
1.54 + void ReleaseFont(CFont*) {}
1.55 + };
1.56 +
1.57 +class CTestPicture : public CPicture
1.58 + {
1.59 +public:
1.60 + CTestPicture() {}
1.61 + virtual void Draw(CGraphicsContext&, const TPoint&, const TRect&, MGraphicsDeviceMap*) const {}
1.62 + virtual void ExternalizeL(RWriteStream&) const {}
1.63 + virtual void GetOriginalSizeInTwips(TSize&) const {}
1.64 + virtual TBool LineBreakPossible(TUint aClass,TBool aBeforePicture,TBool aHaveSpaces) const
1.65 + {
1.66 + ++iRequestCount;
1.67 + if (aBeforePicture)
1.68 + {
1.69 + TESTPOINT(aClass == iClassBefore);
1.70 + TESTPOINT(aHaveSpaces == iSpacesBefore);
1.71 + return iResultBefore;
1.72 + }
1.73 + TESTPOINT(aClass == iClassAfter);
1.74 + TESTPOINT(aHaveSpaces == iSpacesAfter);
1.75 + return iResultAfter;
1.76 + }
1.77 + // expected parameters for LineBreakPossible
1.78 + TUint iClassBefore;
1.79 + TUint iClassAfter;
1.80 + TBool iSpacesBefore;
1.81 + TBool iSpacesAfter;
1.82 + // Results for breaking before/breaking after
1.83 + TBool iResultBefore;
1.84 + TBool iResultAfter;
1.85 + mutable TInt iRequestCount;
1.86 + };
1.87 +
1.88 +class TTestSource : public MTmSource
1.89 + {
1.90 +public:
1.91 + TTestSource() : iPicturePos(-1) {}
1.92 + virtual ~TTestSource() {}
1.93 + MGraphicsDeviceMap& FormatDevice() const { return iGDM; }
1.94 + MGraphicsDeviceMap& InterpretDevice() const { return iGDM; }
1.95 + TInt DocumentLength() const
1.96 + {
1.97 + return iText->Length();
1.98 + }
1.99 + void GetText(TInt aPos,TPtrC& aText, TTmCharFormat& aFormat) const
1.100 + {
1.101 + TTmCharFormat f;
1.102 + aFormat = f;
1.103 + aText.Set(iText->Mid(aPos));
1.104 + }
1.105 + void GetParagraphFormatL(TInt, RTmParFormat& aFormat) const
1.106 + {
1.107 + RTmParFormat p;
1.108 + aFormat.CopyL(p);
1.109 + }
1.110 + CPicture* PictureL(TInt aPos) const
1.111 + {
1.112 + return aPos == iPicturePos? iPicture : 0;
1.113 + }
1.114 + TInt ParagraphStart(TInt) const { return 0; }
1.115 +
1.116 + virtual TUint LineBreakClass(TUint aCode, TUint& aRangeStart,
1.117 + TUint& aRangeEnd) const
1.118 + {
1.119 + if ('@' == aCode)
1.120 + {
1.121 + aRangeStart = aRangeEnd = aCode;
1.122 + return ESaLineBreakClass;
1.123 + }
1.124 + if ('0' <= aCode && aCode <= '9')
1.125 + {
1.126 + aRangeStart = aRangeEnd = aCode;
1.127 + return ELineBreakClasses + aCode - '0';
1.128 + }
1.129 + return MTmSource::LineBreakClass(aCode, aRangeStart, aRangeEnd);
1.130 + }
1.131 +
1.132 + virtual TBool LineBreakPossible(TUint aPrevClass, TUint aNextClass,
1.133 + TBool aHaveSpaces) const
1.134 + {
1.135 + TInt first = static_cast<TInt>(aPrevClass);
1.136 + TInt second = static_cast<TInt>(aNextClass);
1.137 + TInt customCount = 0;
1.138 + if (iDirection < 0)
1.139 + {
1.140 + first = aNextClass;
1.141 + second = aPrevClass;
1.142 + }
1.143 + if (ELineBreakClasses <= first && first < ELineBreakClasses + 10)
1.144 + {
1.145 + ++customCount;
1.146 + TESTPOINT(first - ELineBreakClasses + '0' == FindNextCustomClass());
1.147 + TInt countSpaces = CountSpaces();
1.148 + TESTPOINT(!aHaveSpaces == !countSpaces);
1.149 + }
1.150 + if (ELineBreakClasses <= second && second < ELineBreakClasses + 10)
1.151 + {
1.152 + ++customCount;
1.153 + TInt c = FindNextCustomClass();
1.154 + TESTPOINT(second - ELineBreakClasses + '0' == c);
1.155 + }
1.156 + if (0 == customCount)
1.157 + return MTmSource::LineBreakPossible(aPrevClass, aNextClass, aHaveSpaces);
1.158 + // Between custom and non-custom classes, allow a break only with spaces
1.159 + // or between @ and 5
1.160 + if (1 == customCount)
1.161 + return aHaveSpaces
1.162 + || (first == ESaLineBreakClass && second == ELineBreakClasses + 5)
1.163 + || (second == ESaLineBreakClass && first == ELineBreakClasses + 5);
1.164 + // Allow a break with spaces except after '0' or before '9'
1.165 + if (aHaveSpaces)
1.166 + return aPrevClass != ELineBreakClasses && aNextClass != ELineBreakClasses + 9;
1.167 + // Allow a break only between a class and the class one more than it.
1.168 + return aPrevClass + 1 == aNextClass;
1.169 + }
1.170 +
1.171 + virtual TBool GetLineBreakInContext(
1.172 + const TDesC& aText, TInt aMinBreakPos, TInt aMaxBreakPos,
1.173 + TBool aForwards,TInt& aBreakPos) const
1.174 + {
1.175 + TESTPOINT (iDirection == (aForwards? 1 : -1));
1.176 + // The allowable break-points should not include the first
1.177 + // and last characters of the run.
1.178 + TESTPOINT (aMinBreakPos != 0);
1.179 + for (TInt i = aMinBreakPos - 1; i <= aMaxBreakPos; ++i)
1.180 + TESTPOINT('@' == aText[i]);
1.181 + ++iSaRequestCount;
1.182 + aBreakPos = iText->Ptr() + iSaBreakpoint - aText.Ptr();
1.183 + return aMinBreakPos <= aBreakPos && aBreakPos <= aMaxBreakPos;
1.184 + }
1.185 +
1.186 + virtual TBool IsHangingCharacter(TUint aChar) const
1.187 + {
1.188 + ++iHangingCharRequestCount;
1.189 + TESTPOINT(aChar == (*iText)[iMaxBreakPos]);
1.190 + if (!iHangingChar)
1.191 + return EFalse;
1.192 + if (iDirection < 0)
1.193 + ++iCurrentPos;
1.194 + return ETrue;
1.195 + }
1.196 +
1.197 + // non-virtual
1.198 + TBool GetLineBreakL(const TDesC& aText, TInt aDocPos,
1.199 + TInt aMinBreakPos, TInt aMaxBreakPos, TBool aForwards,
1.200 + TInt& aBreakPos, TInt& aHangingChars, TInt& aBreakPosAfterSpaces) const
1.201 + {
1.202 + iText = &aText;
1.203 + iMaxBreakPos = aMaxBreakPos;
1.204 + iMinBreakPos = aMinBreakPos;
1.205 + iHangingCharRequestCount = 0;
1.206 + iSaRequestCount = 0;
1.207 + iDirection = aForwards? 1 : -1;
1.208 + iCurrentPos = aForwards? aMinBreakPos : aMaxBreakPos - 1;
1.209 + TBool r = MTmSource::GetLineBreakL(aText, aDocPos,
1.210 + aMinBreakPos, aMaxBreakPos, aForwards,
1.211 + aBreakPos, aHangingChars, aBreakPosAfterSpaces);
1.212 + if (r)
1.213 + {
1.214 + TESTPOINT(aMinBreakPos <= aBreakPos);
1.215 + TESTPOINT(0 < aBreakPos);
1.216 + TESTPOINT(aBreakPos <= aHangingChars);
1.217 + TESTPOINT(aHangingChars <= aBreakPosAfterSpaces);
1.218 + TESTPOINT(aBreakPos <= aMaxBreakPos);
1.219 + TESTPOINT(aHangingChars == aBreakPos || iHangingChar);
1.220 + // If the direction was backwards, the algorithm should have
1.221 + // checked if a hanging character was allowed.
1.222 + // This condition could be relaxed to allow it not to be checked
1.223 + // if there is no break allowed between the possible hanging
1.224 + // character and the previous character.
1.225 + TESTPOINT(!aForwards || aText.Length() == aMaxBreakPos
1.226 + || 0 < iHangingCharRequestCount);
1.227 + // If the maximum break point was chosen or exceeded, the algorithm
1.228 + // should have checked to find out whether a hanging character is
1.229 + // allowed.
1.230 + TESTPOINT(aHangingChars < aMaxBreakPos
1.231 + || 0 < iHangingCharRequestCount);
1.232 + // Check that only spaces exist between aHangingChars and
1.233 + // aMaxBreakPos
1.234 + for (TInt i = aHangingChars; i != aBreakPosAfterSpaces; ++i)
1.235 + {
1.236 + TUint n;
1.237 + TESTPOINT(ESpLineBreakClass == LineBreakClass(aText[i], n, n));
1.238 + }
1.239 + // Check that all the spaces were counted
1.240 + TESTPOINT(aBreakPosAfterSpaces == aText.Length()
1.241 + || aText[aBreakPosAfterSpaces] != ' ');
1.242 + }
1.243 + // Find out how many runs of two or more Sa there are, and check that
1.244 + // this matches the number of times that it was requested.
1.245 + TInt minChecked = aMinBreakPos - 1;
1.246 + TInt maxChecked = aMaxBreakPos + 2;
1.247 + if (r)
1.248 + {
1.249 + if (aForwards)
1.250 + maxChecked = aBreakPos + 1;
1.251 + else
1.252 + minChecked = aBreakPos - 1;
1.253 + }
1.254 + if (minChecked < 0)
1.255 + minChecked = 0;
1.256 + if (aText.Length() < maxChecked)
1.257 + maxChecked = aText.Length();
1.258 + TInt runs = 0;
1.259 + TInt sasSoFar = 0;
1.260 + TESTPOINT (maxChecked - minChecked < 2
1.261 + || aText[minChecked] != '@'
1.262 + || aText[minChecked + 1] != '@'
1.263 + || !aForwards
1.264 + || aHangingChars == iSaBreakpoint);
1.265 + for (; minChecked != maxChecked; ++minChecked)
1.266 + {
1.267 + if (aText[minChecked] == '@')
1.268 + ++sasSoFar;
1.269 + else
1.270 + {
1.271 + if (1 < sasSoFar)
1.272 + ++runs;
1.273 + sasSoFar = 0;
1.274 + }
1.275 + }
1.276 + if (1 < sasSoFar)
1.277 + ++runs;
1.278 + TESTPOINT(sasSoFar < 2 || aForwards || aHangingChars == iSaBreakpoint);
1.279 + TESTPOINT(runs == iSaRequestCount);
1.280 + return r;
1.281 + }
1.282 +
1.283 + TInt FindNextCustomClass() const
1.284 + {
1.285 + TInt end = iDirection < 0? -1 : iText->Length();
1.286 + for (; iCurrentPos != end; iCurrentPos += iDirection)
1.287 + {
1.288 + TInt c = (*iText)[iCurrentPos];
1.289 + if ('0' <= c && c <= '9')
1.290 + return c;
1.291 + }
1.292 + return -1;
1.293 + }
1.294 + TInt CountSpaces() const
1.295 + {
1.296 + TInt end = iDirection < 0? -1 : iText->Length();
1.297 + TInt count = 0;
1.298 + if (iCurrentPos == end)
1.299 + return 0;
1.300 + iCurrentPos += iDirection;
1.301 + for (; iCurrentPos != end; iCurrentPos += iDirection, ++count)
1.302 + {
1.303 + TInt c = (*iText)[iCurrentPos];
1.304 + if (' ' != c)
1.305 + return count;
1.306 + }
1.307 + return count;
1.308 + }
1.309 +
1.310 +private:
1.311 + mutable TTestGraphicsDeviceMap iGDM;
1.312 + mutable const TDesC* iText;
1.313 + mutable TInt iMaxBreakPos;
1.314 + mutable TInt iMinBreakPos;
1.315 +
1.316 + mutable TInt iDirection;
1.317 + mutable TInt iCurrentPos;
1.318 + mutable TInt iHangingCharRequestCount;
1.319 + mutable TInt iSaRequestCount;
1.320 +
1.321 +public:
1.322 + TInt iPicturePos;
1.323 + CPicture* iPicture;
1.324 +
1.325 + TBool iHangingChar;
1.326 +
1.327 + TInt iSaBreakpoint;
1.328 + };
1.329 +
1.330 +TInt TestLineBreak(const TDesC& aText, TInt aSaBreak, TBool aHangingChar,
1.331 + TInt aMin, TInt aMax, TBool aForwards)
1.332 + {
1.333 + if (aMax == 0)
1.334 + aMax = aText.Length();
1.335 + TTestSource t;
1.336 + t.iHangingChar = aHangingChar;
1.337 + t.iSaBreakpoint = aSaBreak;
1.338 + TInt b0, b1, b2;
1.339 + b0 = KMaxTInt;
1.340 + b1 = KMaxTInt;
1.341 + b2 = KMaxTInt;
1.342 + return t.GetLineBreakL(aText, 0, aMin, aMax, aForwards, b0, b1, b2)?
1.343 + b1 : -1;
1.344 + }
1.345 +
1.346 +CTTmSourceStep::CTTmSourceStep()
1.347 + {
1.348 +
1.349 + }
1.350 +
1.351 +
1.352 +TVerdict CTTmSourceStep::doTestStepL()
1.353 + {
1.354 + SetTestStepResult(EPass);
1.355 + TestStep = this;
1.356 + TESTPRINT(_L("TTmSource - MTmSource tests"));
1.357 + TESTPRINT(_L(" @SYMTestCaseID:SYSLIB-FORM-LEGACY-TTMSOURCE-0001 Line-Break Tests: "));
1.358 +
1.359 + TEST(-1 == TestLineBreak(_L(""), 0, 0, 0, 0, 0));
1.360 + TEST(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 0));
1.361 + TEST(-1 == TestLineBreak(_L("5"), 0, 0, 0, 0, 1));
1.362 + TEST(-1 == TestLineBreak(_L("@"), 1, 0, 0, 0, 0));
1.363 + TEST(1 == TestLineBreak(_L("a b"), 0, 0, 0, 0, 0));
1.364 + TEST(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 0));
1.365 + TEST(-1 == TestLineBreak(_L("0 0 0 9 9"), 0, 0, 0, 0, 1));
1.366 + TEST(9 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 0));
1.367 + TEST(5 == TestLineBreak(_L("4242454445"), 0, 0, 0, 0, 1));
1.368 + TEST(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 0));
1.369 + TEST(5 == TestLineBreak(_L("hello there"), 0, 0, 0, 0, 1));
1.370 + TEST(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 0));
1.371 + TEST(-1 == TestLineBreak(_L("hel the re"), 0, 0, 5, 7, 1));
1.372 + TEST(8 == TestLineBreak(_L("hel the re"), 0, 1, 5, 7, 0));
1.373 + TEST(8 == TestLineBreak(_L("hel the re"), 0, 1, 6, 7, 1));
1.374 + TEST(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 0));
1.375 + TEST(3 == TestLineBreak(_L("@@@@@"), 3, 0, 0, 0, 1));
1.376 + TEST(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 0));
1.377 + TEST(5 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 5, 0, 5, 0, 1));
1.378 + TEST(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 0));
1.379 + TEST(16 == TestLineBreak(_L("9999@@@@@00099@@@@gfra"), 16, 0, 0, 0, 1));
1.380 + TEST(5 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 0));
1.381 + TEST(2 == TestLineBreak(_L("55@@@55"), 0, 0, 0, 0, 1));
1.382 + TEST(3 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 0));
1.383 + TEST(2 == TestLineBreak(_L("55@55"), 0, 0, 0, 0, 1));
1.384 +
1.385 + // Test for DEF046468, which was caused by the TLineBreakIterator constructor accessing past the end of a string
1.386 + TESTPRINT(_L("Line-Break DEF046468 Test:"));
1.387 + // Create a string of 16 chars with a picture code at the 17th position
1.388 + _LIT(KLarsString, "dolor sit amet, \xFFFC");
1.389 + // Create a TPtrC for the 16 character string ( with the picture code after the string in memory )
1.390 + TBufC<20> KTestBuffer(KLarsString);
1.391 + TPtrC KTestString( reinterpret_cast<const TUint16*>(KTestBuffer.Ptr()), 16);
1.392 + // Test the iterator overrun. If iterator accesses past the end of the array, it'll get picture code and crash
1.393 + TEST(9 == TestLineBreak(KTestString,0,0,1,15,0));
1.394 +
1.395 + return TestStepResult();
1.396 + }