textrendering/texthandling/stext/TXTIXSTR.CPP
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/stext/TXTIXSTR.CPP	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,1574 @@
+/*
+* 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 <e32base.h>
+
+#include <gdi.h>
+
+#include "TXTFMLYR.H"
+#include "TXTMRTSR.H"
+#include "TXTRICH.H"
+#include "TXTINDEX.H"
+#include "TXTSTD.H"
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "TXTFMLYR_INTERNAL.H"
+#endif
+
+const TUint8 KRegisterItemPresent=1;
+
+
+GLDEF_C void DiscardPhraseOnCleanup(TAny* aPhrase)
+// Allows RPhraseAttribsEntry on the CleanupStack to be destroyed correctly,
+// when included as a PushL(TCleanupItem).
+//
+	{
+	((RPhraseAttribsEntry*)aPhrase)->Discard();
+	User::Free(aPhrase);
+	}
+
+
+TRtPasteContext::TRtPasteContext(const CStreamStore* aStore,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,const CStyleList* aStyleList)
+//
+	:iStore(aStore),
+	iGlobalParaLayer(aGlobalParaLayer),iGlobalCharLayer(aGlobalCharLayer),iStyleList(aStyleList),
+	iParagraphStylesFlag(EFalse),iIncompleteParaFlag(ETrue),iPastePos(),iParasPasted(0)
+	{}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+CRichTextIndex* CRichTextIndex::NewL(const CStreamStore& aStore,TStreamId aId,
+//										MPictureFactory* aPictureFactory,MRichTextStoreResolver* aStoreResolver,
+										const CParaFormatLayer* aGlobalParaLayer,
+										const CCharFormatLayer* aGlobalCharLayer,
+										const CRichText& aText)
+//										const CStyleList* aStyleList)
+//
+	{
+	CRichTextIndex* self=new(ELeave) CRichTextIndex(aText);
+	CleanupStack::PushL(self);
+	self->ConstructL(aGlobalParaLayer,aGlobalCharLayer,KMultiParaGranularity,KLargePhraseGranularity);
+	self->RestoreL(aStore,aId,aGlobalParaLayer,aGlobalCharLayer,aText.StyleList());
+//	self->SetPictureFactory(aPictureFactory,aStoreResolver);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+void CRichTextIndex::RestoreL(const CStreamStore& aStore,TStreamId aId,
+									   const CParaFormatLayer* aGlobalParaLayer,
+									   const CCharFormatLayer* aGlobalCharLayer,
+									   const CStyleList* aStyleList)
+//
+	{
+	RStoreReadStream stream;
+	stream.OpenLC(aStore,aId);
+	//
+	InternalizeL(stream,aGlobalParaLayer,aGlobalCharLayer,aStyleList);
+	CleanupStack::PopAndDestroy();  // stream
+	}
+
+
+TStreamId CRichTextIndex::StoreMarkupL(CStreamStore& aStore,const CStyleList* /*aStyleList*/) const
+// Store this rich text markup out-of-line along with its components.
+//
+	{
+	CStoreMap* map=CStoreMap::NewLC(aStore);
+	StorePicturesL(aStore,*map);
+//
+	RStoreWriteStream stream(*map);
+	TStreamId id=stream.CreateLC(aStore);
+//	CONST_CAST(CRichTextIndex*,this)->iStyleList=CONST_CAST(CStyleList*,aStyleList);
+	ExternalizeL(stream);
+	stream.CommitL();
+//
+	map->Reset();
+	CleanupStack::PopAndDestroy(2);  // map,stream
+	return id;
+	}
+
+
+void CRichTextIndex::StorePicturesL(CStreamStore& aStore,CStoreMap& aMap) const
+// Store any picture components in the specified store.
+// Due to deferred loading, any pictures that are not in memory at this point are loaded,
+// and then saved.
+//
+	{
+	__TEST_INVARIANT;
+
+	StorePicturesL(aStore,aMap,0,iText.DocumentLength()+1);
+	}
+
+
+void CRichTextIndex::StorePicturesL(CStreamStore& aStore,CStoreMap& aMap,TInt aPos,TInt aLength) const
+// Store all picture components that are contained within the specified range (inclusive), in the store provided.
+// Prior to storing the picture, its size is written to its picture header which is stored in-line in 
+// the markup.
+// Any pictures that are not in memory are now deleted, as a previous call to LoadAllPicturesNowL()
+// should have been made.
+// We are guaranteed that all pictures that are in memory are fully restored & detached from their store
+//
+	{
+	__TEST_INVARIANT;
+
+	if (iPictureCount==0)
+		return;
+	CONST_CAST(CRichTextIndex*,this)->DetachFromStoreL(CPicture::EDetachFull,aPos,aLength);	// ensure all pictures have been loaded
+	TInt currentPos=aPos;
+	DocumentChanged();  // reset the cache logical position
+	while (currentPos<aPos+aLength)
+		{// Store next picture & increment pos.
+		CONST_CAST(CRichTextIndex*,this)->ScanToPosition(currentPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed));
+		TCurrentIndexRecords current;
+		GetCurrentRecords(current);
+		if (current.iPhrase && current.iPhrase->IsPicturePhrase())
+			{
+			RPhraseAttribsEntry& phrase=*current.iPhrase;
+			TPictureHeader* hdr=phrase.PictureHeaderPtr();
+			__ASSERT_DEBUG(hdr,Panic(ERichTextStorePictureIntegrityError));
+			TBool pictureInMemory=(hdr->iPicture.IsPtr() && hdr->iPicture.AsPtr());
+			if (pictureInMemory)
+				{// Store the picture
+				CPicture& picture=*hdr->iPicture;
+				picture.GetSizeInTwips(hdr->iSize);  //  write picture size to picture header.
+				TStreamId id=picture.StoreL(aStore);
+				aMap.BindL(hdr->iPicture,id);
+				}
+			else
+				{// Replace the picture phrase with a simple text equivalent.
+				CCharFormatLayer* charLayer=phrase.ReleaseCharFormatLayerOwnership();
+				phrase.Discard();  // destroy the redundant picture phrase
+				RPhraseAttribsEntry newTextPhrase(charLayer,1);
+				(*iPhraseIx)[iPos.iPhraseElement]=newTextPhrase;
+				CONST_CAST(CRichTextIndex*,this)->iPictureCount--;  // the picture has now been removed
+				// I do not bother tidying up the phrase index here,
+				// since the benefit does not currently match the cost involved.
+				//
+				}
+			}
+		//
+		// increment the current position to the *start* of the next phrase/paragraph
+		TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
+		currentPos+=CurrentPhraseLength()-offsetIntoUnit;
+		}
+	}
+
+
+void CRichTextIndex::DetachFromStoreL(CPicture::TDetach aDegree,TInt aPos,TInt aLength)
+// Attempts to restore all pictures not already present in memory.
+// A deep (door+document) or shallow (door only) restoration may occur, depending
+// on the value of detach.
+//
+	{
+	__TEST_INVARIANT;
+
+	if (iPictureCount==0)
+		return;
+	DocumentChanged();  // reset the cache logical position
+	TInt currentPos=aPos;
+	while (currentPos<aPos+aLength)
+		{
+		CONST_CAST(CRichTextIndex*,this)->ScanToPosition(currentPos,EScanToPositionAbsolute,&iLastUsed);
+		TCurrentIndexRecords current;
+		GetCurrentRecords(current);
+		if (current.iPhrase)
+			{
+			RPhraseAttribsEntry& phrase=*current.iPhrase;
+			if (phrase.IsPicturePhrase())
+				{
+				TPictureHeader* hdr=phrase.PictureHeaderPtr();
+				__ASSERT_DEBUG(hdr,Panic(ERichTextStorePictureIntegrityError));
+				//
+				if (hdr->iPicture.IsId())
+					{
+					TRAPD(r,
+					phrase.PictureHandleL(iText.PictureFactory(),iText.StoreResolver(),iPos.iDocPos,MLayDoc::EForceLoadTrue));  // swizzles
+					__ASSERT_DEBUG(r==KErrNone || hdr->iPicture.IsId(),Panic(ERichTextStorePictureIntegrityError));
+					if (r==KErrNotSupported)  // we don't recognise the picture type
+						{
+						TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
+						currentPos+=CurrentPhraseLength()-offsetIntoUnit;
+						continue;
+						}
+					User::LeaveIfError(r);
+					}
+				//
+				// recurse the call to detach the picture from the store
+				__ASSERT_DEBUG(hdr->iPicture.IsPtr(),Panic(ERichTextStorePictureIntegrityError));
+				hdr->iPicture->DetachFromStoreL(aDegree);
+				}
+			}
+		//
+		// increment the current position to the *start* of the next phrase/paragraph
+		TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
+		currentPos+=CurrentPhraseLength()-offsetIntoUnit;
+		}
+	__TEST_INVARIANT;
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+void CRichTextIndex::ExternalizeL(RWriteStream& aStream)const
+// Persist the current state of this object in the specified stream.
+// Saved records include the terminating paragraph delimiter. 
+//
+//
+	{
+	__TEST_INVARIANT;
+
+	CONST_CAST(CRichTextIndex*,this)->CancelInsertCharFormat();  // cancel any insert-pending state.
+	TInt charCount=iText.DocumentLength()+1;  // includes the end of document character
+	((CRichTextIndex*)this)->ScanToPosition(0,EScanToPositionAbsolute);
+	TLogicalPosition startPos=iPos;
+	((CRichTextIndex*)this)->ScanToPosition(charCount-1,EScanToPositionMatchLeft);
+	TLogicalPosition endPos=iPos;
+	CStyleList* styleList=iText.StyleList();
+	ExternalizeRtiHeaderL(aStream,endPos,styleList);
+	ExternalizeSharedFormatsL(aStream,startPos,endPos,styleList);
+	// DEF126934 begin: memory leak
+	RPhraseAttribsEntry *pForRelease = ExternalizeParaIxL(aStream,startPos,endPos,styleList);
+	if (pForRelease)
+		delete pForRelease;
+	// DEF126934 end
+	ExternalizePhraseIxL(aStream);
+	}
+
+
+void CRichTextIndex::InternalizeL(RReadStream& aStream,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,const CStyleList* aStyleList)
+// Load a rich text index.  Has construct semantics only!
+// Restores this object from the specified stream.  As specific format layers are restored, they are based
+// on the specified global format layers. 
+//
+	{
+	__ASSERT_ALWAYS(iParaIx->Count()==1 && (*iParaIx)[0].iLength==1,Panic(ERtIndexInternalizeCalledOnNonEmptySource));
+	TRtPasteContext context(NULL,aGlobalParaLayer,aGlobalCharLayer,aStyleList);
+	InternalizeRtiHeaderL(aStream,context);
+	InternalizeSharedFormatsL(aStream,context);
+	InternalizeParaIxL(aStream,context);
+	InternalizePhraseIxL(aStream,aGlobalCharLayer);
+	if (context.iParagraphStylesFlag)
+		GenerateAllPhraseLinksL();
+	SetSpecificMarkupInternalized(ETrue);
+
+	__TEST_INVARIANT;
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+void CRichTextIndex::GenerateAllPhraseLinksL()
+// Go through the index, and for each specific character format layer (shared or otherwise), regenerate
+// the appropriate based-on link, (normal or style).
+// 
+	{
+	TInt count=ParagraphCount();
+	TInt phraseElement=0;
+	for (TInt ii=0; ii<count; ii++)
+		{
+		const CParaAttribs& paraAttribs=*(*iParaIx)[ii].iParaAttribs;
+		const CParaFormatLayer* base=STATIC_CAST(const CParaFormatLayer*,paraAttribs.iParaFormat->SenseBase());
+		TInt phraseCount=paraAttribs.PhraseCount();
+		if (phraseCount==1)
+			{
+			// If the reference count is zero, iCharFormat cannot be valid, so the CParaAttribs object is corrupt.
+			if (paraAttribs.iRefCount == 0)
+				User::Leave(KErrCorrupt);
+
+			GeneratePhraseLink(paraAttribs.iCharFormat,base);  // constant character formatting
+			}
+		else
+			{
+			 __ASSERT_DEBUG(phraseCount>1,Panic(EDebug));
+
+			// If the phrase count is too great the CParaAttribs object is corrupt.
+			if (phraseElement + phraseCount > iPhraseIx->Count())
+				User::Leave(KErrCorrupt);
+
+			for (TInt nn=0; nn<phraseCount; nn++)
+				GeneratePhraseLink((*iPhraseIx)[phraseElement+nn].CharFormat(),base);
+			phraseElement+=phraseCount;
+			}
+		}
+	}
+
+
+void CRichTextIndex::GeneratePhraseLink(CCharFormatLayer* aPhraseCharFormatLayer,const CParaFormatLayer* aBase)
+// Set the based on link for this character format layer appropriately.
+// By default, all specific character format layers are based on the global default.
+//
+	{
+	TUid type=aBase->Type();
+	if (type!=KNormalParagraphStyleUid)
+		aPhraseCharFormatLayer->SetBase(((CParagraphStyle*)aBase)->CharFormatLayer());
+	}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+void CRichTextIndex::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength, TBool aCopyStyles)const
+// Copies the markup corresponding to the specified rich text region to the specified write stream.
+// aPos/aLength has already been validated in RichText
+// Saved records can NOT include the terminating paragraph delimiter.
+//
+	{
+	__TEST_INVARIANT;
+
+	((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute);
+	TLogicalPosition startPos=iPos;
+	((CRichTextIndex*)this)->ScanToPosition((aPos+aLength)-1,EScanToPositionAbsolute);
+	TLogicalPosition endPos=iPos;
+
+	CStyleList* docStyleList = NULL;
+	if (aCopyStyles)
+		docStyleList = (CStyleList*)iText.StyleList();
+
+	ExternalizeRtiHeaderL(aStream,endPos,docStyleList);
+	
+	if (docStyleList)
+		ExternalizeReferencedStylesL(aStream,startPos,endPos);
+	
+	ExternalizeSharedFormatsL(aStream,startPos,endPos,docStyleList); 
+	RPhraseAttribsEntry* virtualTrailingText=ExternalizeParaIxL(aStream,startPos,endPos,docStyleList);
+	if (virtualTrailingText)
+	    CleanupStack::PushL(virtualTrailingText);
+	ExternalizePhraseIxL(aStream,startPos,endPos,virtualTrailingText);
+	if (virtualTrailingText)
+	    CleanupStack::PopAndDestroy(virtualTrailingText);
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+
+void CRichTextIndex::ExternalizeRtiHeaderL(RWriteStream& aStream,const TLogicalPosition& aEnd,const CStyleList* aStyleList)const
+// Stores index specific information.
+//
+	{
+	TBool incompleteParaFlag=((*iParaIx)[aEnd.iParaElement].iLength>(aEnd.iParaElementOffset+1));
+	aStream.WriteUint8L((TUint8)(aStyleList!=NULL));  // flags the presence of paragraph styles.
+	aStream.WriteUint8L((TUint8)(incompleteParaFlag!=EFalse)); // the last para has no paragraph delimiter
+	if(incompleteParaFlag)
+		{//apply paragraph format to final text fragment if logical end is at document end
+		aStream.WriteUint8L((TUint8)(aEnd.iDocPos+1 == iText.DocumentLength()));
+		}
+	}
+
+
+void CRichTextIndex::InternalizeRtiHeaderL(RReadStream& aStream,TRtPasteContext& aContext)
+// Load index specific information.
+//
+	{
+	TUint8 flag=0;
+	aStream>> flag;
+	aContext.iParagraphStylesFlag=(TBool)flag;
+	aStream>> flag;
+	aContext.iIncompleteParaFlag=(TBool)flag;
+	aContext.iApplyFormatToLastFlag=EFalse;
+	if(aContext.iIncompleteParaFlag)
+		{
+		aStream>> flag;
+		aContext.iApplyFormatToLastFlag=(TBool)flag;
+		}
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////
+                                                                                                                     
+void CRichTextIndex::ExternalizeReferencedStylesL(RWriteStream& aStream,const TLogicalPosition& aStart,
+												  const TLogicalPosition& aEnd) const
+// Write those styles that are referenced by the paragraphs in the range aStart to aEnd.
+//
+	{
+	CStyleList* list = iText.StyleList();
+	__ASSERT_DEBUG(list,Panic(EStyleClipboardIntegrityError));
+	__ASSERT_DEBUG(aStart.iParaElement <= aEnd.iParaElement,Panic(EStyleClipboardIntegrityError));
+
+	TUint8 numStyles = 0;
+	if (list) 
+		numStyles = (TUint8)list->Count();
+
+	HBufC8* buf=HBufC8::NewL(numStyles);
+	TPtr8 paraRegister=buf->Des();
+	paraRegister.FillZ(numStyles);
+	TInt refCount=MarkStyleRegister(paraRegister,aStart.iParaElement,aEnd.iParaElement);
+	CleanupStack::PushL(buf);
+	ExternalizeItemsPresentInStyleRegisterL(aStream,refCount,paraRegister);
+	CleanupStack::PopAndDestroy();
+	}
+
+
+void CRichTextIndex::InternalizeSharedFormatsL(RReadStream& aStream, const TRtPasteContext& aContext)
+// Restores the list of shared para attribs.
+// All existing CParaAttribs on the shared list are removed.
+// The reference counts are not restored, but modified dynamically as the para index is loaded.
+//
+	{
+	iParaIx->Reset();  // stops paraIx referencing shared paraAttribs that are about to be released.
+	CParaAttribs* currentSharedPara;
+	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
+	while ( (currentSharedPara = iterator++) != NULL )
+		currentSharedPara->Release(currentSharedPara->iRefCount);
+	TUint8 sharedParaCount = ReadTUint8CountL(aStream);
+	for (TUint8 paraItem = 0; paraItem < sharedParaCount; paraItem++)
+		{
+		(void)aStream.ReadInt32L();  // consume the data.
+		CParaFormatLayer* paraLayer = InternalizeParagraphFormatL(aStream, aContext);
+		CleanupStack::PushL(paraLayer);
+
+		CCharFormatLayer* charLayer = CCharFormatLayer::NewL(aStream);  // Does not restore based on link.
+		charLayer->SetBase(aContext.iGlobalCharLayer);  // base on 'Normal' global char format
+		CleanupStack::PushL(charLayer);
+		CParaAttribs* paraAttribs = CParaAttribs::NewL(paraLayer, charLayer);
+		CleanupStack::PopAndDestroy(2);
+		paraAttribs->iRefCount = 0;  // Otherwise recalculating reference counts on internalization of paraIx will result in 1 too many.
+		iSharedParaQueHead.AddLast(*paraAttribs);
+		}
+	}
+
+
+void CRichTextIndex::ExternalizeSharedFormatsL(RWriteStream& aStream,const TLogicalPosition& aStart,const TLogicalPosition& aEnd,const CStyleList* aStyleList)const
+// Persist those items in the shared list that are referenced by the paragraphs in the 
+// range aStart para to aEnd para.
+//
+	{
+	TUint8 sharedParaCount=SharedParaAttribsEntryCountL();
+	// Some paras coverd, so take register
+	HBufC8* buf=HBufC8::NewL(sharedParaCount);
+	TPtr8 sharedAttribsRegister=buf->Des();
+	sharedAttribsRegister.FillZ(sharedParaCount);
+	TInt sharedCount=MarkRegister(sharedAttribsRegister,aStart.iParaElement,aEnd.iParaElement);
+	CleanupStack::PushL(buf);
+	ExternalizeItemsPresentInRegisterL(aStream,sharedCount,sharedAttribsRegister,aStyleList);
+	CleanupStack::PopAndDestroy();
+	}
+
+
+TUint8 CRichTextIndex::SharedParaAttribsEntryCountL()const
+// Return a count of the number of items currently
+// in the sharedParaFormats list.
+//
+// This will leave if more than 255 found, as this is not supported
+	{
+	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
+	TUint16 sharedParaCount = 0;
+	while (iterator++ != NULL)
+		sharedParaCount++;
+		
+	// Currently more than 255 paragraph formats are not supported 
+	// If the current document has more, leave with KErrNotSupported
+	if (sharedParaCount > 255)
+		User::Leave(KErrNotSupported);
+	
+	return (TUint8)sharedParaCount;
+	}
+
+
+TInt CRichTextIndex::MarkRegister(TDes8& aBuf,TInt aStartPara,TInt aEndPara)const
+// Indicate in the register, aBuf, once and once only, each paraAttribs that is
+// referenced by each of the paragraphs in the specified range.
+// Return the number of shared para formats referenced.
+//
+	{
+	TInt parasReferenced=0;
+	for (TInt item=aStartPara;item<=aEndPara;item++)
+		{
+		CParaAttribs* paraAttribs=(*iParaIx)[item].iParaAttribs;
+		TInt offset=RefNum(paraAttribs);  // 0 return shows para attribs not in shared list
+		if (offset>0)
+			{// para entry references a shared para attribs
+			if (aBuf[offset-1]==0)
+				{
+				aBuf[offset-1]=KRegisterItemPresent;  // mark item as needing to be stored
+				parasReferenced++;
+				}
+			}
+		}
+	return parasReferenced;
+	}
+
+
+TInt CRichTextIndex::MarkStyleRegister(TDes8& aBuf,TInt aStartPara,TInt aEndPara)const
+// Indicate in the register, aBuf, once and once only, each paragraph style thar is
+// referenced by each of the paragraphs in the speciifed range.
+// Return the umber of paragraph styles referenced.
+//
+	{
+	TInt stylesReferenced=0;
+	const CParaAttribs* para=NULL;
+	for (TInt item=aStartPara;item<=aEndPara;item++)
+		{
+		para=(*iParaIx)[item].iParaAttribs;
+		TInt index=iText.StyleList()->IndexByPtr(STATIC_CAST(const CParaFormatLayer*,para->iParaFormat->SenseBase()));
+		if (index!=KErrNotFound)
+			{
+			__ASSERT_DEBUG(index<aBuf.Length(),Panic(EStyleClipboardIntegrityError));
+			if (aBuf[index]!=KRegisterItemPresent)
+				{
+				aBuf[index]=KRegisterItemPresent;  // mark item as needing to be stored
+		
+				stylesReferenced++;
+				}
+			}
+		}
+	return stylesReferenced;
+	}
+
+
+void CRichTextIndex::ExternalizeItemsPresentInRegisterL(RWriteStream& aStream,TInt aSharedCount,const TDes8& aBuf,const CStyleList* aStyleList)const
+// Externalize each object from the shared list that has a corresponding mark in the
+// register, aBuf.
+//
+	{
+	__ASSERT_DEBUG(aSharedCount<=(TInt)KMaxTUint8,Panic(ESharedParaCountStreamOverflow));
+	aStream.WriteUint8L(aSharedCount);
+	CParaAttribs* currentSharedPara=NULL;
+	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
+	TInt offset=0;
+	while ((currentSharedPara=iterator++)!=NULL)
+		{
+		if (aBuf[offset]==KRegisterItemPresent)
+			{
+			aStream.WriteInt32L(offset+1);  // the ref-no of the shared para - so it can be spotted in the paste.
+			ExternalizeParagraphFormatL(aStream,*currentSharedPara->iParaFormat,aStyleList);
+			aStream<< *currentSharedPara->iCharFormat;
+			}
+		offset++;
+		}
+	}
+
+
+void CRichTextIndex::ExternalizeItemsPresentInStyleRegisterL(RWriteStream& aStream,TInt aRefStyleCount,
+															 const TDes8& aBuf) const
+// Externalize each object from the paragraph style list that has a corresponding mark in the register aBuf.
+//
+	{
+	__ASSERT_DEBUG(aRefStyleCount <= (TInt)KMaxTUint8,Panic(EStyleClipboardIntegrityError));
+	aStream.WriteUint8L(aRefStyleCount);
+	TInt count=aBuf.Length();
+
+	for (TInt ii=0;ii<count;ii++)
+		{
+		if (aBuf[ii]==KRegisterItemPresent)
+			{
+			aStream.WriteInt8L(ii+1);  // cannot use 0 index as this represents an absence.
+			iText.StyleList()->At(ii).iStyle->ExternalizeL(aStream);
+			}
+		}
+  }
+
+
+RPhraseAttribsEntry* CRichTextIndex::ExternalizeParaIxL(RWriteStream& aStream,
+										const TLogicalPosition& aStart,
+										const TLogicalPosition& aEnd,
+										const CStyleList* aStyleList)const
+// Externalize each para entry from the para index that falls between 
+// aStart paragraph and aEnd paragraph inclusive.
+// Any specific paraAttribs (ie not on the shared list) are also externalized.
+// * paragraph count
+// * 	paragraph length
+// *	ref no.  (ref no. 0 means specific/non-shared one)
+// *	[specific paragraph format layer - including based-on link]
+// *	[specific phrase count]
+//
+	{
+	TParaAttribsEntry lastParaEntry=(*iParaIx)[aEnd.iParaElement];
+	TBool incompleteParaFlag=(lastParaEntry.iLength>(aEnd.iParaElementOffset+1));
+	aStream.WriteInt32L(1+aEnd.iParaElement-aStart.iParaElement);  // paragraph count
+	for (TInt paraItem=aStart.iParaElement;paraItem<aEnd.iParaElement;paraItem++)
+		{// Externalize all but last TParaAttribsEntrys from the para index
+		TParaAttribsEntry paraEntry=(*iParaIx)[paraItem];
+		TInt phraseCount=(paraEntry.iParaAttribs->IsShared()) 
+			? 0 
+			: paraEntry.iParaAttribs->iPhraseCount;
+		if (paraItem==aStart.iParaElement)
+			{// Fix & write length & phrase count of the first paragraph.
+			paraEntry.iLength=(paraEntry.iLength-aStart.iParaElementOffset);  // fix 1st para length
+			if (phraseCount>0)
+				phraseCount=phraseCount-(aStart.iPhraseElement-aStart.iParaBasePhraseElement);
+			}
+		aStream.WriteInt32L(paraEntry.iLength);
+		CParaAttribs* paraAttribs=paraEntry.iParaAttribs;
+		TUint8 refNo=RefNum(paraAttribs);
+		aStream.WriteUint8L(refNo);
+		if (refNo==0)
+			{// Write specific para layer & phrase count
+			ExternalizeParagraphFormatL(aStream,*paraAttribs->iParaFormat,aStyleList);
+			aStream.WriteInt32L(phraseCount);
+			}
+		}
+	// Fix & write the length of the last paragraph.
+	if (aStart.iParaElement==aEnd.iParaElement)
+		lastParaEntry.iLength=(aEnd.iParaElementOffset-aStart.iParaElementOffset)+1;  // copied text contained within 1 para
+	else
+		lastParaEntry.iLength-=(lastParaEntry.iLength-aEnd.iParaElementOffset)-1;
+	aStream.WriteInt32L(lastParaEntry.iLength);
+	// Fix & write the phrase count of the last paragraph if it has specific char format
+	CParaAttribs* lastParaAttribs=lastParaEntry.iParaAttribs;
+	TUint8 refNo=RefNum(lastParaAttribs);
+	RPhraseAttribsEntry* virtualTextPhrase=NULL;
+	if (incompleteParaFlag)
+		{// Adjust the phrase count for this paragraph that is not complete
+		TInt phraseCount=0;
+		if (aStart.iParaElement==aEnd.iParaElement)
+			phraseCount=(aEnd.iPhraseElement-aStart.iPhraseElement)+1;  // copied text contained within 1 para
+		else
+			phraseCount=(aEnd.iPhraseElement-aEnd.iParaBasePhraseElement)+1;
+		__ASSERT_DEBUG(phraseCount<=lastParaAttribs->iPhraseCount,Panic(ERtExternalizeParaIx));
+		aStream.WriteInt32L(phraseCount);
+		if (refNo>0)
+			{// Set the virtual phrase representing the trailing text from the shared paragraph.
+			virtualTextPhrase=new(ELeave) RPhraseAttribsEntry(lastParaAttribs->iCharFormat,lastParaEntry.iLength);
+			CleanupStack::PushL(virtualTextPhrase);
+			}
+
+		// Write out the paragraph format for the paragraph that is not complete
+		// - necessary since we need to patch up the style character formatting
+		if (aStyleList || aEnd.iDocPos+1 == iText.DocumentLength())
+			ExternalizeParagraphFormatL(aStream, *lastParaAttribs->iParaFormat, aStyleList);
+		}
+	else
+		{// This is a complete para - copy region ends on a paragraph delimiter.
+		aStream.WriteUint8L(refNo);
+		if (refNo==0)
+			{// Write specific para layer & phrase count
+			ExternalizeParagraphFormatL(aStream,*lastParaAttribs->iParaFormat,aStyleList);
+			TInt phraseCount=lastParaAttribs->iPhraseCount;
+			if (aStart.iParaElement==aEnd.iParaElement && aStart.iParaElementOffset && aStart.iParaElementOffset>0)
+				phraseCount=(aEnd.iPhraseElement-aStart.iPhraseElement)+1;  // copied text contained within 1 para
+			aStream.WriteInt32L(phraseCount);
+			}
+		}
+	if (virtualTextPhrase)
+	    CleanupStack::Pop(virtualTextPhrase);
+	return virtualTextPhrase;
+	}
+
+
+void CRichTextIndex::ExternalizeParagraphFormatL(RWriteStream& aStream,const CParaFormatLayer& aLayer,const CStyleList* aStyleList)const
+// If a style list is present, write out the based-on links for every paragraph format layer,
+// in order to reconnect each paragraph to the right style on loading.
+//
+	{
+	aStream<< aLayer;
+	if (aStyleList)
+		{
+		TInt refNo=0;
+		refNo=aStyleList->IndexByPtr(((CParaFormatLayer*)aLayer.SenseBase()));
+		// returns the offset in the style list, or a negative error.
+		//
+		refNo=(refNo!=KErrNotFound)
+			? refNo+1  // the nth style where 1st item is offset 1.
+			: 0;  // An error value was returned so this thing has no paragraph style as its base
+		aStream.WriteInt8L((TInt8)-refNo);
+		}
+ 	}
+
+
+CParaFormatLayer* CRichTextIndex::InternalizeParagraphFormatL(RReadStream& aStream,const TRtPasteContext& aContext)
+// 
+	{
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(aStream);  // specific paragraph format layer
+	TUint index=0;
+	if (aContext.iParagraphStylesFlag)
+		{
+		CleanupStack::PushL(paraLayer);
+		TInt refNo=aStream.ReadInt8L();  // Read in the based on link to fix up to the style table
+		CleanupStack::Pop();
+		index=Abs(refNo);
+		}
+	if (index>0 && aContext.iStyleList)
+		paraLayer->SetBase(aContext.iStyleList->At(index-1).iStyle);
+	else
+		paraLayer->SetBase(aContext.iGlobalParaLayer);
+	return paraLayer;
+	}
+
+
+CParaFormatLayer* CRichTextIndex::PasteParagraphFormatL(RReadStream& aStream,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
+// 
+	{
+	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(aStream);  // specific paragraph format layer
+ 
+	TUint index=0;
+	if (aContext.iParagraphStylesFlag)
+		{
+		CleanupStack::PushL(paraLayer);
+		TInt refNo=aStream.ReadInt8L();  // Read in the based on link to fix up to the style table
+		CleanupStack::Pop(paraLayer);	// paraLayer
+		index=Abs(refNo);
+		}
+
+	// If a style exists for this paragraph, set it as the base.
+	// If a style list doesn't exist, the base paragraph style will be set instead.
+	
+	if (index>0 && aContext.iStylePasteMode != CParagraphStyle::EIgnoreNewStyles)
+	{
+		if (!aContext.iStyleList || (aContext.iStyleList && aContext.iStylePasteMode == CParagraphStyle::EConvertNewStyles))
+		{
+			CleanupStack::PushL(paraLayer);
+			iLastCharacterStyle = (aStyleMap->Item(index))->iCharFormatLayer;
+
+			// If the application doesn't have a style list, 
+			// the new paragraph style has to be enforced by merging the old
+			// paralayer with the style paralayer
+			CParaFormat* MergedParaFormat = CParaFormat::NewLC();
+			TParaFormatMask MergedParaFormatMask;
+
+			CParaFormatLayer* newParaLayer;
+
+			// Extract the masks from both layers
+			paraLayer->SenseL(MergedParaFormat, MergedParaFormatMask);
+			(aStyleMap->Item(index))->SenseL(MergedParaFormat, MergedParaFormatMask);
+
+			newParaLayer = CParaFormatLayer::NewL(MergedParaFormat, MergedParaFormatMask);
+
+			// Now on stack: MergedParaFormat, paraLayer, ...
+			CleanupStack::PopAndDestroy();	// delete MergedParaFormat
+
+			// Now on stack: paraLayer, ...
+			CleanupStack::PopAndDestroy();	// paraLayer
+			paraLayer = newParaLayer;
+
+			paraLayer->SetBase(aContext.iGlobalParaLayer);
+
+		}
+		else 
+		{
+			paraLayer->SetBase(aStyleMap->Item(index));		
+			iLastCharacterStyle = NULL;
+		}
+	}
+	else 
+	// Otherwise set the character style to NULL, which will set the global
+	// character style (see line 983 approx)
+	{
+		iLastCharacterStyle = NULL;
+		paraLayer->SetBase(aContext.iGlobalParaLayer);
+	}
+		
+	return paraLayer;
+	}
+
+
+void CRichTextIndex::InternalizeParaIxL(RReadStream& aStream,const TRtPasteContext& aContext)
+// Restore the paragraph index & all associated specific para formats,
+// All existing index data is lost.
+//
+	{
+	// The para index has been reset at the start of internalize shared formats.
+	TInt paraIxCount=aStream.ReadInt32L();  // paragraph count
+	for (TInt currentPara=0;currentPara<paraIxCount;currentPara++)
+		{// Restore each paragraph
+		TParaAttribsEntry para;
+		para.iLength=aStream.ReadInt32L();  // paragraph length
+		TUint8 refNo=aStream.ReadUint8L();  // ref no
+		if (refNo>0)
+			{// Link to para attribs in shared list & up its reference count
+			para.iParaAttribs=SharedParaAttribs(refNo);
+			para.iParaAttribs->iRefCount++;
+			iParaIx->AppendL(para);
+			}
+		else
+			{// Have to build up the specific para attribs
+			CParaFormatLayer* paraLayer=InternalizeParagraphFormatL(aStream,aContext);
+			CleanupStack::PushL(paraLayer);
+			CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
+				CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
+			specificParaAttribs->iPhraseCount=aStream.ReadInt32L();  // specific phrase count
+				CleanupStack::Pop();	// specificParaAttribs
+			CleanupStack::PopAndDestroy(); // paraLayer
+			para.iParaAttribs=specificParaAttribs;
+			CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
+			iParaIx->AppendL(para);
+			CleanupStack::Pop();  // specificParaAttribs
+			}
+		}
+	}
+
+void CRichTextIndex::ExternalizePhraseIxL(RWriteStream& aStream)const
+// Called from an Externalize.
+// All phrases must be saved.
+//
+	{ExternalizePhrasesL(aStream,0,PhraseCount());}
+
+
+void CRichTextIndex::ExternalizePhraseIxL(RWriteStream& aStream,
+										  const TLogicalPosition& aStart,
+										  TLogicalPosition& aEnd,
+										  const RPhraseAttribsEntry* aVirtualTrailingText)const
+// Called from CopyToStream.
+// Here, a text fragment only, is to be saved.
+// The last argument may be NULL.  If it is other than NULL, it represents trailing text
+// that has no paragraph delimiter, which was part of a shared paragraph.  This must be presented as
+// a distinct phrase, since this is the context in which it is pasted back into a document.
+//
+	{
+	TInt phraseCount=PhraseCount();
+	phraseCount+=(aVirtualTrailingText) ? 1 : 0;
+	TBool noRealPhrasesInRegion=ETrue;
+	TInt nn=aStart.iParaElement;
+	while (nn<=aEnd.iParaElement && noRealPhrasesInRegion)
+		{
+		if (!(*iParaIx)[nn].iParaAttribs->IsShared())
+			noRealPhrasesInRegion=EFalse;
+		nn++;
+		}
+	//
+	if (phraseCount==0 || (phraseCount==1 && aVirtualTrailingText || noRealPhrasesInRegion))  // save this phrase count
+		ExternalizePhrasesL(aStream,aStart.iPhraseElement,0,aVirtualTrailingText);
+	else
+		{
+		TBool endParaShared=(*iParaIx)[aEnd.iParaElement].iParaAttribs->IsShared();
+		if (endParaShared && aEnd.iPhraseElement>0)
+			aEnd.iPhraseElement--;  // Due to action of ScanToPosition
+		//
+		RPhraseAttribsEntry* backPhrase=&(*iPhraseIx)[aEnd.iPhraseElement];
+		TInt backLength=backPhrase->Length();
+		if (!(endParaShared || backPhrase->IsPicturePhrase()))
+			backPhrase->SetLength(aEnd.iPhraseElementOffset+1);
+		//
+		RPhraseAttribsEntry* frontPhrase=&(*iPhraseIx)[aStart.iPhraseElement];
+		TInt frontLength=frontPhrase->Length();
+		if (!frontPhrase->IsPicturePhrase())  // Fix length of first phrase.
+			frontPhrase->SetLength(frontLength-aStart.iPhraseElementOffset);
+		TRAPD(ret,
+			ExternalizePhrasesL(aStream,aStart.iPhraseElement,aEnd.iPhraseElement-aStart.iPhraseElement+1,aVirtualTrailingText));
+		//
+		// Now fix the altered phrase lengths.
+		if (!frontPhrase->IsPicturePhrase())
+			frontPhrase->SetLength(frontLength);
+		if (!(endParaShared || backPhrase->IsPicturePhrase()))
+			backPhrase->SetLength(backLength);
+
+		__TEST_INVARIANT;	// we lied about being const
+
+		User::LeaveIfError(ret);
+		}
+	}
+
+
+void CRichTextIndex::ExternalizePhrasesL(RWriteStream& aStream,TInt aStart,TInt aPhraseCount,
+										 const RPhraseAttribsEntry* aVirtualPhrase)const
+// Save the specified number of phrases present in the phrase index,
+// starting from phrase offset aStart.
+//
+	{
+	ExternalizePhraseCountL(aStream,aPhraseCount+ ((aVirtualPhrase)?1:0) );
+	for (TInt phraseItem=aStart;phraseItem<aStart+aPhraseCount;phraseItem++)
+		{
+		RPhraseAttribsEntry& phraseEntry=(*iPhraseIx)[phraseItem];
+		aStream<< phraseEntry;
+		}
+	if (aVirtualPhrase)
+		aStream<< *aVirtualPhrase;
+	}
+
+
+void CRichTextIndex::InternalizePhraseIxL(RReadStream& aStream,const CCharFormatLayer* aGlobalCharFormat)
+// Load all the phrases from the stream, and insert them into the phrase index
+//
+	{
+	iPhraseIx->Reset();
+	TInt phraseCount=aStream.ReadInt32L();
+
+	// Extend phrase index by required amount
+	iPhraseIx->AppendL(RPhraseAttribsEntry(),phraseCount);
+	
+	for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++)
+		{// Restore each phrase & insert into the phrase index.
+		TBool isPicture=(TBool)aStream.ReadUint8L();
+		TInt phraseLength=aStream.ReadInt32L();
+		CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);
+		charLayer->SetBase(aGlobalCharFormat);
+		RPhraseAttribsEntry& tPhrase=iPhraseIx->At(phraseItem);
+		if (!isPicture)
+			new(&tPhrase) RPhraseAttribsEntry(charLayer,phraseLength);
+		else
+			{// Manufacture new picture header & set its picture store
+			CleanupStack::PushL(charLayer);
+			TPictureHeader hdr;
+			aStream>> hdr;
+			TBool ownershipTaken(EFalse);
+			CPicturePhrase* picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken);
+			CleanupStack::Pop();  // char layer
+			new(&tPhrase) RPhraseAttribsEntry(picPhrase);
+			iPictureCount++;
+			}
+		}
+	}
+
+
+CParaAttribs* CRichTextIndex::SharedParaAttribs(TUint8 aOrdinal)
+// Return the handle of the para attribs in the shared para attribs list,
+// whose position in the list is specified by the argument aOrdinal.
+//
+	{
+	CParaAttribs* currentSharedPara;
+	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
+	TInt match=1;
+	while ((currentSharedPara=iterator++)!=NULL && aOrdinal!=match)
+		match++;
+	__ASSERT_ALWAYS(currentSharedPara!=NULL,Panic(EEndOfSharedParaListEncountered));
+	return currentSharedPara;
+	}
+
+
+TUint8 CRichTextIndex::RefNum(const CParaAttribs* aParaAttribs)const
+// If the para attribs argument is present in the shared list, return a 
+// reference to it; otherwise return zero as the reference.
+//
+	{
+	CParaAttribs* currentSharedPara;
+	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
+	TUint8	 refNo=1;
+	while ((currentSharedPara=iterator++)!=NULL)
+		{
+		if (currentSharedPara==aParaAttribs)
+			return refNo;
+		refNo++;
+		}
+	return 0;
+	}
+
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+//////////////////////////////////////////////////
+
+void CRichTextIndex::PasteFromStreamL(const CStreamStore& aStore,RReadStream& aStream,TInt aPos,CParagraphStyle::TStylePasteMode aStylePasteMode,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer)
+//
+	{
+	__TEST_INVARIANT;
+	
+	CancelInsertCharFormat();
+	ScanToPosition(aPos,EScanToPositionAbsolute);
+
+	//
+	//  Get the header
+	TRtPasteContext context(&aStore,aGlobalParaLayer,aGlobalCharLayer,iText.StyleList());
+	context.iPastePos=iPos;
+	context.iStylePasteMode = aStylePasteMode;
+
+	InternalizeRtiHeaderL(aStream,context);  // no rollback required on the header.  Does not alter iPos.
+	//
+	// Get the pargraph styles
+
+	CStyleMap* styleMap = NULL;
+	if (context.iParagraphStylesFlag)
+	{
+		TUint8 styleCount=ReadTUint8CountL(aStream);
+		styleMap=CStyleMap::NewLC(styleCount);
+		TRAPD(ret,
+		PasteStylesL(aStream,*styleMap,context));  // Does not alter iPos.
+		if (ret!=KErrNone) {RbPasteSharedFormatsL(ret);}
+	}
+	//
+	// Get the shared formats
+	TUint8 sharedParaCount=ReadTUint8CountL(aStream);
+	CParaAttribsMap* paraMap=CParaAttribsMap::NewLC(sharedParaCount);
+	TRAPD(ret,
+	PasteSharedFormatsL(aStream,*paraMap,context,styleMap));  // Does not alter iPos.
+	if (ret!=KErrNone)
+		{
+		// beginning of fixing DEF 126651 (1/2)
+		// free orphan object before leave.
+		if (context.iParagraphStylesFlag)
+		{
+			if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
+			{
+			TInt maxSize = styleMap->Count();
+			for (TInt count=0; count<maxSize; count++)
+				{
+				delete (CParagraphStyle*)styleMap->At(count).iT;	
+				}
+			}
+			CleanupStack::PopAndDestroy();	// cleanup styleMap
+		}
+		CleanupStack::PopAndDestroy();  // cleanup paraMap
+		// end of fixing DEF 126651 (1/2)
+		RbPasteSharedFormatsL(ret);
+		}
+	//
+	// Get the markup
+	TRAP(ret,
+	PasteIxL(aStream,context,*paraMap, styleMap));  // context now has both global layers & pastePos
+	if (ret!=KErrNone)
+		{
+		// beginning of fixing DEF 126651 (2/2)
+		// free orphan object before leave.
+		if (context.iParagraphStylesFlag)
+		{
+			if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
+			{
+			TInt maxSize = styleMap->Count();
+			for (TInt count=0; count<maxSize; count++)
+				{
+				delete (CParagraphStyle*)styleMap->At(count).iT;	
+				}
+			}
+			CleanupStack::PopAndDestroy();	// cleanup styleMap
+		}
+		CleanupStack::PopAndDestroy();  // cleanup paraMap
+		// end of fixing DEF 126651 (2/2)
+		RbPasteSharedFormatsL(ret);
+		}
+
+
+	if (context.iParagraphStylesFlag)
+	{
+		TRAP(ret,GenerateAllPhraseLinksL());
+		if (ret != KErrNone)
+			RbPasteSharedFormatsL(ret);
+
+		if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
+		{
+		TInt maxSize = styleMap->Count();
+		for (TInt count=0; count<maxSize; count++)
+			{
+			delete (CParagraphStyle*)styleMap->At(count).iT;	
+			}
+		}
+		CleanupStack::PopAndDestroy();	// cleanup styleMap
+	}
+
+	CleanupStack::PopAndDestroy();  // cleanup paraMap
+
+	__TEST_INVARIANT;
+	}
+
+
+void CRichTextIndex::PasteStylesL(RReadStream& aStream,CStyleMap& aMap,const TRtPasteContext& aContext)
+// Restore the paragraph styles from the specified stream.
+// Restoration is controlled by the flag TStylePasteMode.
+//
+	{
+	
+	TInt styleCount=aMap.iCapacity;
+//	TBool docSupportsStyles = iText.StyleListPresent();	// detect if document has style list
+	CParagraphStyle* style=NULL;
+	for(TUint8 ii=0; ii<styleCount; ii++)
+	{
+		TInt refNo=aStream.ReadInt8L();
+		style=CParagraphStyle::NewL(aStream,*aContext.iGlobalParaLayer,*aContext.iGlobalCharLayer);
+
+		// Now attempt to map this style to one in the document we are adding it to
+		// refNo contains the style number when the selection was cut, which
+		//   is needed to map to the reference no's coming in with the paragraph
+		//   format info
+
+		if (aContext.iStylePasteMode == CParagraphStyle::EIgnoreNewStyles)
+			// We're ignoring all style info, so delete it now
+			delete style;
+		else
+		{
+
+		if (aContext.iStyleList && aContext.iStylePasteMode == CParagraphStyle::EAddNewStyles)
+		{
+			TInt docStyle = iText.StyleList()->IndexByName(style->iName);
+			if (docStyle!=KErrNotFound)
+			{
+				/* Add the existing style into the stylemap */
+				aMap.Bind(refNo,iText.StyleList()->PtrByName(style->iName)->iStyle);
+
+				/* Since this style exists, we can safely delete this copy */
+				delete style;
+
+			}
+			else
+			{
+				// Ok, the document doesn't have this style in it.
+				// So let's add it in, and put a reference in the stylemap
+
+				RParagraphStyleInfo newStyle(style);
+
+				iText.StyleList()->AppendL(&newStyle);
+
+				aMap.Bind(refNo,style);
+
+				// the StyeList takes care of style destruction, so no deletion
+				// is necessary here
+			}
+		}
+		else
+		{
+			// Document doesn't support styles, so save them so they can
+			// be converted to character specific formatting later on
+			aMap.Bind(refNo, style);
+		}
+		}
+
+	}
+}
+
+
+void CRichTextIndex::ImposeCharacterStyleL(CCharFormatLayer** aCharLayer)
+{
+	// This function is used to impose the current character style onto
+	// the character layer for this paragraph. It's used when translating
+	// style information into specific formatting when pasting text containing
+	// styles into text without styles.
+
+	TCharFormatX MergedCharFormat;
+	TCharFormatXMask MergedCharFormatMask;
+			
+	CCharFormatLayer* newCharLayer;
+
+	// Extract the masks from both layers.
+	// use MergedCharFormat to hold the char info which we don't want yet
+
+	(*aCharLayer)->Sense(MergedCharFormat, MergedCharFormatMask);
+	iLastCharacterStyle->Sense(MergedCharFormat, MergedCharFormatMask);
+			
+	// Re-build charLayer;
+	CleanupStack::PushL(*aCharLayer);
+	newCharLayer = CCharFormatLayer::NewL(MergedCharFormat,MergedCharFormatMask);
+	CleanupStack::Pop(*aCharLayer);
+
+	delete (*aCharLayer);
+	(*aCharLayer) = newCharLayer;
+}
+
+
+void CRichTextIndex::PasteSharedFormatsL(RReadStream& aStream,CParaAttribsMap& aMap,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
+// Load shared formats from the specified stream.
+// Only adds the loaded shared format to the list of shared formats
+// if it does not already exist in that list.
+// A map is kept, that for each loaded format specifies its offset within
+// the shared list.
+//
+
+	{
+	TInt mapCount=aMap.iCapacity;
+	for (TUint8 paraItem=0;paraItem<mapCount;paraItem++)
+		{
+		TInt refNo=aStream.ReadInt32L();
+		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
+		CleanupStack::PushL(paraLayer);
+
+		CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);  // Does not restore based on link.
+//// Change specific formatting for this paragraph
+
+		if (iLastCharacterStyle != NULL)
+			ImposeCharacterStyleL(&charLayer);
+		
+		charLayer->SetBase(aContext.iGlobalCharLayer);
+
+		CleanupStack::PushL(charLayer);
+		CParaAttribs* paraAttribs=GetParaAttribsL(paraLayer,charLayer);
+		CleanupStack::PopAndDestroy(2);  // charLayer & paraLayer
+		aMap.Bind(refNo,paraAttribs);
+		paraAttribs->iRefCount--;
+		}
+	}
+
+
+void CRichTextIndex::PasteIxL(RReadStream& aStream,TRtPasteContext& aContext,const CParaAttribsMap& aMap,CStyleMap* aStyleMap/*,CParaAttribs* aSecondReserved*/)
+//
+	{
+	TInt completeParaCount=aStream.ReadInt32L();
+	completeParaCount-=(aContext.iIncompleteParaFlag)? 1 : 0;
+//	Create rollback states
+	TParaAttribsEntry para=(*iParaIx)[aContext.iPastePos.iParaElement];
+	CParaAttribs* reclaimed=RequestReclaimShareL(para.iParaAttribs,&para);  // does not release share
+	iRollbackParaAttribsHandle=NULL;
+	if (reclaimed)
+		{
+		iRollbackParaAttribsHandle=para.iParaAttribs;
+		CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed));
+		(*iParaIx)[aContext.iPastePos.iParaElement].iParaAttribs=reclaimed;  // Use this reclaimed para attribs
+		}
+//	Split the phrase at the paste position, ready to insert clipboard content
+	TRAPD(ret,
+	SplitPhraseL(aContext.iPastePos.iDocPos));
+		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
+	ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);  // pick up the changes
+	aContext.iPastePos=iPos;
+//	Paste all complete paragraphs from the clipboard
+	TInt characterCount=0;
+	RPhraseAttribsEntry* firstParaVirtualPhrase=NULL;
+	TRAP(ret,
+	characterCount=PasteParaIxL(aStream,aContext,completeParaCount,aMap,firstParaVirtualPhrase,aStyleMap));
+		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
+	CleanupStack::PushL(firstParaVirtualPhrase);
+//	Paste any remaining text fragment.
+	TTextFragment textFragment;
+	if (aContext.iIncompleteParaFlag)
+		{
+		TRAPD(ret,
+		textFragment=GetTextFragmentL(aStream));
+			if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}			
+		characterCount+=textFragment.iLength;
+
+		// Restore the character stle info for the final text fragment
+		if (aContext.iParagraphStylesFlag || aContext.iApplyFormatToLastFlag)
+			{
+			CParaFormatLayer* paraLayer = PasteParagraphFormatL(aStream, aContext, aStyleMap);
+			CleanupStack::PushL(paraLayer);
+			//Restore the paragraph formatting for the final text fragment
+			if (aContext.iApplyFormatToLastFlag)
+				{
+				CParaFormat* paraFormat = CParaFormat::NewLC();
+				TParaFormatMask mask;
+				paraLayer->SenseL(paraFormat,mask);
+				(*iParaIx)[completeParaCount].iParaAttribs->iParaFormat->SetL(paraFormat,mask);
+				CleanupStack::PopAndDestroy(paraFormat);
+				}
+			// We can now discard the format layer, but the character format has been safely
+			// patched to the style character format
+			CleanupStack::PopAndDestroy(paraLayer);
+			}
+		}
+//
+	TRAP(ret,
+	PastePhraseIxL(aStream,aContext,firstParaVirtualPhrase));
+		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
+	CleanupStack::PopAndDestroy();  // firstParaVirtualPhrase / shallow destroy only - deep copy in phraseIx
+
+//	ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);  // phraseIx not pasted at this point
+//	TLogicalPosition headParaNormalizePos=iPos;
+	
+	
+	if (completeParaCount==0)
+		{// Adjust paragraph length & phrase count
+		TParaAttribsEntry* para=&(*iParaIx)[aContext.iPastePos.iParaElement];
+		para->iLength+=textFragment.iLength;
+		para->iParaAttribs->iPhraseCount+=textFragment.iPhraseCount;
+		ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);
+		TLogicalPosition headParaNormalizePos=iPos;
+		MergePhrases(headParaNormalizePos);
+		MergePhrases(aContext.iPastePos.iDocPos+characterCount);
+		DoPasteCleanup(headParaNormalizePos,reclaimed);
+		}
+	else
+		{// Adjust paragraph lengths & phrase counts	
+		TParaAttribsEntry* firstPara=&(*iParaIx)[aContext.iPastePos.iParaElement];
+		firstPara->iLength+=aContext.iPastePos.iParaElementOffset;  // Update length of the first para
+		firstPara->iParaAttribs->iPhraseCount+=(aContext.iPastePos.iPhraseElement-aContext.iPastePos.iParaBasePhraseElement);  // Update the phrase count of the first para attribs
+		ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);
+		TLogicalPosition headParaNormalizePos=iPos;
+		MergePhrases(headParaNormalizePos);
+		DoPasteCleanup(headParaNormalizePos,reclaimed);
+		//
+		// Adjust the length & phrase count of the new final paragraph
+		TParaAttribsEntry* lastPara=&(*iParaIx)[aContext.iPastePos.iParaElement+completeParaCount];
+		lastPara->iLength=(lastPara->iLength-aContext.iPastePos.iParaElementOffset)+textFragment.iLength;
+		lastPara->iParaAttribs->iPhraseCount-=(aContext.iPastePos.iPhraseElement-aContext.iPastePos.iParaBasePhraseElement);
+		// phrase count may be wrong - since the added phrase may have been merged into the current one.
+		// Cant just add these phrases.
+		lastPara->iParaAttribs->iPhraseCount+=textFragment.iPhraseCount;
+		ScanToPosition(aContext.iPastePos.iDocPos+characterCount,EScanToPositionAbsolute);
+		MergePhrases(iPos);
+		DoPasteCleanup(iPos,(CParaAttribs*)NULL);
+		}
+	RebalanceIndex();
+	NormalizeSharedList();
+	}
+
+
+void CRichTextIndex::DoPasteCleanup(TLogicalPosition& aNormalizePos,CParaAttribs* aReclaimed)
+//
+	{
+	NormalizeNow(aNormalizePos);
+	if (aReclaimed)
+		CleanupStack::Pop();
+	}
+
+
+TInt CRichTextIndex::PasteParaIxL(RReadStream& aStream,TRtPasteContext& aContext,TInt aCompleteParaCount,const CParaAttribsMap& aMap,RPhraseAttribsEntry*& aFirstParaVirtualPhrase, CStyleMap* aStyleMap)
+//
+	{
+	TParaAttribsEntry para;
+	iParaIx->InsertL(aContext.iPastePos.iParaElement,para,aCompleteParaCount);	
+	aContext.iParasPasted=aCompleteParaCount;
+	TInt characterCount=0;
+	if (aCompleteParaCount>0)
+		{
+		para=DoPasteFirstIntoParaL(aStream,aMap,aContext,aFirstParaVirtualPhrase, aStyleMap);
+		TInt paraItem=0;
+		(*iParaIx)[aContext.iPastePos.iParaElement+paraItem]=para;
+		characterCount+=para.iLength;
+		}
+	CleanupStack::PushL(TCleanupItem(DiscardPhraseOnCleanup,aFirstParaVirtualPhrase));
+	for (TInt paraItem=1;paraItem<aCompleteParaCount;paraItem++)
+		{// Paste all the paras that have paragraph delimiters.
+		para=DoPasteIntoParaL(aStream,aMap,aContext,aStyleMap);
+		(*iParaIx)[aContext.iPastePos.iParaElement+paraItem]=para;
+		characterCount+=para.iLength;
+		}
+	CleanupStack::Pop();  // firstParaVirtualPhrase
+// ASSERT: At this point we have pasted all paras that were in the stream.	
+	__ASSERT_DEBUG(aContext.iParasPasted==aCompleteParaCount,Panic(EPasteParaIxError));
+	return characterCount;
+	}
+			
+			
+TParaAttribsEntry CRichTextIndex::DoPasteFirstIntoParaL(RReadStream& aStream,const CParaAttribsMap& aMap,const TRtPasteContext& aContext,RPhraseAttribsEntry*& aFirstParaVirtualPhrase,CStyleMap* aStyleMap)
+//
+	{
+	TParaAttribsEntry para;
+	para.iLength=aStream.ReadInt32L();
+	TUint8 refNo=aStream.ReadUint8L();
+	if (refNo>0)
+		{// This is the first pasted para, so if shared, must convert to phrase on the fly.
+		CParaAttribs* paraAttribs=aMap.Item(refNo);
+		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraAttribs->iParaFormat);
+		CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
+		//
+		CCharFormatLayer* layer=CCharFormatLayer::NewCopyBaseL(paraAttribs->iCharFormat);
+		CleanupStack::PushL(layer);
+		aFirstParaVirtualPhrase=new(ELeave) RPhraseAttribsEntry(layer,para.iLength);
+		CleanupStack::Pop(2);  // layer & specificParaAttribs
+		//
+		para.iParaAttribs=specificParaAttribs;
+		__ASSERT_ALWAYS(para.iParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError));
+		}
+	else
+		{// Have to build up the specific para attribs
+		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
+		CleanupStack::PushL(paraLayer);
+		TInt phraseCount=aStream.ReadInt32L();  // specific phrase count
+		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
+		specificParaAttribs->iPhraseCount=phraseCount;
+		para.iParaAttribs=specificParaAttribs;
+		CleanupStack::PopAndDestroy();  // a copy of paraLayer is taken!
+		}
+	return para;
+	}
+
+
+TParaAttribsEntry CRichTextIndex::DoPasteIntoParaL(RReadStream& aStream,const CParaAttribsMap& aMap,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
+//
+	{
+	TParaAttribsEntry para;
+	para.iLength=aStream.ReadInt32L();
+	TUint8 refNo=aStream.ReadUint8L();
+	if (refNo>0)
+		{// Link to para attribs in shared list & up its reference count
+		para.iParaAttribs=aMap.Item(refNo);
+		__ASSERT_ALWAYS(para.iParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError));
+		para.iParaAttribs->iRefCount++;
+		}
+	else
+		{// Have to build up the specific para attribs
+		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
+		CleanupStack::PushL(paraLayer);
+		TInt phraseCount=aStream.ReadInt32L();  // specific phrase count
+		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
+		specificParaAttribs->iPhraseCount=phraseCount;
+		para.iParaAttribs=specificParaAttribs;
+		CleanupStack::PopAndDestroy();  // a copy of paraLayer is taken!
+		}
+	return para;
+	}
+
+
+TTextFragment CRichTextIndex::GetTextFragmentL(RReadStream& aStream)
+//
+	{
+	TTextFragment textFragment;
+	textFragment.iLength=aStream.ReadInt32L();
+	textFragment.iPhraseCount=aStream.ReadInt32L();
+	return textFragment;
+	}
+
+
+void CRichTextIndex::PastePhraseIxL(RReadStream& aStream,TRtPasteContext& aContext,const RPhraseAttribsEntry* aFirstParaVirtualPhrase)
+// The character position to paste at should now fall on a phrase boundary.
+//
+	{
+// ASSERT: Having pasted the paraIx, the para containig pastePos has had the containing phrase split at that point.
+	__ASSERT_ALWAYS(aContext.iPastePos.iPhraseElementOffset==0,Panic(EPastePhraseIxErr));
+
+	TInt offset=0;
+	TInt phraseCount=aStream.ReadInt32L();  // leave caught by calling function.  No state change yet.
+	if (aFirstParaVirtualPhrase)
+		{
+		iPhraseIx->InsertL(aContext.iPastePos.iPhraseElement,*aFirstParaVirtualPhrase);
+		offset++;
+		}
+	RPhraseAttribsEntry holdingPhrase;
+	iPhraseIx->InsertL(aContext.iPastePos.iPhraseElement+offset,holdingPhrase,phraseCount);
+	for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++)
+		{// Restore each phrase & insert into the phrase index.
+		RPhraseAttribsEntry phrase;
+		TRAPD(ret,
+//		phrase=DoPastePhraseL(aStream,aContext));  // !! delete this if the code works
+		DoPastePhraseL(aStream,aContext,phrase));
+			if (ret!=KErrNone) {RbPastePhraseIxL(aContext.iPastePos,phraseCount+offset,ret);}
+		(*iPhraseIx)[aContext.iPastePos.iPhraseElement+phraseItem+offset]=phrase;
+		if (phrase.IsPicturePhrase() && iText.PictureFactory())
+			iPictureCount++;
+		}
+	}
+
+
+void CRichTextIndex::DoPastePhraseL(RReadStream& aStream,const TRtPasteContext& aContext,RPhraseAttribsEntry& aPhrase)
+//
+	{
+	TBool isPicture=(TBool)aStream.ReadUint8L();
+	TInt phraseLength=aStream.ReadInt32L();
+
+	__ASSERT_ALWAYS(isPicture && phraseLength==1 || !isPicture,User::Leave(KErrCorrupt));
+	
+	CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);
+/// Change this character format if style formatting is to be applied
+
+// Paste style for the trailing text
+	if (iLastCharacterStyle != NULL)
+			ImposeCharacterStyleL(&charLayer);
+	
+		charLayer->SetBase(aContext.iGlobalCharLayer);
+
+	CPicturePhrase* picPhrase=NULL;
+	const MPictureFactory* factory=iText.PictureFactory();
+	TBool pictureLoadError=EFalse;
+	if (isPicture)
+		{
+		TPictureHeader hdr;
+		aStream>> hdr;  // hdr.iPicture always references a picture in the deferred store.
+		if (isPicture && factory)
+			{// Manufacture new picture phrase & set its picture store
+			CleanupStack::PushL(charLayer);
+			TBool ownershipTaken(EFalse);
+			picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken);
+			CleanupStack::Pop();  // charLayer - picPhrase takes ownership
+			CleanupStack::PushL(picPhrase);
+			TRAPD(r,factory->NewPictureL(hdr,*aContext.iStore));  // load picture since clipboard store is transient.
+			// r=KErrNotSupported  // we don't recognise the picture type
+			if (r==KErrNone)
+				{
+				picPhrase->iPicHdr.iPicture=hdr.iPicture;  // make picPhrase point at the restored picture object.
+				TRAP(r,
+				hdr.iPicture->DetachFromStoreL(CPicture::EDetachFull));  // recurse the call to detach the picture from the store
+				}
+			switch (r)
+				{
+				case(KErrNone):
+					break;
+				default:
+					pictureLoadError=ETrue;
+					picPhrase->iCharFormat=NULL;
+					CleanupStack::PopAndDestroy(picPhrase);
+					if (r!=KErrNotSupported)
+						User::Leave(r);
+				}
+			}
+		}
+	if (isPicture && factory && !pictureLoadError)
+		new(&aPhrase) RPhraseAttribsEntry(picPhrase);
+	else
+		new(&aPhrase) RPhraseAttribsEntry(charLayer,phraseLength);
+	
+	// The ownership has been transfered to RPhraseAttribsEntry
+	if(picPhrase)
+	    CleanupStack::Pop(picPhrase);
+	}
+
+
+TUint8 CRichTextIndex::ReadTUint8CountL(RReadStream& aStream)const
+	{return aStream.ReadUint8L();}
+
+
+void CRichTextIndex::RbPasteSharedFormatsL(TInt aRet)
+// For each para attribs that has been read in, release all shares on it, if it
+// does not already exist in shared list.
+//
+	{
+	NormalizeSharedList();
+	User::Leave(aRet);
+	}
+		
+	
+void CRichTextIndex::NormalizeSharedList()
+// Removes unreferenced (non-shared) shared paras from the shared list.
+// Called in rollback situations.
+// Also called naturally following a paste, since an incoming shared para
+// may be pasted into an existing para, making it non-shared.
+//
+	{
+	CParaAttribs* currentSharedPara=NULL;
+	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
+	while ((currentSharedPara=iterator++)!=NULL)
+		{// Rollback the shared list.
+		if (currentSharedPara->iRefCount==0)
+			{// Remove this unreferenced item from the shared list.
+			currentSharedPara->iRefCount=1;
+			currentSharedPara->Release();
+			}
+		}
+	}
+
+
+void CRichTextIndex::RbRemoveInsertedParaAttribsEntries(TInt aFirstParaInsertPos,TInt aInsertedParaCount)
+// Rollback on leaving part way through inserting paragraph records into the para index.
+// For all pasted paragraph records, release their share on their paraAttribs if present.
+//
+	{
+	for (TInt ii=0;ii<aInsertedParaCount;ii++)
+		{
+		CParaAttribs* paraAttribs=(*iParaIx)[aFirstParaInsertPos+ii].iParaAttribs;
+		if (paraAttribs)
+			paraAttribs->Release();
+		}
+	iParaIx->Delete(aFirstParaInsertPos,aInsertedParaCount);
+	}
+
+
+void CRichTextIndex::RbPasteParaIxL(const TLogicalPosition& aPos,TInt aParasPasted,TInt aRet)
+// Rollback on leaving part way through the pasting of the para index.
+// For all pasted paras, release their share on their paraAttribs.
+//
+	{
+	RbRemoveInsertedParaAttribsEntries(aPos.iParaElement,aParasPasted);
+	MergePhrases(aPos.iDocPos);  // updates iPos to paste pos.
+	// 
+	//
+	if (iRollbackParaAttribsHandle)
+		{
+		RemoveFromPhraseIx(iPos.iPhraseElement,1);  // Removes the phrase created from ResquestReclaim on para
+		(*iParaIx)[aPos.iParaElement].iParaAttribs=iRollbackParaAttribsHandle;
+		iRollbackParaAttribsHandle=NULL;
+		}
+	User::Leave(aRet);
+	}
+
+
+void CRichTextIndex::RbRemoveInsertedPhraseAttribsEntries(TInt aFirstPhraseInsertPos,TInt aInsertedPhraseCount)
+// Rollback on leaving part way through the pasting of the phrase index.
+// For all pasted phrases, discard their components.
+//
+	{
+	for (TInt ii=0;ii<aInsertedPhraseCount;ii++)
+		{
+		RPhraseAttribsEntry& phrase=(*iPhraseIx)[aFirstPhraseInsertPos+ii];
+		if (phrase.IsPicturePhrase())
+			iPictureCount--;
+		if (phrase.CharFormat())
+			phrase.Discard();
+		}
+	iPhraseIx->Delete(aFirstPhraseInsertPos,aInsertedPhraseCount);
+	}
+
+
+void CRichTextIndex::RbPastePhraseIxL(const TLogicalPosition& aPos,TInt aPhraseCount,TInt aRet)
+// Rollback on leaving part way through the pasting of the phrase index.
+// For all pasted phrases, discard their components.
+//
+	{
+	RbRemoveInsertedPhraseAttribsEntries(aPos.iPhraseElement,aPhraseCount);
+	User::Leave(aRet);
+	}