/*
* 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;
}