textrendering/texthandling/stext/TXTFMSTM.CPP
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/stext/TXTFMSTM.CPP	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,1838 @@
+/*
+* 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 <e32std.h>
+
+#include <s32strm.h>
+#include <s32mem.h>
+#include "TXTFRMAT.H"
+#include <txtfmstm.h>
+
+#include "TXTSTD.H"
+
+const TInt KMaxFormatStreamLength=0x400;  // 1024 bytes
+
+// Standard attributes
+const TUint KFontProportional=0x01;
+const TUint KFontSerif=0x02;
+const TUint KFontSymbol=0x04;
+
+const TUint KTypefaceFlags=sizeof(TUint8);
+const TInt KTypeSize=sizeof(TUint8);
+const TInt KColor=sizeof(TUint8)+sizeof(TUint8)+sizeof(TUint8);
+const TInt KFontHeight=sizeof(TInt32);
+const TInt KParaBorderThickness=sizeof(TInt32);
+const TInt KTabPosition=sizeof(TUint32);
+const TInt KTabType=sizeof(TUint8);
+
+// Paragraph format attributes
+const TInt KVariableLengthAttribute=0;
+const TInt KParaLanguage=sizeof(TUint8);
+const TInt KParaFillColor=KColor;
+const TInt KParaLeftMargin=sizeof(TInt32);
+const TInt KParaRightMargin=sizeof(TInt32);
+const TInt KParaIndent=sizeof(TInt32);
+const TInt KParaAlignment=sizeof(TUint8);
+const TInt KParaVerticalAlignment=sizeof(TUint8);
+const TInt KParaLineSpacing=sizeof(TInt32);
+const TInt KParaLineSpacingControl=sizeof(TUint8);
+const TInt KParaSpaceBefore=sizeof(TInt32);
+const TInt KParaSpaceAfter=sizeof(TInt32);
+const TInt KParaKeepTogether=sizeof(TUint8);
+const TInt KParaKeepWithNext=sizeof(TUint8);
+const TInt KParaStartNewPage=sizeof(TUint8);
+const TInt KParaWidowOrphan=sizeof(TUint8);
+const TInt KParaWrap=sizeof(TUint8);
+const TInt KParaBorderMargin=sizeof(TInt32);
+const TInt KParaTopBorder=sizeof(TUint8)+KParaBorderThickness+KColor+sizeof(TUint8);//linestyle/thickness/color/autocolor
+const TInt KParaBottomBorder=KParaTopBorder;
+const TInt KParaLeftBorder=KParaTopBorder;
+const TInt KParaRightBorder=KParaTopBorder;
+const TInt KParaBullet=KVariableLengthAttribute;
+const TInt KParaDefaultTabWidth=sizeof(TUint32);
+const TInt KParaTabStop=KTabPosition+KTabType;
+const TInt KParaFillSystemColor=sizeof(TUint8);
+const TInt KParaBulletSystemColor=sizeof(TUint8);
+const TInt KParaTopBorderSystemColor=sizeof(TUint8);
+const TInt KParaBottomBorderSystemColor=sizeof(TUint8);
+const TInt KParaLeftBorderSystemColor=sizeof(TUint8);
+const TInt KParaRightBorderSystemColor=sizeof(TUint8);
+const TInt KParaLanguageX=sizeof(TInt32);
+const TInt KParaBulletX=sizeof(TInt32) + 2;
+const TInt KBitmapType=sizeof(TUint8);
+
+// Character format attributes
+const TInt KCharLanguage=sizeof(TUint8);
+const TInt KCharColor=KColor;
+const TInt KCharHighlightColor=KColor;
+const TInt KCharHighlightStyle=sizeof(TUint8);
+const TInt KCharStrikethrough=sizeof(TUint8);
+const TInt KCharUnderline=sizeof(TUint8);
+const TInt KCharStrokeWeight=sizeof(TUint8);
+const TInt KCharPosture=sizeof(TUint8);
+const TInt KCharPrintPos=sizeof(TUint8);
+const TInt KCharFontHeight=KFontHeight;
+const TInt KCharTypeface=KVariableLengthAttribute;
+const TInt KCharHiddenText=sizeof(TUint8);
+const TInt KCharPictureAlignment=sizeof(TUint8);
+const TInt KCharTextSystemColor=sizeof(TUint8);
+const TInt KCharFontHighlightSystemColor=sizeof(TUint8);
+const TInt KCharLanguageX=sizeof(TInt32);
+const TInt KCharParserTag=sizeof(TUint32);
+
+/*
+Lookup table indexed by TTextFormatAttribute enumerated constants.
+Specifies the length in bytes of the format attributes.
+*/
+static const TInt8 TheAttributeLength[EAttributeCount] =
+	{
+	// Paragraph attribute value lengths.	
+	KParaLanguage,
+	KParaFillColor,
+	KParaLeftMargin,
+	KParaRightMargin,
+	KParaIndent,
+	KParaAlignment,
+	KParaVerticalAlignment,
+	KParaLineSpacing,
+	KParaLineSpacingControl,
+	KParaSpaceBefore,
+	KParaSpaceAfter,
+	KParaKeepTogether,
+	KParaKeepWithNext,
+	KParaStartNewPage,
+	KParaWidowOrphan,
+	KParaWrap,
+	KParaBorderMargin,
+	KParaTopBorder,
+	KParaBottomBorder,
+	KParaLeftBorder,
+	KParaRightBorder,
+	KParaBullet,
+	KParaDefaultTabWidth,
+	KParaTabStop,
+
+	// Character attribute value lengths.
+	KCharLanguage,
+	KCharColor,
+	KCharHighlightColor,
+	KCharHighlightStyle,
+	KCharFontHeight,
+	KCharStrikethrough,
+	KCharUnderline,
+	KCharStrokeWeight,
+	KCharPosture,
+	KCharPrintPos,
+	KCharTypeface,
+	KCharHiddenText,
+	KCharPictureAlignment,
+
+	// Lengths of extended attributes.
+	KParaFillSystemColor,
+	KParaBulletSystemColor,
+	KParaTopBorderSystemColor,
+	KParaBottomBorderSystemColor,
+	KParaLeftBorderSystemColor,
+	KParaRightBorderSystemColor,
+	KCharTextSystemColor,
+	KCharFontHighlightSystemColor,
+	KParaLanguageX,
+	KCharLanguageX,
+	KParaBulletX,
+    KBitmapType,
+
+	// Lengths of internal attributes
+	KCharParserTag
+	};
+
+
+DLLEXPORT_C void RFormatStream::__DbgTestInvariant()const
+// Provides class invariants.
+// This class invariant checks the integrity of a completed format stream.
+// As such, this invariant is only called by those methods that act upon a completed
+// format stream; that is, not the set methods, since the format stream will not be complete until
+// this call has completed.
+//
+	{
+#ifdef _DEBUG
+		__ASSERT_DEBUG(DoInvariantCheck(),User::Invariant());
+#endif
+	}
+
+void RFormatStream::TestInvariantL()const
+// Provides class invariants.
+// This class invariant checks the integrity of a completed format stream.
+// As such, this invariant is only called by those methods that act upon a completed
+// format stream; that is, not the set methods, since the format stream will not be complete until
+// this call has completed.
+//
+	{
+	if (!DoInvariantCheck())
+		User::Leave(KErrCorrupt);
+	}
+
+TBool RFormatStream::DoInvariantCheck() const
+// Provides class invariants.
+// This class invariant checks the integrity of a completed format stream.
+// As such, this invariant is only called by those methods that act upon a completed
+// format stream; that is, not the set methods, since the format stream will not be complete until
+// this call has completed.
+//
+	{
+	if (!iBase)
+		return ETrue;
+	if (iEnd>iBase)
+		{// Assert: stream is self consistent
+		// Walks through the stream (aBuffer), checking that it is in a consistent state.
+		// (1) All entries in the buffer conform to a TYPE-VALUE structure, checking that
+		// types do not occur in contiguous bytes.  ie there is a value.
+		// (2) Checks that all encountered types are valid types.
+		// (3) Checks that the buffer has not changed size as a result of this check
+		// (4) Checks that all attributes in the stream occur only once.  Done by taking a register
+		// as each attribute is read from the stream.  (The exception to this rule are Tab identifiers
+		// which, if present, will typically occur several times in the stream).
+		//
+		enum {ENotPresent,EPresent};
+		TInt8 attributeRegister[EAttributeCount];
+		for (TInt offset=0;offset<EAttributeCount;offset++)
+			{// Mark attributeRegister as all absent
+			attributeRegister[offset]=(TInt8)ENotPresent;  // clear all items in the register
+			}
+		TUint8* tempStreamLoc=iBase;
+		TUint8* streamLoc=iBase;
+		TUint8* endOfStreamLoc=iEnd;
+		TUint8 data=0;
+		while (streamLoc<endOfStreamLoc)
+			{
+			data=*streamLoc;
+			streamLoc++;
+// Assert: data read is a valid format attribute type.
+			if (!(data<((TUint8)EAttributeCount))) return EFalse;
+			if (data!=EAttTabStop)
+				{// Tab Identifiers can occur multiple times in a stream!!
+// Assert: attribute type does not already exist in attributeRegister.
+				if (!(attributeRegister[data]!=(TInt8)EPresent)) return EFalse;
+				}
+			attributeRegister[data]=(TInt8)EPresent;
+			tempStreamLoc=streamLoc+Length(streamLoc,(TTextFormatAttribute)data);
+			if (!(tempStreamLoc>=streamLoc)) return EFalse;
+			streamLoc=tempStreamLoc;
+			}
+// Assert: everything is still the same size.
+		if (!(streamLoc==endOfStreamLoc)) return EFalse;
+		}
+	return ETrue;
+	}
+
+static inline TUint32 Read32(const TUint8* aPtr)
+	{
+	TUint32 val = aPtr[0];
+	val |= aPtr[1] << 8;
+	val |= aPtr[2] << 16;
+	val |= aPtr[3] << 24;
+	return val;
+	}
+
+
+static inline void Write32(TUint8*& aPtr,TUint32 aVal)
+	{
+	*aPtr++ = TUint8(aVal);
+	*aPtr++ = TUint8(aVal >> 8);
+	*aPtr++ = TUint8(aVal >> 16);
+	*aPtr++ = TUint8(aVal >> 24);
+	}
+
+
+RFormatStream::RFormatStream():
+	iBase(NULL),
+	iEnd(NULL)
+	{
+	}
+
+		
+// Allocate the buffer
+void RFormatStream::AllocL(TInt aSize)
+	{
+    TUint8* pT = reinterpret_cast<TUint8*>(User::ReAllocL(iBase, aSize));
+    
+    iBase=pT;
+    iEnd=pT+aSize;
+	}
+
+
+void RFormatStream::Reset()
+// Free all storage
+//
+	{
+	if (iBase)
+		{
+		User::Free(iBase);
+		iBase = iEnd = NULL;
+		}
+	}
+
+
+void RFormatStream::CopyL(const RFormatStream& aSource)
+	{
+	TInt size = aSource.iEnd - aSource.iBase;
+	__ASSERT_DEBUG(size >= 0,Panic(EDebug));
+	if (size == 0)
+		Reset();
+	else
+		{
+		AllocL(size);
+		Mem::Copy(iBase,aSource.iBase,size);
+		}
+	}
+
+
+/*
+Write the bytecode to a stream. Don't write internal attributes; these are not part of the stored format,
+but are used for transitory marking of text by URL parsers, etc.
+*/
+void RFormatStream::ExternalizeL(RWriteStream& aStream) const
+	{
+	__TEST_INVARIANT;
+	
+	const TUint8* base=iBase;
+	if (base)
+		{
+		const TUint8* end = base;
+		while (end < iEnd && *end < EExternalizedAttributeCount)
+			{
+			int bytes = TheAttributeLength[*end++];
+			if (bytes == 0)
+				bytes = *end++;
+			end += bytes;
+			}
+		int length = end - base;
+		aStream.WriteInt32L(length);
+		aStream.WriteL(base,length);
+		}
+	else
+		aStream.WriteInt32L(0);
+	}
+
+
+void RFormatStream::InternalizeL(RReadStream& aStream)
+// Load the buffer from the specified stream
+//
+	{
+	TestInvariantL();
+
+	TInt length=aStream.ReadInt32L();
+	//
+	if (length<0 || length>KMaxFormatStreamLength)
+		User::Leave(KErrCorrupt);
+	//
+	if (length==0)
+		Reset();
+	else
+		{
+		AllocL(length);
+		aStream.ReadL(iBase,length);
+		}
+
+	TestInvariantL();
+	}
+
+
+// Return a pointer to the stored bytecode and put its length in bytes in aLength.
+const TUint8* RFormatStream::Ptr(TInt& aLength) const
+	{
+	__TEST_INVARIANT;
+	aLength=iEnd-iBase;
+	__ASSERT_DEBUG((iBase==NULL && aLength==0) || (iBase!=NULL && aLength>0),Panic(ECorruptFormatLayer));
+	return iBase;
+	}
+
+
+// Save the attributes of aCharFormat specified by the corresponding mask aMask.
+void RFormatStream::SetCharFormatL(const TCharFormatX& aCharFormatX,const TCharFormatXMask& aMask)
+	{
+	TInt size=DoCalcSizeCharFormat(aCharFormatX,aMask);
+	if (size==0)
+		Reset();
+	else
+		{
+		AllocL(size);  // delete the current contents, after allocing a temporary
+		DoStoreCharFormat(aCharFormatX,aMask);
+		}
+
+	__TEST_INVARIANT;
+	}
+
+
+void RFormatStream::SetParaFormatL(const CParaFormat& aDesiredFormat,const TParaFormatMask& aDesiredMask,
+											const CParaFormat& aCurrentFormat)
+// Sets the format layer with the specified paragraph format attributes.
+// If a leave occurs at any stage, then revert back to original state, and
+// propagate the leave.
+//
+	{
+	TInt size=DoCalcSizeParaFormat(aDesiredFormat,aDesiredMask,aCurrentFormat);
+	if (size==0)
+		Reset();
+	else
+		{
+		AllocL(size);  // delete the current contents, after allocing a temporary
+		DoSetParaFormat(aDesiredFormat,aDesiredMask,aCurrentFormat);
+		}
+
+	__TEST_INVARIANT;
+	}
+	
+// Write an auxiliary attribute for a system colour byte. Update aPtr.
+static void WriteSystemColor(TUint8*& aPtr,TTextFormatNonMaskableAttribute aAttrib,const TLogicalRgb& aColor)
+	{
+	TUint8 index = (TUint8)aColor.SystemColorIndex();
+	if (index)
+		{
+		*aPtr++ = TUint8(aAttrib);
+		*aPtr++ = index;
+		}
+	}
+
+
+// Read a system colour byte into a logical colour. Don't change aPtr.
+static void ReadSystemColor(const TUint8* aPtr,TLogicalRgb& aColor)
+	{
+	TUint index = *aPtr;
+	aColor.SetSystemColorIndex(index); 
+	}
+
+
+// Write paragraph attributes specified by aDesiredMask from aDesiredFormat to the stream.
+void RFormatStream::DoSetParaFormat(const CParaFormat& aDesiredFormat,
+									TParaFormatMask aMask,
+									const CParaFormat& aCurrentFormat)
+	{
+	TUint8* ptr=iBase;
+	if (aMask.AttribIsSet(EAttFillColor))
+		{
+		*ptr++=TUint8(EAttFillColor);
+		ptr=Store(ptr,aDesiredFormat.iFillColor);
+		}
+	if (aMask.AttribIsSet(EAttLeftMargin))
+		{
+		*ptr++=TUint8(EAttLeftMargin);
+		Write32(ptr,aDesiredFormat.iLeftMarginInTwips);
+		}
+	if (aMask.AttribIsSet(EAttRightMargin))
+		{
+		*ptr++=TUint8(EAttRightMargin);
+		Write32(ptr,aDesiredFormat.iRightMarginInTwips);
+		}
+	if (aMask.AttribIsSet(EAttIndent))
+		{
+		*ptr++=TUint8(EAttIndent);
+		Write32(ptr,aDesiredFormat.iIndentInTwips);
+		}
+	if (aMask.AttribIsSet(EAttAlignment))
+		{
+		*ptr++=TUint8(EAttAlignment);
+		*ptr++=TUint8(aDesiredFormat.iHorizontalAlignment);
+		}
+	if (aMask.AttribIsSet(EAttVerticalAlignment))
+		{
+		*ptr++=TUint8(EAttVerticalAlignment);
+		*ptr++=TUint8(aDesiredFormat.iVerticalAlignment);
+		}
+	if (aMask.AttribIsSet(EAttLineSpacing))
+		{
+		*ptr++=TUint8(EAttLineSpacing);
+		Write32(ptr,aDesiredFormat.iLineSpacingInTwips);
+		}
+	if (aMask.AttribIsSet(EAttLineSpacingControl))
+		{
+		*ptr++=TUint8(EAttLineSpacingControl);
+		*ptr++=TUint8(aDesiredFormat.iLineSpacingControl);
+		}
+	if (aMask.AttribIsSet(EAttSpaceBefore))
+		{
+		*ptr++=TUint8(EAttSpaceBefore);
+		Write32(ptr,aDesiredFormat.iSpaceBeforeInTwips);
+		}
+	if (aMask.AttribIsSet(EAttSpaceAfter))
+		{
+		*ptr++=TUint8(EAttSpaceAfter);
+		Write32(ptr,aDesiredFormat.iSpaceAfterInTwips);
+		}
+	if (aMask.AttribIsSet(EAttKeepTogether))
+		{
+		*ptr++=TUint8(EAttKeepTogether);
+		*ptr++=TUint8(aDesiredFormat.iKeepTogether!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttKeepWithNext))
+		{
+		*ptr++=TUint8(EAttKeepWithNext);
+		*ptr++=TUint8(aDesiredFormat.iKeepWithNext!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttStartNewPage))
+		{
+		*ptr++=TUint8(EAttStartNewPage);
+		*ptr++=TUint8(aDesiredFormat.iStartNewPage!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttWidowOrphan))
+		{
+		*ptr++=TUint8(EAttWidowOrphan);
+		*ptr++=TUint8(aDesiredFormat.iWidowOrphan!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttWrap))
+		{
+		*ptr++=TUint8(EAttWrap);
+		*ptr++=TUint8(aDesiredFormat.iWrap!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttBorderMargin))
+		{
+		*ptr++=TUint8(EAttBorderMargin);
+		Write32(ptr,aDesiredFormat.iBorderMarginInTwips);
+		}
+	if ( aDesiredFormat.BordersPresent() || aCurrentFormat.BordersPresent() )
+		{
+		if (aMask.AttribIsSet(EAttTopBorder))
+			ptr=StoreBorder(ptr,EAttTopBorder,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderTop));
+		if (aMask.AttribIsSet(EAttBottomBorder))
+			ptr=StoreBorder(ptr,EAttBottomBorder,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderBottom));
+		if (aMask.AttribIsSet(EAttLeftBorder))
+			ptr=StoreBorder(ptr,EAttLeftBorder,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderLeft));
+		if (aMask.AttribIsSet(EAttRightBorder))
+			ptr=StoreBorder(ptr,EAttRightBorder,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderRight));
+		}
+	if (aMask.AttribIsSet(EAttDefaultTabWidth))
+		{
+		*ptr++=TUint8(EAttDefaultTabWidth);
+		Write32(ptr,aDesiredFormat.iDefaultTabWidthInTwips);
+		}
+	if (aMask.AttribIsSet(EAttTabStop))
+		{
+		TUint8* tptr=ptr;	// prevent stacking of ptr;
+		StoreTabs(tptr,aDesiredFormat,aCurrentFormat,ETrue);
+		ptr=tptr;
+		}
+	if (aMask.AttribIsSet(EAttBullet))
+		{
+		if (aDesiredFormat.iBullet || aCurrentFormat.iBullet)
+			{
+			if (aDesiredFormat.iBullet)
+				ptr = StoreBullet(ptr,*aDesiredFormat.iBullet);
+			else if (aCurrentFormat.iBullet)
+				ptr = StoreBullet(ptr,TBullet());
+			}
+		}
+	if (!(aDesiredFormat.iLanguage & ~0xFF) && aMask.AttribIsSet(EAttParaLanguage))
+		{
+		*ptr++=TUint8(EAttParaLanguage);
+		*ptr++=TUint8(aDesiredFormat.iLanguage);
+		}
+
+	/*
+	Write the auxiliary attributes for system colours, language codes greater than 255, etc.
+	These must go at the end of the stream because they will not be recognised by earlier versions
+	of ETEXT and will prevent any further attributes from being read.
+	*/
+	if (aMask.AttribIsSet(EAttFillColor))
+		WriteSystemColor(ptr,EAttFillSystemColor,aDesiredFormat.iFillColor);
+	if (aMask.AttribIsSet(EAttBullet))
+		{
+		if (aDesiredFormat.iBullet)
+			WriteSystemColor(ptr,EAttBulletSystemColor,aDesiredFormat.iBullet->iColor);
+		else if (aCurrentFormat.iBullet)
+			WriteSystemColor(ptr,EAttBulletSystemColor,TBullet().iColor);
+		}
+	if (aDesiredFormat.BordersPresent())
+		{
+		if (aMask.AttribIsSet(EAttTopBorder))
+			WriteSystemColor(ptr,EAttTopBorderSystemColor,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderTop).iColor);
+		if (aMask.AttribIsSet(EAttBottomBorder))
+			WriteSystemColor(ptr,EAttBottomBorderSystemColor,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderBottom).iColor);
+		if (aMask.AttribIsSet(EAttLeftBorder))
+			WriteSystemColor(ptr,EAttLeftBorderSystemColor,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderLeft).iColor);
+		if (aMask.AttribIsSet(EAttRightBorder))
+			WriteSystemColor(ptr,EAttRightBorderSystemColor,aDesiredFormat.ParaBorder(CParaFormat::EParaBorderRight).iColor);
+		}
+	if ((aDesiredFormat.iLanguage & ~0xFF) && aMask.AttribIsSet(EAttParaLanguage))
+		{
+		*ptr++ = TUint8(EAttParaLanguageX);
+		Write32(ptr,aDesiredFormat.iLanguage);
+		}
+	if (aMask.AttribIsSet(EAttBullet))
+		{
+		if (aDesiredFormat.iBullet || aCurrentFormat.iBullet)
+			{
+			TBullet bullet;
+			const TBullet* b = aDesiredFormat.iBullet;
+			if (!b)
+				b = &bullet;
+			*ptr++ = TUint8(EAttBulletX);
+			*ptr++ = TUint8(b->iStyle);
+			Write32(ptr,b->iStartNumber);
+			*ptr++ = TUint8(b->iAlignment);
+			}
+		}
+	}
+
+
+TInt RFormatStream::DoCalcSizeParaFormat(const CParaFormat& aDesiredFormat,TParaFormatMask aMask,
+										 const CParaFormat& aCurrentFormat)
+// determine the amount of memory required to store the
+// specified attriubutes from the specified paragraph format.
+//
+	{
+	TInt size=0;
+	if (aMask.AttribIsSet(EAttFillColor))
+		{
+		size+=(KTypeSize+KParaFillColor);
+		if (aDesiredFormat.iFillColor.SystemColorIndex())
+			size += KTypeSize + KParaFillSystemColor;
+		}
+	if (aMask.AttribIsSet(EAttLeftMargin))
+		size+=(KTypeSize+KParaLeftMargin);
+	if (aMask.AttribIsSet(EAttRightMargin))
+		size+=(KTypeSize+KParaRightMargin);
+	if (aMask.AttribIsSet(EAttIndent))
+		size+=(KTypeSize+KParaIndent);
+	if (aMask.AttribIsSet(EAttAlignment))
+		size+=(KTypeSize+KParaAlignment);
+	if (aMask.AttribIsSet(EAttVerticalAlignment))
+		size+=(KTypeSize+KParaVerticalAlignment);
+	if (aMask.AttribIsSet(EAttLineSpacing))
+		size+=(KTypeSize+KParaLineSpacing);
+	if (aMask.AttribIsSet(EAttLineSpacingControl))
+		size+=(KTypeSize+KParaLineSpacingControl);
+	if (aMask.AttribIsSet(EAttSpaceBefore))
+		size+=(KTypeSize+KParaSpaceBefore);
+	if (aMask.AttribIsSet(EAttSpaceAfter))
+		size+=(KTypeSize+KParaSpaceAfter);
+	if (aMask.AttribIsSet(EAttKeepTogether))
+		size+=(KTypeSize+KParaKeepTogether);
+	if (aMask.AttribIsSet(EAttKeepWithNext))
+		size+=(KTypeSize+KParaKeepWithNext);
+	if (aMask.AttribIsSet(EAttStartNewPage))
+		size+=(KTypeSize+KParaStartNewPage);
+	if (aMask.AttribIsSet(EAttWidowOrphan))
+		size+=(KTypeSize+KParaWidowOrphan);
+	if (aMask.AttribIsSet(EAttWrap))
+		size+=(KTypeSize+KParaWrap);
+	if (aMask.AttribIsSet(EAttBorderMargin))
+		size+=(KTypeSize+KParaBorderMargin);
+	if ( aDesiredFormat.BordersPresent() || aCurrentFormat.BordersPresent() )
+		{
+		if (aMask.AttribIsSet(EAttTopBorder))
+			{
+			size+=(KTypeSize+
+			sizeof(TUint8)+  // line style
+			sizeof(TInt32)+  // line thickness
+			KColor+
+			sizeof(TUint8));  // auto color flag
+			if (aDesiredFormat.ParaBorder(CParaFormat::EParaBorderTop).iColor.SystemColorIndex())
+				size += KTypeSize + KParaTopBorderSystemColor;
+			}
+		if (aMask.AttribIsSet(EAttBottomBorder))
+			{
+			size+=(KTypeSize+
+			sizeof(TUint8)+  // line style
+			sizeof(TInt32)+  // line thickness
+			KColor+
+			sizeof(TUint8));  // auto color flag
+			if (aDesiredFormat.ParaBorder(CParaFormat::EParaBorderBottom).iColor.SystemColorIndex())
+				size += KTypeSize + KParaBottomBorderSystemColor;
+			}
+		if (aMask.AttribIsSet(EAttLeftBorder))
+			{
+			size+=(KTypeSize+
+			sizeof(TUint8)+  // line style
+			sizeof(TInt32)+  // line thickness
+			KColor+
+			sizeof(TUint8));  // auto color flag
+			if (aDesiredFormat.ParaBorder(CParaFormat::EParaBorderLeft).iColor.SystemColorIndex())
+				size += KTypeSize + KParaLeftBorderSystemColor;
+			}
+		if (aMask.AttribIsSet(EAttRightBorder))
+			{
+			size+=(KTypeSize+
+			sizeof(TUint8)+  // line style
+			sizeof(TInt32)+  // line thickness
+			KColor+
+			sizeof(TUint8));  // auto color flag
+			if (aDesiredFormat.ParaBorder(CParaFormat::EParaBorderRight).iColor.SystemColorIndex())
+				size += KTypeSize + KParaBulletSystemColor;
+			}
+		}
+	if (aMask.AttribIsSet(EAttDefaultTabWidth))
+		size+=(KTypeSize+KParaDefaultTabWidth);
+	if (aMask.AttribIsSet(EAttTabStop))
+		{
+		TUint8* ptr=NULL;
+		size+=StoreTabs(ptr,aDesiredFormat,aCurrentFormat,EFalse);
+		}
+	if (aMask.AttribIsSet(EAttBullet))
+		{
+		if (aDesiredFormat.iBullet || aCurrentFormat.iBullet)
+			{
+			size += KTypeSize +
+					sizeof(TUint8) +		// length of following data
+					sizeof(TText) +			// iCharacterCode
+					KFontHeight +			// iHeightInTwips
+					sizeof(TUint8) +		// iHanging indent
+					KCharColor +			// iColor
+					sizeof(TUint8) +		// typeface name size
+					KTypefaceFlags;			// typeface flags
+
+			if (aDesiredFormat.iBullet)
+				size += aDesiredFormat.iBullet->iTypeface.iName.Size();  // font name
+
+			if ((aDesiredFormat.iBullet && aDesiredFormat.iBullet->iColor.SystemColorIndex()) ||
+				(aCurrentFormat.iBullet))
+				size += KTypeSize + KParaBulletSystemColor;
+
+			size += KTypeSize + KParaBulletX;
+			}
+		}
+	if (aMask.AttribIsSet(EAttParaLanguage))
+		{
+		if (aDesiredFormat.iLanguage & ~0xFF)
+			size += KTypeSize + KParaLanguageX;
+		else
+			size += KTypeSize + KParaLanguage;
+		}
+	return size;
+	}
+
+
+// Store the specified values in this (allocated) format stream.
+void RFormatStream::DoStoreCharFormat(const TCharFormatX& aCharFormat,TCharFormatXMask aMask)
+	{
+	TUint8* ptr = iBase;
+	const TCharFormat format = aCharFormat.iCharFormat;
+
+	if (aMask.AttribIsSet(EAttColor))
+		{
+		*ptr++=TUint8(EAttColor);
+		ptr=Store(ptr,format.iFontPresentation.iTextColor);
+		}
+	if (aMask.AttribIsSet(EAttFontHighlightColor))
+		{
+		*ptr++=TUint8(EAttFontHighlightColor);
+		ptr=Store(ptr,format.iFontPresentation.iHighlightColor);
+		}
+	if (aMask.AttribIsSet(EAttFontHighlightStyle))
+		{
+		*ptr++=TUint8(EAttFontHighlightStyle);
+		*ptr++=(TUint8)format.iFontPresentation.iHighlightStyle;
+		}
+	if (aMask.AttribIsSet(EAttFontStrikethrough))
+		{
+		*ptr++=TUint8(EAttFontStrikethrough);
+		*ptr++=(TUint8)format.iFontPresentation.iStrikethrough;
+		}
+	if (aMask.AttribIsSet(EAttFontUnderline))
+		{
+		*ptr++=TUint8(EAttFontUnderline);
+		*ptr++=(TUint8)format.iFontPresentation.iUnderline;
+		}
+	if (aMask.AttribIsSet(EAttFontHeight))
+		{
+		*ptr++=TUint8(EAttFontHeight);
+		Write32(ptr,format.iFontSpec.iHeight);
+		}
+	if (aMask.AttribIsSet(EAttFontPosture))
+		{
+		*ptr++=TUint8(EAttFontPosture);
+		*ptr++=TUint8(format.iFontSpec.iFontStyle.Posture());
+		}
+	if (aMask.AttribIsSet(EAttFontStrokeWeight))
+		{
+		*ptr++=TUint8(EAttFontStrokeWeight);
+		*ptr++=TUint8(format.iFontSpec.iFontStyle.StrokeWeight());
+		}
+	if (aMask.AttribIsSet(EAttFontPrintPos))
+		{
+		*ptr++=TUint8(EAttFontPrintPos);
+		*ptr++=TUint8(format.iFontSpec.iFontStyle.PrintPosition());
+		}
+	if (aMask.AttribIsSet(EAttFontTypeface))
+		{
+		*ptr++=TUint8(EAttFontTypeface);
+		ptr=Store(ptr,format.iFontSpec.iTypeface);
+		*ptr++=TUint8(EAttBitmapType);
+		*ptr++=TUint8(format.iFontSpec.iFontStyle.BitmapType());
+		}
+	if (!(format.iLanguage & ~0xFF) && aMask.AttribIsSet(EAttCharLanguage))
+		{
+		*ptr++=TUint8(EAttCharLanguage);
+		*ptr++=TUint8(format.iLanguage);
+		}
+	if (aMask.AttribIsSet(EAttFontHiddenText))
+		{
+		*ptr++=TUint8(EAttFontHiddenText);
+		*ptr++=TUint8(format.iFontPresentation.iHiddenText!=EFalse);
+		}
+	if (aMask.AttribIsSet(EAttFontPictureAlignment))
+		{
+		*ptr++=TUint8(EAttFontPictureAlignment);
+		*ptr++=TUint8(format.iFontPresentation.iPictureAlignment);
+		}
+
+	// Auxiliary attributes for system colours, etc.
+	if (aMask.AttribIsSet(EAttColor))
+		WriteSystemColor(ptr,EAttTextSystemColor,format.iFontPresentation.iTextColor);
+	if (aMask.AttribIsSet(EAttFontHighlightColor))
+		WriteSystemColor(ptr,EAttFontHighlightSystemColor,format.iFontPresentation.iHighlightColor);
+	if ((format.iLanguage & ~0xFF) && aMask.AttribIsSet(EAttCharLanguage))
+		{
+		*ptr++ = TUint8(EAttCharLanguageX);
+		Write32(ptr,format.iLanguage);
+		}
+
+	// Internal character attributes:
+	if (aMask.AttribIsSet(EAttParserTag))
+		{
+		*ptr++ = TUint8(EAttParserTag);
+		Write32(ptr,aCharFormat.iParserTag);
+		}
+	}
+
+
+TInt RFormatStream::DoCalcSizeCharFormat(const TCharFormatX& aCharFormatX,const TCharFormatXMask& aMask)
+	{
+	TInt size = 0;
+	const TCharFormat format = aCharFormatX.iCharFormat;
+
+	if (aMask.AttribIsSet(EAttColor))
+		{
+		size+=(KTypeSize+KCharColor);
+		if (format.iFontPresentation.iTextColor.SystemColorIndex())
+			size += KTypeSize + KCharTextSystemColor;
+		}
+	if (aMask.AttribIsSet(EAttFontHighlightColor))
+		{
+		size+=(KTypeSize+KCharHighlightColor);
+		if (format.iFontPresentation.iHighlightColor.SystemColorIndex())
+			size += KTypeSize + KCharFontHighlightSystemColor;
+		}
+	if (aMask.AttribIsSet(EAttFontHighlightStyle))
+		size+=(KTypeSize+KCharHighlightStyle);
+	if (aMask.AttribIsSet(EAttFontStrikethrough))
+		size+=(KTypeSize+KCharStrikethrough);
+	if (aMask.AttribIsSet(EAttFontUnderline))
+		size+=(KTypeSize+KCharUnderline);
+	if (aMask.AttribIsSet(EAttFontHeight))
+		size+=(KTypeSize+KCharFontHeight);
+	if (aMask.AttribIsSet(EAttFontPosture))
+		size+=(KTypeSize+KCharPosture);
+	if (aMask.AttribIsSet(EAttFontStrokeWeight))
+		size+=(KTypeSize+KCharStrokeWeight);
+	if (aMask.AttribIsSet(EAttFontPrintPos))
+		size+=(KTypeSize+KCharPrintPos);
+	if (aMask.AttribIsSet(EAttFontTypeface))
+		{
+		TUint8 length=(TUint8)format.iFontSpec.iTypeface.iName.Size();
+		size+=(KTypeSize+sizeof(TUint8)+length+sizeof(TUint8));  // size in bytes
+		size+=(KTypeSize+KBitmapType);
+		}
+	if (aMask.AttribIsSet(EAttCharLanguage))
+		{
+		if (format.iLanguage & ~0xFF)
+			size += KTypeSize + KCharLanguageX;
+		else
+			size += KTypeSize + KCharLanguage;
+		}
+	if (aMask.AttribIsSet(EAttFontHiddenText))
+		size+=(KTypeSize+KCharHiddenText);
+	if (aMask.AttribIsSet(EAttFontPictureAlignment))
+		size+=(KTypeSize+KCharPictureAlignment);
+
+	// Internal character attributes
+	if (aMask.AttribIsSet(EAttParserTag))
+		size += KTypeSize + KCharParserTag;
+	
+	return size;
+	}
+
+void RFormatStream::RemoveRedundantCharFormat(TCharFormatMask& aMask,
+											  const TCharFormatX& aFormat,const TCharFormatX& aEffectiveFormat)
+	{
+	TCharFormatXMask mask = aMask;
+	const TCharFormat format = aFormat.iCharFormat;
+	const TCharFormat effective_format = aEffectiveFormat.iCharFormat;
+
+	if (mask.AttribIsSet(EAttColor))
+		{
+		if (format.iFontPresentation.iTextColor==effective_format.iFontPresentation.iTextColor)
+			mask.ClearAttrib(EAttColor);
+		}
+	if (mask.AttribIsSet(EAttFontHighlightColor))
+		{
+		if (format.iFontPresentation.iHighlightColor==effective_format.iFontPresentation.iHighlightColor)
+			mask.ClearAttrib(EAttFontHighlightColor);
+		}
+	if (mask.AttribIsSet(EAttFontHighlightStyle))
+		{
+		if (format.iFontPresentation.iHighlightStyle==effective_format.iFontPresentation.iHighlightStyle)
+			mask.ClearAttrib(EAttFontHighlightStyle);
+		}
+	if (mask.AttribIsSet(EAttFontStrikethrough))
+		{
+		if (format.iFontPresentation.iStrikethrough==effective_format.iFontPresentation.iStrikethrough)
+			mask.ClearAttrib(EAttFontStrikethrough);
+		}
+	if (mask.AttribIsSet(EAttFontUnderline))
+		{
+		if (format.iFontPresentation.iUnderline==effective_format.iFontPresentation.iUnderline)
+			mask.ClearAttrib(EAttFontUnderline);
+		}
+	if (mask.AttribIsSet(EAttFontHeight))
+		{
+		if (format.iFontSpec.iHeight==effective_format.iFontSpec.iHeight)
+			mask.ClearAttrib(EAttFontHeight);
+		}
+	if (mask.AttribIsSet(EAttFontPosture))
+		{
+		if (format.iFontSpec.iFontStyle.Posture()==effective_format.iFontSpec.iFontStyle.Posture())
+			mask.ClearAttrib(EAttFontPosture);
+		}
+	if (mask.AttribIsSet(EAttFontStrokeWeight))
+		{
+		if (format.iFontSpec.iFontStyle.StrokeWeight()==effective_format.iFontSpec.iFontStyle.StrokeWeight())
+			mask.ClearAttrib(EAttFontStrokeWeight);
+		}
+	if (mask.AttribIsSet(EAttFontPrintPos))
+		{
+		if (format.iFontSpec.iFontStyle.PrintPosition()==effective_format.iFontSpec.iFontStyle.PrintPosition())
+			mask.ClearAttrib(EAttFontPrintPos);
+		}
+	if (mask.AttribIsSet(EAttFontTypeface))
+		{
+		if (format.iFontSpec.iTypeface==effective_format.iFontSpec.iTypeface)
+			mask.ClearAttrib(EAttFontTypeface);
+		}
+	if (mask.AttribIsSet(EAttCharLanguage))
+		{
+		if (format.iLanguage==effective_format.iLanguage)
+			mask.ClearAttrib(EAttCharLanguage);
+		}
+	if (mask.AttribIsSet(EAttFontHiddenText))
+		{
+		if (format.iFontPresentation.iHiddenText==effective_format.iFontPresentation.iHiddenText)
+			mask.ClearAttrib(EAttFontHiddenText);
+		}
+	if (mask.AttribIsSet(EAttFontPictureAlignment))
+		{
+		if (format.iFontPresentation.iPictureAlignment==effective_format.iFontPresentation.iPictureAlignment)
+			mask.ClearAttrib(EAttFontPictureAlignment);
+		}
+	if (mask.AttribIsSet(EAttParserTag))
+		{
+		if (aFormat.iParserTag == aEffectiveFormat.iParserTag)
+			mask.ClearAttrib(EAttParserTag);
+		}
+	aMask = mask;
+	}
+
+
+void RFormatStream::SenseParaFormatL(CParaFormat& aParaFormat,TParaFormatMask& aMask,CParaFormat::TParaFormatGetMode aMode)const
+// Dumps contents of the stream into aParaFormat.  The attributes written to aParaFormat
+// are determined by the mode, aMode.
+// If the mode is EAllAttributes, then all attributes are written,
+// if the mode is EFixedAttributes, then only the fixed atttibutes are written,
+// ie, not tabs,borders,bullet (which are variable).
+// For each format attribute found in the stream:
+// write it into a ParaFormat if the corresponding flag in aMask is not set,
+// and set this flag showing the attribute has been written into aParaFormat.
+//
+// If aMode is EAllAttributes this function may leave through out-of-memory allocating paragraph borders,
+// bullets or tabs.
+// If aMode is EFixedAttributes, this function is guaranteed not to leave.
+//
+	{
+	__TEST_INVARIANT;
+
+	TUint8* ptr=iBase;
+	if (ptr==NULL)
+		return;
+	TParaFormatMask old_mask = aMask;
+	TParaFormatMask new_mask = aMask;
+	TUint8* end=iEnd;
+	TParaBorder* b = NULL;
+
+	while (ptr < end)
+		{
+		TUint8 type = *ptr;
+		ptr += KTypeSize;
+		switch (type)
+			{
+			case EAttFillColor:
+				if (!old_mask.AttribIsSet(EAttFillColor))
+					{
+					new_mask.SetAttrib(EAttFillColor);
+					ptr=ReadValue(ptr,aParaFormat.iFillColor);
+					}
+				else
+					ptr+=KParaFillColor;
+				break;
+			case EAttLeftMargin:
+				if (!old_mask.AttribIsSet(EAttLeftMargin))
+					{
+					new_mask.SetAttrib(EAttLeftMargin);
+					aParaFormat.iLeftMarginInTwips = Read32(ptr);
+					}
+				ptr+=KParaLeftMargin;
+				break;
+			case EAttRightMargin:
+				if (!old_mask.AttribIsSet(EAttRightMargin))
+					{
+					new_mask.SetAttrib(EAttRightMargin);
+					aParaFormat.iRightMarginInTwips = Read32(ptr);
+					}
+				ptr+=KParaRightMargin;
+				break;
+			case EAttIndent:
+				if (!old_mask.AttribIsSet(EAttIndent))
+					{
+					new_mask.SetAttrib(EAttIndent);
+					aParaFormat.iIndentInTwips = Read32(ptr);
+					}
+				ptr+=KParaIndent;
+				break;
+			case EAttAlignment:
+				if (!old_mask.AttribIsSet(EAttAlignment))
+					{
+					new_mask.SetAttrib(EAttAlignment);
+					aParaFormat.iHorizontalAlignment=CParaFormat::TAlignment(*ptr);
+					}
+				ptr+=KParaAlignment;
+				break;
+			case EAttVerticalAlignment:
+				if (!old_mask.AttribIsSet(EAttVerticalAlignment))
+					{
+					new_mask.SetAttrib(EAttVerticalAlignment);
+					aParaFormat.iVerticalAlignment=CParaFormat::TAlignment(*ptr);
+					}
+				ptr+=KParaVerticalAlignment;
+				break;
+			case EAttLineSpacing:
+				if (!old_mask.AttribIsSet(EAttLineSpacing))
+					{
+					new_mask.SetAttrib(EAttLineSpacing);
+					aParaFormat.iLineSpacingInTwips = Read32(ptr);
+					}
+				ptr+=KParaLineSpacing;
+				break;
+			case EAttLineSpacingControl:
+				if (!old_mask.AttribIsSet(EAttLineSpacingControl))
+					{
+					new_mask.SetAttrib(EAttLineSpacingControl);
+					aParaFormat.iLineSpacingControl=(CParaFormat::TLineSpacingControl)*ptr;
+					}
+				ptr+=KParaLineSpacingControl;
+				break;
+			case EAttSpaceBefore:
+				if (!old_mask.AttribIsSet(EAttSpaceBefore))
+					{
+					new_mask.SetAttrib(EAttSpaceBefore);
+					aParaFormat.iSpaceBeforeInTwips = Read32(ptr);
+					}
+				ptr+=KParaSpaceBefore;
+				break;
+			case EAttSpaceAfter:
+				if (!old_mask.AttribIsSet(EAttSpaceAfter))
+					{
+					new_mask.SetAttrib(EAttSpaceAfter);
+					aParaFormat.iSpaceAfterInTwips = Read32(ptr);
+					}
+				ptr+=KParaSpaceAfter;
+				break;
+			case EAttKeepTogether:
+				if (!old_mask.AttribIsSet(EAttKeepTogether))
+					{
+					new_mask.SetAttrib(EAttKeepTogether);
+					aParaFormat.iKeepTogether=TBool(*ptr);
+					}
+				ptr+=KParaKeepTogether;
+				break;
+			case EAttKeepWithNext:
+				if (!old_mask.AttribIsSet(EAttKeepWithNext))
+					{
+					new_mask.SetAttrib(EAttKeepWithNext);
+					aParaFormat.iKeepWithNext=(TBool)*ptr;
+					}
+				ptr+=KParaKeepWithNext;
+				break;
+			case EAttStartNewPage:
+				if (!old_mask.AttribIsSet(EAttStartNewPage))
+					{
+					new_mask.SetAttrib(EAttStartNewPage);
+					aParaFormat.iStartNewPage=TBool(*ptr);
+					}
+				ptr+=KParaStartNewPage;
+				break;
+			case EAttWidowOrphan:
+				if (!old_mask.AttribIsSet(EAttWidowOrphan))
+					{
+					new_mask.SetAttrib(EAttWidowOrphan);
+					aParaFormat.iWidowOrphan=TBool(*ptr);
+					}
+				ptr+=KParaWidowOrphan;
+				break;
+			case EAttWrap:
+				if (!old_mask.AttribIsSet(EAttWrap))
+					{
+					new_mask.SetAttrib(EAttWrap);
+					aParaFormat.iWrap=TBool(*ptr);
+					}
+				ptr+=KParaWrap;
+				break;
+			case EAttBorderMargin:
+				if (!old_mask.AttribIsSet(EAttBorderMargin))
+					{
+					new_mask.SetAttrib(EAttBorderMargin);
+					aParaFormat.iBorderMarginInTwips = Read32(ptr);
+					}
+				ptr+=KParaBorderMargin;
+				break;
+			case EAttTopBorder:
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttTopBorder) )
+					{
+					ptr+=KParaTopBorder;
+					}
+				else
+					{
+					TParaBorder border;
+					ptr=ReadValue(ptr,border);
+					aParaFormat.SetParaBorderL(CParaFormat::EParaBorderTop,border);
+					new_mask.SetAttrib(EAttTopBorder);
+					}
+				break;
+			case EAttBottomBorder:
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttBottomBorder))
+					{
+					ptr+=KParaBottomBorder;
+					}
+				else
+					{
+					TParaBorder border;
+					ptr=ReadValue(ptr,border);
+					aParaFormat.SetParaBorderL(CParaFormat::EParaBorderBottom,border);
+					new_mask.SetAttrib(EAttBottomBorder);
+					}
+				break;
+			case EAttLeftBorder:
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttLeftBorder))
+					{
+					ptr+=KParaLeftBorder;
+					}
+				else
+					{
+					TParaBorder border;
+					ptr=ReadValue(ptr,border);
+					aParaFormat.SetParaBorderL(CParaFormat::EParaBorderLeft,border);
+					new_mask.SetAttrib(EAttLeftBorder);
+					}
+				break;
+			case EAttRightBorder:
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttRightBorder))
+					{
+					ptr+=KParaRightBorder;
+					}
+				else
+					{
+					TParaBorder border;
+					ptr=ReadValue(ptr,border);
+					aParaFormat.SetParaBorderL(CParaFormat::EParaBorderRight,border);
+					new_mask.SetAttrib(EAttRightBorder);
+					}
+				break;
+			case EAttDefaultTabWidth:
+				if (!old_mask.AttribIsSet(EAttDefaultTabWidth))
+					{
+					new_mask.SetAttrib(EAttDefaultTabWidth);
+					aParaFormat.iDefaultTabWidthInTwips = Read32(ptr);
+					}
+				ptr+=KParaDefaultTabWidth;
+				break;
+			case EAttTabStop:
+				{
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttTabStop))
+					ptr += KParaTabStop;
+				else
+					{
+					ptr=ReadTabL(ptr,aParaFormat);
+					new_mask.SetAttrib(EAttTabStop);
+					}
+				break;
+				}
+			case EAttBullet:
+				{
+				if (aMode==CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttBullet))
+					{
+					ptr+=*ptr+1;  // variable length attribute
+					}
+				else
+					{
+					TBullet* bullet=aParaFormat.iBullet;
+					if (!bullet)
+						aParaFormat.iBullet=bullet=new(ELeave) TBullet;
+					ptr=ReadValue(ptr,*bullet);
+					new_mask.SetAttrib(EAttBullet);
+					//coverity[memory_leak]
+					}
+				break;
+				}
+			case EAttParaLanguage:
+				if (!old_mask.AttribIsSet(EAttParaLanguage))
+					{
+					new_mask.SetAttrib(EAttParaLanguage);
+					aParaFormat.iLanguage=TInt32(*ptr);
+					}
+				ptr+=KParaLanguage;
+				break;
+
+			// Auxiliary attributes for system colours, etc.
+			case EAttFillSystemColor:
+				if (!old_mask.AttribIsSet(EAttFillColor))
+					ReadSystemColor(ptr,aParaFormat.iFillColor);
+				ptr++;
+				break;
+			case EAttBulletSystemColor:
+				if (aMode != CParaFormat::EFixedAttributes && !old_mask.AttribIsSet(EAttBullet) &&
+					aParaFormat.iBullet)
+					ReadSystemColor(ptr,aParaFormat.iBullet->iColor);
+				ptr++;					
+				break;
+			case EAttTopBorderSystemColor:
+				if (aMode != CParaFormat::EFixedAttributes && !old_mask.AttribIsSet(EAttTopBorder))
+					{
+					b = aParaFormat.ParaBorderPtr(CParaFormat::EParaBorderTop);
+					if (b)
+						ReadSystemColor(ptr,b->iColor);
+					}
+				ptr++;
+				break;
+			case EAttBottomBorderSystemColor:
+				if (aMode != CParaFormat::EFixedAttributes && !old_mask.AttribIsSet(EAttBottomBorder))
+					{
+					b = aParaFormat.ParaBorderPtr(CParaFormat::EParaBorderBottom);
+					if (b)
+						ReadSystemColor(ptr,b->iColor);
+					}
+				ptr++;
+				break;
+			case EAttLeftBorderSystemColor:
+				if (aMode != CParaFormat::EFixedAttributes && !old_mask.AttribIsSet(EAttLeftBorder))
+					{
+					b = aParaFormat.ParaBorderPtr(CParaFormat::EParaBorderLeft);
+					if (b)
+						ReadSystemColor(ptr,b->iColor);
+					}
+				ptr++;
+				break;
+			case EAttRightBorderSystemColor:
+				if (aMode != CParaFormat::EFixedAttributes && !old_mask.AttribIsSet(EAttRightBorder))
+					{
+					b = aParaFormat.ParaBorderPtr(CParaFormat::EParaBorderRight);
+					if (b)
+						ReadSystemColor(ptr,b->iColor);
+					}
+				ptr++;
+				break;
+			case EAttParaLanguageX:
+				if (!old_mask.AttribIsSet(EAttParaLanguage))
+					{
+					new_mask.SetAttrib(EAttParaLanguage);
+					aParaFormat.iLanguage = Read32(ptr);
+					}
+				ptr += KParaLanguageX;
+				break;
+			case EAttBulletX:
+				if (aMode == CParaFormat::EFixedAttributes || old_mask.AttribIsSet(EAttBullet) ||
+					!aParaFormat.iBullet)
+					ptr += KParaBulletX;
+				else
+					{
+					aParaFormat.iBullet->iStyle = (TBullet::TStyle)(*ptr++);
+					aParaFormat.iBullet->iStartNumber = Read32(ptr);
+					ptr += sizeof(TInt32);
+					aParaFormat.iBullet->iAlignment = (TBullet::TAlignment)(*ptr++);
+					}
+				break;
+
+			default:  // have maybe read an attribute defined by a later version; stop here
+				aMask = new_mask;
+				return;
+			}
+		}
+	aMask = new_mask;
+	}
+
+/*
+Extract format attributes selected by cleared bits in aMask.
+Put them into aCharFormatX if the corresponding bit in aMask is NOT set, and set the bit.
+*/
+void RFormatStream::SenseCharFormat(TCharFormatX& aCharFormat,TCharFormatXMask& aMask) const
+	{
+	__TEST_INVARIANT;
+
+	TUint8* ptr = iBase;
+	if (ptr == NULL)
+		return;
+	TCharFormatXMask old_mask = aMask;
+	TCharFormatXMask new_mask = aMask;
+	TUint8* end = iEnd;
+	TCharFormat& format = aCharFormat.iCharFormat;
+
+	while (ptr<end)
+		{
+		TUint8 type = *ptr;
+		ptr+=KTypeSize;
+		switch (type)
+			{
+			case EAttColor:
+				if (!old_mask.AttribIsSet(EAttColor))
+					{
+					new_mask.SetAttrib(EAttColor);
+					ptr=ReadValue(ptr,format.iFontPresentation.iTextColor);
+					}
+				else
+					ptr+=KCharColor;
+				break;
+			case EAttFontHighlightColor:
+				if (!old_mask.AttribIsSet(EAttFontHighlightColor))
+					{
+					new_mask.SetAttrib(EAttFontHighlightColor);
+					ptr=ReadValue(ptr,format.iFontPresentation.iHighlightColor);
+					}
+				else
+					ptr+=KCharHighlightColor;
+				break;
+			case EAttFontHighlightStyle:
+				if (!old_mask.AttribIsSet(EAttFontHighlightStyle))
+					{
+					new_mask.SetAttrib(EAttFontHighlightStyle);
+					format.iFontPresentation.iHighlightStyle=(TFontPresentation::TFontHighlightStyle)*ptr;
+					}
+				ptr+=KCharHighlightStyle;
+				break;
+			case EAttFontStrikethrough:
+				if (!old_mask.AttribIsSet(EAttFontStrikethrough))
+					{
+					new_mask.SetAttrib(EAttFontStrikethrough);
+					format.iFontPresentation.iStrikethrough=(TFontStrikethrough)*ptr;
+					}
+				ptr+=KCharStrikethrough;
+				break;
+			case EAttFontUnderline:
+				if (!old_mask.AttribIsSet(EAttFontUnderline))
+					{
+					new_mask.SetAttrib(EAttFontUnderline);
+					format.iFontPresentation.iUnderline=(TFontUnderline)*ptr;
+					}
+				ptr+=KCharUnderline;
+				break;
+			case EAttFontHeight:
+				if (!old_mask.AttribIsSet(EAttFontHeight))
+					{
+					new_mask.SetAttrib(EAttFontHeight);
+					format.iFontSpec.iHeight = Read32(ptr);
+					}
+				ptr+=KCharFontHeight;
+				break;
+			case EAttFontPosture:
+				if (!old_mask.AttribIsSet(EAttFontPosture))
+					{
+					new_mask.SetAttrib(EAttFontPosture);
+					format.iFontSpec.iFontStyle.SetPosture((TFontPosture)*ptr);
+					}
+				ptr+=KCharPosture;
+				break;
+			case EAttFontStrokeWeight:
+				if (!old_mask.AttribIsSet(EAttFontStrokeWeight))
+					{
+					new_mask.SetAttrib(EAttFontStrokeWeight);
+					format.iFontSpec.iFontStyle.SetStrokeWeight((TFontStrokeWeight)*ptr);
+					}
+				ptr+=KCharStrokeWeight;
+				break;
+			case EAttFontPrintPos:
+				if (!old_mask.AttribIsSet(EAttFontPrintPos))
+					{
+					new_mask.SetAttrib(EAttFontPrintPos);
+					format.iFontSpec.iFontStyle.SetPrintPosition((TFontPrintPosition)*ptr);
+					}
+				ptr+=KCharPrintPos;
+				break;
+			case EAttFontTypeface:
+				if (!old_mask.AttribIsSet(EAttFontTypeface))
+					{
+					new_mask.SetAttrib(EAttFontTypeface);
+					ptr=ReadValue(ptr,format.iFontSpec.iTypeface);  // updates ptr
+					}
+				else
+					ptr+=*ptr+1;	// variable length attribute
+				break;
+			case EAttBitmapType:
+				if (!old_mask.AttribIsSet(EAttFontTypeface))
+					{
+					format.iFontSpec.iFontStyle.SetBitmapType(static_cast <TGlyphBitmapType> (*ptr));
+					}
+				ptr+=KBitmapType;
+				break;
+			case EAttCharLanguage:
+				if (!old_mask.AttribIsSet(EAttCharLanguage))
+					{
+					new_mask.SetAttrib(EAttCharLanguage);
+					format.iLanguage=*ptr;
+					}
+				ptr+=KCharLanguage;
+				break;
+			case EAttFontHiddenText:
+				if (!old_mask.AttribIsSet(EAttFontHiddenText))
+					{
+					new_mask.SetAttrib(EAttFontHiddenText);
+					format.iFontPresentation.iHiddenText=(TBool)*ptr;
+					}
+				ptr+=KCharHiddenText;
+				break;
+			case EAttFontPictureAlignment:
+				if (!old_mask.AttribIsSet(EAttFontPictureAlignment))
+					{
+					new_mask.SetAttrib(EAttFontPictureAlignment);
+					format.iFontPresentation.iPictureAlignment=(TFontPresentation::TAlignment)*ptr;
+					}
+				ptr+=KCharPictureAlignment;
+				break;
+
+			// Auxiliary attributes for system colours, etc.
+			case EAttTextSystemColor:
+				if (!old_mask.AttribIsSet(EAttColor))
+					ReadSystemColor(ptr,format.iFontPresentation.iTextColor);
+				ptr++;
+				break;
+
+			case EAttFontHighlightSystemColor:
+				if (!old_mask.AttribIsSet(EAttFontHighlightColor))
+					ReadSystemColor(ptr,format.iFontPresentation.iHighlightColor);
+				ptr++;
+				break;
+
+			case EAttCharLanguageX:
+				if (!old_mask.AttribIsSet(EAttCharLanguage))
+					{
+					new_mask.SetAttrib(EAttCharLanguage);
+					format.iLanguage = Read32(ptr);
+					}
+				ptr += KCharLanguageX;
+				break;
+
+			// Internal character attributes:
+			case EAttParserTag:
+				if (!old_mask.AttribIsSet(EAttParserTag))
+					{
+					new_mask.SetAttrib(EAttParserTag);
+					aCharFormat.iParserTag = Read32(ptr);
+					}
+				ptr += KCharParserTag;
+				break;
+
+			default:	// have maybe read an attribute defined by a later version; stop here
+				aMask = new_mask;
+				return;
+			}
+		}
+	aMask = new_mask;
+	}
+
+/** Swaps the contents of this stream with aStream.
+@param aStream Object to swap contents with. */
+void RFormatStream::Swap(RFormatStream& aStream)
+	{
+	TUint8* t = iBase;
+	iBase = aStream.iBase;
+	aStream.iBase = t;
+	t = iEnd;
+	iEnd = aStream.iEnd;
+	aStream.iEnd = t;
+	}
+
+TInt RFormatStream::StoreTabs(TUint8*& aPtr,const CParaFormat& aDesiredFormat,const CParaFormat& aCurrentFormat,TBool aStoreData)
+// Merges the tabs from the desired paraFormat with those from the current effective paraFormat, resolving differences
+// as described below, and store the resultant tablist in this layer.
+// If aStoreData is false, then return the number of bytes necessary to store all required tabs
+//
+	{
+	TInt requiredTabCount=0;
+	TInt desiredTabCount=aDesiredFormat.TabCount();
+	TInt currentTabCount=aCurrentFormat.TabCount();
+	if (desiredTabCount==0 && currentTabCount==0)
+		{// Nothing needs to be stored.
+		return requiredTabCount;
+		}
+	if (desiredTabCount>0 && currentTabCount>0)
+		{// The 2 tab lists need merging.
+		requiredTabCount=MergeTabLists(aPtr,aDesiredFormat,desiredTabCount,aCurrentFormat,currentTabCount,aStoreData);
+		}
+	else if (desiredTabCount>0 && currentTabCount==0)
+			{// There are no previous tabs to merge so just store all the desired ones.
+			if (aStoreData)
+				StoreAllTabs(aPtr,aDesiredFormat);
+			else
+				requiredTabCount+=desiredTabCount;
+			}
+		else if (desiredTabCount==0 && currentTabCount>0)
+				{// We want to delete (NULL) all existing tabs.
+				if (aStoreData)
+					{
+					for (TInt index=0;index<currentTabCount;index++)
+						{
+						TTabStop tab=aCurrentFormat.TabStop(index);
+						tab.iType=TTabStop::ENullTab;
+						StoreTab(aPtr,tab);
+						}
+					}
+				else requiredTabCount+=currentTabCount;
+				}
+	return requiredTabCount*(KTypeSize+KParaTabStop);
+	}
+
+
+TInt RFormatStream::MergeTabLists(TUint8*& aPtr,const CParaFormat& aDesiredFormat,TInt aDesiredTabCount,
+								  const CParaFormat& aCurrentFormat,TInt aCurrentTabCount,TBool aStoreData)
+// Compares the desired tablist (from a dialog interaction) with that of the current tablist.
+// The resulting tab stop is stored if aStoreData is TRUE.
+// There may be 2 tabs for any for any given tabstops.
+// The possible results of the comparison are:
+// (1) Tab is in desired but not current --> Store the desired tab.
+// (2) Tab is in current but not desired --> Null the current and store.
+// (3) Tab is in both current and desired -->
+//			(i) if tab type is the same then store nothing -- rely on the base one being inherited.
+//			(ii)if tab type is not same then store the current -- overriding whatevers in the base.
+//
+	{
+	TInt requiredTabCount=0;
+	TInt offsetInDesired,offsetInCurrent;
+	offsetInDesired=offsetInCurrent=0;
+	TTabStop desiredTab,currentTab;
+	while ((offsetInDesired!=aDesiredTabCount) && (offsetInCurrent!=aCurrentTabCount))
+		{// Do this until we exhaust one of the tab lists.
+		desiredTab=aDesiredFormat.TabStop(offsetInDesired);
+		currentTab=aCurrentFormat.TabStop(offsetInCurrent);
+		if (desiredTab.iTwipsPosition<currentTab.iTwipsPosition)
+			{
+			if (aStoreData)
+				aPtr=StoreTab(aPtr,desiredTab);  // Store desiredTab.
+			else 
+				requiredTabCount++;
+			offsetInDesired++;  // Move to the next tab in the desired tablist.
+			continue;
+			}
+		if (desiredTab.iTwipsPosition>currentTab.iTwipsPosition)
+			{
+			if (aStoreData)
+				{
+				currentTab.iType=TTabStop::ENullTab;  // Null the current current tab.
+				aPtr=StoreTab(aPtr,currentTab);  // Store NULL'd currentTab
+				}
+			else
+				requiredTabCount++;
+			offsetInCurrent++;  // Move to the next tab in the current tablist.
+			continue;
+			}
+		if (desiredTab.iTwipsPosition==currentTab.iTwipsPosition)
+			{
+			if (desiredTab.iType!=currentTab.iType)
+				{// Store desired type to override the one from the lower layer.
+				if (aStoreData)
+					aPtr=StoreTab(aPtr,desiredTab);
+				else
+					requiredTabCount++;
+				}// Otherwise rely on the one in the base - store nothing but increment.
+			offsetInDesired++;
+			offsetInCurrent++;
+			continue;
+			}
+		}
+	TInt currentLeftToDo=aCurrentTabCount-offsetInCurrent;
+	TInt desiredLeftToDo=aDesiredTabCount-offsetInDesired;
+	// Spot which list is exhausted and process the rest of the remainder appropriately.
+	if (currentLeftToDo)
+		{// Store null'd remainder of current tab list.
+		for (;offsetInCurrent<aCurrentTabCount;offsetInCurrent++)
+			{
+			if (aStoreData)
+				{
+				currentTab=aCurrentFormat.TabStop(offsetInCurrent);
+				currentTab.iType=TTabStop::ENullTab;  // Null the current current tab.
+				aPtr=StoreTab(aPtr,currentTab);  // Store NULL'd currentTab
+				}
+			else
+				requiredTabCount++;
+			}
+		}
+	if (desiredLeftToDo)
+		{// Store remainder of desired tab list.
+		for (;offsetInDesired<aDesiredTabCount;offsetInDesired++)
+			{
+			if (aStoreData)
+				aPtr=StoreTab(aPtr,aDesiredFormat.TabStop(offsetInDesired));
+			else
+				requiredTabCount++;
+			}
+		}
+// ASSERT: The tabList offsets are as we would expect in a normal (correct) completion.	
+	__ASSERT_ALWAYS(offsetInDesired==aDesiredTabCount,Panic(EStoreTabError));
+	__ASSERT_ALWAYS(offsetInCurrent==aCurrentTabCount,Panic(EStoreTabError));
+	return requiredTabCount;
+	}
+
+
+// Writes all tabs from aSource.
+void RFormatStream::StoreAllTabs(TUint8*& aPtr,const CParaFormat& aSource)
+	{
+	int tabs = aSource.TabCount();
+	for (TInt index = 0;index < tabs; index++)
+		aPtr = StoreTab(aPtr,TTabStop(aSource.TabStop(index)));
+	}
+
+
+TUint8* RFormatStream::StoreBullet(TUint8* aPtr,const TBullet& aBullet)
+	{
+	// Write the attribute code and leave a gap for the length.
+	*aPtr++ = TUint8(EAttBullet);
+	TUint8* length_ptr = aPtr++;
+
+	// Store the font height.
+	Write32(aPtr,aBullet.iHeightInTwips);
+
+	// Store the bullet character code.
+	aPtr[0] = (TUint8)(aBullet.iCharacterCode);
+	aPtr[1] = (TUint8)(aBullet.iCharacterCode >> 8);
+	aPtr += sizeof(TText);
+
+	// Store the hanging indent
+	*aPtr++ = TUint8(aBullet.iHangingIndent != FALSE);
+
+	// Store the colour.
+	aPtr = Store(aPtr,aBullet.iColor);
+
+	// Store the typeface
+	aPtr = Store(aPtr,aBullet.iTypeface);
+
+	// Store the number of data bytes stored.
+	*length_ptr = (TUint8)(aPtr - length_ptr - 1);
+
+	return aPtr;
+	}
+
+
+TUint8* RFormatStream::StoreBorder(TUint8* aPtr,TTextFormatAttribute aType,const TParaBorder& aSource)
+// Stores paragraph border attributes.
+// Writes the line style, thickness,autoColor flag
+// and Color, from aSource to the end of the format stream.
+// aType is converted from an enum to a TUint8 as it is stored in the format stream.
+//
+	{
+	*aPtr++=TUint8(aType);
+	// border line style
+	*aPtr++=TUint8(aSource.iLineStyle);
+	// border line thickness
+	Write32(aPtr,aSource.iThickness);
+	// border color
+	aPtr=Store(aPtr,aSource.iColor);
+	// border autocolor
+	*aPtr++=TUint8(aSource.iAutoColor!=EFalse);
+	return aPtr;
+	}
+
+
+TUint8* RFormatStream::StoreTab(TUint8* aPtr,const TTabStop& aSource)
+// Stores a tabstop compound attribute at the end of the stream.
+// Writes the tabstop twips position and the tab type, from aSource, to the end of the format stream.
+// aType is converted from an enum to a TUint8 as it is stored in the format stream.
+// The tab type is compressed from a TTabType enum to a TUint8.
+// Uses InsertL, which may cause expansion of the stream storage, and thus may fail.
+//
+	{
+	*aPtr++=TUint8(EAttTabStop);
+	// Store tab poisition.
+	Write32(aPtr,aSource.iTwipsPosition);
+	// Compress the tab type.
+	*aPtr++=TUint8(aSource.iType);
+	return aPtr;
+	}
+
+
+TUint8* RFormatStream::Store(TUint8* aPtr,const TLogicalRgb& aRgb)
+   // Store color value
+   //
+   	{
+	*aPtr++=TUint8(aRgb.Red());
+	*aPtr++=TUint8(aRgb.Green());
+	*aPtr++=TUint8(aRgb.Blue());
+	return aPtr;
+   	}
+
+
+TUint8* RFormatStream::Store(TUint8* aPtr,const TTypeface& aTypeface)
+// Stores typeface name and flags.
+//
+	{
+	//
+	// Store typeface name size
+	TUint8 length=TUint8(aTypeface.iName.Size());
+	length+=KTypefaceFlags;
+	*aPtr++=length;  // byte count.
+	//
+	// Store typeface name
+	aPtr=Mem::Copy(aPtr,aTypeface.iName.Ptr(),length-KTypefaceFlags);
+	//
+	// Store typeface flags
+	TUint8 flags=0;
+	if (aTypeface.IsProportional())
+		flags|=KFontProportional;
+	if (aTypeface.IsSerif())
+		flags|=KFontSerif;	
+	if (aTypeface.IsSymbol())
+		flags|=KFontSymbol;
+	*aPtr=flags;
+	aPtr+=KTypefaceFlags;
+	//
+	return aPtr;
+	}
+
+TUint8* RFormatStream::ReadValue(TUint8* aPtr,TLogicalRgb& aRgb)const
+// Reads a color value from storage.
+//
+	{
+	aRgb.SetRed(*aPtr++);
+	aRgb.SetGreen(*aPtr++);
+	aRgb.SetBlue(*aPtr++);
+	aRgb.SetSystemColorIndex(0);
+	return aPtr;
+	}
+
+
+TUint8* RFormatStream::ReadValue(TUint8* aPtr,TParaBorder& aBorder)const
+// Reads a paragraph border from storage.
+//
+	{
+	// Read line style
+	aBorder.iLineStyle=TParaBorder::TLineStyle(*aPtr++);
+	// Read thickness
+	aBorder.iThickness = Read32(aPtr);
+	aPtr+=sizeof(TInt32);
+	// Read color
+	aPtr=ReadValue(aPtr,aBorder.iColor);  // returns aPtr
+	// Read autocolor
+	aBorder.iAutoColor=TBool(*aPtr++);
+	return aPtr;
+	}
+
+
+TUint8* RFormatStream::ReadValue(TUint8* aPtr,TBullet& aBullet)const
+// Read the bullet compound attribute.
+//
+	{
+	// Read the length of this bullet attribute
+	aPtr++;  // length not used in this context, skip it
+	// Read bullet twips height into target
+	aBullet.iHeightInTwips = Read32(aPtr);
+	aPtr+=sizeof(TInt32);
+	// Read bullet character code into target.
+	aBullet.iCharacterCode = (TText)aPtr[0] | ((TText)aPtr[1] << 8);
+	aPtr+=sizeof(TText);
+	// Read hanging indent.
+	aBullet.iHangingIndent=TBool(*aPtr++);
+	// Read Color.
+	aPtr=ReadValue(aPtr,aBullet.iColor);  // returns aPtr
+	// Read typeface
+	return ReadValue(aPtr,aBullet.iTypeface);  // returns aPtr
+	}
+
+
+TUint8* RFormatStream::ReadValue(TUint8* aPtr,TTypeface& aTypeface)const
+// Read a typeface name from storage and associated flags.
+//
+	{
+	//
+	// Read typeface name size
+	TInt length=*aPtr++;
+	//
+	// Read typeface name
+	TInt typefaceLength=length-KTypefaceFlags;
+	__ASSERT_DEBUG((typefaceLength%2)==0,Panic(ECorruptFormatLayer)); // must be an even number
+
+	TPtr name=aTypeface.iName.Des();
+	Mem::Copy(CONST_CAST(TText*,name.Ptr()),aPtr,typefaceLength);
+	typefaceLength>>=1;
+	name.SetLength(typefaceLength);
+
+	aPtr+=length-KTypefaceFlags;
+	//
+	// Read typeface name flags
+	TInt attrib=0;
+	TUint flags=*aPtr;
+	if (flags & KFontProportional)
+		attrib|=TTypeface::EProportional;
+	if (flags & KFontSerif)
+		attrib|=TTypeface::ESerif;
+	if (flags & KFontSymbol)
+		attrib|=TTypeface::ESymbol;
+	aTypeface.SetAttributes(attrib);  // reset the attributes
+	return aPtr+KTypefaceFlags;
+	}
+
+
+TUint8* RFormatStream::ReadTabL(TUint8* aPtr,CParaFormat& aTarget)const
+// Read the tab stop data from the stream, located at aPos, into 
+// a temporary TTabStop, and use this to fill in aTarget.
+// Does not read the tab if one already exists at the same twips position.
+// (Implementation of tab inheritance policy).
+// aPos is updated manually, rather than using Length(), since this is
+// a compound attribute.
+//
+	{
+	TTabStop tab;
+	// Read tab position
+	tab.iTwipsPosition = Read32(aPtr);
+	aPtr+=sizeof(TInt32);
+	// Read tab type
+	tab.iType=TTabStop::TTabType(*aPtr++);
+	// Set this tab in the paragraph format
+	TInt ret=aTarget.LocateTab(tab.iTwipsPosition);		// is this necessary
+	if (ret==KTabNotFound)
+		aTarget.StoreTabL(tab);
+	return aPtr;
+	}
+
+
+TInt RFormatStream::Length(TUint8*& aPtr,TTextFormatAttribute aType) const
+// Returns the length of a Type's value
+// A length of zero in the lookup table, indicates a variable
+// length value.  In this case, the length is stored in the byte
+// following the type, which is read and returned.
+// aPtr is incremented by the appropriate amount following a read.
+//
+	{
+	TInt length=TheAttributeLength[aType];
+
+	__ASSERT_DEBUG(length>=0,Panic(EAttributeLengthLookupNegative));
+	if (length>0)
+		return length;
+	else
+		return *aPtr++;
+	}