textrendering/texthandling/ttext/T_CONVS.CPP
changeset 0 1fb32624e06b
child 51 a7c938434754
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/ttext/T_CONVS.CPP	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,828 @@
+/*
+* Copyright (c) 1997-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: 
+*
+*/
+
+
+#include <txtetext.h>
+#include <txtglobl.h>
+#include <txtfmlyr.h>
+#include <s32mem.h>
+#include <s32file.h>
+#include <e32test.h>
+#include <fldbase.h>
+#include <fldbltin.h>
+#include <flddef.h>
+
+const TInt KTestCleanupStack=0x20;
+const TInt KTestExpandSize=0x20;
+
+LOCAL_D CTrapCleanup* TheTrapCleanup;
+LOCAL_D RTest test(_L("T_CONVS - EditableText Persistence"));
+LOCAL_D	TPtrC bigBuf(_L("This is a very big buffer indeed, containing text and special characters,\
+ big enough to fill a segment of an editable text component that employs segmented storage"));
+
+////////////////////////////////////////////////////////////////////////////////////////////
+class TTestFieldFactory : public MTextFieldFactory
+	{
+public:
+	// from MTextFieldFactory
+	virtual CTextField* NewFieldL(TUid aFieldType); 
+	// Creates a field of the type specified
+	// Returns NULL if it does not recognise/support the field type
+	};
+
+CTextField* TTestFieldFactory::NewFieldL(TUid aFieldType)
+// Creates a field (in aHeader) of the type specified in aHeader
+// 
+	{
+	CTextField* field=NULL;
+	if (aFieldType==KDateTimeFieldUid)
+		field = (CTextField*)new(ELeave) CDateTimeField();
+	return field;
+	}
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+void testCopy(T &aCopy,const T &anOriginal)
+//
+// Copy anOriginal to aCopy using memory-based streams.
+//
+	{
+	CBufSeg *buf=CBufSeg::NewL(KTestExpandSize);
+	if (buf==NULL)
+		test.Panic(_L("Allocating buffer"));
+	
+//	Write anOriginal out to the buffer.
+	RBufWriteStream out(*buf);
+	TRAPD(r,out<<anOriginal);
+	test(r==KErrNone);
+	TRAP(r,out.CommitL());
+	if (r!=KErrNone)
+			test.Panic(_L("Committing write stream"));
+
+//	Read anOriginal in from the buffer.
+	RBufReadStream in(*buf);
+	TRAP(r,in>>aCopy);
+	test(r==KErrNone);
+
+//	See if it's consumed the lot.
+	TRAP(r,in.ReadUint8L());
+	test(r==KErrEof);
+//
+	delete buf;
+	}
+
+_LIT(KOutputFile, "c:\\etext\\t_convs.tst");
+template <class T>
+void testStoreRestoreL(T& aCopy,const T& aOriginal)
+// Test document persistance.
+//
+    {
+	// set up the store
+	RFs	theFs;
+	theFs.Connect();
+	//
+	theFs.Delete(KOutputFile);
+	theFs.MkDirAll(KOutputFile);
+	CFileStore* theStore=CDirectFileStore::CreateL(theFs,KOutputFile,EFileRead|EFileWrite);
+	CleanupStack::PushL(theStore);
+	theStore->SetTypeL(KDirectFileStoreLayoutUid);
+	//
+	// store the original
+	TStreamId id(0);
+	TRAPD(ret,id=aOriginal.StoreL(*theStore));
+		test(ret==KErrNone);
+	//
+	// restore into the copy
+	TRAP(ret,aCopy.RestoreL(*theStore,id));
+		test(ret==KErrNone);
+	//
+	// tidy up
+	CleanupStack::PopAndDestroy();  // theStore
+	theFs.Close();
+    }
+
+
+template <class T>
+void testCopyChain(T &aCopy,const T &anOriginal,TInt aExcludeCount,const CFormatLayer* aBase)
+//
+// Copy anOriginal to aCopy using memory-based streams.
+//
+	{
+	CBufSeg *buf=CBufSeg::NewL(KTestExpandSize);
+	if (buf==NULL)
+		test.Panic(_L("Allocating buffer"));
+	
+//	Write anOriginal out to the buffer.
+	RBufWriteStream out(*buf);
+	TRAPD(r,anOriginal.ExternalizeChainL(out,aExcludeCount));
+	test(r==KErrNone);
+	TRAP(r,out.CommitL());
+	if (r!=KErrNone)
+			test.Panic(_L("Committing write stream"));
+
+//	Read anOriginal in from the buffer.
+	RBufReadStream in(*buf);
+	TRAP(r,aCopy.InternalizeChainL(in,aBase));
+	test(r==KErrNone);
+
+//	See if it's consumed the lot.
+	TRAP(r,in.ReadUint8L());
+	test(r!=KErrNone);
+//
+	delete buf;
+	}
+
+
+LOCAL_C TInt IsEqual(const CPlainText* aCopy,const CPlainText* aOriginal)
+//
+// Returns true if aCopy contents matches aOriginal contents.
+// Takes account of multiple segments of a segmented text component.
+//
+	{
+	TInt lengthOfOriginal=aOriginal->DocumentLength();
+	TInt lengthOfCopy=aCopy->DocumentLength();
+	test(lengthOfOriginal==lengthOfCopy);
+//
+	TPtrC copy,orig;
+//
+	TInt lengthRead=0;
+	while(lengthRead<=lengthOfOriginal)
+		{
+		copy.Set((aCopy->Read(lengthRead)));
+		orig.Set((aOriginal->Read(lengthRead)));
+		for (TInt offset=0; offset<orig.Length(); offset++)
+			test(copy[offset]==orig[offset]);
+		lengthRead+=orig.Length();
+		}
+	test(lengthRead==lengthOfOriginal+1);
+	test(aCopy->FieldCount()==aOriginal->FieldCount());
+	return 1;
+	}
+
+
+void testPlainTextL(CEditableText::TDocumentStorage aStorage)
+//
+// Test streaming CPlainText.
+//
+	{// Create the plain text components.
+	test.Start(_L("Streaming CPlainText"));
+	CPlainText* copy=CPlainText::NewL(aStorage);
+	CPlainText* testDoc=CPlainText::NewL(aStorage);
+	//
+	// Set the original - empty
+	test.Start(_L("empty."));
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+	//	
+	test.Next(_L("paragraph delimiter"));
+	TRAPD(r,testDoc->InsertL(0,CEditableText::EParagraphDelimiter));
+	test(r==KErrNone);
+	testStoreRestoreL(*copy,*testDoc);	
+	test(IsEqual(copy,testDoc));
+	//
+	// Next test with tons of text guaranteed to force segment break when using segmented storage.	
+	test.Next(_L("big text component"));
+	testDoc->InsertL(0,bigBuf);
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+	//
+	// Now test with field components.
+	test.Next(_L("big text doc with field components."));
+	TTestFieldFactory factory;
+	testDoc->SetFieldFactory(&factory);
+	copy->SetFieldFactory(&factory);
+	CTextField* field=NULL;
+	TRAPD(ret,
+	field=factory.NewFieldL(KDateTimeFieldUid));
+	test(ret==KErrNone);
+	TRAP(ret,
+	testDoc->InsertFieldL(0,field,KDateTimeFieldUid));
+	test(ret==KErrNone);
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+	//
+	//
+	test.End();
+	delete copy;
+	delete testDoc;
+	}
+
+
+void testGlobalTextL(CEditableText::TDocumentStorage aStorage)
+//
+// Test streaming CGlobalText.
+//
+	{// Create the plain text components.
+	test.Next(_L("Streaming CGlobalText"));
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL();
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL();
+	// Set something interesting in the layers:
+	CParaFormat* paraFormat1=CParaFormat::NewL(); TParaFormatMask paraMask1;
+	TCharFormat charFormat1; TCharFormatMask charMask1;
+	paraFormat1->iHorizontalAlignment=CParaFormat::ECenterAlign; paraMask1.SetAttrib(EAttAlignment);
+	paraFormat1->iLeftMarginInTwips=4000; paraMask1.SetAttrib(EAttLeftMargin);
+	paraLayer->SetL(paraFormat1,paraMask1);
+	charFormat1.iFontSpec.iFontStyle.SetPosture(EPostureItalic); charMask1.SetAttrib(EAttFontPosture);
+	charFormat1.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold); charMask1.SetAttrib(EAttFontStrokeWeight);
+	charLayer->SetL(charFormat1,charMask1);
+	//	
+	CGlobalText* copy=CGlobalText::NewL(paraLayer,charLayer,aStorage);
+	CGlobalText* testDoc=CGlobalText::NewL(paraLayer,charLayer,aStorage);
+
+//	Set the original - empty
+	test.Start(_L("empty."));
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+//	
+	test.Next(_L("paragraph delimiter"));
+	TRAPD(r,testDoc->InsertL(0,CEditableText::EParagraphDelimiter));
+	test(r==KErrNone);
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+
+//	Next test with tons of text guaranteed to force segment break when using segmented storage.	
+	test.Next(_L("big text component"));
+	testDoc->InsertL(0,bigBuf);
+	testStoreRestoreL(*copy,*testDoc);
+	test(IsEqual(copy,testDoc));
+		
+	test.End();
+	test.End();
+	delete copy;
+	delete testDoc;
+	delete paraLayer;
+	delete charLayer;
+	delete paraFormat1;
+	}
+
+
+LOCAL_C TInt LayerIsEqual(const CParaFormatLayer* aRestored,const CParaFormatLayer* aOriginal)
+//
+// Returns true if aRestored contents matches aOriginal contents.
+//
+	{
+	CParaFormat* restored=NULL;  TParaFormatMask rm;
+	CParaFormat* original=NULL;  TParaFormatMask om;
+	TRAPD(r,restored=CParaFormat::NewL());     test(r==KErrNone);
+	TRAP(r,original=CParaFormat::NewL());     test(r==KErrNone);
+
+	aOriginal->SenseL(original,om);
+	aRestored->SenseL(restored,rm);
+
+	test(original->IsEqual(*restored));
+
+	delete restored;
+	delete original;
+	return 1;
+	}
+
+
+LOCAL_C TInt LayerIsEqual(const CCharFormatLayer* aRestored,const CCharFormatLayer* aOriginal)
+//
+// Returns true if aRestored contents matches aOriginal contents.
+//
+	{
+	TCharFormat restored;  TCharFormatMask rm;
+	TCharFormat original;  TCharFormatMask om;
+
+	aOriginal->Sense(original,om);
+	aRestored->Sense(restored,rm);
+
+	test(original.IsEqual(restored));
+	
+	return 1;
+	}
+
+
+void testFmtLayerStoreL()
+//
+// Test the format layer StoreL().
+//
+	{
+	test.Start(_L("CParaFormatLayer"));
+//	Create test layers.
+	CParaFormatLayer* pfl1=NULL;
+	CParaFormatLayer* restored=NULL;
+	CParaFormat* pf1=NULL;
+	TRAPD(r,restored=CParaFormatLayer::NewL());     test(r==KErrNone);
+	// Force *restored* to allocate storage for iteself by storing a null layer.
+	TParaFormatMask rm;     rm.ClearAll(); CParaFormat* rpf=NULL;
+	restored->SetL(rpf,rm);
+	TRAP(r,pfl1=CParaFormatLayer::NewL());     test(r==KErrNone);
+	TRAP(r,pf1=CParaFormat::NewL());     test(r==KErrNone);
+	TParaFormatMask pm1;
+	pm1.SetAll();  // Sets all but the compound attributes.
+//	TEST ONE DEFAULT CASES
+	test.Start(_L("Default paragraph format values."));
+	TRAP(r,pfl1->SetL(pf1,pm1));     test(r==KErrNone);
+	testCopy(*restored,*pfl1);
+	test(LayerIsEqual(restored,pfl1));
+	test(restored->SenseBase()==pfl1->SenseBase());  // Both should default to based on NULL
+//	TEST TWO 
+	test.Next(_L("Setting all attributes"));
+	pf1->iLeftMarginInTwips=5000; pm1.ClearAll(); pm1.SetAttrib(EAttLeftMargin);
+	pf1->iRightMarginInTwips=5001; pm1.SetAttrib(EAttRightMargin);
+	pf1->iIndentInTwips=5002;pm1.SetAttrib(EAttIndent);
+	pf1->iHorizontalAlignment=CParaFormat::ERightAlign; pm1.SetAttrib(EAttAlignment);
+	pf1->iVerticalAlignment=CParaFormat::ECenterAlign; pm1.SetAttrib(EAttVerticalAlignment);
+	pf1->iLineSpacingInTwips=5003; pm1.SetAttrib(EAttLineSpacing);
+	pf1->iLineSpacingControl=CParaFormat::ELineSpacingAtLeastInTwips; pm1.SetAttrib(EAttLineSpacingControl);
+	pf1->iSpaceBeforeInTwips=5004; pm1.SetAttrib(EAttSpaceBefore);
+	pf1->iSpaceAfterInTwips=5005; pm1.SetAttrib(EAttSpaceAfter);
+	pf1->iKeepTogether=ETrue; pm1.SetAttrib(EAttKeepTogether);
+	pf1->iKeepWithNext=ETrue; pm1.SetAttrib(EAttKeepWithNext);
+	pf1->iStartNewPage=ETrue; pm1.SetAttrib(EAttStartNewPage);
+	pf1->iWidowOrphan=ETrue; pm1.SetAttrib(EAttWidowOrphan);
+	pf1->iWrap=EFalse; pm1.SetAttrib(EAttWrap);
+	pf1->iBorderMarginInTwips=5006; pm1.SetAttrib(EAttBorderMargin);
+	pf1->iDefaultTabWidthInTwips=5007; pm1.SetAttrib(EAttDefaultTabWidth);
+	// TopBorder
+	TParaBorder top;
+	top.iLineStyle=TParaBorder::ESolid;
+	top.iThickness=4;
+	top.iAutoColor=ETrue;
+	pf1->SetParaBorderL(CParaFormat::EParaBorderTop,top);
+	pm1.SetAttrib(EAttTopBorder);
+	// BottomBorder
+	TParaBorder bottom;	
+	bottom.iLineStyle=TParaBorder::ESolid;
+	bottom.iThickness=4;
+	bottom.iAutoColor=ETrue;
+	pf1->SetParaBorderL(CParaFormat::EParaBorderBottom,bottom);
+	pm1.SetAttrib(EAttBottomBorder);
+	// LeftBorder
+	TParaBorder left;
+	left.iLineStyle=TParaBorder::ESolid;
+	left.iThickness=4;
+	left.iAutoColor=ETrue;
+	pf1->SetParaBorderL(CParaFormat::EParaBorderLeft,left);
+	pm1.SetAttrib(EAttLeftBorder);
+	// RightBorder
+	TParaBorder right;
+	right.iLineStyle=TParaBorder::ESolid;
+	right.iThickness=4;
+	top.iAutoColor=ETrue;
+	pf1->SetParaBorderL(CParaFormat::EParaBorderRight,right);
+	pm1.SetAttrib(EAttRightBorder);
+	// Bullet
+	pf1->iBullet=new(ELeave)TBullet;
+	TUint charCode=5008;
+	pf1->iBullet->iCharacterCode=(TUint8)charCode;
+	pf1->iBullet->iHeightInTwips=5009;
+	pf1->iBullet->iTypeface.iName=_L("Duncan");
+	pf1->iBullet->iTypeface.SetIsProportional(EFalse);
+	pf1->iBullet->iTypeface.SetIsSerif(EFalse);
+	pm1.SetAttrib(EAttBullet);
+	// 2 Tab Stops.
+	TTabStop tab1,tab2;
+	tab1.iTwipsPosition=5010; tab1.iType=TTabStop::ERightTab;
+	tab2.iTwipsPosition=5011; tab2.iType=TTabStop::ECenteredTab;
+	pf1->StoreTabL(tab1);
+	pf1->StoreTabL(tab2);
+	pm1.SetAttrib(EAttTabStop);
+//
+	TRAP(r,pfl1->SetL(pf1,pm1));
+	testCopy(*restored,*pfl1);
+	test(LayerIsEqual(restored,pfl1));
+	test(restored->SenseBase()==pfl1->SenseBase());  // Both should default to based on NULL
+	test.End();
+//
+	delete pf1;
+	delete pfl1;
+	delete restored;
+//
+//	Now the CCharFormatLayer Store/Restore
+//
+	test.Next(_L("CCharFormatLayer"));
+// 	
+	test.Start(_L("Setting all attributes"));
+//	Create test layers.
+	CCharFormatLayer* cfl1=NULL;
+	CCharFormatLayer* cRestored=NULL;
+	TCharFormat cf1; TCharFormatMask cm1;
+//
+	TRAP(r,cRestored=CCharFormatLayer::NewL());     test(r==KErrNone);
+	// Force *restored* to allocate storage for iteself by storing a null layer.
+	TCharFormatMask rcm;     rcm.ClearAll(); TCharFormat rcf;
+	cRestored->SetL(rcf,rcm);
+//
+	TRAP(r,cfl1=CCharFormatLayer::NewL());     test(r==KErrNone);
+//	
+	TRgb color(20,20,20);
+	cf1.iFontPresentation.iTextColor=color;	cm1.SetAttrib(EAttColor);
+	cf1.iFontSpec.iTypeface.iName=_L("DUNCANXZE");
+	cf1.iFontSpec.iTypeface.SetIsProportional(ETrue);	cm1.SetAttrib(EAttFontTypeface);
+	cf1.iFontSpec.iTypeface.SetIsSerif(EFalse);
+    cf1.iFontSpec.iFontStyle.SetBitmapType(EMonochromeGlyphBitmap);
+
+	cf1.iFontSpec.iHeight=6000;	cm1.SetAttrib(EAttFontHeight);
+	cf1.iFontSpec.iFontStyle.SetPosture(EPostureItalic);	cm1.SetAttrib(EAttFontPosture);
+	cf1.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);	cm1.SetAttrib(EAttFontStrokeWeight);
+	cf1.iFontSpec.iFontStyle.SetPrintPosition(EPrintPosSuperscript);	cm1.SetAttrib(EAttFontPrintPos);
+	cf1.iFontPresentation.iUnderline=EUnderlineOn;	cm1.SetAttrib(EAttFontUnderline);
+	cf1.iFontPresentation.iStrikethrough=EStrikethroughOn;	cm1.SetAttrib(EAttFontStrikethrough);
+	cf1.iFontPresentation.iHighlightColor=color;  cm1.SetAttrib(EAttFontHighlightColor);
+	cf1.iFontPresentation.iHighlightStyle=TFontPresentation::EFontHighlightNormal;  cm1.SetAttrib(EAttFontHighlightStyle);
+//
+	TRAP(r,cfl1->SetL(cf1,cm1));
+	test(r==KErrNone);
+	testCopy(*cRestored,*cfl1);
+	test(LayerIsEqual(cRestored,cfl1));
+
+	TCharFormat rfmt;  
+    TCharFormatMask rmask;
+	cRestored->Sense(rfmt, rmask);
+    test(rfmt.iFontSpec.iFontStyle.BitmapType() == EMonochromeGlyphBitmap);
+
+//
+	delete cfl1;
+	delete cRestored;
+	test.End();
+	}
+
+
+LOCAL_C TInt ChainIsEqual(const CParaFormatLayer* aCopy,const CParaFormatLayer* aOriginal)
+//
+// Tests that the restored chain is identical to the original chain.
+//
+	{
+	TInt origChainCount=aOriginal->ChainCount();
+	/*TInt copyChainCount=*/aCopy->ChainCount();
+//	Check the chain heads are equal.
+	test(LayerIsEqual(aCopy,aOriginal));
+	TInt descendantCount=origChainCount-1;
+	
+	const CFormatLayer* nextCopyLayer=aCopy->SenseBase();
+	const CFormatLayer* nextOrigLayer=aOriginal->SenseBase();
+	for (TInt loop=0;loop<descendantCount;loop++)
+		{
+		test(LayerIsEqual((CParaFormatLayer*)nextCopyLayer,(CParaFormatLayer*)nextOrigLayer));
+
+		nextCopyLayer=nextCopyLayer->SenseBase();
+		nextOrigLayer=nextOrigLayer->SenseBase();
+		}
+	return 1;
+	}
+
+
+LOCAL_C TInt ChainIsEqual(const CCharFormatLayer* aCopy,const CCharFormatLayer* aOriginal)
+//
+// Tests that the restored chain is identical to the original chain.
+//
+	{
+	TInt origChainCount=aOriginal->ChainCount();
+	/*TInt copyChainCount=*/aCopy->ChainCount();
+//	Check the chain heads are equal.
+	test(LayerIsEqual(aCopy,aOriginal));
+	TInt descendantCount=origChainCount-1;
+	
+	const CFormatLayer* nextCopyLayer=aCopy->SenseBase();
+	const CFormatLayer* nextOrigLayer=aOriginal->SenseBase();
+	for (TInt loop=0;loop<descendantCount;loop++)
+		{
+		test(LayerIsEqual((CCharFormatLayer*)nextCopyLayer,(CCharFormatLayer*)nextOrigLayer));
+
+		nextCopyLayer=nextCopyLayer->SenseBase();
+		nextOrigLayer=nextOrigLayer->SenseBase();
+		}
+	return 1;
+	}
+
+
+void DoParaChainL()
+//
+// Tests the streaming of a chain of format layers
+//
+	{
+	test.Next(_L("Re/StoreChainL()"));
+	test.Start(_L("CParaFormatLayer"));
+//	Create the chain of para format layers.
+	CParaFormatLayer* l1=CParaFormatLayer::NewL();
+	CParaFormatLayer* l2=CParaFormatLayer::NewL();
+	CParaFormatLayer* l3=CParaFormatLayer::NewL();
+	CParaFormatLayer* l4=CParaFormatLayer::NewL();
+//	Chain together.
+	l1->SetBase(l2);
+	l2->SetBase(l3);
+	l3->SetBase(l4);
+//	Create head of restored format stream, and force it to get storage.	
+	CParaFormatLayer* restoredChainHead=CParaFormatLayer::NewL();
+	CParaFormat* restoredParaFormat=CParaFormat::NewL();
+	TParaFormatMask restoredParaMask;
+	restoredParaMask.ClearAll();
+	restoredChainHead->SetL(restoredParaFormat,restoredParaMask);
+//	General paraformat and its mask.
+	CParaFormat* paraFormat=CParaFormat::NewL();
+	TParaFormatMask paraMask;
+	paraMask.ClearAll();
+//	Set layer one stuff
+	TTabStop tab1,tab2;
+	tab1.iTwipsPosition=5000;	tab2.iTwipsPosition=5001;
+	tab1.iType=TTabStop::ERightTab;	tab2.iType=TTabStop::ECenteredTab;
+	paraFormat->StoreTabL(tab1);
+	paraFormat->StoreTabL(tab2);
+	paraMask.SetAttrib(EAttTabStop);
+	l1->SetL(paraFormat,paraMask);
+	paraMask.ClearAll();
+//	Set layer two stuff
+	TParaBorder top1;
+	top1.iLineStyle=TParaBorder::ESolid;
+	top1.iThickness=3;
+	top1.iAutoColor=ETrue;
+	paraFormat->SetParaBorderL(CParaFormat::EParaBorderTop,top1);
+	paraMask.SetAttrib(EAttTopBorder);
+	l2->SetL(paraFormat,paraMask);
+	paraMask.ClearAll();
+//	Set the layer 3 stuff.
+	paraFormat->iBullet=new(ELeave)TBullet;
+	paraFormat->iBullet->iTypeface.iName=_L("SKELTON");
+	paraFormat->iBullet->iTypeface.SetIsProportional(EFalse);
+	paraFormat->iBullet->iTypeface.SetIsSerif(EFalse);
+	paraFormat->iBullet->iHeightInTwips=3003;
+	paraFormat->iBullet->iCharacterCode=32;
+	paraMask.SetAttrib(EAttBullet);
+	l3->SetL(paraFormat,paraMask);
+	paraMask.ClearAll();
+// Set the layer 4 stuff.
+	paraFormat->iHorizontalAlignment=CParaFormat::EJustifiedAlign;	paraMask.SetAttrib(EAttAlignment);
+	paraFormat->iSpaceAfterInTwips=6000;			paraMask.SetAttrib(EAttSpaceAfter);
+	paraFormat->iKeepTogether=ETrue;			paraMask.SetAttrib(EAttKeepTogether);
+	l4->SetL(paraFormat,paraMask);
+// NOW DO IT
+	testCopyChain(*restoredChainHead,*l1,0,(const CFormatLayer*)NULL);
+	TInt restoredChainCount=restoredChainHead->ChainCount();
+	test(ChainIsEqual(restoredChainHead,l1));
+//	DESTROY STUFF
+	CParaFormatLayer* current=restoredChainHead;
+	CParaFormatLayer* next=(CParaFormatLayer*)restoredChainHead->SenseBase();
+	delete current;
+	for (TInt loop=0;loop<restoredChainCount-1;loop++)	
+		{
+		current=next;
+		next=(CParaFormatLayer*)current->SenseBase();
+		delete current;
+		}
+	delete l1;
+	delete l2;
+	delete l3;
+	delete l4;
+	delete paraFormat;
+	delete restoredParaFormat;
+	}
+
+
+void DoCharChainL()
+//
+//
+//
+	{
+	test.Next(_L("CCharFormatLayer"));
+//	Create the chain of character format layers.
+	CCharFormatLayer* cl1=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl2=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl3=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl4=CCharFormatLayer::NewL();
+//	Chain together.
+	cl1->SetBase(cl2);
+	cl2->SetBase(cl3);
+	cl3->SetBase(cl4);
+//	Create head of restored format stream, and force it to get storage.	
+	CCharFormatLayer* rChar=CCharFormatLayer::NewL();
+	TCharFormat restoredCharFormat;
+	TCharFormatMask restoredCharMask;
+	restoredCharMask.ClearAll();
+	rChar->SetL(restoredCharFormat,restoredCharMask);
+//	General charformat and its mask.
+	TCharFormat charFormat;	TCharFormatMask charMask;
+	charMask.ClearAll();
+//	Set layer one stuff
+	charFormat.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);	charMask.SetAttrib(EAttFontStrokeWeight);
+	charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic);	charMask.SetAttrib(EAttFontPosture);
+	charFormat.iFontPresentation.iUnderline=EUnderlineOn;	charMask.SetAttrib(EAttFontUnderline);
+	cl1->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set layer two stuff
+	charFormat.iFontSpec.iFontStyle.SetPrintPosition(EPrintPosSubscript);	charMask.SetAttrib(EAttFontPrintPos);
+	cl2->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set the layer 3 stuff.
+	charFormat.iFontPresentation.iStrikethrough=EStrikethroughOn;	charMask.SetAttrib(EAttFontStrikethrough);
+	cl3->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set the layer 4 stuff.
+	charFormat.iFontSpec.iTypeface.iName=_L("Arial");
+	charFormat.iFontSpec.iHeight=200;
+	charMask.SetAttrib(EAttFontHeight);
+	charMask.SetAttrib(EAttFontTypeface);
+	cl4->SetL(charFormat,charMask);
+//	NOW DO IT
+	test.Start(_L("Chain 4 layers deep, terminating on a based on NULL"));
+	testCopyChain(*rChar,*cl1,0,(const CFormatLayer*)NULL);
+	TInt restoredChainCount=rChar->ChainCount();
+	test(ChainIsEqual(rChar,cl1));
+//	DESTROY STUFF
+	CCharFormatLayer* chCurrent=rChar;
+	CCharFormatLayer* chNext=(CCharFormatLayer*)rChar->SenseBase();
+	delete chCurrent;
+	for (TInt loop=0;loop<restoredChainCount-1;loop++)	
+		{
+		chCurrent=chNext;
+		chNext=(CCharFormatLayer*)chCurrent->SenseBase();
+		delete chCurrent;
+		}
+	delete cl1;
+	delete cl2;
+	delete cl3;
+	delete cl4;
+	}
+		
+
+void DoCharChainVariant1()
+//
+// Case 2: Where the chain does not terminate at a NULL link.
+//
+	{
+//	Create the chain of character format layers.
+	CCharFormatLayer* cl1=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl2=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl3=CCharFormatLayer::NewL();
+	CCharFormatLayer* cl4=CCharFormatLayer::NewL();
+//	Chain together.
+	cl1->SetBase(cl2);
+	cl2->SetBase(cl3);
+	cl3->SetBase(cl4);
+//	Create head of restored format stream, and force it to get storage.	
+	CCharFormatLayer* rChar=CCharFormatLayer::NewL();
+	TCharFormat restoredCharFormat;
+	TCharFormatMask restoredCharMask;
+	restoredCharMask.ClearAll();
+	rChar->SetL(restoredCharFormat,restoredCharMask);
+//	General charformat and its mask.
+	TCharFormat charFormat;	TCharFormatMask charMask;
+	charMask.ClearAll();
+//	Set layer one stuff
+	charFormat.iFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);	charMask.SetAttrib(EAttFontStrokeWeight);
+	charFormat.iFontSpec.iFontStyle.SetPosture(EPostureItalic);	charMask.SetAttrib(EAttFontPosture);
+	charFormat.iFontPresentation.iUnderline=EUnderlineOn;	charMask.SetAttrib(EAttFontUnderline);
+	cl1->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set layer two stuff
+	charFormat.iFontSpec.iFontStyle.SetPrintPosition(EPrintPosSubscript);	charMask.SetAttrib(EAttFontPrintPos);
+	cl2->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set the layer 3 stuff.
+	charFormat.iFontPresentation.iStrikethrough=EStrikethroughOn;	charMask.SetAttrib(EAttFontStrikethrough);
+	cl3->SetL(charFormat,charMask);
+	charMask.ClearAll();
+//	Set the layer 4 stuff.
+	charFormat.iFontSpec.iTypeface.iName=_L("Arial");
+	charFormat.iFontSpec.iHeight=200;
+	charMask.SetAttrib(EAttFontHeight);
+	charMask.SetAttrib(EAttFontTypeface);
+	cl4->SetL(charFormat,charMask);
+//	NOW DO IT
+	test.Next(_L("Chain 3 layers deep, terminating on a non-NULL based-on"));
+	testCopyChain(*rChar,*cl1,1,(const CFormatLayer*)cl4);
+	TInt restoredChainCount=rChar->ChainCount();
+	test(ChainIsEqual(rChar,cl1));
+//	DESTROY STUFF
+	CCharFormatLayer* chCurrent=rChar;
+	CCharFormatLayer* chNext=(CCharFormatLayer*)rChar->SenseBase();
+	delete chCurrent;
+	for (TInt loop=0;loop<restoredChainCount-2;loop++)	
+		{
+		chCurrent=chNext;
+		chNext=(CCharFormatLayer*)chCurrent->SenseBase();
+		delete chCurrent;
+		}
+	delete cl1;
+	delete cl2;
+	delete cl3;
+	delete cl4;
+	
+	test.End();
+	test.End();
+	test.End();
+	}
+
+
+void testFmtLayerStoreChainL()
+//
+// Controls the testing of the chainig stuff.
+//
+	{
+	DoParaChainL();
+	DoCharChainL();
+	DoCharChainVariant1();
+//	DoCharChainVariant2();  TO BE IMPLEMENTED
+//	doCharChainVariant3();	TO BE IMPLEMENTED
+	}
+
+
+void testFmtLayerL()
+//
+// Tests the streaming of format layers.
+//
+	{
+	testFmtLayerStoreL();
+	testFmtLayerStoreChainL();
+	}
+
+
+LOCAL_C void setupCleanup()
+//
+// Initialise the cleanup stack.
+//
+    {
+
+	TheTrapCleanup=CTrapCleanup::New();
+	TRAPD(r,\
+		{\
+		for (TInt i=KTestCleanupStack;i>0;i--)\
+			CleanupStack::PushL((TAny*)1);\
+		test(r==KErrNone);\
+		CleanupStack::Pop(KTestCleanupStack);\
+		});
+	}
+
+
+LOCAL_C void DeleteDataFile(const TDesC& aFullName)
+	{
+	RFs fsSession;
+	TInt err = fsSession.Connect();
+	if(err == KErrNone)
+		{
+		TEntry entry;
+		if(fsSession.Entry(aFullName, entry) == KErrNone)
+			{
+			RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName);
+			err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
+			if(err != KErrNone) 
+				{
+				RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
+				}
+			err = fsSession.Delete(aFullName);
+			if(err != KErrNone) 
+				{
+				RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
+				}
+			}
+		fsSession.Close();
+		}
+	else
+		{
+		RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
+		}
+	}
+
+GLDEF_C TInt E32Main()
+//
+// Test streaming conversions.
+//
+    {
+	setupCleanup();
+	test.Title();
+	__UHEAP_MARK;
+	
+	test.Start(_L(" @SYMTestCaseID:SYSLIB-ETEXT-LEGACY-T_CONVS-0001 EText components using Flat Storage ")); 
+	TRAPD(r,testPlainTextL(CEditableText::EFlatStorage));
+	test(r==KErrNone);
+	TRAP(r,testGlobalTextL(CEditableText::EFlatStorage));
+	test(r==KErrNone);
+
+//
+	test.Next(_L("EText components using Segmented storage"));
+	TRAP(r,testPlainTextL(CEditableText::ESegmentedStorage));
+	test(r==KErrNone);
+	TRAP(r,testGlobalTextL(CEditableText::ESegmentedStorage));
+	test(r==KErrNone);
+
+	test.Next(_L("Format Layer components"));
+	TRAP(r,testFmtLayerL());
+	test(r==KErrNone);
+	
+//	test.End();
+	__UHEAP_MARKEND;
+	
+	::DeleteDataFile(KOutputFile);	//deletion of data files must be before call to End() - DEF047652
+	test.End();
+	test.Close();
+	delete TheTrapCleanup;
+
+	return 0;
+    }
+