--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/test/src/TTagmaImp.cpp Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,1779 @@
+/*
+* Copyright (c) 2001-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:
+* TTagmaImp.cpp test file for Tagma classes
+*
+*/
+
+
+#include "TGraphicsContext.h"
+#include <e32test.h>
+#include <e32std.h>
+#include <coemain.h>
+#include <gdi.h>
+#include <txtlaydc.h>
+#include "TAGMA.H"
+#include "TMSTD.H"
+#include "TmLayoutImp.h"
+#include "TMINTERP.H"
+#include "TmText.h"
+#include "InlineText.h"
+
+namespace LocalToFile
+{
+enum TTagmaImpPanic { EAccessOutsideText = 1 };
+void Panic(TTagmaImpPanic)
+ {
+ User::Panic(_L("TTagmaImp"), EAccessOutsideText);
+ }
+RTest test(_L("Tagma internals tests"));
+
+const TInt KPictureCharacter = 0xFFFC;
+
+class CPinkSquare : public CPicture
+ {
+public:
+ // Size of square in twips.
+ // 600 is 15 pixels using the standard test graphics device at
+ // its default resolution.
+ enum { KWidth = 600, KHeight = 600 };
+ CPinkSquare() {}
+ void Draw(CGraphicsContext& aGc, const TPoint& aTopLeft,
+ const TRect& aClipRect, MGraphicsDeviceMap* aMap) const
+ {
+ // This picture is a magenta square
+ TPoint size(KWidth, KHeight);
+ if (aMap)
+ size = aMap->TwipsToPixels(size);
+ TRect rect(aTopLeft, aTopLeft + size);
+ aGc.SetClippingRect(aClipRect);
+ aGc.SetDrawMode(CGraphicsContext::EDrawModePEN);
+ aGc.SetPenColor(KRgbMagenta);
+ aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+ aGc.SetBrushColor(KRgbMagenta);
+ aGc.DrawRect(rect);
+ }
+ void ExternalizeL(RWriteStream&) const {}
+ void GetOriginalSizeInTwips(TSize& a) const
+ {
+ a.iWidth = CPinkSquare::KWidth;
+ a.iHeight = CPinkSquare::KHeight;
+ }
+ };
+
+_LIT(KEnd, "\x2029");
+class TDocModel : public MLayDoc
+ {
+public:
+ TDocModel(const TDesC& aDes)
+ : iDes(&aDes), iParagraphFormat(0) {}
+ void SetParagraphFormat(CParaFormat* a)
+ {
+ iParagraphFormat = a;
+ }
+ // From MLayDoc
+ TInt LdDocumentLength() const { return iDes->Length(); }
+ TInt LdToParagraphStart(TInt& a) const
+ {
+ TInt curr = a;
+ if (a < LdDocumentLength())
+ {
+ a = iDes->Left(a).LocateReverse(0x2029);
+ a = a < 0? 0 : a + 1;
+ }
+ return curr - a;
+ }
+ void GetParagraphFormatL(CParaFormat* aFormat, TInt) const
+ {
+ if (iParagraphFormat)
+ {
+ aFormat->CopyL(*iParagraphFormat);
+ return;
+ }
+ aFormat->Reset();
+ TTabStop tabStop;
+ tabStop.iTwipsPosition = 1000;
+ tabStop.iType = TTabStop::ELeftTab;
+ aFormat->StoreTabL(tabStop);
+ }
+ void GetChars(TPtrC& aView,TCharFormat& aFormat, TInt aStartPos)const
+ {
+ TCharFormat cf;
+ aFormat = cf;
+ if (aStartPos == LdDocumentLength())
+ aView.Set(KEnd);
+ else
+ aView.Set(iDes->Mid(aStartPos));
+ }
+ TInt GetPictureSizeInTwips(TSize& aSize, TInt aPos) const
+ {
+ if ((*iDes)[aPos] != KPictureCharacter)
+ return KErrNotFound;
+ aSize.iWidth = CPinkSquare::KWidth;
+ aSize.iHeight = CPinkSquare::KHeight;
+ return KErrNone;
+ }
+ CPicture* PictureHandleL(TInt aPos, TForcePictureLoad) const
+ {
+ if ((*iDes)[aPos] != KPictureCharacter)
+ return 0;
+ return new(ELeave) CPinkSquare;
+ }
+ TBool EnquirePageBreak(TInt aPos, TInt aLength)const
+ {
+ return iDes->Mid(aPos, aLength).Locate(0x000C) < 0?
+ EFalse : ETrue;
+ }
+ TBool SelectParagraphLabel(TInt) { return EFalse; }
+ void CancelSelectLabel() {}
+private:
+ const TDesC* iDes;
+ CParaFormat* iParagraphFormat;
+ };
+
+class THandleTester
+ {
+ TInt iProcessHandles;
+ TInt iThreadHandles;
+ RTest& iTest;
+public:
+ THandleTester(RTest& rt) : iTest(rt)
+ {
+ RThread().HandleCount(iProcessHandles, iThreadHandles);
+ }
+ ~THandleTester()
+ {
+ TInt p;
+ TInt t;
+ RThread().HandleCount(p, t);
+// this seems to break at random...
+// iTest(p == iProcessHandles);
+ iTest(t == iThreadHandles);
+ }
+ };
+
+class CFallableDeviceMap : public CBase, public MGraphicsDeviceMap
+ {
+ MGraphicsDeviceMap& iDeviceMap;
+public:
+ CFallableDeviceMap(MGraphicsDeviceMap& aDeviceMap) : iDeviceMap(aDeviceMap) {}
+ TInt HorizontalTwipsToPixels(TInt aTwips) const
+ {
+ return iDeviceMap.HorizontalTwipsToPixels(aTwips);
+ }
+ TInt VerticalTwipsToPixels(TInt aTwips) const
+ {
+ return iDeviceMap.VerticalTwipsToPixels(aTwips);
+ }
+ TInt HorizontalPixelsToTwips(TInt aPixels) const
+ {
+ return iDeviceMap.HorizontalPixelsToTwips(aPixels);
+ }
+ TInt VerticalPixelsToTwips(TInt aPixels) const
+ {
+ return iDeviceMap.VerticalPixelsToTwips(aPixels);
+ }
+ TInt GetNearestFontInTwips(CFont*& aFont,const TFontSpec& aFontSpec)
+ {
+ TInt *i = new TInt;
+ if (i)
+ {
+ delete i;
+ return iDeviceMap.GetNearestFontInTwips(aFont, aFontSpec);
+ }
+ return KErrNoMemory;
+ }
+ void ReleaseFont(CFont* aFont)
+ {
+ iDeviceMap.ReleaseFont(aFont);
+ }
+ };
+
+class CTestSource : public CBase, public MTmSource
+ {
+ MGraphicsDeviceMap* iDeviceMap;
+ TPtrC iText;
+ TTmCharFormat iDefaultCharFormat;
+ TTmCharFormat iSpecialCharFormat;
+ TInt iBeginSpecialCharFormat;
+ TInt iEndSpecialCharFormat;
+public:
+ ~CTestSource()
+ {
+ delete iDeviceMap;
+ }
+ CTestSource(const TDesC& aText,
+ TTmCharFormat aDefault, TTmCharFormat aSpecial,
+ TInt aBeginSpecialCharFormat, TInt aEndSpecialCharFormat)
+ : iText(aText),
+ iDefaultCharFormat(aDefault), iSpecialCharFormat(aSpecial),
+ iBeginSpecialCharFormat(aBeginSpecialCharFormat),
+ iEndSpecialCharFormat(aEndSpecialCharFormat)
+ {
+ }
+ void ConstructL(MGraphicsDeviceMap& aDeviceMap)
+ {
+ iDeviceMap = new(ELeave) CFallableDeviceMap(aDeviceMap);
+ }
+ MGraphicsDeviceMap& FormatDevice() const { return *iDeviceMap; }
+ MGraphicsDeviceMap& InterpretDevice() const { return *iDeviceMap; }
+ TInt DocumentLength() const { return iText.Length(); }
+ void SetText(const TDesC& aStaticText)
+ {
+ iText.Set(aStaticText);
+ }
+ void GetText(TInt aPos, TPtrC& aText, TTmCharFormat& aFormat) const
+ {
+ TInt length = iText.Length()+1;
+ if (aPos < iBeginSpecialCharFormat)
+ {
+ length = iBeginSpecialCharFormat;
+ aFormat = iDefaultCharFormat;
+ }
+ else if (aPos < iEndSpecialCharFormat)
+ {
+ length = iEndSpecialCharFormat;
+ aFormat = iSpecialCharFormat;
+ }
+ else
+ {
+ aFormat = iDefaultCharFormat;
+ }
+ if (aPos == length)
+ aText.Set(0, 0);
+ else
+ aText.Set(&iText[aPos], length - aPos);
+ }
+
+ void GetParagraphFormatL(TInt, RTmParFormat& aFormat) const
+ {
+ RTmParFormat defParFormat;
+ CleanupClosePushL(defParFormat);
+ aFormat.CopyL(defParFormat);
+ CleanupStack::PopAndDestroy();
+ }
+ TInt ParagraphStart(TInt aPos) const
+ {
+ if (aPos <= iText.Length())
+ aPos = iText.Length() - 1;
+ TPtrC p(&iText[0], aPos + 1);
+ TInt delim = p.LocateReverse(TChar(CEditableText::EParagraphDelimiter));
+ return delim < 0? 0 : delim + 1;
+ }
+ CPicture* PictureL(TInt aPos) const
+ {
+ // There are no pictures, but we need to check that code never tries to
+ // take one from beyond the bounds of the text.
+ __ASSERT_ALWAYS(0 <= aPos, Panic(EAccessOutsideText));
+ __ASSERT_ALWAYS(aPos < iText.Length(), Panic(EAccessOutsideText));
+ return 0;
+ }
+ };
+
+}
+using namespace LocalToFile;
+
+
+class CTagmaImpTest : public CBase
+ {
+public:
+ CTagmaImpTest() : iDevice(0), iGc(0)
+ {
+ }
+ void ConstructL()
+ {
+ TSize size(100, 100);
+ iDevice = CTestGraphicsDevice::NewL(size, 0);
+ iDevice->CreateContext(iGc);
+ }
+ ~CTagmaImpTest()
+ {
+ delete iDevice;
+ }
+ void ExerciseCTmCodeL();
+ void AddSome1L(CTmCode& aCode, TInt aStartValue);
+ TInt AddLotsL(CTmCode& aCode, TInt aAmountToAdd);
+ TInt InsertSomeL(CTmCode& aCode, TInt aStartValue, TInt aIndex);
+ TInt InsertLotsL(CTmCode& aCode, TInt aAmountToAdd, TInt aIndex);
+ TInt CheckLots(CTmCode& aCode, TInt aIndex, TInt aStartValue, TInt aCount);
+ void CTmCodeOOML();
+ CTestSource* NewTestSourceLC();
+ CTmCode* NewFormattedCTmCodeLC(MTmSource&);
+ void ExerciseFormatL();
+ void FormatOOML();
+ void ExerciseRTmTextCacheWidthL();
+ void RTmTextCacheWidthOOM();
+ void ExerciseRTmGeneralInterpreterGetDisplayedTextL();
+ void RTmGeneralInterpreterGetDisplayedTextOOM();
+ void CTmTextImp_RRunArrayL();
+ void WEP_55BHBF_DefectL();
+ void BUR_58FGE8_DefectL();
+ void EXT_5ATF8D_DefectL();
+ void INC_044969_DefectL();
+ void DEF_073838_DefectL();
+ void PDEF_101464_DefectL();
+ void DEF101994_DefectL();
+ void CTmTextImp_BidirectionalAlignmentL();
+ void ExerciseCopyL();
+ void ExerciseGetCParaFormatL();
+ void CustomFormattingL();
+ void TestChunkContext();
+ void TestBytecodeLineContext();
+ void TestBytecodeChunkContext();
+ void TestL();
+
+ void GetIndices(TDes8& aBuf, const CTmTextImp::RRunArray& aRunArray);
+ // Function to test the API's of CTmTextImp
+ void TestAPIL();
+ private:
+ CTestGraphicsDevice* iDevice;
+ CGraphicsContext* iGc;
+ };
+
+TInt CTagmaImpTest::CheckLots(CTmCode& aCode, TInt aIndex,
+ TInt aStartValue, TInt aCount)
+ {
+ TTmCodeReader reader(aCode, aIndex, aCode.Size());
+ for (; aCount; --aCount, aStartValue += 6)
+ {
+ TUint8 byte = reader.ReadByte();
+ TInt num = reader.ReadNumber();
+ TRect rect = reader.ReadRect();
+ TRect testRect(aStartValue + 2, aStartValue + 3, aStartValue + 4, aStartValue + 5);
+ test(byte == static_cast<TUint8>(aStartValue));
+ test(num == aStartValue + 1);
+ test(rect == testRect);
+ }
+ return reader.CodePos();
+ }
+
+void CTagmaImpTest::AddSome1L(CTmCode& aCode, TInt aStartValue)
+ {
+ aCode.AppendByteL(static_cast<TUint8>(aStartValue));
+ aCode.AppendNumberL(aStartValue + 1);
+ TRect rect(aStartValue + 2, aStartValue + 3, aStartValue + 4, aStartValue + 5);
+ aCode.AppendRectL(rect);
+ }
+
+TInt CTagmaImpTest::AddLotsL(CTmCode& aCode, TInt aAmountToAdd)
+ {
+ TInt finalSize = aAmountToAdd + aCode.Size();
+ TInt count = 0;
+ for (TInt i = 0; aCode.Size() < finalSize; i += 6)
+ {
+ AddSome1L(aCode, i);
+ ++count;
+ }
+ return count;
+ }
+
+TInt CTagmaImpTest::InsertSomeL(CTmCode& aCode, TInt aStartValue, TInt aIndex)
+ {
+ TInt offset = aIndex - aCode.Size();
+ aCode.InsertByteL(static_cast<TUint8>(aStartValue), aIndex);
+ aCode.InsertNumberL(aStartValue + 1, aCode.Size() + offset);
+ TRect rect(aStartValue + 2, aStartValue + 3, aStartValue + 4, aStartValue + 5);
+ aCode.InsertRectL(rect, aCode.Size() + offset);
+ return aCode.Size() + offset;
+ }
+
+TInt CTagmaImpTest::InsertLotsL(CTmCode& aCode, TInt aAmountToAdd, TInt aIndex)
+ {
+ TInt finalSize = aAmountToAdd + aCode.Size();
+ TInt count = 0;
+ for (TInt i = 0; aCode.Size() < finalSize; i += 6)
+ {
+ aIndex = InsertSomeL(aCode, i, aIndex);
+ ++count;
+ }
+ return count;
+ }
+
+void CTagmaImpTest::ExerciseCTmCodeL()
+ {
+ CTmCode* code = new (ELeave) CTmCode;
+ CleanupStack::PushL(code);
+ code->CreateBufferL();
+ TInt count1 = AddLotsL(*code, 400);
+ TInt size1 = code->Size();
+ TInt count2 = AddLotsL(*code, 2000);
+ TInt size2 = code->Size() - size1;
+ TInt count3 = InsertLotsL(*code, 997, size1);
+ TInt size3 = code->Size() - size1 - size2;
+ CheckLots(*code, 0, 0, count1);
+ CheckLots(*code, size1, 0, count3);
+ CheckLots(*code, size1 + size3, 0, count2);
+ CTmCode* code2 = new (ELeave) CTmCode;
+ CleanupStack::PushL(code2);
+ code2->CreateBufferL();
+ TInt count4 = AddLotsL(*code2, 3000);
+ TInt size4 = code2->Size();
+ code->ChangeL(size1, size1 + size3, *code2);
+ CheckLots(*code, 0, 0, count1);
+ CheckLots(*code, size1, 0, count4);
+ CheckLots(*code, size1 + size4, 0, count2);
+ code->Delete(size1, size4);
+ CheckLots(*code, 0, 0, count1);
+ CheckLots(*code, size1, 0, count2);
+ test(code2->Size() == 0);
+ CleanupStack::PopAndDestroy(code2);
+ CleanupStack::PopAndDestroy(code);
+ }
+
+void CTagmaImpTest::CTmCodeOOML()
+ {
+ ExerciseCTmCodeL();
+ TInt err;
+ TInt failAt = 1;
+ do {
+ THandleTester h(test);
+
+ __UHEAP_MARK;
+ __UHEAP_SETFAIL(RHeap::EDeterministic, failAt);
+ TRAP(err, ExerciseCTmCodeL());
+ __UHEAP_SETFAIL(RHeap::ENone, 0);
+ __UHEAP_MARKENDC(0);
+
+ ++failAt;
+ } while (err == KErrNoMemory);
+ test(err == KErrNone);
+ }
+
+CTestSource* CTagmaImpTest::NewTestSourceLC()
+ {
+ _LIT(KTestText, "Some text for you to format for me.\x2029");
+ TTmCharFormat defCharFormat(_L("SwissA"), 60);
+ TTmCharFormat specialCharFormat(_L("Arial"), 50);
+ CTestSource* source = new(ELeave) CTestSource(KTestText,
+ defCharFormat, specialCharFormat, 5, 9);
+ CleanupStack::PushL(source);
+ source->ConstructL(*iDevice);
+ return source;
+ }
+
+CTmCode* CTagmaImpTest::NewFormattedCTmCodeLC(MTmSource& aSource)
+ {
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+ TTmFormatParam formatParam;
+ formatParam.iStartChar = 0;
+ formatParam.iEndChar = aSource.DocumentLength();
+ formatParam.iLineInPar = 0;
+ formatParam.iWrapWidth = 50;
+ formatParam.iMaxHeight = KMaxTInt;
+ formatParam.iMaxLines = KMaxTInt;
+ formatParam.iFlags = TTmFormatParam::EWrap;
+ CTmFormatContext::TInfo info;
+ CTmTextLayout *layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+ CTmFormatContext::FormatL(aSource, formatParam, *code, info, layout);
+ CleanupStack::PopAndDestroy(layout);
+ return code;
+ }
+
+void CTagmaImpTest::ExerciseFormatL()
+ {
+ CTestSource* source = NewTestSourceLC();
+ CTmCode* code = NewFormattedCTmCodeLC(*source);
+ CleanupStack::PopAndDestroy(code);
+ CleanupStack::PopAndDestroy(source);
+ }
+
+void CTagmaImpTest::FormatOOML()
+ {
+ // dry run- this will help the typeface store to settle down.
+ ExerciseFormatL();
+ TInt err;
+ TInt failAt = 1;
+ do {
+ THandleTester h(test);
+
+ __UHEAP_MARK;
+ __UHEAP_SETFAIL(RHeap::EDeterministic, failAt);
+ TRAP(err, ExerciseFormatL());
+ __UHEAP_SETFAIL(RHeap::ENone, 0);
+ __UHEAP_MARKENDC(0);
+
+ ++failAt;
+ } while (err == KErrNoMemory);
+ test(err == KErrNone);
+ }
+
+void CTagmaImpTest::ExerciseRTmTextCacheWidthL()
+ {
+ _LIT(KOnions, "How easily happiness starts, slicing onions.\x2029");
+ TTmCharFormat defCharFormat(_L("SwissA"), 60);
+ TTmCharFormat specialCharFormat(_L("Arial"), 50);
+ CTestSource* source = new (ELeave) CTestSource(KOnions,
+ defCharFormat, specialCharFormat, 11, 20);
+ CleanupStack::PushL(source);
+ source->ConstructL(*iDevice);
+ RTmTextCache textCache(*source, source->FormatDevice());
+ CleanupClosePushL(textCache);
+ textCache.TotalWidthL(0, KOnions().Length(), EFalse);
+ textCache.AdvanceWidthL(0, KOnions().Length(), EFalse);
+ CleanupStack::PopAndDestroy();
+ CleanupStack::PopAndDestroy(source);
+ }
+
+void CTagmaImpTest::RTmTextCacheWidthOOM()
+ {
+ TInt err;
+ TInt failAt = 1;
+ do {
+ THandleTester h(test);
+
+ __UHEAP_MARK;
+ __UHEAP_SETFAIL(RHeap::EDeterministic, failAt);
+ TRAP(err, ExerciseRTmTextCacheWidthL());
+ __UHEAP_SETFAIL(RHeap::ENone, 0);
+ __UHEAP_MARKENDC(0);
+
+ ++failAt;
+ } while (err == KErrNoMemory);
+ test(err == KErrNone);
+ }
+
+void CTagmaImpTest::ExerciseRTmGeneralInterpreterGetDisplayedTextL()
+ {
+ CTestSource* source = NewTestSourceLC();
+ CTmCode* code = NewFormattedCTmCodeLC(*source);
+ TTmInterpreterParam param(*code);
+ param.iCodeStart = 0;
+ param.iCodeEnd = code->Size();
+ param.iTextStart = 0;
+ param.iWidth = 50;
+ RTmGeneralInterpreter interp(*source, param);
+ CleanupClosePushL(interp);
+ TInt needed;
+ TBuf<50> buf;
+ interp.GetDisplayedTextL(0, buf,0, needed);
+ CleanupStack::PopAndDestroy(); // interp.Close()
+ RTmGeneralInterpreter interp2(*source, param);
+ CleanupClosePushL(interp2);
+ interp2.GetDisplayedTextL(1, buf, 0,needed);
+ CleanupStack::PopAndDestroy(); // interp2.Close()
+ CleanupStack::PopAndDestroy(code);
+ CleanupStack::PopAndDestroy(source);
+ }
+
+void CTagmaImpTest::RTmGeneralInterpreterGetDisplayedTextOOM()
+ {
+ TInt err;
+ TInt failAt = 1;
+ do {
+ THandleTester h(test);
+
+ __UHEAP_MARK;
+ __UHEAP_SETFAIL(RHeap::EDeterministic, failAt);
+ TRAP(err, ExerciseRTmGeneralInterpreterGetDisplayedTextL());
+ __UHEAP_SETFAIL(RHeap::ENone, 0);
+ __UHEAP_MARKENDC(0);
+
+ ++failAt;
+ } while (err == KErrNoMemory);
+ test(err == KErrNone);
+ }
+
+void CTagmaImpTest::WEP_55BHBF_DefectL()
+ {
+ __UHEAP_MARK;
+ // defect WEP-55BHBF: EikLabels index out of bounds!!!!
+ // There is a picture character at the end to trick GetLineBreakL
+ // into looking outside the text for a picture.
+ _LIT(KHello, "hello\xFFFC");
+ TPtrC helloSeg(KHello().Ptr(), 5);
+ CTestSource* source = NewTestSourceLC();
+
+ TInt bp, hc, bpas;
+ source->SetText(helloSeg);
+ source->GetLineBreakL(helloSeg, 0, 0, 5, ETrue, bp, hc, bpas);
+ CleanupStack::PopAndDestroy();
+ __UHEAP_MARKEND;
+ }
+
+/** test code for INC044969 - Word app: Missing words on right of page
+
+ When Word is formating a block of text which consists of 8 repeats of
+ "this is a test " and the line break occurs just after "a", the defect caused the "a"
+ to disappear, so the line ended with "this is" and the next line started with
+ "test".
+ */
+void CTagmaImpTest::INC_044969_DefectL()
+ {
+
+ // create a CTestSource containing the test data
+ _LIT(KTest, " this is a test this is a test this is a test this is a test this is a test this is a test this is a test this is a test.");
+ TPtrC testSeg(KTest().Ptr(), KTest().Length() );
+ CTestSource* source = NewTestSourceLC();
+ source->SetText(testSeg);
+
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+
+ // format the text, a wrap width of 100 should produce
+ // the required break position of 10 (just after the a of " this is a")
+ CTmFormatContext::TInfo info;
+ TTmFormatParam formatParam;
+ formatParam.iStartChar = 0;
+ formatParam.iEndChar = source->DocumentLength();
+ formatParam.iLineInPar = 0;
+ formatParam.iMaxHeight = KMaxTInt;
+ formatParam.iMaxLines = KMaxTInt;
+ formatParam.iFlags = TTmFormatParam::EWrap;
+ formatParam.iWrapWidth = 100;
+ CTmTextLayout* layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+ CTmFormatContext::FormatL(*source, formatParam, *code, info, layout);
+
+ // check that format has found the break at 11 characters
+ // This is at the end of "this is a "
+ test( info.iFirstLineEndChar == 11 );
+
+ // get the text that would be displayed into displayBuffer
+ TTmInterpreterParam interpreter_param(*code);
+ interpreter_param.iCodeStart = 0;
+ interpreter_param.iCodeEnd = code->Size();
+ interpreter_param.iTextStart = 0;
+ interpreter_param.iWidth = 50;
+ RTmGeneralInterpreter interpreter(*source, interpreter_param);
+ TInt noCharsToDisplay =0;
+ TBuf<200> displayBuffer;
+ interpreter.GetDisplayedTextL(0, displayBuffer,0, noCharsToDisplay);
+
+ // now check the content of the buffer returned
+ // The defect caused this buffer to be missing the final 'a'
+ // from "...this is a" at the end of the line
+ // When this defect happens noCharsToDisplay != info.iFirstLineEndChar
+ test( info.iFirstLineEndChar == noCharsToDisplay );
+ test( displayBuffer[9] == 'a' );
+
+ interpreter.Close();
+ CleanupStack::PopAndDestroy(layout);
+ CleanupStack::PopAndDestroy(code); // code
+ CleanupStack::PopAndDestroy(source); // source
+
+ }
+
+/** test code for DEF073838 - Line break problem with WORD
+
+ When appending a space to the last line of a Word document, the defect
+ caused the last word of the line to be moved to a new line as if the space
+ were part of the word itself. So, if a paragraph ended with the words
+ "this is a test " and the final space was after the right margin, the line
+ was broken at the position of the 't' of "test".
+ */
+void CTagmaImpTest::DEF_073838_DefectL()
+ {
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+
+
+ // 1. format the text, a wrap width of 520 should produce no line breaks.
+ // 0x2029 is EParagraphDelimiter
+ CTestSource* source1 = NewTestSourceLC();
+
+ _LIT(KTest1, "Quo usque tandem, Catilina, abutere patientia nostra \x2029");
+ TPtrC testSeg1(KTest1().Ptr(), KTest1().Length() );
+ source1->SetText(testSeg1);
+
+ CTmFormatContext::TInfo info1;
+ TTmFormatParam formatParam1;
+ formatParam1.iStartChar = 0;
+ formatParam1.iEndChar = source1->DocumentLength();
+ formatParam1.iLineInPar = 0;
+ formatParam1.iMaxHeight = KMaxTInt;
+ formatParam1.iMaxLines = KMaxTInt;
+ formatParam1.iFlags = TTmFormatParam::EWrap;
+ formatParam1.iWrapWidth = 520;
+ CTmTextLayout* layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+ CTmFormatContext::FormatL(*source1, formatParam1, *code, info1, layout);
+
+ // check that format didn't found any breaks
+ test( info1.iFirstLineEndChar == KTest1().Length());
+ test( info1.iLastLineStartChar == 0 );
+ test( info1.iHeight == 12 ); // just 1 line
+
+
+
+ // 2. now append more than one space and verify that the line is not broken
+ CTestSource* source2 = NewTestSourceLC();
+
+ _LIT(KTest2, "Quo usque tandem, Catilina, abutere patientia nostra \x2029");
+ TPtrC testSeg2(KTest2().Ptr(), KTest2().Length() );
+ source2->SetText(testSeg2);
+
+ CTmFormatContext::TInfo info2;
+ TTmFormatParam formatParam2;
+ formatParam2.iStartChar = 0;
+ formatParam2.iEndChar = source2->DocumentLength();
+ formatParam2.iLineInPar = 0;
+ formatParam2.iMaxHeight = KMaxTInt;
+ formatParam2.iMaxLines = KMaxTInt;
+ formatParam2.iFlags = TTmFormatParam::EWrap;
+ formatParam2.iWrapWidth = 520;
+ CTmFormatContext::FormatL(*source2, formatParam2, *code, info2, layout);
+
+ // check that format didn't found any breaks
+ test( info2.iFirstLineEndChar == KTest2().Length());
+ test( info2.iLastLineStartChar == 0 );
+ test( info2.iHeight == 12 ); // just 1 line
+
+
+
+ // 3. now test with page breaks (0x000C) and line breaks (0x2028)
+ CTestSource* source3 = NewTestSourceLC();
+
+ _LIT(KTest3, "Quo usque tandem, Catilina, abutere patientia nostra \x2028Quo usque tandem, Catilina, abutere patientia nostra \x000CQuo usque tandem, Catilina, abutere patientia nostra \x2029");
+ TPtrC testSeg3(KTest3().Ptr(), KTest3().Length() );
+ source3->SetText(testSeg3);
+
+ CTmFormatContext::TInfo info3;
+ TTmFormatParam formatParam3;
+ formatParam3.iStartChar = 0;
+ formatParam3.iEndChar = source3->DocumentLength();
+ formatParam3.iLineInPar = 0;
+ formatParam3.iMaxHeight = KMaxTInt;
+ formatParam3.iMaxLines = KMaxTInt;
+ formatParam3.iFlags = TTmFormatParam::EWrap;
+ formatParam3.iWrapWidth = 520;
+ CTmFormatContext::FormatL(*source3, formatParam3, *code, info3, layout);
+
+ // check that format didn't found any breaks
+ test( info3.iFirstLineEndChar == 54 );
+ test( info3.iLastLineStartChar == 108 );
+ test( info3.iHeight == 36 ); // 3 lines
+
+ CleanupStack::PopAndDestroy(source3);
+ CleanupStack::PopAndDestroy(source2);
+ CleanupStack::PopAndDestroy(layout);
+ CleanupStack::PopAndDestroy(source1);
+ CleanupStack::PopAndDestroy(code);
+ }
+
+class TTestParLabelSource : public MTmSource, public MFormLabelApi
+ {
+ MGraphicsDeviceMap* iDevice;
+ TPtrC iBody;
+ TPtrC iLabel;
+ TPtrC* iCurrent;
+public:
+ TTestParLabelSource(MGraphicsDeviceMap* aDevice,
+ const TDesC& aBody, const TDesC& aLabel)
+ : iDevice(aDevice)
+ {
+ iBody.Set(aBody.Ptr(), aBody.Length());
+ iLabel.Set(aLabel.Ptr(), aLabel.Length());
+ iCurrent = &iBody;
+ }
+ void Close()
+ {
+ }
+ TInt DocumentLength() const { return iCurrent->Length(); }
+ MGraphicsDeviceMap& FormatDevice() const
+ {
+ return *iDevice;
+ }
+ TAny* GetExtendedInterface(const TUid& aInterfaceId)
+ {
+ if (aInterfaceId == KFormLabelApiExtensionUid)
+ {
+ return static_cast<MFormLabelApi*>(this);
+ }
+ else
+ {
+ // In this instance, calling the parent class will always return NULL
+ // but the pattern should be followed by all implementors for safety
+ return MTmSource::GetExtendedInterface(aInterfaceId);
+ }
+ }
+ void LabelMetrics(TLabelType /*aType*/, TSize& aLabelSize, TInt& aMarginSize) const
+ {
+ aLabelSize.iWidth = 100;
+ aLabelSize.iHeight = 10;
+ aMarginSize = 10;
+ }
+ void GetParagraphFormatL(TInt aPos, RTmParFormat& aFormat) const
+ {
+ __ASSERT_ALWAYS(0 <= aPos, User::Invariant());
+ __ASSERT_ALWAYS(aPos <= iCurrent->Length(), User::Invariant());
+ const RTmParFormat f;
+ aFormat.CopyL(f);
+ }
+ void GetText(TInt aPos,TPtrC& aText,TTmCharFormat& aFormat) const
+ {
+ ASSERT(0 <= aPos);
+ ASSERT(aPos <= iCurrent->Length());
+ aText.Set(iCurrent->Ptr() + aPos, iCurrent->Length()+1 - aPos);
+ TTmCharFormat f;
+ aFormat = f;
+ }
+ MGraphicsDeviceMap& InterpretDevice() const
+ {
+ return *iDevice;
+ }
+ TInt ParagraphStart(TInt) const { return 0; }
+ TBool LabelModeSelect(TLabelType,TInt)
+ {
+ if (iCurrent == &iLabel)
+ return EFalse;
+ iCurrent = &iLabel;
+ return ETrue;
+ }
+ void LabelModeCancel() { iCurrent = &iBody; }
+ TRgb SystemColor(TUint aColorIndex,TRgb aDefaultColor) const
+ {
+ if (aColorIndex == TLogicalRgb::ESystemSelectionForegroundIndex)
+ return KRgbWhite;
+ if (aColorIndex == TLogicalRgb::ESystemSelectionBackgroundIndex)
+ return KRgbRed;
+ return MTmSource::SystemColor(aColorIndex, aDefaultColor);
+ }
+ };
+
+void CTagmaImpTest::BUR_58FGE8_DefectL()
+ {
+ // Int: Application panic when selecting, Select All from the edit menu
+ _LIT(KBody, "small\x2029");
+ _LIT(KLabel, "longer than the body\x2029");
+ TTestParLabelSource s(iDevice, KBody, KLabel);
+ CTmTextLayout* lay = new(ELeave) CTmTextLayout;
+ TTmFormatParam fp;
+ fp.iWrapWidth = 200;
+ fp.iEndChar = KBody().Length();
+ lay->SetTextL(s, fp);
+ TPoint zero;
+ TRect clip(0, 0, 200, 200);
+ lay->HighlightSection(*iGc, zero, 0, KBody().Length(), clip);
+ s.Close();
+ }
+
+/**
+ * EXT-5ATF8D: "TAGMA - different character formats" The complaint is that
+ * CTmText does not seem to display differently formatted characters in their
+ * different formats. The defect is due to the fact that the function to get
+ * the text from the buffer ignores the length of run of characters, so the
+ * rendering assumes that all the characters are in the same format.
+ * @internalComponent
+ */
+void CTagmaImpTest::EXT_5ATF8D_DefectL()
+ {
+ TTmFormatParamBase formatParam;
+ CTmTextImp* text = new(ELeave)
+ CTmTextImp(*iDevice, formatParam);
+ CleanupStack::PushL(text);
+
+ TTmCharFormat cf1;
+ cf1.iEffects |= TTmCharFormat::EUnderline;
+ TTmCharFormat cf2;
+ cf2.iEffects &= ~TTmCharFormat::EUnderline;
+ RTmParFormat pf1;
+ CleanupClosePushL(pf1);
+ pf1.iSpaceAbove = 1;
+ RTmParFormat pf2;
+ CleanupClosePushL(pf2);
+ pf2.iSpaceAbove = 2;
+ text->InsertL(0, _L("first line\x2029second."), &cf1, &pf1, 0, 0);
+ text->InsertL(14, _L("t p"), &cf2, &pf2, 0, 0);
+
+ TPtrC testText;
+ TTmCharFormat cft;
+ RTmParFormat pft;
+ CleanupClosePushL(pft);
+
+ text->GetText(0, testText, cft);
+ text->GetParagraphFormatL(0, pft);
+ test(testText.Length() == 14);
+ test(testText.Compare(_L("first line\x2029sec")) == 0);
+ test(cft == cf1);
+ test(pft == pf1);
+
+ text->GetText(11, testText, cft);
+ text->GetParagraphFormatL(11, pft);
+ test(testText.Length() == 3);
+ test(testText.Compare(_L("sec")) == 0);
+ test(cft == cf1);
+ test(pft == pf2);
+
+ text->GetText(14, testText, cft);
+ text->GetParagraphFormatL(14, pft);
+ test(testText.Length() == 3);
+ test(testText.Compare(_L("t p")) == 0);
+ test(cft == cf2);
+ test(pft == pf2);
+
+ text->GetText(17, testText, cft);
+ text->GetParagraphFormatL(17, pft);
+ test(cft == cf1);
+ test(pft == pf2);
+
+ text->GetText(21, testText, cft);
+ text->GetParagraphFormatL(21, pft);
+ test(pft == pf2);
+ CleanupStack::PopAndDestroy(&pft);
+ CleanupStack::PopAndDestroy(&pf2);
+ CleanupStack::PopAndDestroy(&pf1);
+ CleanupStack::PopAndDestroy(text);
+ }
+
+void CTagmaImpTest::GetIndices(TDes8& aBuf, const CTmTextImp::RRunArray& aRunArray)
+ {
+ test(aRunArray.Index(0) == aRunArray.Index(1));
+ aBuf.Zero();
+ TInt index;
+ for (TInt i = 1; 0 <= (index = aRunArray.Index(i)); ++i)
+ {
+ aBuf.Append('0' + index);
+ }
+ }
+
+/**
+@SYMTestCaseID SYSLIB-FORM-UT-1886
+@SYMTestCaseDesc Testing the API's of CTmTextImp: ChangeFormatL, MemoryUsed, SystemColor, CustomizeL
+@SYMTestPriority Low
+@SYMTestActions Tests by changing the format, checking the memory usage, setting the system colour and Changing the custom formatting
+@SYMTestExpectedResults Tests must not fail
+@SYMREQ REQ0000
+*/
+void CTagmaImpTest::TestAPIL()
+ {
+ TTmFormatParam formatParam;
+ CTmTextImp* text = new(ELeave)
+ CTmTextImp(*iDevice, formatParam);
+ CleanupStack::PushL(text);
+ TTmCharFormat cf1;
+ cf1.iEffects |= TTmCharFormat::EUnderline;
+ RTmParFormat pf1;
+ CleanupClosePushL(pf1);
+ pf1.iSpaceAbove = 1;
+ text->InsertL(0, _L("Some text"), &cf1, &pf1, 0, 0);
+
+ TInt memUsed = text->MemoryUsed();
+ text->ChangeFormatL(formatParam);
+ test(text->MemoryUsed()==memUsed);
+
+ TTmFormatParam formatParam1;
+ formatParam1.iStartChar = 0;
+ formatParam1.iEndChar = 15;
+ formatParam1.iLineInPar = 0;
+ formatParam1.iWrapWidth = 50;
+ formatParam1.iMaxHeight = KMaxTInt;
+ formatParam1.iMaxLines = KMaxTInt;
+ formatParam1.iFlags = TTmFormatParam::EWrap;
+ //Setting the format of the text
+ text->ChangeFormatL(formatParam1);
+ //After changing the format, memory used by the text differs from the initial value
+ test(text->MemoryUsed()!=memUsed);
+ TRgb color1(100,10,20);
+ TRgb color2;
+ //Setting the system colour with an index representing the system background colour
+ color2 = text->SystemColor(TLogicalRgb::ESystemBackgroundIndex,color1);
+ test(color2==color1);
+
+ _LIT(KBody, "Body");
+ _LIT(KLabel, "Label, Longer than Body");
+ TTestParLabelSource sourceLabel(iDevice, KBody, KLabel);
+ CTmTextLayout* iLayout = new (ELeave) CTmTextLayout;
+ iLayout->SetTextL(sourceLabel, formatParam);
+ //Changing the custom formatting
+ text->CustomizeL(iLayout->Source());
+
+ //Setting the system colour with an index representing the system foreground colour
+ color2 = text->SystemColor(TLogicalRgb::ESystemSelectionForegroundIndex,color1);
+ test(color2!=color1);
+ CleanupStack::PopAndDestroy(&pf1);
+ CleanupStack::PopAndDestroy(text);
+ }
+
+void CTagmaImpTest::CTmTextImp_RRunArrayL()
+ {
+ TBuf8<50> indexBuf;
+ CTmTextImp::RRunArray ra;
+ CleanupClosePushL(ra);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("")));
+ ra.Insert(0, 10, 0);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("0000000000")));
+ ra.Insert(5, 10, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000111111111100000")));
+ ra.Delete(13, 4);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("0000011111111000")));
+ ra.Delete(2, 12);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("0000")));
+ ra.Delete(0, 4);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("")));
+ ra.Insert(0, 20, 0);
+ ra.Set(5, 10, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000111111111100000")));
+ ra.Set(6, 4, 2);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000122221111100000")));
+ ra.Set(10, 4, 3);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000122223333100000")));
+ ra.Set(9, 2, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000122211333100000")));
+ ra.Set(6, 1, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000112211333100000")));
+ ra.Set(8, 1, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000112111333100000")));
+ ra.Set(7, 1, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000111111333100000")));
+ ra.Set(7, 2, 2);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("00000112211333100000")));
+ ra.Set(1, 19, 1);
+ GetIndices(indexBuf, ra);
+ test(0 == indexBuf.Compare(_L8("01111111111111111111")));
+ CleanupStack::PopAndDestroy(&ra);
+ }
+
+
+void CTagmaImpTest::CTmTextImp_BidirectionalAlignmentL()
+ {
+ ExerciseCopyL();
+ ExerciseGetCParaFormatL();
+ }
+
+void CTagmaImpTest::ExerciseCopyL()
+ {
+ CParaFormat* pF = CParaFormat::NewL();
+ CleanupStack::PushL(pF);
+ RTmParFormat rPF;
+
+ test(RTmParFormat::EAlignNormalBidirectional == rPF.iAlignment);
+
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignNormal == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::ELeftAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignNormal == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::ECenterAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignCenter == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::ERightAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignReverse == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::EJustifiedAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignJustify == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::EAbsoluteLeftAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignAbsoluteLeft == rPF.iAlignment);
+
+ pF->iHorizontalAlignment = CParaFormat::EAbsoluteRightAlign;
+ rPF.CopyL(*pF);
+ test(RTmParFormat::EAlignAbsoluteRight == rPF.iAlignment);
+
+ rPF.Close();
+ CleanupStack::PopAndDestroy(); //pF
+ }
+
+void CTagmaImpTest::ExerciseGetCParaFormatL()
+ {
+ CParaFormat* pF = CParaFormat::NewL();
+ CleanupStack::PushL(pF);
+ RTmParFormat rPF;
+
+ test(pF->iHorizontalAlignment == CParaFormat::ELeftAlign);
+
+ rPF.iAlignment = RTmParFormat::EAlignNormal;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::ELeftAlign == pF->iHorizontalAlignment);
+
+ rPF.iAlignment = RTmParFormat::EAlignCenter;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::ECenterAlign == pF->iHorizontalAlignment);
+
+ rPF.iAlignment = RTmParFormat::EAlignReverse;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::ERightAlign == pF->iHorizontalAlignment);
+
+ rPF.iAlignment = RTmParFormat::EAlignJustify;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::EJustifiedAlign == pF->iHorizontalAlignment);
+
+ rPF.iAlignment = RTmParFormat::EAlignAbsoluteLeft;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::EAbsoluteLeftAlign == pF->iHorizontalAlignment);
+
+ rPF.iAlignment = RTmParFormat::EAlignAbsoluteRight;
+ rPF.GetCParaFormatL(*pF);
+ test(CParaFormat::EAbsoluteRightAlign == pF->iHorizontalAlignment);
+
+ rPF.Close();
+ CleanupStack::PopAndDestroy(); // pF
+ }
+
+class TTestCustomFormattingSource : public MTmSource, public MTmInlineTextSource
+ {
+ MGraphicsDeviceMap* iDevice;
+ TInt iCustomFormatType;
+ TPtrC iBody;
+ TPtrC* iCurrent;
+ TPtrC iNullText;
+public:
+ TTestCustomFormattingSource(MGraphicsDeviceMap* aDevice,
+ const TDesC& aBody, TInt aCustomFormatType)
+ : iDevice(aDevice)
+ {
+ iCustomFormatType = aCustomFormatType;
+ iBody.Set(aBody.Ptr(), aBody.Length());
+ iCurrent = &iBody;
+ }
+ void Close()
+ {
+ }
+ TInt DocumentLength() const { return iCurrent->Length(); }
+ MGraphicsDeviceMap& FormatDevice() const
+ {
+ return *iDevice;
+ }
+ TAny* GetExtendedInterface(const TUid& aInterfaceId)
+ {
+ if (aInterfaceId == KInlineTextApiExtensionUid)
+ {
+ return static_cast<MTmInlineTextSource*>(this);
+ }
+ else
+ {
+ // In this instance, calling the parent class will always return NULL
+ // but the pattern should be followed by all implementors for safety
+ return MTmSource::GetExtendedInterface(aInterfaceId);
+ }
+ }
+ void GetParagraphFormatL(TInt aPos, RTmParFormat& aFormat) const
+ {
+ __ASSERT_ALWAYS(0 <= aPos, User::Invariant());
+ __ASSERT_ALWAYS(aPos <= iCurrent->Length(), User::Invariant());
+ const RTmParFormat f;
+ aFormat.CopyL(f);
+ }
+ void GetText(TInt aPos,TPtrC& aText,TTmCharFormat& aFormat) const
+ {
+ ASSERT(0 <= aPos);
+ ASSERT(aPos <= iCurrent->Length());
+ aText.Set(iCurrent->Ptr() + aPos, iCurrent->Length() - aPos);
+ TTmCharFormat f;
+ aFormat = f;
+ }
+ MGraphicsDeviceMap& InterpretDevice() const
+ {
+ return *iDevice;
+ }
+ TInt ParagraphStart(TInt) const { return 0; }
+ TRgb SystemColor(TUint aColorIndex,TRgb aDefaultColor) const
+ {
+ if (aColorIndex == TLogicalRgb::ESystemSelectionForegroundIndex)
+ return KRgbWhite;
+ if (aColorIndex == TLogicalRgb::ESystemSelectionBackgroundIndex)
+ return KRgbRed;
+ return MTmSource::SystemColor(aColorIndex, aDefaultColor);
+ }
+ TInt GetNextInlineTextPosition(const TTmDocPos& aFrom, TInt aMaxLength, TTmDocPos& aNext)
+ {
+ if (iCustomFormatType == 0)
+ {
+ return KErrNotFound;
+ }
+ else if (iCustomFormatType == 1)
+ {
+ _LIT(KCFS1, "EPOC");
+ TInt from = aFrom.iPos;
+ if (from < 4)
+ from = 0;
+ else
+ { // let's move back to look for the target string
+ from -= (aFrom.iLeadingEdge ? 3 : 4); // adjustment takes care of not returning trailing edge if at start pos
+ }
+ TInt pos = iBody.Mid(from).Find(KCFS1);
+ if (pos != KErrNotFound)
+ {
+ pos += from;
+ aNext.iPos = pos + 4; // Adjust by length of string "EPOC"
+ aNext.iLeadingEdge = EFalse;
+ if (aNext.iPos - aFrom.iPos < aMaxLength + (aNext.iLeadingEdge ? 0 : 1))
+ return KErrNotFound;
+ test.Printf(_L("GetPos-InlineTextAt-%d %c-From-%d\n"), aNext.iPos, aNext.iLeadingEdge ? 'L' : 'T', aFrom.iPos);
+ return KErrNone;
+ }
+ return KErrNotFound;
+ }
+ else if (iCustomFormatType == 2)
+ {
+ _LIT(KCFS2, "(ABCDEFGHI)");
+ TInt from = aFrom.iPos;
+ if (from < 7)
+ from = 0;
+ else
+ { // let's move back to look for the target string
+ from -= (aFrom.iLeadingEdge ? 6 : 7); // adjustment takes care of not returning trailing edge if at start pos
+ }
+ TInt pos = iBody.Mid(from).Find(KCFS2);
+ if (pos != KErrNotFound)
+ {
+ pos += from;
+ if (pos + 4 >= aFrom.iPos)
+ { // search position is before the first break space
+ aNext.iPos = pos + 4; // adjust to position of first space
+ aNext.iLeadingEdge = ETrue;
+ if (aNext.iPos - aFrom.iPos < aMaxLength + (aNext.iLeadingEdge ? 0 : 1))
+ return KErrNotFound;
+ test.Printf(_L("GetPos-InlineTextAt-%d %c-From-%d\n"), aNext.iPos, aNext.iLeadingEdge ? 'L' : 'T', aFrom.iPos);
+ return KErrNone;
+ }
+ // if it gets here search position is after the first break space
+ if (pos + 7 >= aFrom.iPos)
+ { // but before the second
+ aNext.iPos = pos + 7; // adjust to position of second space
+ aNext.iLeadingEdge = EFalse;
+ if (aNext.iPos - aFrom.iPos < aMaxLength + (aNext.iLeadingEdge ? 0 : 1))
+ return KErrNotFound;
+ test.Printf(_L("GetPos-InlineTextAt-%d %c-From-%d\n"), aNext.iPos, aNext.iLeadingEdge ? 'L' : 'T', aFrom.iPos);
+ return KErrNone;
+ }
+ }
+ return KErrNotFound;
+ }
+ return KErrNotFound;
+ }
+ TPtrC GetInlineText(const TTmDocPos& aAt)
+ {
+ test.Printf(_L("QueryTextAt-%d %c\n"), aAt.iPos, aAt.iLeadingEdge ? 'L' : 'T');
+ if (iCustomFormatType == 0)
+ {
+ return iNullText;
+ }
+ else if (iCustomFormatType == 1)
+ {
+ _LIT(KCFS1, "EPOC");
+ TInt at = aAt.iPos;
+ if (at < 4)
+ at = 0;
+ else
+ at -= 4; // let's move back to look for the target string
+ TInt pos = iBody.Mid(at).Find(KCFS1);
+ if (pos != KErrNotFound)
+ {
+ pos += at;
+ if ((pos + 4 == aAt.iPos) && !aAt.iLeadingEdge)
+ {
+ _LIT(KCFS3, "?");
+ TPtrC tPtrC(KCFS3);
+ test.Printf(_L("GetText-QuestionMark-%d\n"), aAt.iPos);
+ return tPtrC;
+ }
+ }
+ return iNullText;
+ }
+ else if (iCustomFormatType == 2)
+ {
+ _LIT(KCFS2, "(ABCDEFGHI)");
+ TInt at = aAt.iPos;
+ if (at < 7)
+ at = 0;
+ else
+ at -= 7; // let's move back to look for the target string
+ TInt pos = iBody.Mid(at).Find(KCFS2);
+ if (pos != KErrNotFound)
+ {
+ pos += at;
+ if ((pos + 4 == aAt.iPos) && aAt.iLeadingEdge)
+// if ((pos + 4 == aAt.iPos) && !aAt.iLeadingEdge)
+ { // search position is on the first break space
+ _LIT(KCFS4, " ");
+ TPtrC tPtrC(KCFS4);
+ test.Printf(_L("GetText-Space-%d-L\n"), aAt.iPos);
+ return tPtrC;
+ }
+ // if it gets here search position is not on the first break space
+ if ((pos + 7 == aAt.iPos) && !aAt.iLeadingEdge)
+ { // but it is on the second
+ _LIT(KCFS4, " ");
+ TPtrC tPtrC(KCFS4);
+ test.Printf(_L("GetText-Space-%d-T\n"), aAt.iPos);
+ return tPtrC;
+ }
+ }
+ return iNullText;
+ }
+ return iNullText;
+ }
+ };
+
+void CTagmaImpTest::CustomFormattingL()
+ {
+ // Test implementation of CustomFormatting
+ // ========
+ // Test one
+ // ========
+ // First test is where inline text is enabled but where there is none to insert
+ _LIT(KBody0, "This is a bunch of boring plain text that doesn't get any inline text inserted.\x2029");
+ TTestCustomFormattingSource s0(iDevice, KBody0, 0); // No inline text
+ CTmTextLayout* lay0 = new(ELeave) CTmTextLayout;
+ TTmFormatParam fp0;
+ fp0.iWrapWidth = 200;
+ fp0.iEndChar = KBody0().Length();
+ lay0->SetTextL(s0, fp0);
+ s0.Close();
+ // ========
+ // Test two
+ // ========
+ // Second test is where a single inline question mark will be inserted after the word EPOC
+ _LIT(KBody1, "With luck the word EPOC will be followed by a question mark\x2029");
+ TTestCustomFormattingSource s1(iDevice, KBody1, 1); // No inline text
+ CTmTextLayout* lay1 = new(ELeave) CTmTextLayout;
+ TTmFormatParam fp1;
+ fp1.iWrapWidth = 200;
+ fp1.iEndChar = KBody1().Length();
+ lay1->SetTextL(s1, fp1);
+ s1.Close();
+ // ==========
+ // Test three
+ // ==========
+ // Third test looks for a pair of brackets separated by 9 chars and inserts spaces to
+ // split them into three blocks of three chars
+ _LIT(KBody2, "Take 9 chars inside brackets (ABCDEFGHI) and split by spaces into 3 x 3.\x2029");
+ TTestCustomFormattingSource s2(iDevice, KBody2, 2); // No inline text
+ CTmTextLayout* lay2 = new(ELeave) CTmTextLayout;
+ TTmFormatParam fp2;
+ fp2.iWrapWidth = 200;
+ fp2.iEndChar = KBody2().Length();
+ lay2->SetTextL(s2, fp2);
+ s2.Close();
+ }
+
+
+/**
+@SYMTestCaseID SYSLIB-FORM-CT-3353
+@SYMTestCaseDesc Test Handling of ZWJ characters in latin text
+@SYMTestPriority High
+@SYMTestActions Format some Latin strings with ZWJ characters and
+ verify the formatted string and length of text.
+@SYMTestExpectedResults The formatted string should exclude the ZWJ character
+ and the length of the string should equal the
+ number of characters in the original string + 1.
+ for the terminator.
+ The formatting of the string must not cause a panic.
+@SYMDEF PDEF101464
+ */
+void CTagmaImpTest::PDEF_101464_DefectL()
+{
+ //Latin ZWJ example strings
+ _LIT(KLatinZWJ1,"\x200D\x0061\x0062\x0063");
+ _LIT(KLatinZWJ2,"\x0061\x0062\x200D\x0063");
+ _LIT(KLatinZWJ3,"\x0061\x0062\x0063\x200D");
+
+ //Expected displayed result from Latin strings - ZJW has no effect
+ _LIT(KDisplayedLatinZWJ,"\x0061\x0062\x0063");
+ //Expected length is four characters plus terminator
+ TInt KExpectedTextLength = 5;
+
+ CTmText *text = CTmText::NewL(*iDevice,KMaxTInt,FALSE);
+ CleanupStack::PushL(text);
+
+ TBuf<32> buffer;
+ TInt needed;
+ TInt textLength;
+
+ //Test the sample text with ZWJ at the beginning of the string
+ text->InsertL(0,KLatinZWJ1);
+ text->GetDisplayedText(0,buffer,needed);
+
+ //Verify that the text is formatted correctly
+ test(buffer == KDisplayedLatinZWJ);
+
+ //Verify that the length of the string is as expected
+ textLength = (text->EndChar()) - (text->StartChar());
+ test(textLength == KExpectedTextLength);
+ text->Clear();
+
+ //Test the sample text with ZWJ in the middle of the string
+ text->InsertL(0,KLatinZWJ2);
+ text->GetDisplayedText(0,buffer,needed);
+
+ //Verify that the text is formatted correctly
+ test(buffer == KDisplayedLatinZWJ);
+
+ //Verify that the length of the string is as expected
+ textLength = (text->EndChar()) - (text->StartChar());
+ test(textLength == KExpectedTextLength);
+ text->Clear();
+
+ //Test the sample text with ZWJ at the end of the string
+ text->InsertL(0,KLatinZWJ3);
+ text->GetDisplayedText(0,buffer,needed);
+
+ //Verify that the text is formatted correctly
+ test(buffer == KDisplayedLatinZWJ);
+
+ //Verify that the length of the string is as expected
+ textLength = (text->EndChar()) - (text->StartChar());
+ test(textLength == KExpectedTextLength);
+ text->Clear();
+
+ CleanupStack::PopAndDestroy(); // text
+}
+
+
+
+/**
+@SYMTestCaseID SYSLIB-FORM-CT-3398
+@SYMTestCaseDesc Test Mapping Of Post Unicode 2.0 Characters
+@SYMTestPriority High
+@SYMTestActions Format some Unicdoe 5.0 characters and test if they have
+ been formatted
+@SYMTestExpectedResults The formatted string should include the Unicode 5.0 characters
+@SYMDEF DEF101994
+ */
+void CTagmaImpTest::DEF101994_DefectL()
+{
+ // Kannada and Tamil characters
+ _LIT(KKannadaTamil,"\x0CBC\x0CBD\x0BB6\x0BE6\x0BF3\x0BF4\x0BF5\x0BF6\x0BF7\x0BF8\x0BF9\x0BFA");
+ //Expected displayed result - all characters should be mapped and displayed
+ _LIT(KDisplayedKannadaTamil,"\x0CBC\x0CBD\x0BB6\x0BE6\x0BF3\x0BF4\x0BF5\x0BF6\x0BF7\x0BF8\x0BF9\x0BFA");
+ //Expected length is twelve characters plus terminator
+ TInt KExpectedTextLength = 13;
+
+ CTmText *text = CTmText::NewL(*iDevice,KMaxTInt,FALSE);
+ CleanupStack::PushL(text);
+
+ TBuf<32> buffer;
+ TInt needed;
+ TInt textLength;
+
+ //Test the sample text the Kananda and Tamil characters
+ text->InsertL(0,KKannadaTamil);
+ text->GetDisplayedText(0,buffer,needed);
+
+ //Verify that the text is formatted correctly
+ test(buffer == KDisplayedKannadaTamil);
+
+ //Verify that the length of the string is as expected
+ textLength = (text->EndChar()) - (text->StartChar());
+ test(textLength == KExpectedTextLength);
+ text->Clear();
+
+ CleanupStack::PopAndDestroy(); // text
+}
+
+ /**
+ @SYMTestCaseID SYSLIB-FORM-UT-4010
+ @SYMTestCaseDesc Automated Form testing for Drawing Text with Context
+ @SYMTestPriority High
+ @SYMTestActions Format text and check the line context stored in chunks.
+ @SYMTestExpectedResults Each chunk should contain the correct context based on the script used in the source text.
+ @SYMPREQ 1766: Support Bengali, Tamil and Telugu Scripts
+ @SYMREQ 854: Text I18N Drawing Latin Punctuation along the Indic text baseline
+ */
+ void CTagmaImpTest::TestChunkContext()
+ {
+ TTmChunk chunk;
+ TTmChunk::TInfo chunkInfo;
+
+ // create a CTestSource containing the test data
+ _LIT(KTest, "\x0915\x094d\x0915...abc.");
+ TPtrC testSeg(KTest().Ptr(), KTest().Length() );
+ CTestSource* source = NewTestSourceLC();
+ source->SetText(testSeg);
+
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+
+ // format the text
+ TTmFormatParam formatParam;
+ formatParam.iStartChar = 0;
+ formatParam.iEndChar = source->DocumentLength();
+ formatParam.iLineInPar = 0;
+ formatParam.iMaxHeight = KMaxTInt;
+ formatParam.iMaxLines = KMaxTInt;
+ formatParam.iFlags = TTmFormatParam::EWrap;
+ formatParam.iWrapWidth = 533;
+ CTmTextLayout* layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+
+ CTmFormatContext* formatContext = new CTmFormatContext(*source, formatParam, *code, layout);
+ CleanupStack::PushL(formatContext);
+
+ chunk.SetL(*formatContext,0,0,10,533,0,chunkInfo);
+ TUint context = chunk.iContextCharInByteCode;
+ // Test that the first chunk's context has been recognised as not needing supplied context.
+ test(0 == context);
+ chunk.SetL(*formatContext,3,0,10,533,0,chunkInfo);
+ context = chunk.iContextCharInByteCode;
+ // Test that the next chunk retains the Hindi context.
+ test(2325 == context);
+ chunk.SetL(*formatContext,4,0,10,533,0,chunkInfo);
+ context = chunk.iContextCharInByteCode;
+ // Test that the next chunk retains the Hindi context.
+ test(2325 == context);
+ chunk.SetL(*formatContext,5,0,10,533,0,chunkInfo);
+ context = chunk.iContextCharInByteCode;
+ // Test that the next chunk retains the Hindi context.
+ test(2325 == context);
+ chunk.SetL(*formatContext,6,0,10,533,0,chunkInfo);
+ context = chunk.iContextCharInByteCode;
+ // Test that the next chunk has been recognised as not needing supplied context.
+ test(0 == context);
+ chunk.SetL(*formatContext,9,0,10,533,0,chunkInfo);
+ context = chunk.iContextCharInByteCode;
+ // Test that the next chunk retains the Latin context.
+ test(99 == context);
+
+
+ CleanupStack::PopAndDestroy(formatContext); // formatContext
+ CleanupStack::PopAndDestroy(layout); // layout
+ CleanupStack::PopAndDestroy(code); // code
+ CleanupStack::PopAndDestroy(source); // source
+ }
+
+ /**
+ @SYMTestCaseID SYSLIB-FORM-UT-4011
+ @SYMTestCaseDesc Automated Form testing for Drawing Text with Context
+ @SYMTestPriority High
+ @SYMTestActions Format text and check the line context from the generated bytecode.
+ @SYMTestExpectedResults The bytecode should contain the correct context based on the script used in the source text.
+ @SYMPREQ 1766: Support Bengali, Tamil and Telugu Scripts
+ @SYMREQ 854: Text I18N Drawing Latin Punctuation along the Indic text baseline
+ */
+ void CTagmaImpTest::TestBytecodeLineContext()
+ {
+ // create a CTestSource containing the test data
+ _LIT(KTest, "abcdefghij..........\x0915\x0915\x0915\x0915\x0915\x0915\x0915\x0915\x0915\x0915..........");
+
+ TPtrC testSeg(KTest().Ptr(), KTest().Length());
+ CTestSource* source = NewTestSourceLC();
+ source->SetText(testSeg);
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+
+ // Format the text.
+ CTmFormatContext::TInfo info;
+ TTmFormatParam formatParam;
+ formatParam.iStartChar = 0;
+ formatParam.iEndChar = source->DocumentLength();
+ formatParam.iLineInPar = 0;
+ formatParam.iMaxHeight = KMaxTInt;
+ formatParam.iMaxLines = KMaxTInt;
+ formatParam.iFlags = TTmFormatParam::EWrap;
+ formatParam.iWrapWidth = 100;
+ CTmTextLayout* layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+ CTmFormatContext::FormatL(*source, formatParam, *code, info, layout);
+
+ // Set up the interpreter.
+ TTmInterpreterParam interpreter_param(*code);
+ interpreter_param.iCodeStart = 0;
+ interpreter_param.iCodeEnd = code->Size();
+ interpreter_param.iTextStart = 0;
+ interpreter_param.iWidth = 50;
+ RTmGeneralInterpreter interpreter(*source, interpreter_param);
+
+ // Expected context per line.
+ TInt expectedResults[] = {106, 106, 2325, 2325};
+ TInt lines = 0;
+
+ // Iterate through lines in bytecode and check the context.
+ while (interpreter.Next())
+ {
+ if (interpreter.Op() == TTmInterpreter::EOpLine)
+ {
+ test(interpreter.LineContextCharChar() == expectedResults[lines++]);
+ }
+ interpreter.Skip();
+ }
+
+ // Test the correct amount of lines have been tested.
+ test(4 == lines);
+
+ // Close the interpreter and clean up the heap.
+ interpreter.Close();
+ CleanupStack::PopAndDestroy(layout); // layout
+ CleanupStack::PopAndDestroy(code); // code
+ CleanupStack::PopAndDestroy(source); // source
+ }
+
+
+ /**
+ @SYMTestCaseID SYSLIB-FORM-UT-4012
+ @SYMTestCaseDesc Automated Form testing for Drawing Text with Context
+ @SYMTestPriority High
+ @SYMTestActions Format text and check the chunk context from the generated bytecode.
+ @SYMTestExpectedResults Chunks within the bytecode should contain the correct context based on the script used in the source text.
+ @SYMPREQ 1766: Support Bengali, Tamil and Telugu Scripts
+ @SYMREQ 854: Text I18N Drawing Latin Punctuation along the Indic text baseline
+ */
+ void CTagmaImpTest::TestBytecodeChunkContext()
+ {
+ // create a CTestSource containing the test data.
+ _LIT(KTest, "a. b\x915.c. \x916.d \x917. chunk");
+ TPtrC testSeg(KTest().Ptr(), KTest().Length());
+ CTestSource* source = NewTestSourceLC();
+ source->SetText(testSeg);
+
+ // Create a bytecode object.
+ CTmCode* code = new(ELeave) CTmCode;
+ CleanupStack::PushL(code);
+
+ // Format the text.
+ CTmFormatContext::TInfo info;
+ TTmFormatParam formatParam;
+ formatParam.iStartChar = 0;
+ formatParam.iEndChar = source->DocumentLength();
+ formatParam.iLineInPar = 0;
+ formatParam.iMaxHeight = KMaxTInt;
+ formatParam.iMaxLines = KMaxTInt;
+ formatParam.iFlags = TTmFormatParam::EWrap;
+ formatParam.iWrapWidth = KMaxTInt;
+ CTmTextLayout* layout = new(ELeave) CTmTextLayout;
+ CleanupStack::PushL(layout);
+ CTmFormatContext::FormatL(*source, formatParam, *code, info, layout);
+
+ // Set up the interpreter.
+ TTmInterpreterParam interpreter_param(*code);
+ interpreter_param.iCodeStart = 0;
+ interpreter_param.iCodeEnd = code->Size();
+ interpreter_param.iTextStart = 0;
+ interpreter_param.iWidth = KMaxTInt;
+ RTmGeneralInterpreter interpreter(*source, interpreter_param);
+
+ // Expected context per chunk.
+ TInt expectedResults[] = {0, 2325, 0};
+ TInt chunks = 0;
+
+ // Make sure we're starting at the begining.
+ TBool found = interpreter.LineNumberToLine(0);
+
+ // Iterate through the chunks, testing context.
+ while (interpreter.Next() && interpreter.Op() != TTmInterpreter::EOpLine)
+ {
+ TUint32 op = interpreter.Op();
+ if (interpreter.Op() == TTmInterpreter::EOpText || interpreter.Op() == TTmInterpreter::EOpSpecialChar)
+ {
+ test(expectedResults[chunks++] == interpreter.ContextCharChar());
+ }
+ else
+ {
+ interpreter.Skip();
+ }
+ }
+
+ // Test that the expected number of chunks were found in the bytecode.
+ test(3 == chunks);
+
+ // Close the interpreter and clean up the heap.
+ interpreter.Close();
+ CleanupStack::PopAndDestroy(layout); // layout
+ CleanupStack::PopAndDestroy(code); // code
+ CleanupStack::PopAndDestroy(source); // source
+ }
+
+void CTagmaImpTest::TestL()
+ {
+// __UHEAP_MARK;
+
+ test.Start(_L("Regression test: DEF073838")); // Line break problem with WORD
+ DEF_073838_DefectL();
+
+ test.Next(_L("Regression test: INC044969"));
+ INC_044969_DefectL();
+
+ test.Next(_L("CTmTextImp::RRunArray tests"));
+ CTmTextImp_RRunArrayL();
+
+ test.Next(_L("Regression test: BUR-58FGE8"));
+ BUR_58FGE8_DefectL();
+
+ test.Next(_L("Regression test: WEP-55BHBF"));
+ WEP_55BHBF_DefectL();
+
+ test.Next(_L("Regression test: EXT-5ATF8D"));
+ EXT_5ATF8D_DefectL();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-UT-1886 Test for CTmTextImp API's "));
+ TestAPIL();
+
+ test.Next(_L("CTmCode tests"));
+ CTmCodeOOML();
+
+ test.Next(_L("CTmFormatContext::FormatL tests"));
+ FormatOOML();
+
+ test.Next(_L("RTmTextCache::Width tests"));
+ RTmTextCacheWidthOOM();
+
+ test.Next(_L("RTmGeneralInterpreter::GetDisplayedText tests"));
+ RTmGeneralInterpreterGetDisplayedTextOOM();
+
+ test.Next(_L("Bidirectional alignment tests"));
+ CTmTextImp_BidirectionalAlignmentL();
+
+ test.Next(_L("Custom formatting tests"));
+ CustomFormattingL();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-3353 Regression test: PDEF101464 "));
+ PDEF_101464_DefectL();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-CT-3398 Regression test: DEF101994 "));
+ DEF101994_DefectL();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-UT-4010 Drawing Text within context: Testing chunk context."));
+ TestChunkContext();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-UT-4011 Drawing Text within context: Testing line context within bytecode."));
+ TestBytecodeLineContext();
+
+ test.Next(_L(" @SYMTestCaseID:SYSLIB-FORM-UT-4012 Drawing Text within context: Testing chunk context within bytecode."));
+ TestBytecodeChunkContext();
+
+ test.End();
+
+// __UHEAP_MARKEND;
+ }
+
+
+void RunTestsL()
+ {
+ CTagmaImpTest* t = new(ELeave) CTagmaImpTest();
+ CleanupStack::PushL(t);
+ t->ConstructL();
+ t->TestL();
+ CleanupStack::PopAndDestroy(t);
+ }
+
+TInt E32Main()
+ {
+ CTrapCleanup* theCleanup =CTrapCleanup::New();
+ test.Title();
+ TRAPD(err, RunTestsL());
+ test.Close();
+ delete theCleanup;
+ return err;
+ }