--- /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,¶); // 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);
+ }