diff -r 000000000000 -r 1fb32624e06b textrendering/textformatting/test/src/TTagmaImp.cpp --- /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 +#include +#include +#include +#include +#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(aStartValue)); + test(num == aStartValue + 1); + test(rect == testRect); + } + return reader.CodePos(); + } + +void CTagmaImpTest::AddSome1L(CTmCode& aCode, TInt aStartValue) + { + aCode.AppendByteL(static_cast(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(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(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(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; + }