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