textrendering/texthandling/stext/TXTIXSTR.CPP
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 /*
       
     2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <e32std.h>
       
    20 #include <e32base.h>
       
    21 
       
    22 #include <gdi.h>
       
    23 
       
    24 #include "TXTFMLYR.H"
       
    25 #include "TXTMRTSR.H"
       
    26 #include "TXTRICH.H"
       
    27 #include "TXTINDEX.H"
       
    28 #include "TXTSTD.H"
       
    29 
       
    30 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    31 #include "TXTFMLYR_INTERNAL.H"
       
    32 #endif
       
    33 
       
    34 const TUint8 KRegisterItemPresent=1;
       
    35 
       
    36 
       
    37 GLDEF_C void DiscardPhraseOnCleanup(TAny* aPhrase)
       
    38 // Allows RPhraseAttribsEntry on the CleanupStack to be destroyed correctly,
       
    39 // when included as a PushL(TCleanupItem).
       
    40 //
       
    41 	{
       
    42 	((RPhraseAttribsEntry*)aPhrase)->Discard();
       
    43 	User::Free(aPhrase);
       
    44 	}
       
    45 
       
    46 
       
    47 TRtPasteContext::TRtPasteContext(const CStreamStore* aStore,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,const CStyleList* aStyleList)
       
    48 //
       
    49 	:iStore(aStore),
       
    50 	iGlobalParaLayer(aGlobalParaLayer),iGlobalCharLayer(aGlobalCharLayer),iStyleList(aStyleList),
       
    51 	iParagraphStylesFlag(EFalse),iIncompleteParaFlag(ETrue),iPastePos(),iParasPasted(0)
       
    52 	{}
       
    53 
       
    54 //////////////////////////////////////////////////////////////////////////////////////
       
    55 
       
    56 
       
    57 CRichTextIndex* CRichTextIndex::NewL(const CStreamStore& aStore,TStreamId aId,
       
    58 //										MPictureFactory* aPictureFactory,MRichTextStoreResolver* aStoreResolver,
       
    59 										const CParaFormatLayer* aGlobalParaLayer,
       
    60 										const CCharFormatLayer* aGlobalCharLayer,
       
    61 										const CRichText& aText)
       
    62 //										const CStyleList* aStyleList)
       
    63 //
       
    64 	{
       
    65 	CRichTextIndex* self=new(ELeave) CRichTextIndex(aText);
       
    66 	CleanupStack::PushL(self);
       
    67 	self->ConstructL(aGlobalParaLayer,aGlobalCharLayer,KMultiParaGranularity,KLargePhraseGranularity);
       
    68 	self->RestoreL(aStore,aId,aGlobalParaLayer,aGlobalCharLayer,aText.StyleList());
       
    69 //	self->SetPictureFactory(aPictureFactory,aStoreResolver);
       
    70 	CleanupStack::Pop();
       
    71 	return self;
       
    72 	}
       
    73 
       
    74 
       
    75 void CRichTextIndex::RestoreL(const CStreamStore& aStore,TStreamId aId,
       
    76 									   const CParaFormatLayer* aGlobalParaLayer,
       
    77 									   const CCharFormatLayer* aGlobalCharLayer,
       
    78 									   const CStyleList* aStyleList)
       
    79 //
       
    80 	{
       
    81 	RStoreReadStream stream;
       
    82 	stream.OpenLC(aStore,aId);
       
    83 	//
       
    84 	InternalizeL(stream,aGlobalParaLayer,aGlobalCharLayer,aStyleList);
       
    85 	CleanupStack::PopAndDestroy();  // stream
       
    86 	}
       
    87 
       
    88 
       
    89 TStreamId CRichTextIndex::StoreMarkupL(CStreamStore& aStore,const CStyleList* /*aStyleList*/) const
       
    90 // Store this rich text markup out-of-line along with its components.
       
    91 //
       
    92 	{
       
    93 	CStoreMap* map=CStoreMap::NewLC(aStore);
       
    94 	StorePicturesL(aStore,*map);
       
    95 //
       
    96 	RStoreWriteStream stream(*map);
       
    97 	TStreamId id=stream.CreateLC(aStore);
       
    98 //	CONST_CAST(CRichTextIndex*,this)->iStyleList=CONST_CAST(CStyleList*,aStyleList);
       
    99 	ExternalizeL(stream);
       
   100 	stream.CommitL();
       
   101 //
       
   102 	map->Reset();
       
   103 	CleanupStack::PopAndDestroy(2);  // map,stream
       
   104 	return id;
       
   105 	}
       
   106 
       
   107 
       
   108 void CRichTextIndex::StorePicturesL(CStreamStore& aStore,CStoreMap& aMap) const
       
   109 // Store any picture components in the specified store.
       
   110 // Due to deferred loading, any pictures that are not in memory at this point are loaded,
       
   111 // and then saved.
       
   112 //
       
   113 	{
       
   114 	__TEST_INVARIANT;
       
   115 
       
   116 	StorePicturesL(aStore,aMap,0,iText.DocumentLength()+1);
       
   117 	}
       
   118 
       
   119 
       
   120 void CRichTextIndex::StorePicturesL(CStreamStore& aStore,CStoreMap& aMap,TInt aPos,TInt aLength) const
       
   121 // Store all picture components that are contained within the specified range (inclusive), in the store provided.
       
   122 // Prior to storing the picture, its size is written to its picture header which is stored in-line in 
       
   123 // the markup.
       
   124 // Any pictures that are not in memory are now deleted, as a previous call to LoadAllPicturesNowL()
       
   125 // should have been made.
       
   126 // We are guaranteed that all pictures that are in memory are fully restored & detached from their store
       
   127 //
       
   128 	{
       
   129 	__TEST_INVARIANT;
       
   130 
       
   131 	if (iPictureCount==0)
       
   132 		return;
       
   133 	CONST_CAST(CRichTextIndex*,this)->DetachFromStoreL(CPicture::EDetachFull,aPos,aLength);	// ensure all pictures have been loaded
       
   134 	TInt currentPos=aPos;
       
   135 	DocumentChanged();  // reset the cache logical position
       
   136 	while (currentPos<aPos+aLength)
       
   137 		{// Store next picture & increment pos.
       
   138 		CONST_CAST(CRichTextIndex*,this)->ScanToPosition(currentPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed));
       
   139 		TCurrentIndexRecords current;
       
   140 		GetCurrentRecords(current);
       
   141 		if (current.iPhrase && current.iPhrase->IsPicturePhrase())
       
   142 			{
       
   143 			RPhraseAttribsEntry& phrase=*current.iPhrase;
       
   144 			TPictureHeader* hdr=phrase.PictureHeaderPtr();
       
   145 			__ASSERT_DEBUG(hdr,Panic(ERichTextStorePictureIntegrityError));
       
   146 			TBool pictureInMemory=(hdr->iPicture.IsPtr() && hdr->iPicture.AsPtr());
       
   147 			if (pictureInMemory)
       
   148 				{// Store the picture
       
   149 				CPicture& picture=*hdr->iPicture;
       
   150 				picture.GetSizeInTwips(hdr->iSize);  //  write picture size to picture header.
       
   151 				TStreamId id=picture.StoreL(aStore);
       
   152 				aMap.BindL(hdr->iPicture,id);
       
   153 				}
       
   154 			else
       
   155 				{// Replace the picture phrase with a simple text equivalent.
       
   156 				CCharFormatLayer* charLayer=phrase.ReleaseCharFormatLayerOwnership();
       
   157 				phrase.Discard();  // destroy the redundant picture phrase
       
   158 				RPhraseAttribsEntry newTextPhrase(charLayer,1);
       
   159 				(*iPhraseIx)[iPos.iPhraseElement]=newTextPhrase;
       
   160 				CONST_CAST(CRichTextIndex*,this)->iPictureCount--;  // the picture has now been removed
       
   161 				// I do not bother tidying up the phrase index here,
       
   162 				// since the benefit does not currently match the cost involved.
       
   163 				//
       
   164 				}
       
   165 			}
       
   166 		//
       
   167 		// increment the current position to the *start* of the next phrase/paragraph
       
   168 		TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
       
   169 		currentPos+=CurrentPhraseLength()-offsetIntoUnit;
       
   170 		}
       
   171 	}
       
   172 
       
   173 
       
   174 void CRichTextIndex::DetachFromStoreL(CPicture::TDetach aDegree,TInt aPos,TInt aLength)
       
   175 // Attempts to restore all pictures not already present in memory.
       
   176 // A deep (door+document) or shallow (door only) restoration may occur, depending
       
   177 // on the value of detach.
       
   178 //
       
   179 	{
       
   180 	__TEST_INVARIANT;
       
   181 
       
   182 	if (iPictureCount==0)
       
   183 		return;
       
   184 	DocumentChanged();  // reset the cache logical position
       
   185 	TInt currentPos=aPos;
       
   186 	while (currentPos<aPos+aLength)
       
   187 		{
       
   188 		CONST_CAST(CRichTextIndex*,this)->ScanToPosition(currentPos,EScanToPositionAbsolute,&iLastUsed);
       
   189 		TCurrentIndexRecords current;
       
   190 		GetCurrentRecords(current);
       
   191 		if (current.iPhrase)
       
   192 			{
       
   193 			RPhraseAttribsEntry& phrase=*current.iPhrase;
       
   194 			if (phrase.IsPicturePhrase())
       
   195 				{
       
   196 				TPictureHeader* hdr=phrase.PictureHeaderPtr();
       
   197 				__ASSERT_DEBUG(hdr,Panic(ERichTextStorePictureIntegrityError));
       
   198 				//
       
   199 				if (hdr->iPicture.IsId())
       
   200 					{
       
   201 					TRAPD(r,
       
   202 					phrase.PictureHandleL(iText.PictureFactory(),iText.StoreResolver(),iPos.iDocPos,MLayDoc::EForceLoadTrue));  // swizzles
       
   203 					__ASSERT_DEBUG(r==KErrNone || hdr->iPicture.IsId(),Panic(ERichTextStorePictureIntegrityError));
       
   204 					if (r==KErrNotSupported)  // we don't recognise the picture type
       
   205 						{
       
   206 						TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
       
   207 						currentPos+=CurrentPhraseLength()-offsetIntoUnit;
       
   208 						continue;
       
   209 						}
       
   210 					User::LeaveIfError(r);
       
   211 					}
       
   212 				//
       
   213 				// recurse the call to detach the picture from the store
       
   214 				__ASSERT_DEBUG(hdr->iPicture.IsPtr(),Panic(ERichTextStorePictureIntegrityError));
       
   215 				hdr->iPicture->DetachFromStoreL(aDegree);
       
   216 				}
       
   217 			}
       
   218 		//
       
   219 		// increment the current position to the *start* of the next phrase/paragraph
       
   220 		TInt offsetIntoUnit=(current.iPhrase)?iPos.iPhraseElementOffset:iPos.iParaElementOffset;
       
   221 		currentPos+=CurrentPhraseLength()-offsetIntoUnit;
       
   222 		}
       
   223 	__TEST_INVARIANT;
       
   224 	}
       
   225 
       
   226 //////////////////////////////////////////////////////////////////////////////////////
       
   227 
       
   228 void CRichTextIndex::ExternalizeL(RWriteStream& aStream)const
       
   229 // Persist the current state of this object in the specified stream.
       
   230 // Saved records include the terminating paragraph delimiter. 
       
   231 //
       
   232 //
       
   233 	{
       
   234 	__TEST_INVARIANT;
       
   235 
       
   236 	CONST_CAST(CRichTextIndex*,this)->CancelInsertCharFormat();  // cancel any insert-pending state.
       
   237 	TInt charCount=iText.DocumentLength()+1;  // includes the end of document character
       
   238 	((CRichTextIndex*)this)->ScanToPosition(0,EScanToPositionAbsolute);
       
   239 	TLogicalPosition startPos=iPos;
       
   240 	((CRichTextIndex*)this)->ScanToPosition(charCount-1,EScanToPositionMatchLeft);
       
   241 	TLogicalPosition endPos=iPos;
       
   242 	CStyleList* styleList=iText.StyleList();
       
   243 	ExternalizeRtiHeaderL(aStream,endPos,styleList);
       
   244 	ExternalizeSharedFormatsL(aStream,startPos,endPos,styleList);
       
   245 	// DEF126934 begin: memory leak
       
   246 	RPhraseAttribsEntry *pForRelease = ExternalizeParaIxL(aStream,startPos,endPos,styleList);
       
   247 	if (pForRelease)
       
   248 		delete pForRelease;
       
   249 	// DEF126934 end
       
   250 	ExternalizePhraseIxL(aStream);
       
   251 	}
       
   252 
       
   253 
       
   254 void CRichTextIndex::InternalizeL(RReadStream& aStream,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,const CStyleList* aStyleList)
       
   255 // Load a rich text index.  Has construct semantics only!
       
   256 // Restores this object from the specified stream.  As specific format layers are restored, they are based
       
   257 // on the specified global format layers. 
       
   258 //
       
   259 	{
       
   260 	__ASSERT_ALWAYS(iParaIx->Count()==1 && (*iParaIx)[0].iLength==1,Panic(ERtIndexInternalizeCalledOnNonEmptySource));
       
   261 	TRtPasteContext context(NULL,aGlobalParaLayer,aGlobalCharLayer,aStyleList);
       
   262 	InternalizeRtiHeaderL(aStream,context);
       
   263 	InternalizeSharedFormatsL(aStream,context);
       
   264 	InternalizeParaIxL(aStream,context);
       
   265 	InternalizePhraseIxL(aStream,aGlobalCharLayer);
       
   266 	if (context.iParagraphStylesFlag)
       
   267 		GenerateAllPhraseLinksL();
       
   268 	SetSpecificMarkupInternalized(ETrue);
       
   269 
       
   270 	__TEST_INVARIANT;
       
   271 	}
       
   272 
       
   273 //////////////////////////////////////////////////////////////////////////////////////
       
   274 
       
   275 
       
   276 void CRichTextIndex::GenerateAllPhraseLinksL()
       
   277 // Go through the index, and for each specific character format layer (shared or otherwise), regenerate
       
   278 // the appropriate based-on link, (normal or style).
       
   279 // 
       
   280 	{
       
   281 	TInt count=ParagraphCount();
       
   282 	TInt phraseElement=0;
       
   283 	for (TInt ii=0; ii<count; ii++)
       
   284 		{
       
   285 		const CParaAttribs& paraAttribs=*(*iParaIx)[ii].iParaAttribs;
       
   286 		const CParaFormatLayer* base=STATIC_CAST(const CParaFormatLayer*,paraAttribs.iParaFormat->SenseBase());
       
   287 		TInt phraseCount=paraAttribs.PhraseCount();
       
   288 		if (phraseCount==1)
       
   289 			{
       
   290 			// If the reference count is zero, iCharFormat cannot be valid, so the CParaAttribs object is corrupt.
       
   291 			if (paraAttribs.iRefCount == 0)
       
   292 				User::Leave(KErrCorrupt);
       
   293 
       
   294 			GeneratePhraseLink(paraAttribs.iCharFormat,base);  // constant character formatting
       
   295 			}
       
   296 		else
       
   297 			{
       
   298 			 __ASSERT_DEBUG(phraseCount>1,Panic(EDebug));
       
   299 
       
   300 			// If the phrase count is too great the CParaAttribs object is corrupt.
       
   301 			if (phraseElement + phraseCount > iPhraseIx->Count())
       
   302 				User::Leave(KErrCorrupt);
       
   303 
       
   304 			for (TInt nn=0; nn<phraseCount; nn++)
       
   305 				GeneratePhraseLink((*iPhraseIx)[phraseElement+nn].CharFormat(),base);
       
   306 			phraseElement+=phraseCount;
       
   307 			}
       
   308 		}
       
   309 	}
       
   310 
       
   311 
       
   312 void CRichTextIndex::GeneratePhraseLink(CCharFormatLayer* aPhraseCharFormatLayer,const CParaFormatLayer* aBase)
       
   313 // Set the based on link for this character format layer appropriately.
       
   314 // By default, all specific character format layers are based on the global default.
       
   315 //
       
   316 	{
       
   317 	TUid type=aBase->Type();
       
   318 	if (type!=KNormalParagraphStyleUid)
       
   319 		aPhraseCharFormatLayer->SetBase(((CParagraphStyle*)aBase)->CharFormatLayer());
       
   320 	}
       
   321 
       
   322 
       
   323 //////////////////////////////////////////////////////////////////////////////////////
       
   324 
       
   325 void CRichTextIndex::CopyToStreamL(RWriteStream& aStream,TInt aPos,TInt aLength, TBool aCopyStyles)const
       
   326 // Copies the markup corresponding to the specified rich text region to the specified write stream.
       
   327 // aPos/aLength has already been validated in RichText
       
   328 // Saved records can NOT include the terminating paragraph delimiter.
       
   329 //
       
   330 	{
       
   331 	__TEST_INVARIANT;
       
   332 
       
   333 	((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute);
       
   334 	TLogicalPosition startPos=iPos;
       
   335 	((CRichTextIndex*)this)->ScanToPosition((aPos+aLength)-1,EScanToPositionAbsolute);
       
   336 	TLogicalPosition endPos=iPos;
       
   337 
       
   338 	CStyleList* docStyleList = NULL;
       
   339 	if (aCopyStyles)
       
   340 		docStyleList = (CStyleList*)iText.StyleList();
       
   341 
       
   342 	ExternalizeRtiHeaderL(aStream,endPos,docStyleList);
       
   343 	
       
   344 	if (docStyleList)
       
   345 		ExternalizeReferencedStylesL(aStream,startPos,endPos);
       
   346 	
       
   347 	ExternalizeSharedFormatsL(aStream,startPos,endPos,docStyleList); 
       
   348 	RPhraseAttribsEntry* virtualTrailingText=ExternalizeParaIxL(aStream,startPos,endPos,docStyleList);
       
   349 	if (virtualTrailingText)
       
   350 	    CleanupStack::PushL(virtualTrailingText);
       
   351 	ExternalizePhraseIxL(aStream,startPos,endPos,virtualTrailingText);
       
   352 	if (virtualTrailingText)
       
   353 	    CleanupStack::PopAndDestroy(virtualTrailingText);
       
   354 	}
       
   355 
       
   356 //////////////////////////////////////////////////////////////////////////////////////
       
   357 
       
   358 
       
   359 void CRichTextIndex::ExternalizeRtiHeaderL(RWriteStream& aStream,const TLogicalPosition& aEnd,const CStyleList* aStyleList)const
       
   360 // Stores index specific information.
       
   361 //
       
   362 	{
       
   363 	TBool incompleteParaFlag=((*iParaIx)[aEnd.iParaElement].iLength>(aEnd.iParaElementOffset+1));
       
   364 	aStream.WriteUint8L((TUint8)(aStyleList!=NULL));  // flags the presence of paragraph styles.
       
   365 	aStream.WriteUint8L((TUint8)(incompleteParaFlag!=EFalse)); // the last para has no paragraph delimiter
       
   366 	if(incompleteParaFlag)
       
   367 		{//apply paragraph format to final text fragment if logical end is at document end
       
   368 		aStream.WriteUint8L((TUint8)(aEnd.iDocPos+1 == iText.DocumentLength()));
       
   369 		}
       
   370 	}
       
   371 
       
   372 
       
   373 void CRichTextIndex::InternalizeRtiHeaderL(RReadStream& aStream,TRtPasteContext& aContext)
       
   374 // Load index specific information.
       
   375 //
       
   376 	{
       
   377 	TUint8 flag=0;
       
   378 	aStream>> flag;
       
   379 	aContext.iParagraphStylesFlag=(TBool)flag;
       
   380 	aStream>> flag;
       
   381 	aContext.iIncompleteParaFlag=(TBool)flag;
       
   382 	aContext.iApplyFormatToLastFlag=EFalse;
       
   383 	if(aContext.iIncompleteParaFlag)
       
   384 		{
       
   385 		aStream>> flag;
       
   386 		aContext.iApplyFormatToLastFlag=(TBool)flag;
       
   387 		}
       
   388 	}
       
   389 
       
   390 //////////////////////////////////////////////////////////////////////////////////////
       
   391                                                                                                                      
       
   392 void CRichTextIndex::ExternalizeReferencedStylesL(RWriteStream& aStream,const TLogicalPosition& aStart,
       
   393 												  const TLogicalPosition& aEnd) const
       
   394 // Write those styles that are referenced by the paragraphs in the range aStart to aEnd.
       
   395 //
       
   396 	{
       
   397 	CStyleList* list = iText.StyleList();
       
   398 	__ASSERT_DEBUG(list,Panic(EStyleClipboardIntegrityError));
       
   399 	__ASSERT_DEBUG(aStart.iParaElement <= aEnd.iParaElement,Panic(EStyleClipboardIntegrityError));
       
   400 
       
   401 	TUint8 numStyles = 0;
       
   402 	if (list) 
       
   403 		numStyles = (TUint8)list->Count();
       
   404 
       
   405 	HBufC8* buf=HBufC8::NewL(numStyles);
       
   406 	TPtr8 paraRegister=buf->Des();
       
   407 	paraRegister.FillZ(numStyles);
       
   408 	TInt refCount=MarkStyleRegister(paraRegister,aStart.iParaElement,aEnd.iParaElement);
       
   409 	CleanupStack::PushL(buf);
       
   410 	ExternalizeItemsPresentInStyleRegisterL(aStream,refCount,paraRegister);
       
   411 	CleanupStack::PopAndDestroy();
       
   412 	}
       
   413 
       
   414 
       
   415 void CRichTextIndex::InternalizeSharedFormatsL(RReadStream& aStream, const TRtPasteContext& aContext)
       
   416 // Restores the list of shared para attribs.
       
   417 // All existing CParaAttribs on the shared list are removed.
       
   418 // The reference counts are not restored, but modified dynamically as the para index is loaded.
       
   419 //
       
   420 	{
       
   421 	iParaIx->Reset();  // stops paraIx referencing shared paraAttribs that are about to be released.
       
   422 	CParaAttribs* currentSharedPara;
       
   423 	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
       
   424 	while ( (currentSharedPara = iterator++) != NULL )
       
   425 		currentSharedPara->Release(currentSharedPara->iRefCount);
       
   426 	TUint8 sharedParaCount = ReadTUint8CountL(aStream);
       
   427 	for (TUint8 paraItem = 0; paraItem < sharedParaCount; paraItem++)
       
   428 		{
       
   429 		(void)aStream.ReadInt32L();  // consume the data.
       
   430 		CParaFormatLayer* paraLayer = InternalizeParagraphFormatL(aStream, aContext);
       
   431 		CleanupStack::PushL(paraLayer);
       
   432 
       
   433 		CCharFormatLayer* charLayer = CCharFormatLayer::NewL(aStream);  // Does not restore based on link.
       
   434 		charLayer->SetBase(aContext.iGlobalCharLayer);  // base on 'Normal' global char format
       
   435 		CleanupStack::PushL(charLayer);
       
   436 		CParaAttribs* paraAttribs = CParaAttribs::NewL(paraLayer, charLayer);
       
   437 		CleanupStack::PopAndDestroy(2);
       
   438 		paraAttribs->iRefCount = 0;  // Otherwise recalculating reference counts on internalization of paraIx will result in 1 too many.
       
   439 		iSharedParaQueHead.AddLast(*paraAttribs);
       
   440 		}
       
   441 	}
       
   442 
       
   443 
       
   444 void CRichTextIndex::ExternalizeSharedFormatsL(RWriteStream& aStream,const TLogicalPosition& aStart,const TLogicalPosition& aEnd,const CStyleList* aStyleList)const
       
   445 // Persist those items in the shared list that are referenced by the paragraphs in the 
       
   446 // range aStart para to aEnd para.
       
   447 //
       
   448 	{
       
   449 	TUint8 sharedParaCount=SharedParaAttribsEntryCountL();
       
   450 	// Some paras coverd, so take register
       
   451 	HBufC8* buf=HBufC8::NewL(sharedParaCount);
       
   452 	TPtr8 sharedAttribsRegister=buf->Des();
       
   453 	sharedAttribsRegister.FillZ(sharedParaCount);
       
   454 	TInt sharedCount=MarkRegister(sharedAttribsRegister,aStart.iParaElement,aEnd.iParaElement);
       
   455 	CleanupStack::PushL(buf);
       
   456 	ExternalizeItemsPresentInRegisterL(aStream,sharedCount,sharedAttribsRegister,aStyleList);
       
   457 	CleanupStack::PopAndDestroy();
       
   458 	}
       
   459 
       
   460 
       
   461 TUint8 CRichTextIndex::SharedParaAttribsEntryCountL()const
       
   462 // Return a count of the number of items currently
       
   463 // in the sharedParaFormats list.
       
   464 //
       
   465 // This will leave if more than 255 found, as this is not supported
       
   466 	{
       
   467 	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
       
   468 	TUint16 sharedParaCount = 0;
       
   469 	while (iterator++ != NULL)
       
   470 		sharedParaCount++;
       
   471 		
       
   472 	// Currently more than 255 paragraph formats are not supported 
       
   473 	// If the current document has more, leave with KErrNotSupported
       
   474 	if (sharedParaCount > 255)
       
   475 		User::Leave(KErrNotSupported);
       
   476 	
       
   477 	return (TUint8)sharedParaCount;
       
   478 	}
       
   479 
       
   480 
       
   481 TInt CRichTextIndex::MarkRegister(TDes8& aBuf,TInt aStartPara,TInt aEndPara)const
       
   482 // Indicate in the register, aBuf, once and once only, each paraAttribs that is
       
   483 // referenced by each of the paragraphs in the specified range.
       
   484 // Return the number of shared para formats referenced.
       
   485 //
       
   486 	{
       
   487 	TInt parasReferenced=0;
       
   488 	for (TInt item=aStartPara;item<=aEndPara;item++)
       
   489 		{
       
   490 		CParaAttribs* paraAttribs=(*iParaIx)[item].iParaAttribs;
       
   491 		TInt offset=RefNum(paraAttribs);  // 0 return shows para attribs not in shared list
       
   492 		if (offset>0)
       
   493 			{// para entry references a shared para attribs
       
   494 			if (aBuf[offset-1]==0)
       
   495 				{
       
   496 				aBuf[offset-1]=KRegisterItemPresent;  // mark item as needing to be stored
       
   497 				parasReferenced++;
       
   498 				}
       
   499 			}
       
   500 		}
       
   501 	return parasReferenced;
       
   502 	}
       
   503 
       
   504 
       
   505 TInt CRichTextIndex::MarkStyleRegister(TDes8& aBuf,TInt aStartPara,TInt aEndPara)const
       
   506 // Indicate in the register, aBuf, once and once only, each paragraph style thar is
       
   507 // referenced by each of the paragraphs in the speciifed range.
       
   508 // Return the umber of paragraph styles referenced.
       
   509 //
       
   510 	{
       
   511 	TInt stylesReferenced=0;
       
   512 	const CParaAttribs* para=NULL;
       
   513 	for (TInt item=aStartPara;item<=aEndPara;item++)
       
   514 		{
       
   515 		para=(*iParaIx)[item].iParaAttribs;
       
   516 		TInt index=iText.StyleList()->IndexByPtr(STATIC_CAST(const CParaFormatLayer*,para->iParaFormat->SenseBase()));
       
   517 		if (index!=KErrNotFound)
       
   518 			{
       
   519 			__ASSERT_DEBUG(index<aBuf.Length(),Panic(EStyleClipboardIntegrityError));
       
   520 			if (aBuf[index]!=KRegisterItemPresent)
       
   521 				{
       
   522 				aBuf[index]=KRegisterItemPresent;  // mark item as needing to be stored
       
   523 		
       
   524 				stylesReferenced++;
       
   525 				}
       
   526 			}
       
   527 		}
       
   528 	return stylesReferenced;
       
   529 	}
       
   530 
       
   531 
       
   532 void CRichTextIndex::ExternalizeItemsPresentInRegisterL(RWriteStream& aStream,TInt aSharedCount,const TDes8& aBuf,const CStyleList* aStyleList)const
       
   533 // Externalize each object from the shared list that has a corresponding mark in the
       
   534 // register, aBuf.
       
   535 //
       
   536 	{
       
   537 	__ASSERT_DEBUG(aSharedCount<=(TInt)KMaxTUint8,Panic(ESharedParaCountStreamOverflow));
       
   538 	aStream.WriteUint8L(aSharedCount);
       
   539 	CParaAttribs* currentSharedPara=NULL;
       
   540 	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
       
   541 	TInt offset=0;
       
   542 	while ((currentSharedPara=iterator++)!=NULL)
       
   543 		{
       
   544 		if (aBuf[offset]==KRegisterItemPresent)
       
   545 			{
       
   546 			aStream.WriteInt32L(offset+1);  // the ref-no of the shared para - so it can be spotted in the paste.
       
   547 			ExternalizeParagraphFormatL(aStream,*currentSharedPara->iParaFormat,aStyleList);
       
   548 			aStream<< *currentSharedPara->iCharFormat;
       
   549 			}
       
   550 		offset++;
       
   551 		}
       
   552 	}
       
   553 
       
   554 
       
   555 void CRichTextIndex::ExternalizeItemsPresentInStyleRegisterL(RWriteStream& aStream,TInt aRefStyleCount,
       
   556 															 const TDes8& aBuf) const
       
   557 // Externalize each object from the paragraph style list that has a corresponding mark in the register aBuf.
       
   558 //
       
   559 	{
       
   560 	__ASSERT_DEBUG(aRefStyleCount <= (TInt)KMaxTUint8,Panic(EStyleClipboardIntegrityError));
       
   561 	aStream.WriteUint8L(aRefStyleCount);
       
   562 	TInt count=aBuf.Length();
       
   563 
       
   564 	for (TInt ii=0;ii<count;ii++)
       
   565 		{
       
   566 		if (aBuf[ii]==KRegisterItemPresent)
       
   567 			{
       
   568 			aStream.WriteInt8L(ii+1);  // cannot use 0 index as this represents an absence.
       
   569 			iText.StyleList()->At(ii).iStyle->ExternalizeL(aStream);
       
   570 			}
       
   571 		}
       
   572   }
       
   573 
       
   574 
       
   575 RPhraseAttribsEntry* CRichTextIndex::ExternalizeParaIxL(RWriteStream& aStream,
       
   576 										const TLogicalPosition& aStart,
       
   577 										const TLogicalPosition& aEnd,
       
   578 										const CStyleList* aStyleList)const
       
   579 // Externalize each para entry from the para index that falls between 
       
   580 // aStart paragraph and aEnd paragraph inclusive.
       
   581 // Any specific paraAttribs (ie not on the shared list) are also externalized.
       
   582 // * paragraph count
       
   583 // * 	paragraph length
       
   584 // *	ref no.  (ref no. 0 means specific/non-shared one)
       
   585 // *	[specific paragraph format layer - including based-on link]
       
   586 // *	[specific phrase count]
       
   587 //
       
   588 	{
       
   589 	TParaAttribsEntry lastParaEntry=(*iParaIx)[aEnd.iParaElement];
       
   590 	TBool incompleteParaFlag=(lastParaEntry.iLength>(aEnd.iParaElementOffset+1));
       
   591 	aStream.WriteInt32L(1+aEnd.iParaElement-aStart.iParaElement);  // paragraph count
       
   592 	for (TInt paraItem=aStart.iParaElement;paraItem<aEnd.iParaElement;paraItem++)
       
   593 		{// Externalize all but last TParaAttribsEntrys from the para index
       
   594 		TParaAttribsEntry paraEntry=(*iParaIx)[paraItem];
       
   595 		TInt phraseCount=(paraEntry.iParaAttribs->IsShared()) 
       
   596 			? 0 
       
   597 			: paraEntry.iParaAttribs->iPhraseCount;
       
   598 		if (paraItem==aStart.iParaElement)
       
   599 			{// Fix & write length & phrase count of the first paragraph.
       
   600 			paraEntry.iLength=(paraEntry.iLength-aStart.iParaElementOffset);  // fix 1st para length
       
   601 			if (phraseCount>0)
       
   602 				phraseCount=phraseCount-(aStart.iPhraseElement-aStart.iParaBasePhraseElement);
       
   603 			}
       
   604 		aStream.WriteInt32L(paraEntry.iLength);
       
   605 		CParaAttribs* paraAttribs=paraEntry.iParaAttribs;
       
   606 		TUint8 refNo=RefNum(paraAttribs);
       
   607 		aStream.WriteUint8L(refNo);
       
   608 		if (refNo==0)
       
   609 			{// Write specific para layer & phrase count
       
   610 			ExternalizeParagraphFormatL(aStream,*paraAttribs->iParaFormat,aStyleList);
       
   611 			aStream.WriteInt32L(phraseCount);
       
   612 			}
       
   613 		}
       
   614 	// Fix & write the length of the last paragraph.
       
   615 	if (aStart.iParaElement==aEnd.iParaElement)
       
   616 		lastParaEntry.iLength=(aEnd.iParaElementOffset-aStart.iParaElementOffset)+1;  // copied text contained within 1 para
       
   617 	else
       
   618 		lastParaEntry.iLength-=(lastParaEntry.iLength-aEnd.iParaElementOffset)-1;
       
   619 	aStream.WriteInt32L(lastParaEntry.iLength);
       
   620 	// Fix & write the phrase count of the last paragraph if it has specific char format
       
   621 	CParaAttribs* lastParaAttribs=lastParaEntry.iParaAttribs;
       
   622 	TUint8 refNo=RefNum(lastParaAttribs);
       
   623 	RPhraseAttribsEntry* virtualTextPhrase=NULL;
       
   624 	if (incompleteParaFlag)
       
   625 		{// Adjust the phrase count for this paragraph that is not complete
       
   626 		TInt phraseCount=0;
       
   627 		if (aStart.iParaElement==aEnd.iParaElement)
       
   628 			phraseCount=(aEnd.iPhraseElement-aStart.iPhraseElement)+1;  // copied text contained within 1 para
       
   629 		else
       
   630 			phraseCount=(aEnd.iPhraseElement-aEnd.iParaBasePhraseElement)+1;
       
   631 		__ASSERT_DEBUG(phraseCount<=lastParaAttribs->iPhraseCount,Panic(ERtExternalizeParaIx));
       
   632 		aStream.WriteInt32L(phraseCount);
       
   633 		if (refNo>0)
       
   634 			{// Set the virtual phrase representing the trailing text from the shared paragraph.
       
   635 			virtualTextPhrase=new(ELeave) RPhraseAttribsEntry(lastParaAttribs->iCharFormat,lastParaEntry.iLength);
       
   636 			CleanupStack::PushL(virtualTextPhrase);
       
   637 			}
       
   638 
       
   639 		// Write out the paragraph format for the paragraph that is not complete
       
   640 		// - necessary since we need to patch up the style character formatting
       
   641 		if (aStyleList || aEnd.iDocPos+1 == iText.DocumentLength())
       
   642 			ExternalizeParagraphFormatL(aStream, *lastParaAttribs->iParaFormat, aStyleList);
       
   643 		}
       
   644 	else
       
   645 		{// This is a complete para - copy region ends on a paragraph delimiter.
       
   646 		aStream.WriteUint8L(refNo);
       
   647 		if (refNo==0)
       
   648 			{// Write specific para layer & phrase count
       
   649 			ExternalizeParagraphFormatL(aStream,*lastParaAttribs->iParaFormat,aStyleList);
       
   650 			TInt phraseCount=lastParaAttribs->iPhraseCount;
       
   651 			if (aStart.iParaElement==aEnd.iParaElement && aStart.iParaElementOffset && aStart.iParaElementOffset>0)
       
   652 				phraseCount=(aEnd.iPhraseElement-aStart.iPhraseElement)+1;  // copied text contained within 1 para
       
   653 			aStream.WriteInt32L(phraseCount);
       
   654 			}
       
   655 		}
       
   656 	if (virtualTextPhrase)
       
   657 	    CleanupStack::Pop(virtualTextPhrase);
       
   658 	return virtualTextPhrase;
       
   659 	}
       
   660 
       
   661 
       
   662 void CRichTextIndex::ExternalizeParagraphFormatL(RWriteStream& aStream,const CParaFormatLayer& aLayer,const CStyleList* aStyleList)const
       
   663 // If a style list is present, write out the based-on links for every paragraph format layer,
       
   664 // in order to reconnect each paragraph to the right style on loading.
       
   665 //
       
   666 	{
       
   667 	aStream<< aLayer;
       
   668 	if (aStyleList)
       
   669 		{
       
   670 		TInt refNo=0;
       
   671 		refNo=aStyleList->IndexByPtr(((CParaFormatLayer*)aLayer.SenseBase()));
       
   672 		// returns the offset in the style list, or a negative error.
       
   673 		//
       
   674 		refNo=(refNo!=KErrNotFound)
       
   675 			? refNo+1  // the nth style where 1st item is offset 1.
       
   676 			: 0;  // An error value was returned so this thing has no paragraph style as its base
       
   677 		aStream.WriteInt8L((TInt8)-refNo);
       
   678 		}
       
   679  	}
       
   680 
       
   681 
       
   682 CParaFormatLayer* CRichTextIndex::InternalizeParagraphFormatL(RReadStream& aStream,const TRtPasteContext& aContext)
       
   683 // 
       
   684 	{
       
   685 	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(aStream);  // specific paragraph format layer
       
   686 	TUint index=0;
       
   687 	if (aContext.iParagraphStylesFlag)
       
   688 		{
       
   689 		CleanupStack::PushL(paraLayer);
       
   690 		TInt refNo=aStream.ReadInt8L();  // Read in the based on link to fix up to the style table
       
   691 		CleanupStack::Pop();
       
   692 		index=Abs(refNo);
       
   693 		}
       
   694 	if (index>0 && aContext.iStyleList)
       
   695 		paraLayer->SetBase(aContext.iStyleList->At(index-1).iStyle);
       
   696 	else
       
   697 		paraLayer->SetBase(aContext.iGlobalParaLayer);
       
   698 	return paraLayer;
       
   699 	}
       
   700 
       
   701 
       
   702 CParaFormatLayer* CRichTextIndex::PasteParagraphFormatL(RReadStream& aStream,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
       
   703 // 
       
   704 	{
       
   705 	CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(aStream);  // specific paragraph format layer
       
   706  
       
   707 	TUint index=0;
       
   708 	if (aContext.iParagraphStylesFlag)
       
   709 		{
       
   710 		CleanupStack::PushL(paraLayer);
       
   711 		TInt refNo=aStream.ReadInt8L();  // Read in the based on link to fix up to the style table
       
   712 		CleanupStack::Pop(paraLayer);	// paraLayer
       
   713 		index=Abs(refNo);
       
   714 		}
       
   715 
       
   716 	// If a style exists for this paragraph, set it as the base.
       
   717 	// If a style list doesn't exist, the base paragraph style will be set instead.
       
   718 	
       
   719 	if (index>0 && aContext.iStylePasteMode != CParagraphStyle::EIgnoreNewStyles)
       
   720 	{
       
   721 		if (!aContext.iStyleList || (aContext.iStyleList && aContext.iStylePasteMode == CParagraphStyle::EConvertNewStyles))
       
   722 		{
       
   723 			CleanupStack::PushL(paraLayer);
       
   724 			iLastCharacterStyle = (aStyleMap->Item(index))->iCharFormatLayer;
       
   725 
       
   726 			// If the application doesn't have a style list, 
       
   727 			// the new paragraph style has to be enforced by merging the old
       
   728 			// paralayer with the style paralayer
       
   729 			CParaFormat* MergedParaFormat = CParaFormat::NewLC();
       
   730 			TParaFormatMask MergedParaFormatMask;
       
   731 
       
   732 			CParaFormatLayer* newParaLayer;
       
   733 
       
   734 			// Extract the masks from both layers
       
   735 			paraLayer->SenseL(MergedParaFormat, MergedParaFormatMask);
       
   736 			(aStyleMap->Item(index))->SenseL(MergedParaFormat, MergedParaFormatMask);
       
   737 
       
   738 			newParaLayer = CParaFormatLayer::NewL(MergedParaFormat, MergedParaFormatMask);
       
   739 
       
   740 			// Now on stack: MergedParaFormat, paraLayer, ...
       
   741 			CleanupStack::PopAndDestroy();	// delete MergedParaFormat
       
   742 
       
   743 			// Now on stack: paraLayer, ...
       
   744 			CleanupStack::PopAndDestroy();	// paraLayer
       
   745 			paraLayer = newParaLayer;
       
   746 
       
   747 			paraLayer->SetBase(aContext.iGlobalParaLayer);
       
   748 
       
   749 		}
       
   750 		else 
       
   751 		{
       
   752 			paraLayer->SetBase(aStyleMap->Item(index));		
       
   753 			iLastCharacterStyle = NULL;
       
   754 		}
       
   755 	}
       
   756 	else 
       
   757 	// Otherwise set the character style to NULL, which will set the global
       
   758 	// character style (see line 983 approx)
       
   759 	{
       
   760 		iLastCharacterStyle = NULL;
       
   761 		paraLayer->SetBase(aContext.iGlobalParaLayer);
       
   762 	}
       
   763 		
       
   764 	return paraLayer;
       
   765 	}
       
   766 
       
   767 
       
   768 void CRichTextIndex::InternalizeParaIxL(RReadStream& aStream,const TRtPasteContext& aContext)
       
   769 // Restore the paragraph index & all associated specific para formats,
       
   770 // All existing index data is lost.
       
   771 //
       
   772 	{
       
   773 	// The para index has been reset at the start of internalize shared formats.
       
   774 	TInt paraIxCount=aStream.ReadInt32L();  // paragraph count
       
   775 	for (TInt currentPara=0;currentPara<paraIxCount;currentPara++)
       
   776 		{// Restore each paragraph
       
   777 		TParaAttribsEntry para;
       
   778 		para.iLength=aStream.ReadInt32L();  // paragraph length
       
   779 		TUint8 refNo=aStream.ReadUint8L();  // ref no
       
   780 		if (refNo>0)
       
   781 			{// Link to para attribs in shared list & up its reference count
       
   782 			para.iParaAttribs=SharedParaAttribs(refNo);
       
   783 			para.iParaAttribs->iRefCount++;
       
   784 			iParaIx->AppendL(para);
       
   785 			}
       
   786 		else
       
   787 			{// Have to build up the specific para attribs
       
   788 			CParaFormatLayer* paraLayer=InternalizeParagraphFormatL(aStream,aContext);
       
   789 			CleanupStack::PushL(paraLayer);
       
   790 			CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
       
   791 				CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
       
   792 			specificParaAttribs->iPhraseCount=aStream.ReadInt32L();  // specific phrase count
       
   793 				CleanupStack::Pop();	// specificParaAttribs
       
   794 			CleanupStack::PopAndDestroy(); // paraLayer
       
   795 			para.iParaAttribs=specificParaAttribs;
       
   796 			CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
       
   797 			iParaIx->AppendL(para);
       
   798 			CleanupStack::Pop();  // specificParaAttribs
       
   799 			}
       
   800 		}
       
   801 	}
       
   802 
       
   803 void CRichTextIndex::ExternalizePhraseIxL(RWriteStream& aStream)const
       
   804 // Called from an Externalize.
       
   805 // All phrases must be saved.
       
   806 //
       
   807 	{ExternalizePhrasesL(aStream,0,PhraseCount());}
       
   808 
       
   809 
       
   810 void CRichTextIndex::ExternalizePhraseIxL(RWriteStream& aStream,
       
   811 										  const TLogicalPosition& aStart,
       
   812 										  TLogicalPosition& aEnd,
       
   813 										  const RPhraseAttribsEntry* aVirtualTrailingText)const
       
   814 // Called from CopyToStream.
       
   815 // Here, a text fragment only, is to be saved.
       
   816 // The last argument may be NULL.  If it is other than NULL, it represents trailing text
       
   817 // that has no paragraph delimiter, which was part of a shared paragraph.  This must be presented as
       
   818 // a distinct phrase, since this is the context in which it is pasted back into a document.
       
   819 //
       
   820 	{
       
   821 	TInt phraseCount=PhraseCount();
       
   822 	phraseCount+=(aVirtualTrailingText) ? 1 : 0;
       
   823 	TBool noRealPhrasesInRegion=ETrue;
       
   824 	TInt nn=aStart.iParaElement;
       
   825 	while (nn<=aEnd.iParaElement && noRealPhrasesInRegion)
       
   826 		{
       
   827 		if (!(*iParaIx)[nn].iParaAttribs->IsShared())
       
   828 			noRealPhrasesInRegion=EFalse;
       
   829 		nn++;
       
   830 		}
       
   831 	//
       
   832 	if (phraseCount==0 || (phraseCount==1 && aVirtualTrailingText || noRealPhrasesInRegion))  // save this phrase count
       
   833 		ExternalizePhrasesL(aStream,aStart.iPhraseElement,0,aVirtualTrailingText);
       
   834 	else
       
   835 		{
       
   836 		TBool endParaShared=(*iParaIx)[aEnd.iParaElement].iParaAttribs->IsShared();
       
   837 		if (endParaShared && aEnd.iPhraseElement>0)
       
   838 			aEnd.iPhraseElement--;  // Due to action of ScanToPosition
       
   839 		//
       
   840 		RPhraseAttribsEntry* backPhrase=&(*iPhraseIx)[aEnd.iPhraseElement];
       
   841 		TInt backLength=backPhrase->Length();
       
   842 		if (!(endParaShared || backPhrase->IsPicturePhrase()))
       
   843 			backPhrase->SetLength(aEnd.iPhraseElementOffset+1);
       
   844 		//
       
   845 		RPhraseAttribsEntry* frontPhrase=&(*iPhraseIx)[aStart.iPhraseElement];
       
   846 		TInt frontLength=frontPhrase->Length();
       
   847 		if (!frontPhrase->IsPicturePhrase())  // Fix length of first phrase.
       
   848 			frontPhrase->SetLength(frontLength-aStart.iPhraseElementOffset);
       
   849 		TRAPD(ret,
       
   850 			ExternalizePhrasesL(aStream,aStart.iPhraseElement,aEnd.iPhraseElement-aStart.iPhraseElement+1,aVirtualTrailingText));
       
   851 		//
       
   852 		// Now fix the altered phrase lengths.
       
   853 		if (!frontPhrase->IsPicturePhrase())
       
   854 			frontPhrase->SetLength(frontLength);
       
   855 		if (!(endParaShared || backPhrase->IsPicturePhrase()))
       
   856 			backPhrase->SetLength(backLength);
       
   857 
       
   858 		__TEST_INVARIANT;	// we lied about being const
       
   859 
       
   860 		User::LeaveIfError(ret);
       
   861 		}
       
   862 	}
       
   863 
       
   864 
       
   865 void CRichTextIndex::ExternalizePhrasesL(RWriteStream& aStream,TInt aStart,TInt aPhraseCount,
       
   866 										 const RPhraseAttribsEntry* aVirtualPhrase)const
       
   867 // Save the specified number of phrases present in the phrase index,
       
   868 // starting from phrase offset aStart.
       
   869 //
       
   870 	{
       
   871 	ExternalizePhraseCountL(aStream,aPhraseCount+ ((aVirtualPhrase)?1:0) );
       
   872 	for (TInt phraseItem=aStart;phraseItem<aStart+aPhraseCount;phraseItem++)
       
   873 		{
       
   874 		RPhraseAttribsEntry& phraseEntry=(*iPhraseIx)[phraseItem];
       
   875 		aStream<< phraseEntry;
       
   876 		}
       
   877 	if (aVirtualPhrase)
       
   878 		aStream<< *aVirtualPhrase;
       
   879 	}
       
   880 
       
   881 
       
   882 void CRichTextIndex::InternalizePhraseIxL(RReadStream& aStream,const CCharFormatLayer* aGlobalCharFormat)
       
   883 // Load all the phrases from the stream, and insert them into the phrase index
       
   884 //
       
   885 	{
       
   886 	iPhraseIx->Reset();
       
   887 	TInt phraseCount=aStream.ReadInt32L();
       
   888 
       
   889 	// Extend phrase index by required amount
       
   890 	iPhraseIx->AppendL(RPhraseAttribsEntry(),phraseCount);
       
   891 	
       
   892 	for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++)
       
   893 		{// Restore each phrase & insert into the phrase index.
       
   894 		TBool isPicture=(TBool)aStream.ReadUint8L();
       
   895 		TInt phraseLength=aStream.ReadInt32L();
       
   896 		CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);
       
   897 		charLayer->SetBase(aGlobalCharFormat);
       
   898 		RPhraseAttribsEntry& tPhrase=iPhraseIx->At(phraseItem);
       
   899 		if (!isPicture)
       
   900 			new(&tPhrase) RPhraseAttribsEntry(charLayer,phraseLength);
       
   901 		else
       
   902 			{// Manufacture new picture header & set its picture store
       
   903 			CleanupStack::PushL(charLayer);
       
   904 			TPictureHeader hdr;
       
   905 			aStream>> hdr;
       
   906 			TBool ownershipTaken(EFalse);
       
   907 			CPicturePhrase* picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken);
       
   908 			CleanupStack::Pop();  // char layer
       
   909 			new(&tPhrase) RPhraseAttribsEntry(picPhrase);
       
   910 			iPictureCount++;
       
   911 			}
       
   912 		}
       
   913 	}
       
   914 
       
   915 
       
   916 CParaAttribs* CRichTextIndex::SharedParaAttribs(TUint8 aOrdinal)
       
   917 // Return the handle of the para attribs in the shared para attribs list,
       
   918 // whose position in the list is specified by the argument aOrdinal.
       
   919 //
       
   920 	{
       
   921 	CParaAttribs* currentSharedPara;
       
   922 	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
       
   923 	TInt match=1;
       
   924 	while ((currentSharedPara=iterator++)!=NULL && aOrdinal!=match)
       
   925 		match++;
       
   926 	__ASSERT_ALWAYS(currentSharedPara!=NULL,Panic(EEndOfSharedParaListEncountered));
       
   927 	return currentSharedPara;
       
   928 	}
       
   929 
       
   930 
       
   931 TUint8 CRichTextIndex::RefNum(const CParaAttribs* aParaAttribs)const
       
   932 // If the para attribs argument is present in the shared list, return a 
       
   933 // reference to it; otherwise return zero as the reference.
       
   934 //
       
   935 	{
       
   936 	CParaAttribs* currentSharedPara;
       
   937 	TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
       
   938 	TUint8	 refNo=1;
       
   939 	while ((currentSharedPara=iterator++)!=NULL)
       
   940 		{
       
   941 		if (currentSharedPara==aParaAttribs)
       
   942 			return refNo;
       
   943 		refNo++;
       
   944 		}
       
   945 	return 0;
       
   946 	}
       
   947 
       
   948 //////////////////////////////////////////////////
       
   949 //////////////////////////////////////////////////
       
   950 //////////////////////////////////////////////////
       
   951 
       
   952 void CRichTextIndex::PasteFromStreamL(const CStreamStore& aStore,RReadStream& aStream,TInt aPos,CParagraphStyle::TStylePasteMode aStylePasteMode,const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer)
       
   953 //
       
   954 	{
       
   955 	__TEST_INVARIANT;
       
   956 	
       
   957 	CancelInsertCharFormat();
       
   958 	ScanToPosition(aPos,EScanToPositionAbsolute);
       
   959 
       
   960 	//
       
   961 	//  Get the header
       
   962 	TRtPasteContext context(&aStore,aGlobalParaLayer,aGlobalCharLayer,iText.StyleList());
       
   963 	context.iPastePos=iPos;
       
   964 	context.iStylePasteMode = aStylePasteMode;
       
   965 
       
   966 	InternalizeRtiHeaderL(aStream,context);  // no rollback required on the header.  Does not alter iPos.
       
   967 	//
       
   968 	// Get the pargraph styles
       
   969 
       
   970 	CStyleMap* styleMap = NULL;
       
   971 	if (context.iParagraphStylesFlag)
       
   972 	{
       
   973 		TUint8 styleCount=ReadTUint8CountL(aStream);
       
   974 		styleMap=CStyleMap::NewLC(styleCount);
       
   975 		TRAPD(ret,
       
   976 		PasteStylesL(aStream,*styleMap,context));  // Does not alter iPos.
       
   977 		if (ret!=KErrNone) {RbPasteSharedFormatsL(ret);}
       
   978 	}
       
   979 	//
       
   980 	// Get the shared formats
       
   981 	TUint8 sharedParaCount=ReadTUint8CountL(aStream);
       
   982 	CParaAttribsMap* paraMap=CParaAttribsMap::NewLC(sharedParaCount);
       
   983 	TRAPD(ret,
       
   984 	PasteSharedFormatsL(aStream,*paraMap,context,styleMap));  // Does not alter iPos.
       
   985 	if (ret!=KErrNone)
       
   986 		{
       
   987 		// beginning of fixing DEF 126651 (1/2)
       
   988 		// free orphan object before leave.
       
   989 		if (context.iParagraphStylesFlag)
       
   990 		{
       
   991 			if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
       
   992 			{
       
   993 			TInt maxSize = styleMap->Count();
       
   994 			for (TInt count=0; count<maxSize; count++)
       
   995 				{
       
   996 				delete (CParagraphStyle*)styleMap->At(count).iT;	
       
   997 				}
       
   998 			}
       
   999 			CleanupStack::PopAndDestroy();	// cleanup styleMap
       
  1000 		}
       
  1001 		CleanupStack::PopAndDestroy();  // cleanup paraMap
       
  1002 		// end of fixing DEF 126651 (1/2)
       
  1003 		RbPasteSharedFormatsL(ret);
       
  1004 		}
       
  1005 	//
       
  1006 	// Get the markup
       
  1007 	TRAP(ret,
       
  1008 	PasteIxL(aStream,context,*paraMap, styleMap));  // context now has both global layers & pastePos
       
  1009 	if (ret!=KErrNone)
       
  1010 		{
       
  1011 		// beginning of fixing DEF 126651 (2/2)
       
  1012 		// free orphan object before leave.
       
  1013 		if (context.iParagraphStylesFlag)
       
  1014 		{
       
  1015 			if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
       
  1016 			{
       
  1017 			TInt maxSize = styleMap->Count();
       
  1018 			for (TInt count=0; count<maxSize; count++)
       
  1019 				{
       
  1020 				delete (CParagraphStyle*)styleMap->At(count).iT;	
       
  1021 				}
       
  1022 			}
       
  1023 			CleanupStack::PopAndDestroy();	// cleanup styleMap
       
  1024 		}
       
  1025 		CleanupStack::PopAndDestroy();  // cleanup paraMap
       
  1026 		// end of fixing DEF 126651 (2/2)
       
  1027 		RbPasteSharedFormatsL(ret);
       
  1028 		}
       
  1029 
       
  1030 
       
  1031 	if (context.iParagraphStylesFlag)
       
  1032 	{
       
  1033 		TRAP(ret,GenerateAllPhraseLinksL());
       
  1034 		if (ret != KErrNone)
       
  1035 			RbPasteSharedFormatsL(ret);
       
  1036 
       
  1037 		if (!context.iStyleList || context.iStylePasteMode == CParagraphStyle::EConvertNewStyles)
       
  1038 		{
       
  1039 		TInt maxSize = styleMap->Count();
       
  1040 		for (TInt count=0; count<maxSize; count++)
       
  1041 			{
       
  1042 			delete (CParagraphStyle*)styleMap->At(count).iT;	
       
  1043 			}
       
  1044 		}
       
  1045 		CleanupStack::PopAndDestroy();	// cleanup styleMap
       
  1046 	}
       
  1047 
       
  1048 	CleanupStack::PopAndDestroy();  // cleanup paraMap
       
  1049 
       
  1050 	__TEST_INVARIANT;
       
  1051 	}
       
  1052 
       
  1053 
       
  1054 void CRichTextIndex::PasteStylesL(RReadStream& aStream,CStyleMap& aMap,const TRtPasteContext& aContext)
       
  1055 // Restore the paragraph styles from the specified stream.
       
  1056 // Restoration is controlled by the flag TStylePasteMode.
       
  1057 //
       
  1058 	{
       
  1059 	
       
  1060 	TInt styleCount=aMap.iCapacity;
       
  1061 //	TBool docSupportsStyles = iText.StyleListPresent();	// detect if document has style list
       
  1062 	CParagraphStyle* style=NULL;
       
  1063 	for(TUint8 ii=0; ii<styleCount; ii++)
       
  1064 	{
       
  1065 		TInt refNo=aStream.ReadInt8L();
       
  1066 		style=CParagraphStyle::NewL(aStream,*aContext.iGlobalParaLayer,*aContext.iGlobalCharLayer);
       
  1067 
       
  1068 		// Now attempt to map this style to one in the document we are adding it to
       
  1069 		// refNo contains the style number when the selection was cut, which
       
  1070 		//   is needed to map to the reference no's coming in with the paragraph
       
  1071 		//   format info
       
  1072 
       
  1073 		if (aContext.iStylePasteMode == CParagraphStyle::EIgnoreNewStyles)
       
  1074 			// We're ignoring all style info, so delete it now
       
  1075 			delete style;
       
  1076 		else
       
  1077 		{
       
  1078 
       
  1079 		if (aContext.iStyleList && aContext.iStylePasteMode == CParagraphStyle::EAddNewStyles)
       
  1080 		{
       
  1081 			TInt docStyle = iText.StyleList()->IndexByName(style->iName);
       
  1082 			if (docStyle!=KErrNotFound)
       
  1083 			{
       
  1084 				/* Add the existing style into the stylemap */
       
  1085 				aMap.Bind(refNo,iText.StyleList()->PtrByName(style->iName)->iStyle);
       
  1086 
       
  1087 				/* Since this style exists, we can safely delete this copy */
       
  1088 				delete style;
       
  1089 
       
  1090 			}
       
  1091 			else
       
  1092 			{
       
  1093 				// Ok, the document doesn't have this style in it.
       
  1094 				// So let's add it in, and put a reference in the stylemap
       
  1095 
       
  1096 				RParagraphStyleInfo newStyle(style);
       
  1097 
       
  1098 				iText.StyleList()->AppendL(&newStyle);
       
  1099 
       
  1100 				aMap.Bind(refNo,style);
       
  1101 
       
  1102 				// the StyeList takes care of style destruction, so no deletion
       
  1103 				// is necessary here
       
  1104 			}
       
  1105 		}
       
  1106 		else
       
  1107 		{
       
  1108 			// Document doesn't support styles, so save them so they can
       
  1109 			// be converted to character specific formatting later on
       
  1110 			aMap.Bind(refNo, style);
       
  1111 		}
       
  1112 		}
       
  1113 
       
  1114 	}
       
  1115 }
       
  1116 
       
  1117 
       
  1118 void CRichTextIndex::ImposeCharacterStyleL(CCharFormatLayer** aCharLayer)
       
  1119 {
       
  1120 	// This function is used to impose the current character style onto
       
  1121 	// the character layer for this paragraph. It's used when translating
       
  1122 	// style information into specific formatting when pasting text containing
       
  1123 	// styles into text without styles.
       
  1124 
       
  1125 	TCharFormatX MergedCharFormat;
       
  1126 	TCharFormatXMask MergedCharFormatMask;
       
  1127 			
       
  1128 	CCharFormatLayer* newCharLayer;
       
  1129 
       
  1130 	// Extract the masks from both layers.
       
  1131 	// use MergedCharFormat to hold the char info which we don't want yet
       
  1132 
       
  1133 	(*aCharLayer)->Sense(MergedCharFormat, MergedCharFormatMask);
       
  1134 	iLastCharacterStyle->Sense(MergedCharFormat, MergedCharFormatMask);
       
  1135 			
       
  1136 	// Re-build charLayer;
       
  1137 	CleanupStack::PushL(*aCharLayer);
       
  1138 	newCharLayer = CCharFormatLayer::NewL(MergedCharFormat,MergedCharFormatMask);
       
  1139 	CleanupStack::Pop(*aCharLayer);
       
  1140 
       
  1141 	delete (*aCharLayer);
       
  1142 	(*aCharLayer) = newCharLayer;
       
  1143 }
       
  1144 
       
  1145 
       
  1146 void CRichTextIndex::PasteSharedFormatsL(RReadStream& aStream,CParaAttribsMap& aMap,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
       
  1147 // Load shared formats from the specified stream.
       
  1148 // Only adds the loaded shared format to the list of shared formats
       
  1149 // if it does not already exist in that list.
       
  1150 // A map is kept, that for each loaded format specifies its offset within
       
  1151 // the shared list.
       
  1152 //
       
  1153 
       
  1154 	{
       
  1155 	TInt mapCount=aMap.iCapacity;
       
  1156 	for (TUint8 paraItem=0;paraItem<mapCount;paraItem++)
       
  1157 		{
       
  1158 		TInt refNo=aStream.ReadInt32L();
       
  1159 		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
       
  1160 		CleanupStack::PushL(paraLayer);
       
  1161 
       
  1162 		CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);  // Does not restore based on link.
       
  1163 //// Change specific formatting for this paragraph
       
  1164 
       
  1165 		if (iLastCharacterStyle != NULL)
       
  1166 			ImposeCharacterStyleL(&charLayer);
       
  1167 		
       
  1168 		charLayer->SetBase(aContext.iGlobalCharLayer);
       
  1169 
       
  1170 		CleanupStack::PushL(charLayer);
       
  1171 		CParaAttribs* paraAttribs=GetParaAttribsL(paraLayer,charLayer);
       
  1172 		CleanupStack::PopAndDestroy(2);  // charLayer & paraLayer
       
  1173 		aMap.Bind(refNo,paraAttribs);
       
  1174 		paraAttribs->iRefCount--;
       
  1175 		}
       
  1176 	}
       
  1177 
       
  1178 
       
  1179 void CRichTextIndex::PasteIxL(RReadStream& aStream,TRtPasteContext& aContext,const CParaAttribsMap& aMap,CStyleMap* aStyleMap/*,CParaAttribs* aSecondReserved*/)
       
  1180 //
       
  1181 	{
       
  1182 	TInt completeParaCount=aStream.ReadInt32L();
       
  1183 	completeParaCount-=(aContext.iIncompleteParaFlag)? 1 : 0;
       
  1184 //	Create rollback states
       
  1185 	TParaAttribsEntry para=(*iParaIx)[aContext.iPastePos.iParaElement];
       
  1186 	CParaAttribs* reclaimed=RequestReclaimShareL(para.iParaAttribs,&para);  // does not release share
       
  1187 	iRollbackParaAttribsHandle=NULL;
       
  1188 	if (reclaimed)
       
  1189 		{
       
  1190 		iRollbackParaAttribsHandle=para.iParaAttribs;
       
  1191 		CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed));
       
  1192 		(*iParaIx)[aContext.iPastePos.iParaElement].iParaAttribs=reclaimed;  // Use this reclaimed para attribs
       
  1193 		}
       
  1194 //	Split the phrase at the paste position, ready to insert clipboard content
       
  1195 	TRAPD(ret,
       
  1196 	SplitPhraseL(aContext.iPastePos.iDocPos));
       
  1197 		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
       
  1198 	ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);  // pick up the changes
       
  1199 	aContext.iPastePos=iPos;
       
  1200 //	Paste all complete paragraphs from the clipboard
       
  1201 	TInt characterCount=0;
       
  1202 	RPhraseAttribsEntry* firstParaVirtualPhrase=NULL;
       
  1203 	TRAP(ret,
       
  1204 	characterCount=PasteParaIxL(aStream,aContext,completeParaCount,aMap,firstParaVirtualPhrase,aStyleMap));
       
  1205 		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
       
  1206 	CleanupStack::PushL(firstParaVirtualPhrase);
       
  1207 //	Paste any remaining text fragment.
       
  1208 	TTextFragment textFragment;
       
  1209 	if (aContext.iIncompleteParaFlag)
       
  1210 		{
       
  1211 		TRAPD(ret,
       
  1212 		textFragment=GetTextFragmentL(aStream));
       
  1213 			if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}			
       
  1214 		characterCount+=textFragment.iLength;
       
  1215 
       
  1216 		// Restore the character stle info for the final text fragment
       
  1217 		if (aContext.iParagraphStylesFlag || aContext.iApplyFormatToLastFlag)
       
  1218 			{
       
  1219 			CParaFormatLayer* paraLayer = PasteParagraphFormatL(aStream, aContext, aStyleMap);
       
  1220 			CleanupStack::PushL(paraLayer);
       
  1221 			//Restore the paragraph formatting for the final text fragment
       
  1222 			if (aContext.iApplyFormatToLastFlag)
       
  1223 				{
       
  1224 				CParaFormat* paraFormat = CParaFormat::NewLC();
       
  1225 				TParaFormatMask mask;
       
  1226 				paraLayer->SenseL(paraFormat,mask);
       
  1227 				(*iParaIx)[completeParaCount].iParaAttribs->iParaFormat->SetL(paraFormat,mask);
       
  1228 				CleanupStack::PopAndDestroy(paraFormat);
       
  1229 				}
       
  1230 			// We can now discard the format layer, but the character format has been safely
       
  1231 			// patched to the style character format
       
  1232 			CleanupStack::PopAndDestroy(paraLayer);
       
  1233 			}
       
  1234 		}
       
  1235 //
       
  1236 	TRAP(ret,
       
  1237 	PastePhraseIxL(aStream,aContext,firstParaVirtualPhrase));
       
  1238 		if (ret!=KErrNone) {RbPasteParaIxL(aContext.iPastePos,aContext.iParasPasted,ret);}
       
  1239 	CleanupStack::PopAndDestroy();  // firstParaVirtualPhrase / shallow destroy only - deep copy in phraseIx
       
  1240 
       
  1241 //	ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);  // phraseIx not pasted at this point
       
  1242 //	TLogicalPosition headParaNormalizePos=iPos;
       
  1243 	
       
  1244 	
       
  1245 	if (completeParaCount==0)
       
  1246 		{// Adjust paragraph length & phrase count
       
  1247 		TParaAttribsEntry* para=&(*iParaIx)[aContext.iPastePos.iParaElement];
       
  1248 		para->iLength+=textFragment.iLength;
       
  1249 		para->iParaAttribs->iPhraseCount+=textFragment.iPhraseCount;
       
  1250 		ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);
       
  1251 		TLogicalPosition headParaNormalizePos=iPos;
       
  1252 		MergePhrases(headParaNormalizePos);
       
  1253 		MergePhrases(aContext.iPastePos.iDocPos+characterCount);
       
  1254 		DoPasteCleanup(headParaNormalizePos,reclaimed);
       
  1255 		}
       
  1256 	else
       
  1257 		{// Adjust paragraph lengths & phrase counts	
       
  1258 		TParaAttribsEntry* firstPara=&(*iParaIx)[aContext.iPastePos.iParaElement];
       
  1259 		firstPara->iLength+=aContext.iPastePos.iParaElementOffset;  // Update length of the first para
       
  1260 		firstPara->iParaAttribs->iPhraseCount+=(aContext.iPastePos.iPhraseElement-aContext.iPastePos.iParaBasePhraseElement);  // Update the phrase count of the first para attribs
       
  1261 		ScanToPosition(aContext.iPastePos.iDocPos,EScanToPositionAbsolute);
       
  1262 		TLogicalPosition headParaNormalizePos=iPos;
       
  1263 		MergePhrases(headParaNormalizePos);
       
  1264 		DoPasteCleanup(headParaNormalizePos,reclaimed);
       
  1265 		//
       
  1266 		// Adjust the length & phrase count of the new final paragraph
       
  1267 		TParaAttribsEntry* lastPara=&(*iParaIx)[aContext.iPastePos.iParaElement+completeParaCount];
       
  1268 		lastPara->iLength=(lastPara->iLength-aContext.iPastePos.iParaElementOffset)+textFragment.iLength;
       
  1269 		lastPara->iParaAttribs->iPhraseCount-=(aContext.iPastePos.iPhraseElement-aContext.iPastePos.iParaBasePhraseElement);
       
  1270 		// phrase count may be wrong - since the added phrase may have been merged into the current one.
       
  1271 		// Cant just add these phrases.
       
  1272 		lastPara->iParaAttribs->iPhraseCount+=textFragment.iPhraseCount;
       
  1273 		ScanToPosition(aContext.iPastePos.iDocPos+characterCount,EScanToPositionAbsolute);
       
  1274 		MergePhrases(iPos);
       
  1275 		DoPasteCleanup(iPos,(CParaAttribs*)NULL);
       
  1276 		}
       
  1277 	RebalanceIndex();
       
  1278 	NormalizeSharedList();
       
  1279 	}
       
  1280 
       
  1281 
       
  1282 void CRichTextIndex::DoPasteCleanup(TLogicalPosition& aNormalizePos,CParaAttribs* aReclaimed)
       
  1283 //
       
  1284 	{
       
  1285 	NormalizeNow(aNormalizePos);
       
  1286 	if (aReclaimed)
       
  1287 		CleanupStack::Pop();
       
  1288 	}
       
  1289 
       
  1290 
       
  1291 TInt CRichTextIndex::PasteParaIxL(RReadStream& aStream,TRtPasteContext& aContext,TInt aCompleteParaCount,const CParaAttribsMap& aMap,RPhraseAttribsEntry*& aFirstParaVirtualPhrase, CStyleMap* aStyleMap)
       
  1292 //
       
  1293 	{
       
  1294 	TParaAttribsEntry para;
       
  1295 	iParaIx->InsertL(aContext.iPastePos.iParaElement,para,aCompleteParaCount);	
       
  1296 	aContext.iParasPasted=aCompleteParaCount;
       
  1297 	TInt characterCount=0;
       
  1298 	if (aCompleteParaCount>0)
       
  1299 		{
       
  1300 		para=DoPasteFirstIntoParaL(aStream,aMap,aContext,aFirstParaVirtualPhrase, aStyleMap);
       
  1301 		TInt paraItem=0;
       
  1302 		(*iParaIx)[aContext.iPastePos.iParaElement+paraItem]=para;
       
  1303 		characterCount+=para.iLength;
       
  1304 		}
       
  1305 	CleanupStack::PushL(TCleanupItem(DiscardPhraseOnCleanup,aFirstParaVirtualPhrase));
       
  1306 	for (TInt paraItem=1;paraItem<aCompleteParaCount;paraItem++)
       
  1307 		{// Paste all the paras that have paragraph delimiters.
       
  1308 		para=DoPasteIntoParaL(aStream,aMap,aContext,aStyleMap);
       
  1309 		(*iParaIx)[aContext.iPastePos.iParaElement+paraItem]=para;
       
  1310 		characterCount+=para.iLength;
       
  1311 		}
       
  1312 	CleanupStack::Pop();  // firstParaVirtualPhrase
       
  1313 // ASSERT: At this point we have pasted all paras that were in the stream.	
       
  1314 	__ASSERT_DEBUG(aContext.iParasPasted==aCompleteParaCount,Panic(EPasteParaIxError));
       
  1315 	return characterCount;
       
  1316 	}
       
  1317 			
       
  1318 			
       
  1319 TParaAttribsEntry CRichTextIndex::DoPasteFirstIntoParaL(RReadStream& aStream,const CParaAttribsMap& aMap,const TRtPasteContext& aContext,RPhraseAttribsEntry*& aFirstParaVirtualPhrase,CStyleMap* aStyleMap)
       
  1320 //
       
  1321 	{
       
  1322 	TParaAttribsEntry para;
       
  1323 	para.iLength=aStream.ReadInt32L();
       
  1324 	TUint8 refNo=aStream.ReadUint8L();
       
  1325 	if (refNo>0)
       
  1326 		{// This is the first pasted para, so if shared, must convert to phrase on the fly.
       
  1327 		CParaAttribs* paraAttribs=aMap.Item(refNo);
       
  1328 		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraAttribs->iParaFormat);
       
  1329 		CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,specificParaAttribs));
       
  1330 		//
       
  1331 		CCharFormatLayer* layer=CCharFormatLayer::NewCopyBaseL(paraAttribs->iCharFormat);
       
  1332 		CleanupStack::PushL(layer);
       
  1333 		aFirstParaVirtualPhrase=new(ELeave) RPhraseAttribsEntry(layer,para.iLength);
       
  1334 		CleanupStack::Pop(2);  // layer & specificParaAttribs
       
  1335 		//
       
  1336 		para.iParaAttribs=specificParaAttribs;
       
  1337 		__ASSERT_ALWAYS(para.iParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError));
       
  1338 		}
       
  1339 	else
       
  1340 		{// Have to build up the specific para attribs
       
  1341 		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
       
  1342 		CleanupStack::PushL(paraLayer);
       
  1343 		TInt phraseCount=aStream.ReadInt32L();  // specific phrase count
       
  1344 		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
       
  1345 		specificParaAttribs->iPhraseCount=phraseCount;
       
  1346 		para.iParaAttribs=specificParaAttribs;
       
  1347 		CleanupStack::PopAndDestroy();  // a copy of paraLayer is taken!
       
  1348 		}
       
  1349 	return para;
       
  1350 	}
       
  1351 
       
  1352 
       
  1353 TParaAttribsEntry CRichTextIndex::DoPasteIntoParaL(RReadStream& aStream,const CParaAttribsMap& aMap,const TRtPasteContext& aContext,CStyleMap* aStyleMap)
       
  1354 //
       
  1355 	{
       
  1356 	TParaAttribsEntry para;
       
  1357 	para.iLength=aStream.ReadInt32L();
       
  1358 	TUint8 refNo=aStream.ReadUint8L();
       
  1359 	if (refNo>0)
       
  1360 		{// Link to para attribs in shared list & up its reference count
       
  1361 		para.iParaAttribs=aMap.Item(refNo);
       
  1362 		__ASSERT_ALWAYS(para.iParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError));
       
  1363 		para.iParaAttribs->iRefCount++;
       
  1364 		}
       
  1365 	else
       
  1366 		{// Have to build up the specific para attribs
       
  1367 		CParaFormatLayer* paraLayer=PasteParagraphFormatL(aStream,aContext,aStyleMap);
       
  1368 		CleanupStack::PushL(paraLayer);
       
  1369 		TInt phraseCount=aStream.ReadInt32L();  // specific phrase count
       
  1370 		CParaAttribs* specificParaAttribs=CParaAttribs::NewL(paraLayer);
       
  1371 		specificParaAttribs->iPhraseCount=phraseCount;
       
  1372 		para.iParaAttribs=specificParaAttribs;
       
  1373 		CleanupStack::PopAndDestroy();  // a copy of paraLayer is taken!
       
  1374 		}
       
  1375 	return para;
       
  1376 	}
       
  1377 
       
  1378 
       
  1379 TTextFragment CRichTextIndex::GetTextFragmentL(RReadStream& aStream)
       
  1380 //
       
  1381 	{
       
  1382 	TTextFragment textFragment;
       
  1383 	textFragment.iLength=aStream.ReadInt32L();
       
  1384 	textFragment.iPhraseCount=aStream.ReadInt32L();
       
  1385 	return textFragment;
       
  1386 	}
       
  1387 
       
  1388 
       
  1389 void CRichTextIndex::PastePhraseIxL(RReadStream& aStream,TRtPasteContext& aContext,const RPhraseAttribsEntry* aFirstParaVirtualPhrase)
       
  1390 // The character position to paste at should now fall on a phrase boundary.
       
  1391 //
       
  1392 	{
       
  1393 // ASSERT: Having pasted the paraIx, the para containig pastePos has had the containing phrase split at that point.
       
  1394 	__ASSERT_ALWAYS(aContext.iPastePos.iPhraseElementOffset==0,Panic(EPastePhraseIxErr));
       
  1395 
       
  1396 	TInt offset=0;
       
  1397 	TInt phraseCount=aStream.ReadInt32L();  // leave caught by calling function.  No state change yet.
       
  1398 	if (aFirstParaVirtualPhrase)
       
  1399 		{
       
  1400 		iPhraseIx->InsertL(aContext.iPastePos.iPhraseElement,*aFirstParaVirtualPhrase);
       
  1401 		offset++;
       
  1402 		}
       
  1403 	RPhraseAttribsEntry holdingPhrase;
       
  1404 	iPhraseIx->InsertL(aContext.iPastePos.iPhraseElement+offset,holdingPhrase,phraseCount);
       
  1405 	for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++)
       
  1406 		{// Restore each phrase & insert into the phrase index.
       
  1407 		RPhraseAttribsEntry phrase;
       
  1408 		TRAPD(ret,
       
  1409 //		phrase=DoPastePhraseL(aStream,aContext));  // !! delete this if the code works
       
  1410 		DoPastePhraseL(aStream,aContext,phrase));
       
  1411 			if (ret!=KErrNone) {RbPastePhraseIxL(aContext.iPastePos,phraseCount+offset,ret);}
       
  1412 		(*iPhraseIx)[aContext.iPastePos.iPhraseElement+phraseItem+offset]=phrase;
       
  1413 		if (phrase.IsPicturePhrase() && iText.PictureFactory())
       
  1414 			iPictureCount++;
       
  1415 		}
       
  1416 	}
       
  1417 
       
  1418 
       
  1419 void CRichTextIndex::DoPastePhraseL(RReadStream& aStream,const TRtPasteContext& aContext,RPhraseAttribsEntry& aPhrase)
       
  1420 //
       
  1421 	{
       
  1422 	TBool isPicture=(TBool)aStream.ReadUint8L();
       
  1423 	TInt phraseLength=aStream.ReadInt32L();
       
  1424 
       
  1425 	__ASSERT_ALWAYS(isPicture && phraseLength==1 || !isPicture,User::Leave(KErrCorrupt));
       
  1426 	
       
  1427 	CCharFormatLayer* charLayer=CCharFormatLayer::NewL(aStream);
       
  1428 /// Change this character format if style formatting is to be applied
       
  1429 
       
  1430 // Paste style for the trailing text
       
  1431 	if (iLastCharacterStyle != NULL)
       
  1432 			ImposeCharacterStyleL(&charLayer);
       
  1433 	
       
  1434 		charLayer->SetBase(aContext.iGlobalCharLayer);
       
  1435 
       
  1436 	CPicturePhrase* picPhrase=NULL;
       
  1437 	const MPictureFactory* factory=iText.PictureFactory();
       
  1438 	TBool pictureLoadError=EFalse;
       
  1439 	if (isPicture)
       
  1440 		{
       
  1441 		TPictureHeader hdr;
       
  1442 		aStream>> hdr;  // hdr.iPicture always references a picture in the deferred store.
       
  1443 		if (isPicture && factory)
       
  1444 			{// Manufacture new picture phrase & set its picture store
       
  1445 			CleanupStack::PushL(charLayer);
       
  1446 			TBool ownershipTaken(EFalse);
       
  1447 			picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken);
       
  1448 			CleanupStack::Pop();  // charLayer - picPhrase takes ownership
       
  1449 			CleanupStack::PushL(picPhrase);
       
  1450 			TRAPD(r,factory->NewPictureL(hdr,*aContext.iStore));  // load picture since clipboard store is transient.
       
  1451 			// r=KErrNotSupported  // we don't recognise the picture type
       
  1452 			if (r==KErrNone)
       
  1453 				{
       
  1454 				picPhrase->iPicHdr.iPicture=hdr.iPicture;  // make picPhrase point at the restored picture object.
       
  1455 				TRAP(r,
       
  1456 				hdr.iPicture->DetachFromStoreL(CPicture::EDetachFull));  // recurse the call to detach the picture from the store
       
  1457 				}
       
  1458 			switch (r)
       
  1459 				{
       
  1460 				case(KErrNone):
       
  1461 					break;
       
  1462 				default:
       
  1463 					pictureLoadError=ETrue;
       
  1464 					picPhrase->iCharFormat=NULL;
       
  1465 					CleanupStack::PopAndDestroy(picPhrase);
       
  1466 					if (r!=KErrNotSupported)
       
  1467 						User::Leave(r);
       
  1468 				}
       
  1469 			}
       
  1470 		}
       
  1471 	if (isPicture && factory && !pictureLoadError)
       
  1472 		new(&aPhrase) RPhraseAttribsEntry(picPhrase);
       
  1473 	else
       
  1474 		new(&aPhrase) RPhraseAttribsEntry(charLayer,phraseLength);
       
  1475 	
       
  1476 	// The ownership has been transfered to RPhraseAttribsEntry
       
  1477 	if(picPhrase)
       
  1478 	    CleanupStack::Pop(picPhrase);
       
  1479 	}
       
  1480 
       
  1481 
       
  1482 TUint8 CRichTextIndex::ReadTUint8CountL(RReadStream& aStream)const
       
  1483 	{return aStream.ReadUint8L();}
       
  1484 
       
  1485 
       
  1486 void CRichTextIndex::RbPasteSharedFormatsL(TInt aRet)
       
  1487 // For each para attribs that has been read in, release all shares on it, if it
       
  1488 // does not already exist in shared list.
       
  1489 //
       
  1490 	{
       
  1491 	NormalizeSharedList();
       
  1492 	User::Leave(aRet);
       
  1493 	}
       
  1494 		
       
  1495 	
       
  1496 void CRichTextIndex::NormalizeSharedList()
       
  1497 // Removes unreferenced (non-shared) shared paras from the shared list.
       
  1498 // Called in rollback situations.
       
  1499 // Also called naturally following a paste, since an incoming shared para
       
  1500 // may be pasted into an existing para, making it non-shared.
       
  1501 //
       
  1502 	{
       
  1503 	CParaAttribs* currentSharedPara=NULL;
       
  1504 	TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
       
  1505 	while ((currentSharedPara=iterator++)!=NULL)
       
  1506 		{// Rollback the shared list.
       
  1507 		if (currentSharedPara->iRefCount==0)
       
  1508 			{// Remove this unreferenced item from the shared list.
       
  1509 			currentSharedPara->iRefCount=1;
       
  1510 			currentSharedPara->Release();
       
  1511 			}
       
  1512 		}
       
  1513 	}
       
  1514 
       
  1515 
       
  1516 void CRichTextIndex::RbRemoveInsertedParaAttribsEntries(TInt aFirstParaInsertPos,TInt aInsertedParaCount)
       
  1517 // Rollback on leaving part way through inserting paragraph records into the para index.
       
  1518 // For all pasted paragraph records, release their share on their paraAttribs if present.
       
  1519 //
       
  1520 	{
       
  1521 	for (TInt ii=0;ii<aInsertedParaCount;ii++)
       
  1522 		{
       
  1523 		CParaAttribs* paraAttribs=(*iParaIx)[aFirstParaInsertPos+ii].iParaAttribs;
       
  1524 		if (paraAttribs)
       
  1525 			paraAttribs->Release();
       
  1526 		}
       
  1527 	iParaIx->Delete(aFirstParaInsertPos,aInsertedParaCount);
       
  1528 	}
       
  1529 
       
  1530 
       
  1531 void CRichTextIndex::RbPasteParaIxL(const TLogicalPosition& aPos,TInt aParasPasted,TInt aRet)
       
  1532 // Rollback on leaving part way through the pasting of the para index.
       
  1533 // For all pasted paras, release their share on their paraAttribs.
       
  1534 //
       
  1535 	{
       
  1536 	RbRemoveInsertedParaAttribsEntries(aPos.iParaElement,aParasPasted);
       
  1537 	MergePhrases(aPos.iDocPos);  // updates iPos to paste pos.
       
  1538 	// 
       
  1539 	//
       
  1540 	if (iRollbackParaAttribsHandle)
       
  1541 		{
       
  1542 		RemoveFromPhraseIx(iPos.iPhraseElement,1);  // Removes the phrase created from ResquestReclaim on para
       
  1543 		(*iParaIx)[aPos.iParaElement].iParaAttribs=iRollbackParaAttribsHandle;
       
  1544 		iRollbackParaAttribsHandle=NULL;
       
  1545 		}
       
  1546 	User::Leave(aRet);
       
  1547 	}
       
  1548 
       
  1549 
       
  1550 void CRichTextIndex::RbRemoveInsertedPhraseAttribsEntries(TInt aFirstPhraseInsertPos,TInt aInsertedPhraseCount)
       
  1551 // Rollback on leaving part way through the pasting of the phrase index.
       
  1552 // For all pasted phrases, discard their components.
       
  1553 //
       
  1554 	{
       
  1555 	for (TInt ii=0;ii<aInsertedPhraseCount;ii++)
       
  1556 		{
       
  1557 		RPhraseAttribsEntry& phrase=(*iPhraseIx)[aFirstPhraseInsertPos+ii];
       
  1558 		if (phrase.IsPicturePhrase())
       
  1559 			iPictureCount--;
       
  1560 		if (phrase.CharFormat())
       
  1561 			phrase.Discard();
       
  1562 		}
       
  1563 	iPhraseIx->Delete(aFirstPhraseInsertPos,aInsertedPhraseCount);
       
  1564 	}
       
  1565 
       
  1566 
       
  1567 void CRichTextIndex::RbPastePhraseIxL(const TLogicalPosition& aPos,TInt aPhraseCount,TInt aRet)
       
  1568 // Rollback on leaving part way through the pasting of the phrase index.
       
  1569 // For all pasted phrases, discard their components.
       
  1570 //
       
  1571 	{
       
  1572 	RbRemoveInsertedPhraseAttribsEntries(aPos.iPhraseElement,aPhraseCount);
       
  1573 	User::Leave(aRet);
       
  1574 	}