1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/textrendering/texthandling/stext/TXTINDEX.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,3302 @@
1.4 +/*
1.5 +* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include <e32std.h>
1.23 +#include <e32base.h>
1.24 +
1.25 +#include <gdi.h>
1.26 +#include <s32stor.h>
1.27 +#include "TXTFMLYR.H"
1.28 +#include "TXTETEXT.H"
1.29 +#include "TXTLAYDC.H"
1.30 +#include "TXTSTYLE.H"
1.31 +#include "TXTINDEX.H"
1.32 +
1.33 +#include "OstTraceDefinitions.h"
1.34 +#ifdef OST_TRACE_COMPILER_IN_USE
1.35 +#include "TXTINDEXTraces.h"
1.36 +#endif
1.37 +
1.38 +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
1.39 +#include "TXTFMLYR_INTERNAL.H"
1.40 +#include "TXTSTYLE_INTERNAL.H"
1.41 +#endif
1.42 +
1.43 +TGlobalLayerInfoAppend::TGlobalLayerInfoAppend()
1.44 + : iAggParaFormatLayer(NULL),iAggCharFormatLayer(NULL),iComParaFormatLayer(NULL),iComCharFormatLayer(NULL)
1.45 + {}
1.46 +
1.47 +TGlobalLayerInfoAppend::TGlobalLayerInfoAppend(const CParaFormatLayer* aAggParaFormatLayer,const CCharFormatLayer* aAggCharFormatLayer,
1.48 + const CParaFormatLayer* aComParaFormatLayer,const CCharFormatLayer* aComCharFormatLayer)
1.49 + : iAggParaFormatLayer(aAggParaFormatLayer),iAggCharFormatLayer(aAggCharFormatLayer),
1.50 + iComParaFormatLayer(aComParaFormatLayer),iComCharFormatLayer(aComCharFormatLayer)
1.51 + {}
1.52 +
1.53 +
1.54 +TTextFragment::TTextFragment():
1.55 + iLength(0),
1.56 + iPhraseCount(0)
1.57 + {
1.58 + }
1.59 +
1.60 +
1.61 +TCurrentIndexRecords::TCurrentIndexRecords()
1.62 + {
1.63 + }
1.64 +
1.65 +
1.66 +DLLEXPORT_C void CRichTextIndex::__DbgTestInvariant()const
1.67 +// Provides class invariants. Explanations below:
1.68 +//
1.69 + {
1.70 +#ifdef _DEBUG
1.71 +// ASSERT: Every phrase index is consistent with its corresponding paragraph.
1.72 + TInt zeroLengthPhraseCount=0;
1.73 + TInt maxPara=iParaIx->Count();
1.74 + TInt numberOfReferencesToSharedList=0;
1.75 + TInt currentPhraseElement=0;
1.76 + for (TInt para=0;para<maxPara;para++)
1.77 + {
1.78 + // ASSERT: The basedOn link is valid.
1.79 + CFormatLayer* thisLayer=(*iParaIx)[para].iParaAttribs->iParaFormat;
1.80 + CFormatLayer* base=CONST_CAST(CFormatLayer*,thisLayer->SenseBase());
1.81 + if (base==NULL)
1.82 + {
1.83 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_DBGTESTINVARIANT, "base==NULL" );
1.84 + }
1.85 + __ASSERT_DEBUG(base!=NULL,User::Invariant());
1.86 + if ((*iParaIx)[para].iParaAttribs->iRefCount>0)
1.87 + numberOfReferencesToSharedList++;
1.88 + TInt paragraphLength=(*iParaIx)[para].iLength;
1.89 + TInt sumOfPhraseLengths=0;
1.90 + TInt maxPhrase=(*iParaIx)[para].iParaAttribs->PhraseCount();
1.91 + for (TInt phrase=0;phrase<maxPhrase;phrase++)
1.92 + {
1.93 + if (maxPhrase>1)
1.94 + {
1.95 + const RPhraseAttribsEntry* phrase=&(*iPhraseIx)[currentPhraseElement];
1.96 + CCharFormatLayer* charFormatLayer=phrase->CharFormat();
1.97 + // ASSERT: The basedOn link is valid.
1.98 + if (charFormatLayer->SenseBase()==NULL)
1.99 + {
1.100 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_DBGTESTINVARIANT, "charFormatLayer->SenseBase()==NULL" );
1.101 + }
1.102 + __ASSERT_DEBUG(charFormatLayer->SenseBase()!=NULL,User::Invariant());
1.103 + if (TInt(charFormatLayer->SenseBase())<=0x1000)
1.104 + {
1.105 + OstTrace0( TRACE_DUMP, DUP2_CRICHTEXTINDEX_DBGTESTINVARIANT, "TInt(charFormatLayer->SenseBase())<=0x1000" );
1.106 + }
1.107 + __ASSERT_DEBUG(TInt(charFormatLayer->SenseBase())>0x1000,User::Invariant());
1.108 + sumOfPhraseLengths+=(*iPhraseIx)[currentPhraseElement].Length();
1.109 + if ((*iPhraseIx)[currentPhraseElement].Length()==0)
1.110 + zeroLengthPhraseCount++;
1.111 + currentPhraseElement++;
1.112 + }
1.113 + else
1.114 + {
1.115 + CCharFormatLayer* charFormatLayer=(*iParaIx)[para].iParaAttribs->iCharFormat;
1.116 + // ASSERT: The basedOn link is valid.
1.117 + if (charFormatLayer->SenseBase()==NULL)
1.118 + {
1.119 + OstTrace0( TRACE_DUMP, DUP3_CRICHTEXTINDEX_DBGTESTINVARIANT, "charFormatLayer->SenseBase()==NULL" );
1.120 + }
1.121 + __ASSERT_DEBUG(charFormatLayer->SenseBase()!=NULL,User::Invariant());
1.122 + sumOfPhraseLengths+=(*iParaIx)[para].iLength;
1.123 + }
1.124 + }
1.125 + if (sumOfPhraseLengths!=paragraphLength)
1.126 + {
1.127 + OstTrace0( TRACE_DUMP, DUP4_CRICHTEXTINDEX_DBGTESTINVARIANT, "sumOfPhraseLengths!=paragraphLength" );
1.128 + }
1.129 + __ASSERT_DEBUG(sumOfPhraseLengths==paragraphLength,User::Invariant());
1.130 + }
1.131 +// ASSERT: We have no unexpected phrases left over
1.132 + if (currentPhraseElement!=-1 &&
1.133 + currentPhraseElement!=iPhraseIx->Count())
1.134 + {
1.135 + OstTrace0( TRACE_DUMP, DUP5_CRICHTEXTINDEX_DBGTESTINVARIANT, "We have no unexpected phrases left over" );
1.136 + }
1.137 + __ASSERT_DEBUG(currentPhraseElement==-1 ||
1.138 + currentPhraseElement==iPhraseIx->Count(),User::Invariant());
1.139 +// ASSERT: There is either zero(0) or one(1) zero length phrase in the whole index
1.140 + if (!((zeroLengthPhraseCount==0) ||
1.141 + (zeroLengthPhraseCount==1 && iPendingNewPhrasePos!=EInsertCharFormatReset)))
1.142 + {
1.143 + OstTrace0( TRACE_DUMP, DUP6_CRICHTEXTINDEX_DBGTESTINVARIANT, "There is either zero(0) or one(1) zero length phrase in the whole index" );
1.144 + }
1.145 + __ASSERT_DEBUG( (zeroLengthPhraseCount==0) ||
1.146 + (zeroLengthPhraseCount==1 && iPendingNewPhrasePos!=EInsertCharFormatReset),
1.147 + User::Invariant());
1.148 +// ASSERT: the number of paraEntries with paraAttribs of refCount>0 == the sum of refCounts in the shared list.
1.149 +// or is only one less - as is set when SetInsertCharFormat is called on a shared paraAttribs.
1.150 + TInt totalReferenceCount=0;
1.151 + if (!iSharedParaQueHead.IsEmpty())
1.152 + {
1.153 + CParaAttribs* currentSharedPara;
1.154 + TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead);
1.155 + while ((currentSharedPara=iterator++)!=NULL)
1.156 + totalReferenceCount+=currentSharedPara->iRefCount;
1.157 + }
1.158 + if ((numberOfReferencesToSharedList!=totalReferenceCount) &&
1.159 + (numberOfReferencesToSharedList!=totalReferenceCount-1))
1.160 + {
1.161 + OstTrace0( TRACE_DUMP, DUP7_CRICHTEXTINDEX_DBGTESTINVARIANT, "Invariant" );
1.162 + }
1.163 + __ASSERT_DEBUG((numberOfReferencesToSharedList==totalReferenceCount) ||
1.164 + (numberOfReferencesToSharedList==totalReferenceCount-1),User::Invariant());
1.165 +// ASSERT: iPictureCount corresponds to the number of pictures in the stored in the index.
1.166 + TInt picCount=0;
1.167 + TInt phraseCount=(iPhraseIx) ? iPhraseIx->Count() : 0;
1.168 + for (TInt item=0;item<phraseCount;item++)
1.169 + picCount+=((*iPhraseIx)[item].IsPicturePhrase())
1.170 + ? 1
1.171 + : 0;
1.172 + if (iPictureCount!=picCount)
1.173 + {
1.174 + OstTrace0( TRACE_DUMP, DUP8_CRICHTEXTINDEX_DBGTESTINVARIANT, "Invariant" );
1.175 + }
1.176 + __ASSERT_DEBUG(iPictureCount==picCount,User::Invariant());
1.177 +#endif
1.178 + }
1.179 +
1.180 +
1.181 +CRichTextIndex* CRichTextIndex::NewL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,
1.182 + const CRichText& aText,TInt aParaGran,TInt aPhraseGran)
1.183 +// Return a handle to a new instance of this class.
1.184 +// Requires the global format layer handles on which to base the first content.
1.185 +//
1.186 + {
1.187 + CRichTextIndex* self=new(ELeave) CRichTextIndex(aText);
1.188 + CleanupStack::PushL(self);
1.189 + self->ConstructL(aGlobalParaLayer,aGlobalCharLayer,aParaGran,aPhraseGran);
1.190 + CleanupStack::Pop();
1.191 + return self;
1.192 + }
1.193 +
1.194 +
1.195 +CRichTextIndex::CRichTextIndex(const CRichText& aText):
1.196 + iText(aText),
1.197 + iPendingNewPhrasePos(EInsertCharFormatReset),
1.198 + iSharedParaQueHead(_FOFF(CParaAttribs,link))
1.199 + {
1.200 + }
1.201 +
1.202 +
1.203 +void CRichTextIndex::ConstructL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,TInt aParaGran,TInt aPhraseGran)
1.204 +// Provides a fully initialised rich text index.
1.205 +// Upon construction, the index contains a single paragraph of length 1 (para.terminator).
1.206 +// This first paragraph initially has constant character formatting, ie the shared para list
1.207 +// must have one item in it.
1.208 +//
1.209 + {
1.210 + CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(); // Creates empty layer.
1.211 + paraLayer->SetBase(aGlobalParaLayer); // Sets basedOn to global default.
1.212 + CleanupStack::PushL(paraLayer);
1.213 + CCharFormatLayer* charLayer=CCharFormatLayer::NewL(); // Creates empty layer.
1.214 + charLayer->SetBase(aGlobalCharLayer); // Sets basedOn to global default.
1.215 + CleanupStack::PushL(charLayer);
1.216 + CParaAttribs* paraAttribs=GetParaAttribsL(paraLayer,charLayer);
1.217 + CleanupStack::PopAndDestroy(2);
1.218 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,paraAttribs));
1.219 + iParaIx=new(ELeave) CArrayFixSeg<TParaAttribsEntry>(aParaGran);
1.220 + TParaAttribsEntry para(1,paraAttribs);
1.221 + iParaIx->AppendL(para);
1.222 + CleanupStack::Pop();
1.223 + iPhraseIx=new(ELeave) CArrayFixSeg<RPhraseAttribsEntry>(aPhraseGran);
1.224 +
1.225 + __TEST_INVARIANT;
1.226 + }
1.227 +
1.228 +
1.229 +CRichTextIndex::~CRichTextIndex()
1.230 +// Free up all storage allocated in the rich text index.
1.231 +//
1.232 + {
1.233 + TInt count;
1.234 + if (iPhraseIx)
1.235 + {// Destroy the phrase index and its contents.
1.236 + if (!iParaIx)
1.237 + {
1.238 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_CRICHTEXTINDEX, "EPhraseIxPresentWithNoParaIx" );
1.239 + }
1.240 + __ASSERT_ALWAYS(iParaIx,Panic(EPhraseIxPresentWithNoParaIx));
1.241 + count=iPhraseIx->Count();
1.242 + for (TInt offset=0;offset<count;offset++)
1.243 + (*iPhraseIx)[offset].Discard();
1.244 + }
1.245 + delete iPhraseIx;
1.246 + if (iParaIx)
1.247 + {// Destroy the para index and its contents.
1.248 + count=iParaIx->Count();
1.249 + for (TInt offset=0;offset<count;offset++)
1.250 + {
1.251 + CParaAttribs* pA=(*iParaIx)[offset].iParaAttribs;
1.252 + if (!pA->IsShared())
1.253 + pA->Release();
1.254 + }
1.255 + }
1.256 + delete iParaIx;
1.257 + RebalanceIndex();
1.258 + //
1.259 + // Clear the shared list. (Will usually be empty by now
1.260 + // unless internalize failed after getting shared list & before getting all para data.
1.261 + CParaAttribs* currentSharedPara;
1.262 + TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
1.263 + while ((currentSharedPara=iterator++)!=NULL)
1.264 + currentSharedPara->Release(currentSharedPara->iRefCount);
1.265 + if (!iSharedParaQueHead.IsEmpty())
1.266 + {
1.267 + OstTrace0( TRACE_FATAL, DUP1_CRICHTEXTINDEX_CRICHTEXTINDEX, "ERichTextIndexIntegrityErr" );
1.268 + }
1.269 + __ASSERT_ALWAYS(iSharedParaQueHead.IsEmpty(),Panic(ERichTextIndexIntegrityErr));
1.270 + }
1.271 +
1.272 +
1.273 +TInt CRichTextIndex::CharPosOfParagraph(TInt& aLength,TInt aParaOffset)const
1.274 +// Returns the character position of the first character of paragraph aParaOffset,
1.275 +// where aParaOffset specifies the nth paragraph.
1.276 +// The length of this nth paragraph is written to aLength.
1.277 +//
1.278 +// If aParaOffset specifies a paragraph that does not exist, EScanEndOfData is returned.
1.279 +//
1.280 + {
1.281 + __TEST_INVARIANT;
1.282 +
1.283 + if (aParaOffset>=iParaIx->Count())
1.284 + return CPlainText::EScanEndOfData;
1.285 + TInt pos=0,offset=0;
1.286 + for (offset=0;offset<aParaOffset;offset++)
1.287 + pos+=(*iParaIx)[offset].iLength;
1.288 + aLength=(*iParaIx)[offset].iLength;
1.289 + return pos;
1.290 + }
1.291 +
1.292 +
1.293 +TInt CRichTextIndex::ParagraphNumberForPos(TInt& aPos)const
1.294 +// Returns the paragraph offset for the specified character position aPos.
1.295 +// aPos is in turn modified to hold the character position of the first character
1.296 +// of this paragraph. If aPos is already on a paragraph boundary then do nothing.
1.297 +//
1.298 + {
1.299 + __TEST_INVARIANT;
1.300 +
1.301 + ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute);
1.302 + aPos-=iPos.iParaElementOffset;
1.303 + return iPos.iParaElement;
1.304 + }
1.305 +
1.306 +
1.307 +void CRichTextIndex::DocumentChanged()const
1.308 + {
1.309 + MUTABLE_CAST(TLogicalPosition&,iLastUsed).Clear();
1.310 + }
1.311 +
1.312 +
1.313 +void CRichTextIndex::DoSoloInsertL(TInt aPos,TInt aLength)
1.314 +// Updates the index following the insertion of content into a single phrase.
1.315 +// First find the phrase record the governs the insert pos.
1.316 +// (1) If the current phrase is a text phrase, then simply extend the length of the phrase record.
1.317 +// (2) If the current phrase is a picture phrase then this cannot be extended.
1.318 +// There is 1 pathological case here:
1.319 +// (i) The [current] picture phrase is the 1st phrase in the paragraph, and the insert pos
1.320 +// is before this phrase. (paragraph insert pos == 0).
1.321 +// In this case we must insert a new text phrase *before* the picture phrase.
1.322 +// (ii) In normal circumstances the inserted text is after the picture phrase. So, if the
1.323 +// following phrase is of the same character format as the picture then we can re-use this phrase.
1.324 +// If it is not of the same character format (or is also a picture phrase),
1.325 +// then we must insert a new text phrase of the correct format immediately following the current picture phrase.
1.326 +//
1.327 + {
1.328 + RebalanceIndex();
1.329 + if (!((iPendingNewPhrasePos == EInsertCharFormatReset) || (aPos == iPendingNewPhrasePos)))
1.330 + CancelInsertCharFormat();
1.331 +
1.332 + ScanToPosition(aPos,EScanToPositionMatchLeft);
1.333 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.334 + if (current.iPhrase && current.iPhrase->IsPicturePhrase())
1.335 + {// Paragraph has specific char format, and current phrase is picture phrase.
1.336 + TInt newPhraseRequired=EFalse;
1.337 + CCharFormatLayer* charLayer=current.iPhrase->CharFormat();
1.338 + if (FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0)
1.339 + newPhraseRequired=ETrue; // Text is inserted at the start of the para behind the picture.
1.340 + else
1.341 + {// Check for re-use of the next text phrase.
1.342 + iPos.iPhraseElement++;
1.343 + iPos.iPhraseElementOffset=0;
1.344 + const RPhraseAttribsEntry& nextPhrase=(*iPhraseIx)[iPos.iPhraseElement];
1.345 + if (nextPhrase.IsPicturePhrase() || !nextPhrase.CharFormat()->IsIdentical(charLayer,EFalse))
1.346 + {// Need a new phrase if the formats don't match OR the next phrase is a picture phrase.
1.347 + newPhraseRequired=ETrue; // Need to create a new phrase to take this insert.
1.348 + }
1.349 + }
1.350 + if (newPhraseRequired)
1.351 + {// Insert new phrase & record this fact
1.352 + CCharFormatLayer* charFormat=CCharFormatLayer::NewCopyBaseL(charLayer);
1.353 + RPhraseAttribsEntry newPhrase(charFormat);
1.354 + CleanupStack::PushL(charFormat);
1.355 + iPhraseIx->InsertL(iPos.iPhraseElement,newPhrase);
1.356 + CleanupStack::Pop();
1.357 + current.iParaAttribs->iPhraseCount++;
1.358 + }
1.359 + GetCurrentRecords(current); // Update current records, cos used below.
1.360 + }
1.361 + // Extend the lengths in the index.
1.362 + current.iParaEntry->iLength+=aLength; // Increase length of paragraph.
1.363 + if (current.iPhrase)
1.364 + current.iPhrase->AdjustLength(aLength); // Increase the length of this phrase.
1.365 + iPos.iPhraseElementOffset+=aLength;
1.366 + iPos.iParaElementOffset+=aLength;
1.367 + iPos.iDocPos+=aLength;
1.368 + }
1.369 +
1.370 +
1.371 +void CRichTextIndex::InsertL(TInt aPos,const TDesC& aBuf,const CParaFormatLayer& aGlobalParaFormatLayer)
1.372 +// Updates the index following the insertion of a descriptor of text into the document.
1.373 +// Correctly handles embedded paragraph delimiters.
1.374 +//
1.375 + {
1.376 + __TEST_INVARIANT;
1.377 + TInt bufLen=aBuf.Length();
1.378 +
1.379 + RebalanceIndex();
1.380 + TInt paragraphCount=0;
1.381 + const TText* start=aBuf.Ptr();
1.382 + const TText* end=start+bufLen;
1.383 + while (start<end)
1.384 + {
1.385 + if (*start++==CEditableText::EParagraphDelimiter)
1.386 + paragraphCount++;
1.387 + }
1.388 + if (paragraphCount==0)
1.389 + {
1.390 + if (bufLen > 0)
1.391 + {
1.392 + DoSoloInsertL(aPos,bufLen);
1.393 + CancelInsertCharFormat();
1.394 + }
1.395 + __TEST_INVARIANT;
1.396 + return;
1.397 + }
1.398 + ScanToPosition(aPos,EScanToPositionMatchLeft);
1.399 + TLogicalPosition pastePos=iPos; // Used to adjust paragraph/phrase lengths later
1.400 +
1.401 + if (paragraphCount>1)
1.402 + {
1.403 + TCurrentIndexRecords current;
1.404 + GetCurrentRecords(current);
1.405 + const CParaAttribs& paraAttribs=*current.iParaAttribs;
1.406 + CCharFormatLayer* charLayer=(paraAttribs.IsShared())
1.407 + ? paraAttribs.iCharFormat
1.408 + : (*iPhraseIx)[iPos.iPhraseElement].CharFormat();
1.409 + CParaFormatLayer* paraLayer=paraAttribs.iParaFormat;
1.410 + CParaAttribs* theParaAttribs=GetParaAttribsL(paraLayer,charLayer);
1.411 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,theParaAttribs));
1.412 + iParaIx->InsertL(pastePos.iParaElement,TParaAttribsEntry(0,theParaAttribs),paragraphCount-1);
1.413 + CleanupStack::Pop();
1.414 + theParaAttribs->iRefCount+=paragraphCount-2; // add the extra references
1.415 + }
1.416 + TLogicalPosition pos;
1.417 + TRAPD(ret,
1.418 + SplitParagraphAtPastePosL(pastePos,pos,aGlobalParaFormatLayer));
1.419 + if (ret!=KErrNone)
1.420 + {
1.421 + RbRemoveInsertedParaAttribsEntries(pastePos.iParaElement,paragraphCount-1);
1.422 + User::Leave(ret);
1.423 + }
1.424 +
1.425 + if (paragraphCount>1)
1.426 + { // swap the entries for the split and first inserted paragraph
1.427 + TParaAttribsEntry& paraEntry=(*iParaIx)[pastePos.iParaElement+paragraphCount-1];
1.428 + TParaAttribsEntry& insertEntry=(*iParaIx)[pastePos.iParaElement];
1.429 + TParaAttribsEntry temp=paraEntry;
1.430 + paraEntry=insertEntry;
1.431 + insertEntry=temp;
1.432 + }// Cos weve inserted new paragraphs in front of the governing one.
1.433 +
1.434 + // Sort out the front para
1.435 + TParaAttribsEntry& frontPara=(*iParaIx)[pastePos.iParaElement];
1.436 + TPtrC buf(aBuf);
1.437 + TInt lengthOfFirstPara=ParaLengthFromBuffer(buf);
1.438 + frontPara.iLength+=lengthOfFirstPara; // Adjust the para length
1.439 + buf.Set(aBuf.Right(aBuf.Length()-lengthOfFirstPara-1));
1.440 + if (!frontPara.iParaAttribs->IsShared() && lengthOfFirstPara != 0)
1.441 + {
1.442 + RPhraseAttribsEntry* phrase=&(*iPhraseIx)[pastePos.iPhraseElement];
1.443 + if (phrase->IsPicturePhrase())
1.444 + { // move insertion past any picture phrase
1.445 + pastePos.iPhraseElement++;
1.446 + pastePos.iPhraseElementOffset=0;
1.447 + phrase=&(*iPhraseIx)[pastePos.iPhraseElement];
1.448 + }
1.449 + phrase->AdjustLength(lengthOfFirstPara); // Adjust the phrase length
1.450 + }
1.451 + for (TInt paraItem=1;paraItem<paragraphCount;paraItem++)
1.452 + {// For each para inserted between the fist and last
1.453 + TParaAttribsEntry& para=(*iParaIx)[pastePos.iParaElement+paraItem];
1.454 + TInt length=ParaLengthFromBuffer(buf)+1;
1.455 + if (length==KErrNotFound)
1.456 + {
1.457 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_INSERTL, "EInsertEmbeddedParaErr" );
1.458 + }
1.459 + __ASSERT_DEBUG(length!=KErrNotFound,Panic(EInsertEmbeddedParaErr));
1.460 + para.iLength=length;
1.461 + buf.Set(buf.Right(buf.Length()-length));
1.462 + }
1.463 + // For final paragrph
1.464 + TInt trailingTextLen=buf.Length();
1.465 + if (trailingTextLen>0)
1.466 + {
1.467 + TParaAttribsEntry& backPara=(*iParaIx)[pos.iParaElement];
1.468 + backPara.iLength+=trailingTextLen;
1.469 + if (!backPara.iParaAttribs->IsShared())
1.470 + {
1.471 + RPhraseAttribsEntry& phrase=(*iPhraseIx)[pos.iPhraseElement];
1.472 + phrase.AdjustLength(trailingTextLen); // Adjust phrase length
1.473 + }
1.474 + }
1.475 + //
1.476 + // Now tidy up
1.477 + if (bufLen>1 && iPendingNewPhrasePos!=EInsertCharFormatReset)
1.478 + {
1.479 + iPendingNewPhrasePos=aPos+(bufLen-trailingTextLen);
1.480 + CancelInsertCharFormat();
1.481 + }
1.482 +
1.483 + __TEST_INVARIANT;
1.484 + }
1.485 +
1.486 +
1.487 +void CRichTextIndex::SplitParagraphAtPastePosL(TLogicalPosition& aPastePos,TLogicalPosition& aNewPos,
1.488 + const CParaFormatLayer& aGlobalParaFormatLayer)
1.489 +// Breaks the paragraph specified by the logical position aPastePos, inserting a paragraph delimiter.
1.490 +//
1.491 + {
1.492 + TInt insertPendingPos = iPendingNewPhrasePos;
1.493 + DoSoloInsertL(aPastePos.iDocPos,1);
1.494 + TBool insertCharFormatDeleted = EFalse;
1.495 + if (InsertCharFormatIsActive())
1.496 + {
1.497 + insertCharFormatDeleted = DeleteInsertCharFormat();
1.498 + iPendingNewPhrasePos = EInsertCharFormatReset;
1.499 + }
1.500 + TRAPD(ret,
1.501 + InsertParagraphL(aPastePos.iDocPos+1,aGlobalParaFormatLayer)); // Split the current para (and maybe phrase index).
1.502 + if (ret!=KErrNone)
1.503 + {
1.504 + // locate the character inserted by DoSoloInsertL() above
1.505 + ScanToPosition(aPastePos.iDocPos,EScanToPositionAbsolute);
1.506 + TCurrentIndexRecords current;
1.507 + GetCurrentRecords(current);
1.508 + current.iParaEntry->iLength--;
1.509 + if (current.iPhrase)
1.510 + {
1.511 + current.iPhrase->AdjustLength(-1); // collapse phrase by right amount
1.512 + if (insertPendingPos!=EInsertCharFormatReset)
1.513 + {
1.514 + if (current.iPhrase->Length()!=0)
1.515 + {
1.516 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_SPLITPARAGRAPHATPASTEPOSL, "Invariant" );
1.517 + }
1.518 + __ASSERT_DEBUG(current.iPhrase->Length()==0,User::Invariant());
1.519 + iPendingNewPhrasePos=insertPendingPos;
1.520 + }
1.521 + else if (current.iPhrase->Length()==0)
1.522 + {
1.523 + RemoveFromPhraseIx(iPos.iPhraseElement,1);
1.524 + current.iParaAttribs->iPhraseCount--;
1.525 + if (current.iParaAttribs->PhraseCount()<=1)
1.526 + {
1.527 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_SPLITPARAGRAPHATPASTEPOSL, "Invariant" );
1.528 + }
1.529 + __ASSERT_DEBUG(current.iParaAttribs->PhraseCount()>1,User::Invariant());
1.530 + }
1.531 + }
1.532 + OstTrace1( TRACE_DUMP, DUP2_CRICHTEXTINDEX_SPLITPARAGRAPHATPASTEPOSL, "Leave code=%d", ret );
1.533 + User::Leave(ret);
1.534 + }
1.535 + if (insertPendingPos != EInsertCharFormatReset)
1.536 + ConsolidateAt(insertPendingPos, insertCharFormatDeleted?
1.537 + EPositionOnly : EFollowingPhrase);
1.538 + ScanToPosition(aPastePos.iDocPos+1,EScanToPositionMatchLeft); // Gives us the next para.
1.539 + aNewPos=iPos;
1.540 + }
1.541 +
1.542 +
1.543 +TInt CRichTextIndex::ParaLengthFromBuffer(TDesC& aBuf)const
1.544 +// Returns the length of the first para found in the buffer.
1.545 +// The returned length excludes the paragraph delimiter character.
1.546 +// Returns KNotFound if there is no paragraph delimiter.
1.547 +//
1.548 + {return aBuf.Locate(CEditableText::EParagraphDelimiter);}
1.549 +
1.550 +
1.551 +void CRichTextIndex::InsertL(TInt aPos,const TPictureHeader& aPicHdr, TBool& aPictureOwnershipTaken)
1.552 +// Updates the index following the insertion of a picture header object into the text
1.553 +// component. This is accomplished by creating & inserting a picture phrase at the
1.554 +// relevant place.
1.555 +//
1.556 + {
1.557 + __TEST_INVARIANT;
1.558 +
1.559 + RebalanceIndex();
1.560 +// ASSERT: A valid picture header, referencing a valid picture has been inserted.
1.561 + if (!aPicHdr.iPicture.IsPtr() || aPicHdr.iPicture.AsPtr()==NULL)
1.562 + {
1.563 + OstTrace0( TRACE_FATAL, DUP1_CRICHTEXTINDEX_INSERTL, "EInsertNullPicHdrData" );
1.564 + }
1.565 + __ASSERT_ALWAYS(aPicHdr.iPicture.IsPtr() && aPicHdr.iPicture.AsPtr()!=NULL,Panic(EInsertNullPicHdrData));
1.566 +// ASSERT: The current insert pos hasn't been changed without cancelling SetInsertCharFormat.
1.567 + if ((iPendingNewPhrasePos!=EInsertCharFormatReset) && (aPos!=iPendingNewPhrasePos))
1.568 + {
1.569 + OstTrace0( TRACE_FATAL, DUP2_CRICHTEXTINDEX_INSERTL, "ESetInsertCharFormatIntegrityErr" );
1.570 + }
1.571 + __ASSERT_ALWAYS((iPendingNewPhrasePos==EInsertCharFormatReset) || (aPos==iPendingNewPhrasePos),
1.572 + Panic(ESetInsertCharFormatIntegrityErr));
1.573 + if (iPendingNewPhrasePos!=EInsertCharFormatReset)
1.574 + CancelInsertCharFormat(); // Cancel this state before inserting picture. Rebalances the index.
1.575 + ScanToPosition(aPos,EScanToPositionMatchLeft);
1.576 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.577 + TCharFormatX format;
1.578 + TCharFormatXMask mask; //...and build up its format.
1.579 + CCharFormatLayer* baseChar;
1.580 + GetPhraseFormat(current,format,mask,baseChar); //...inherit format from prev. phrase.
1.581 + // Create the picture phrase. Takes ownership of the aPicHdr.iPicture
1.582 + CPicturePhrase* picture=CPicturePhrase::NewL(aPicHdr,format,mask,baseChar,aPictureOwnershipTaken);
1.583 + CleanupStack::PushL(picture);
1.584 + //New reclaimed CParaAttribs instance
1.585 + CParaAttribs* reclaimed=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry);
1.586 + //Store the old CParaAttribs instance in rollbackParaAttribsHandle
1.587 + CParaAttribs* rollbackParaAttribsHandle=current.iParaAttribs;
1.588 + if (reclaimed)
1.589 + {
1.590 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed));
1.591 + current.iParaEntry->iParaAttribs=reclaimed; // Use this reclaimed para attribs (the new CParaAttribs instance)
1.592 + }
1.593 + GetCurrentRecords(current);
1.594 +// ASSERT: The reclaim succeeded. We must always end up with a PhraseIx-not constant char format.
1.595 + if (current.iPhrase==NULL)
1.596 + {
1.597 + OstTrace0( TRACE_DUMP, DUP3_CRICHTEXTINDEX_INSERTL, "EReclaimShareError" );
1.598 + }
1.599 + __ASSERT_DEBUG(current.iPhrase!=NULL,Panic(EReclaimShareError));
1.600 + TRAPD(ret1,
1.601 + SplitPhraseL(aPos)); // Phrase may not be split if at boundary.
1.602 +
1.603 + if (ret1!=KErrNone)
1.604 + {
1.605 + RbInsertPicture(rollbackParaAttribsHandle);//Restore the old CParaAttribs instance
1.606 + User::Leave(ret1);
1.607 + }
1.608 +
1.609 + TInt offset=(PhraseSplit())?1:0; // Insert position of new phrase relative to current.
1.610 + RPhraseAttribsEntry newPhrase(picture);
1.611 + TRAPD(ret2,
1.612 + iPhraseIx->InsertL(iPos.iPhraseElement+offset,newPhrase));
1.613 + if (ret2!=KErrNone)
1.614 + {
1.615 + RbInsertPicture(rollbackParaAttribsHandle);//Restore the old CParaAttribs instance
1.616 + User::Leave(ret2);
1.617 + }
1.618 +
1.619 + if(reclaimed)
1.620 + {
1.621 + CleanupStack::Pop();//"Pop" for CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed));
1.622 + }
1.623 + CleanupStack::Pop(picture);
1.624 + // Update counts etc. - cannot leave now.
1.625 + current.iParaEntry->iLength+=RPhraseAttribsEntry::EPicturePhraseLength;
1.626 + current.iParaAttribs->iPhraseCount++; // for the picture phrase
1.627 + iPictureCount++;
1.628 +
1.629 + // Commit
1.630 + if(reclaimed)
1.631 + {
1.632 + rollbackParaAttribsHandle->Release(); // Release hold on original shared paraAttribs.
1.633 + }
1.634 +
1.635 + __TEST_INVARIANT;
1.636 + //coverity[memory_leak]
1.637 + }
1.638 +
1.639 +void CRichTextIndex::RbInsertPicture(CParaAttribs* aGoodParaAttribs)
1.640 +// Reinstate the original good paraAttribs.
1.641 +// Then rollback the SplitPhrase() call if it succeeded.
1.642 +//
1.643 + {
1.644 + (*iParaIx)[iPos.iParaElement].iParaAttribs=aGoodParaAttribs;
1.645 + if (PhraseSplit())
1.646 + {// Rollback the SplitPhrase()
1.647 + TInt length=(*iPhraseIx)[iPos.iPhraseElement+1].Length();
1.648 + RemoveFromPhraseIx(iPos.iPhraseElement+1);
1.649 + (*iPhraseIx)[iPos.iPhraseElement].AdjustLength(length);
1.650 + }
1.651 + }
1.652 +
1.653 +
1.654 +// Insert a new paragraph immediately following character position aPos, fixing the length of the preceeding
1.655 +// paragraph. The new paragraph preserves any explicit paragraph/character formatting, and is based on the
1.656 +// global layers. (Do not need to rebalance the index here; a previous call to DoSoloInsertL accomplishes this)
1.657 +
1.658 +void CRichTextIndex::InsertParagraphL(TInt aPos,const CParaFormatLayer& aGlobalParaFormatLayer)
1.659 + {
1.660 + ScanToPosition(aPos,EScanToPositionMatchLeft);
1.661 + TCurrentIndexRecords current;
1.662 + GetCurrentRecords(current);
1.663 + TParaAttribsEntry newPara;
1.664 + CCharFormatLayer* charLayer;
1.665 + if (current.iPhrase) // entry in phrase index
1.666 + charLayer=current.iPhrase->CharFormat();
1.667 + else
1.668 + charLayer=current.iParaAttribs->iCharFormat;
1.669 + //
1.670 + // New para format layer, based on normal, inheriting specific format
1.671 + CParaFormatLayer* currentParaFormat=current.iParaAttribs->iParaFormat;
1.672 + CParaFormatLayer* newParaLayer=CParaFormatLayer::NewL(currentParaFormat);
1.673 + const CParaFormatLayer& currentStyle=STATIC_CAST(const CParaFormatLayer&,*currentParaFormat->SenseBase());
1.674 + const TUid currentStyleType=currentStyle.Type();
1.675 +
1.676 + // !!
1.677 + // Only change to Normal if current style is a built-in one
1.678 + // or we are not at the end of a heading style.
1.679 + TBool useNormal;
1.680 + if (currentStyleType==KNormalParagraphStyleUid)
1.681 + useNormal=ETrue;
1.682 + else if (currentStyleType==KUserDefinedParagraphStyleUid)
1.683 + useNormal=EFalse;
1.684 + else if (iPos.iParaElementOffset<=(current.iParaEntry->iLength-2)) // cos of previous call to DoSoloInsertL()
1.685 + useNormal=EFalse;
1.686 + else
1.687 + useNormal=ETrue;
1.688 + newParaLayer->SetBase((useNormal)
1.689 + ? &aGlobalParaFormatLayer
1.690 + : ¤tStyle);
1.691 + const CCharFormatLayer* newCharBase=(useNormal)
1.692 + ? iText.GlobalCharFormatLayer()
1.693 + : STATIC_CAST(const CParagraphStyle&,currentStyle).CharFormatLayer();
1.694 + CleanupStack::PushL(newParaLayer);
1.695 + //
1.696 + if (current.iParaAttribs->IsShared())
1.697 + {// Current para has constant char format - so the new one also has constant char format
1.698 + // New char format layer, based on normal, inheriting specific format
1.699 + CCharFormatLayer* newCharLayer=CCharFormatLayer::NewL(charLayer);
1.700 + newCharLayer->SetBase(newCharBase);
1.701 + CleanupStack::PushL(newCharLayer);
1.702 + newPara.iParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer);
1.703 + CleanupStack::PopAndDestroy(2); // newCharLayer/newParaLayer
1.704 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,newPara.iParaAttribs));
1.705 + iParaIx->InsertL(iPos.iParaElement+1,newPara);
1.706 + CleanupStack::Pop(); // paraAttribs cleanup item
1.707 + GetCurrentRecords(current); // could be changed by InsertL() above
1.708 + }
1.709 + else // Do the split myself since this para has specific character formatting.
1.710 + {// Make the new CParaAttribs
1.711 + CParaAttribs* newParaAttribs=CParaAttribs::NewL(newParaLayer);
1.712 + CleanupStack::PopAndDestroy(); // newParaLayer - copy owned by newParaAttribs
1.713 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,newParaAttribs));
1.714 + //
1.715 + // Split current phrase & insert if necessary.
1.716 + // Split even when we are at a phrase boundary -> this introduces an z.l.p. for the insertion point
1.717 + RPhraseAttribsEntry& insertPhrase=iPhraseIx->At(iPos.iPhraseElement);
1.718 + TInt insertPendingPos=(iPos.iPhraseElementOffset==insertPhrase.Length()) ? aPos : EInsertCharFormatReset;
1.719 + DoSplitPhraseL(insertPhrase,iPos.iPhraseElementOffset,current.iParaAttribs); // Ups iPhraseCount
1.720 + //
1.721 + // Insert the new paragraph.
1.722 + newPara.iParaAttribs=newParaAttribs;
1.723 + TRAPD(ret,
1.724 + iParaIx->InsertL(iPos.iParaElement+1,newPara)); // Inserts the new paraAttribsEntry record.
1.725 + if (ret!=KErrNone)
1.726 + {
1.727 + RemoveFromPhraseIx(iPos.iPhraseElement+1,1); // inserted by DoSplitPhraseL
1.728 + current.iParaAttribs->iPhraseCount--;
1.729 + User::Leave(ret);
1.730 + }
1.731 +
1.732 + iPendingNewPhrasePos=insertPendingPos;
1.733 + CleanupStack::Pop(); // newParaAttribs. All OK now
1.734 + GetCurrentRecords(current); // could be changed by InsertL() above
1.735 + //
1.736 + // Calculate new paraAttribs phrase counts.
1.737 + TInt remainder=(iPos.iPhraseElement+1)-iPos.iParaBasePhraseElement;
1.738 + TInt newPhraseCount=current.iParaAttribs->iPhraseCount-remainder;
1.739 + newParaAttribs->iPhraseCount=newPhraseCount;
1.740 + current.iParaAttribs->iPhraseCount=remainder;
1.741 +
1.742 + const CArrayFix<RPhraseAttribsEntry>& phraseIx=*iPhraseIx;
1.743 + TInt startPhrase=iPos.iPhraseElement+1;
1.744 + for (TInt ii=startPhrase; ii<startPhrase+newPhraseCount; ii++)
1.745 + {
1.746 + RPhraseAttribsEntry phrase=phraseIx[ii];
1.747 + phrase.CharFormat()->SetBase(newCharBase);
1.748 + }
1.749 + //
1.750 + // The index now reflects the correct state.
1.751 + // Next, the efficiency thing - see if the new paras can share existing ones.
1.752 + if (newPhraseCount==1)
1.753 + Share(iParaIx->At(iPos.iParaElement+1),iPos.iParaBasePhraseElement+remainder);
1.754 + if (remainder==1)
1.755 + Share(iParaIx->At(iPos.iParaElement),iPos.iParaBasePhraseElement);
1.756 + }
1.757 + // Alter the length of the original paragraph and the new paragraph.
1.758 + TInt currentLength=current.iParaEntry->iLength;
1.759 + current.iParaEntry->iLength=iPos.iParaElementOffset;
1.760 + ((*iParaIx)[iPos.iParaElement+1]).iLength+=currentLength-current.iParaEntry->iLength; // Alters the length of the copy of aNewPara.
1.761 + }
1.762 +
1.763 +
1.764 +void CRichTextIndex::SetForDeleteL(TIndexDeleteInfo& aInfo,TInt aPos,TInt aLength)
1.765 +//
1.766 + {
1.767 + __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete.
1.768 +
1.769 + aInfo.iDeleteLength=aLength;
1.770 + //
1.771 + // Check for simple cases first
1.772 + DocumentChanged(); // clears internal position record.
1.773 + ScanToPosition(aPos,EScanToPositionAbsolute,&iLastUsed);
1.774 + TCurrentIndexRecords current;
1.775 + GetCurrentRecords(current);
1.776 + aInfo.iStartPara=iPos.iParaElement;
1.777 + aInfo.iEndPara=iPos.iParaElement; // default
1.778 + aInfo.iDeletePos=iPos; // default
1.779 + //
1.780 + TInt startParaLength=current.iParaEntry->iLength;
1.781 + TInt lengthRemainingInPara=startParaLength-iPos.iParaElementOffset;
1.782 + if (aLength<lengthRemainingInPara)
1.783 + {// Case is delete-from-paragraph
1.784 + aInfo.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph;
1.785 + return;
1.786 + }
1.787 + //
1.788 + ScanToPosition(aPos+aLength,EScanToPositionMatchLeft,&iLastUsed); // Forces endPara to be next para when just removing a para delimiter.
1.789 + aInfo.iEndPara=iPos.iParaElement;
1.790 +// if (iPos.iParaElementOffset==0)
1.791 +// {// Can use delete-paragraph
1.792 +// aInfo.iDeleteType=TIndexDeleteInfo::EDeleteParagraph;
1.793 +// return;
1.794 +// }
1.795 + //
1.796 + // Set for the general (leaving) delete.
1.797 + GetCurrentRecords(current);
1.798 + CParaAttribs* reclaimedEndPara=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry); // does not release share.
1.799 + TParaAttribsEntry* origEndParaEntry=current.iParaEntry;
1.800 + CParaAttribs* origParaAttribs=current.iParaAttribs;
1.801 + TInt endPosPhrase=iPos.iPhraseElement;
1.802 + if (reclaimedEndPara)
1.803 + origEndParaEntry->iParaAttribs=reclaimedEndPara;
1.804 + // Get start para info.
1.805 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.806 + GetCurrentRecords(current);
1.807 + CParaAttribs* reclaimedStartPara=NULL;
1.808 + TRAPD(ret,
1.809 + reclaimedStartPara=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry));
1.810 + if (ret!=KErrNone)
1.811 + {
1.812 + if (reclaimedEndPara)
1.813 + {
1.814 + reclaimedEndPara->Release();
1.815 + RemoveFromPhraseIx(endPosPhrase);
1.816 + origEndParaEntry->iParaAttribs=origParaAttribs;
1.817 + }
1.818 + User::Leave(ret);
1.819 + }
1.820 + if (reclaimedEndPara)
1.821 + origParaAttribs->Release(); // Release share on the original end para attribs
1.822 + if (reclaimedStartPara)
1.823 + {// Use the specific start para
1.824 + current.iParaAttribs->Release();
1.825 + current.iParaEntry->iParaAttribs=reclaimedStartPara;
1.826 + ScanToPosition(aPos,EScanToPositionAbsolute); // Pick up reclaimed phrase.
1.827 + }
1.828 + aInfo.iDeletePos=iPos; // internal position of aPos after any reclaim
1.829 + // Note: iDeleteType can surely be made obsolete now? TPB 7/11/2000
1.830 + aInfo.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph;
1.831 +
1.832 + /*
1.833 + * Pointer to memory allocated to 'reclaimedEndPara' is assigned to
1.834 + * 'origEndParaEntry->iParaAttribs' on line 706. The memory will be
1.835 + * released in CRichTextIndex's destructor.
1.836 + */
1.837 + // coverity[memory_leak]
1.838 + }
1.839 +
1.840 +
1.841 +TBool CRichTextIndex::DeleteParagraph(TInt aPos,TInt aLength)
1.842 +// Remove aCount entire paragraphs from the text.
1.843 +// Leave-safe
1.844 +// Returns EFalse indicating that no paragraphs were merged together,
1.845 +// as a result of the delete action.
1.846 +// Does NOT preserve any zero-length/insert pending state.
1.847 +//
1.848 + {
1.849 + __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete.
1.850 +
1.851 + CancelInsertCharFormat();
1.852 + ScanToPosition(aPos,EScanToPositionAbsolute,&iLastUsed);
1.853 +
1.854 + if (iPos.iParaElementOffset!=0)
1.855 + {
1.856 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_DELETEPARAGRAPH, "EDeleteParagraphInvalidStartValue" );
1.857 + }
1.858 + __ASSERT_DEBUG(iPos.iParaElementOffset==0,Panic(EDeleteParagraphInvalidStartValue));
1.859 +
1.860 + TIndexDeleteInfo info;
1.861 + info.iDeleteType=TIndexDeleteInfo::EDeleteParagraph;
1.862 + info.iDeletePos=iPos;
1.863 + info.iStartPara=iPos.iParaElement;
1.864 + //
1.865 + TInt documentLength=iText.DocumentLength();
1.866 + TInt pos=(aPos+aLength>documentLength
1.867 + ? documentLength
1.868 + : aPos+aLength);
1.869 + ScanToPosition(pos,EScanToPositionMatchLeft,&iLastUsed); // Forces endPara to be next para when just removing a para delimiter.
1.870 +
1.871 + info.iEndPara=iPos.iParaElement;
1.872 + info.iDeleteLength=aLength;
1.873 +
1.874 + DeleteNow(info);
1.875 + // do not want to call TidyAfterDelete()
1.876 +
1.877 + return EFalse;
1.878 + }
1.879 +
1.880 +
1.881 +
1.882 +void CRichTextIndex::DeleteFromParagraph(TInt aPos,TInt aLength)
1.883 +// Special case delete for removing content from within a single paragraph only.
1.884 +// Not to be used for deleting an entire paragraph or paragraphs.
1.885 +// Returns EFalse indicating that no paragraphs were merged together,
1.886 +// as a result of the delete action.
1.887 +//
1.888 + {
1.889 + __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete.
1.890 +
1.891 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.892 +
1.893 +#ifdef _DEBUG
1.894 + {
1.895 + TCurrentIndexRecords current;
1.896 + GetCurrentRecords(current);
1.897 + TInt startParaLength=current.iParaEntry->iLength;
1.898 + TInt lengthRemainingInPara=startParaLength-iPos.iParaElementOffset;
1.899 +
1.900 + if (aLength>=lengthRemainingInPara)
1.901 + {
1.902 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_DELETEFROMPARAGRAPH, "EDeleteFromParagraphInvalidRange" );
1.903 + }
1.904 + __ASSERT_ALWAYS(aLength<lengthRemainingInPara,Panic(EDeleteFromParagraphInvalidRange));
1.905 + }
1.906 +#endif
1.907 +
1.908 + TIndexDeleteInfo info;
1.909 + info.iDeleteLength=aLength;
1.910 + info.iStartPara=iPos.iParaElement;
1.911 + info.iEndPara=iPos.iParaElement;
1.912 + info.iDeletePos=iPos;
1.913 + info.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph;
1.914 +
1.915 + DoDeleteFromParagraph(info);
1.916 +
1.917 + __TEST_INVARIANT;
1.918 + }
1.919 +
1.920 +
1.921 +TBool CRichTextIndex::DoDeleteFromParagraph(const TIndexDeleteInfo& aInfo)
1.922 +// Delete content from *within* the boundary of a single paragraph only.0
1.923 +// Returns EFalse indicating that no paragraphs were merged together,
1.924 +// as a result of the delete action.
1.925 +//
1.926 + {
1.927 + iPos=aInfo.iDeletePos;
1.928 + TInt length=aInfo.iDeleteLength;
1.929 + DeleteParagraphText(length);
1.930 + TidyAfterDelete(aInfo);
1.931 +
1.932 + return EFalse;
1.933 + }
1.934 +
1.935 +
1.936 +TBool CRichTextIndex::DeleteNow(TIndexDeleteInfo& aInfo)
1.937 +// Deletes index data corresponding the info argument.
1.938 +// Returns ETrue is 2 paragraphs are merged as a result of the delete, otherwise returns false.
1.939 +//
1.940 + {
1.941 + iPos=aInfo.iDeletePos;
1.942 + TCurrentIndexRecords current;
1.943 + GetCurrentRecords(current);
1.944 + TInt leftToDelete=aInfo.iDeleteLength;
1.945 + TInt charsLeftInPara=(current.iParaEntry->iLength)-(iPos.iParaElementOffset);
1.946 + TBool doParaMerge=((iPos.iPhraseElement>0 || iPos.iPhraseElementOffset>0) && leftToDelete>=charsLeftInPara);
1.947 + // ETrue if the 1st para has content remaining but no paragraph delimiter.
1.948 + //
1.949 + TBool firstParaRemoved=(FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0 && aInfo.iDeleteLength>=current.iParaEntry->iLength);
1.950 + // ETrue if the 1st para has been *wholly* deleted.
1.951 + //
1.952 + DeleteParagraphText(leftToDelete); // Delete range will be in a minimum of 1 paragraph.
1.953 + if (aInfo.iStartPara<aInfo.iEndPara)
1.954 + {// The delete range crosses paragraph boundaries.
1.955 + for (TInt currentPara=aInfo.iStartPara+1;currentPara<=aInfo.iEndPara;currentPara++)
1.956 + {
1.957 + ScanToPosition(aInfo.iDeletePos.iDocPos,EScanToPositionAbsolute);
1.958 + DeleteParagraphText(leftToDelete);
1.959 + }
1.960 + }
1.961 + // Now tidy up
1.962 + if (doParaMerge && !firstParaRemoved)
1.963 + {// Merge the 2 paras together.
1.964 + TParaAttribsEntry* paraEntry=&(*iParaIx)[aInfo.iStartPara];
1.965 + TParaAttribsEntry* paraEntryFollowing=&(*iParaIx)[aInfo.iStartPara+1];
1.966 + paraEntryFollowing->iLength+=paraEntry->iLength; // Extend length of remaining para.
1.967 + paraEntryFollowing->iParaAttribs->iPhraseCount+=paraEntry->iParaAttribs->iPhraseCount; // Extend phrase count
1.968 + paraEntry->iParaAttribs->Release();
1.969 + iParaIx->Delete(aInfo.iStartPara);
1.970 + }
1.971 + if (aInfo.iDeleteType!=TIndexDeleteInfo::EDeleteParagraph)
1.972 + TidyAfterDelete(aInfo);
1.973 +
1.974 + __TEST_INVARIANT;
1.975 + return doParaMerge;
1.976 + }
1.977 +
1.978 +
1.979 +void CRichTextIndex::TidyAfterDelete(const TIndexDeleteInfo& aInfo)
1.980 +//
1.981 +//
1.982 + {
1.983 + MergePhrases(aInfo.iDeletePos.iDocPos); // Alters internal position record.
1.984 + TCurrentIndexRecords current;
1.985 + GetCurrentRecords(current); // So must get records again.
1.986 + if (!current.iParaAttribs->IsShared())
1.987 + {// May be able to reclaim a share from this *specific* record
1.988 + CParaAttribs* sharedParaAttribs=RequestShare(iPos);
1.989 + if (sharedParaAttribs!=NULL && current.iParaAttribs!=sharedParaAttribs)
1.990 + {// Use this shared record
1.991 + current.iParaAttribs->Release();
1.992 + RemoveFromPhraseIx(iPos.iPhraseElement);
1.993 + current.iParaEntry->iParaAttribs=sharedParaAttribs;
1.994 + }
1.995 + }
1.996 + }
1.997 +
1.998 +
1.999 +void CRichTextIndex::Normalize(TInt aPos)
1.1000 +//
1.1001 + {
1.1002 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.1003 + NormalizeNow(iPos);
1.1004 +
1.1005 + __TEST_INVARIANT;
1.1006 + }
1.1007 +
1.1008 +
1.1009 +void CRichTextIndex::NormalizeNow(const TLogicalPosition& aNormalizePos)
1.1010 +//
1.1011 + {
1.1012 + CParaAttribs* currentParaAttribs=(*iParaIx)[aNormalizePos.iParaElement].iParaAttribs;
1.1013 + if (!currentParaAttribs->IsShared())
1.1014 + {
1.1015 + CParaAttribs* sharedParaAttribs=RequestShare(iPos);
1.1016 + if (sharedParaAttribs!=NULL && currentParaAttribs!=sharedParaAttribs)
1.1017 + {// We must have been given a share on something already in the shared list. Dump current stuff.
1.1018 + currentParaAttribs->Release();
1.1019 + (*iParaIx)[aNormalizePos.iParaElement].iParaAttribs=sharedParaAttribs;
1.1020 + RemoveFromPhraseIx(aNormalizePos.iParaBasePhraseElement);
1.1021 + }
1.1022 + }
1.1023 + }
1.1024 +
1.1025 +
1.1026 +CParaAttribs* CRichTextIndex::ReserveCellLC()
1.1027 +// Returns a handle to a newly created CParaAttribs object. This may be used
1.1028 +// during a call to GetParaAttribsL() as a pre-allocated cell, thus ensuring
1.1029 +// that the call cannot possibly leave.
1.1030 +// ASSUMES: that the internal position record has been set correctly.
1.1031 +//
1.1032 + {
1.1033 + CParaAttribs* reservedCell=ReserveCellL();
1.1034 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reservedCell));
1.1035 + return reservedCell;
1.1036 + }
1.1037 +
1.1038 +
1.1039 +CParaAttribs* CRichTextIndex::ReserveCellL()
1.1040 +// Returns a handle to a newly created CParaAttribs object. This may be used
1.1041 +// during a call to GetParaAttribsL() as a pre-allocated cell, thus ensuring
1.1042 +// that the call cannot possibly leave.
1.1043 +// ASSUMES: that the internal position record has been set correctly.
1.1044 +//
1.1045 + {
1.1046 + TCurrentIndexRecords current;
1.1047 + GetCurrentRecords(current);
1.1048 + const CParaAttribs& paraAttribs=*current.iParaAttribs;
1.1049 + CParaFormatLayer* paraLayer=paraAttribs.iParaFormat;
1.1050 + CCharFormatLayer* charLayer=(paraAttribs.IsShared())
1.1051 + ? paraAttribs.iCharFormat
1.1052 + : (*iPhraseIx)[iPos.iPhraseElement].CharFormat();
1.1053 + CParaAttribs* reservedCell=CParaAttribs::NewL(paraLayer,charLayer);
1.1054 + return reservedCell;
1.1055 + }
1.1056 +
1.1057 +
1.1058 +TBool CRichTextIndex::DeleteParagraphText(TInt& aLength)
1.1059 +// Called once for each paragraph that's included in the delete range.
1.1060 +// Assumes the internal position record has already been set correctly.
1.1061 +// The delete range may cover: (1) The entire paragraph - so just destroy the paragraph,
1.1062 +// (2i) At least a portion of a single phrase, and possibly
1.1063 +// (2ii) 0..n whole contiguous phrases, and possibly
1.1064 +// (2iii) a trailing partial phrase.
1.1065 +// Returns ETrue if the full paragraph is deleted, otherwise returns EFalase.
1.1066 +//
1.1067 + {
1.1068 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.1069 + if (FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0 && aLength>=current.iParaEntry->iLength)
1.1070 + {// The entire paragraph needs to be deleted.
1.1071 + aLength-=current.iParaEntry->iLength;
1.1072 + if (!current.iParaAttribs->IsShared())
1.1073 + RemoveFromPhraseIx(iPos.iParaBasePhraseElement,current.iParaAttribs->iPhraseCount);
1.1074 + current.iParaAttribs->Release();
1.1075 + iParaIx->Delete(iPos.iParaElement);
1.1076 + return ETrue;
1.1077 + }
1.1078 + TInt deleteFromPhrase=CurrentPhraseLength()-iPos.iPhraseElementOffset;
1.1079 + TInt maxPhrase=current.iParaAttribs->PhraseCount();
1.1080 + TInt currentPhrase=(iPos.iPhraseElement-iPos.iParaBasePhraseElement);
1.1081 + while (currentPhrase<maxPhrase)
1.1082 + {
1.1083 + TInt deletable=Min(deleteFromPhrase,aLength);
1.1084 + current.iParaEntry->iLength-=deletable; // Adjust the paragraph length.
1.1085 + if (current.iPhrase && deletable>=CurrentPhraseLength())
1.1086 + {// Remove the now empty phrase from the phrase index.
1.1087 + RemoveFromPhraseIx(iPos.iPhraseElement);
1.1088 + current.iParaAttribs->iPhraseCount--;
1.1089 + }
1.1090 + else if (current.iPhrase)
1.1091 + {// Adjust phrase length and move onto the next phrase.
1.1092 + current.iPhrase->AdjustLength(-deletable);
1.1093 + iPos.iPhraseElement++;
1.1094 + iPos.iPhraseElementOffset=0;
1.1095 + }
1.1096 + currentPhrase++;
1.1097 + aLength-=deletable;
1.1098 + if(aLength==0)
1.1099 + break; // Nothing left to delete in this paragraph.
1.1100 + // Get the data for the next phrase.
1.1101 + GetCurrentRecords(current);
1.1102 + deleteFromPhrase=CurrentPhraseLength();
1.1103 + }
1.1104 + return EFalse;
1.1105 + }
1.1106 +
1.1107 +TBool CRichTextIndex::InsertCharFormatIsActive()
1.1108 + {
1.1109 + return iPendingNewPhrasePos != EInsertCharFormatReset;
1.1110 + }
1.1111 +
1.1112 +/** Sets an *InsertPending* state, where format has been inserted into the
1.1113 +text, but no content has yet been inserted. This *state* is cancelled by cursor
1.1114 +movement etc. Split the current phrase at aPos (if necessary) and insert a zero
1.1115 +length phrase, ready to accept the pending content of the specified format.
1.1116 +*/
1.1117 +void CRichTextIndex::SetInsertCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos)
1.1118 + {
1.1119 + if (InsertCharFormatIsActive() && aPos!=iPendingNewPhrasePos)
1.1120 + {
1.1121 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_SETINSERTCHARFORMATL, "ESetInsertCharFormatIntegrityErr" );
1.1122 + }
1.1123 + __ASSERT_ALWAYS(!InsertCharFormatIsActive() || aPos==iPendingNewPhrasePos,
1.1124 + Panic(ESetInsertCharFormatIntegrityErr));
1.1125 + if (InsertCharFormatIsActive())
1.1126 + UpdateInsertCharFormatL(aFormat, aMask);
1.1127 + else
1.1128 + NewInsertCharFormatL(aFormat, aMask, aPos);
1.1129 + }
1.1130 +
1.1131 +void CRichTextIndex::NewInsertCharFormatL(const TCharFormatX& aFormat,
1.1132 + const TCharFormatXMask& aMask, TInt aPos)
1.1133 + {
1.1134 + if (InsertCharFormatIsActive())
1.1135 + {
1.1136 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_NEWINSERTCHARFORMATL, "ESetInsertCharFormatIntegrityErr" );
1.1137 + }
1.1138 + __ASSERT_ALWAYS(!InsertCharFormatIsActive(),
1.1139 + Panic(ESetInsertCharFormatIntegrityErr));
1.1140 + ScanToPosition(aPos,EScanToPositionMatchLeft);
1.1141 + TCurrentIndexRecords current;
1.1142 + GetCurrentRecords(current);
1.1143 + CCharFormatLayer* basedOn;
1.1144 + TCharFormatX applyFormat=aFormat;
1.1145 + TCharFormatXMask applyMask=aMask;
1.1146 + GetPhraseFormat(current,applyFormat,applyMask,basedOn); // Inherit phrase attributes to the left, over what is present.
1.1147 + TBool origParaAttribsShared=current.iParaAttribs->IsShared();
1.1148 + if (origParaAttribsShared)
1.1149 + {// Current paraAttribs is shared.
1.1150 + iRollbackParaAttribsHandle=current.iParaAttribs;
1.1151 + current.iParaEntry->iParaAttribs=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry); // Does not release share.
1.1152 + ScanToPosition(aPos,EScanToPositionMatchLeft); // Pick up reclaimed phrase.
1.1153 + } // Now current.iParaAttribs has specific character formatting - guaranteed.
1.1154 + GetCurrentRecords(current);
1.1155 + TRAPD(ret, DoNewInsertCharFormatL(applyFormat, applyMask,
1.1156 + basedOn, current.iParaAttribs));
1.1157 + if (ret!=KErrNone)
1.1158 + {// Rollback as if this function call never happened.
1.1159 + if (origParaAttribsShared)
1.1160 + {// Revert back to sharing the original.
1.1161 + current.iParaAttribs->Release();
1.1162 + RemoveFromPhraseIx(iPos.iPhraseElement);
1.1163 + current.iParaEntry->iParaAttribs=iRollbackParaAttribsHandle;
1.1164 + }
1.1165 + else
1.1166 + {// Restore the original phrase index.
1.1167 + if (PhraseSplit())
1.1168 + MergePhrases(aPos);
1.1169 + }
1.1170 + OstTrace0( TRACE_FATAL, DUP1_CRICHTEXTINDEX_NEWINSERTCHARFORMATL, "LeaveNoMemory" );
1.1171 + User::LeaveNoMemory();
1.1172 + }
1.1173 + iPendingNewPhrasePos=aPos;
1.1174 + }
1.1175 +
1.1176 +void CRichTextIndex::UpdateInsertCharFormatL(const TCharFormatX& aFormat,
1.1177 + const TCharFormatXMask& aMask)
1.1178 + {
1.1179 + CCharFormatLayer* currentLayer = GetCurrentInsertCharFormat();
1.1180 + CCharFormatLayer* newLayer = CCharFormatLayer::NewCopyBaseL(currentLayer);
1.1181 + CleanupStack::PushL(newLayer);
1.1182 + newLayer->SetL(aFormat, aMask);
1.1183 + currentLayer->Swap(*newLayer);
1.1184 + CleanupStack::PopAndDestroy(newLayer);
1.1185 + }
1.1186 +
1.1187 +CCharFormatLayer* CRichTextIndex::GetCurrentInsertCharFormat()
1.1188 + {
1.1189 + if (!InsertCharFormatIsActive())
1.1190 + {
1.1191 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_GETCURRENTINSERTCHARFORMAT, "ESetInsertCharFormatIntegrityErr" );
1.1192 + }
1.1193 + __ASSERT_DEBUG(InsertCharFormatIsActive(),
1.1194 + Panic(ESetInsertCharFormatIntegrityErr));
1.1195 + ScanToPosition(iPendingNewPhrasePos,EScanToPositionMatchLeft);
1.1196 + TCurrentIndexRecords current;
1.1197 + GetCurrentRecords(current);
1.1198 + if ((*iPhraseIx)[iPos.iPhraseElement].Length() != 0)
1.1199 + {
1.1200 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_GETCURRENTINSERTCHARFORMAT, "ESetInsertCharFormatIntegrityErr" );
1.1201 + }
1.1202 + __ASSERT_DEBUG((*iPhraseIx)[iPos.iPhraseElement].Length() == 0,
1.1203 + Panic(ESetInsertCharFormatIntegrityErr));
1.1204 + return (*iPhraseIx)[iPos.iPhraseElement].CharFormat();
1.1205 + }
1.1206 +
1.1207 +void CRichTextIndex::DoNewInsertCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,
1.1208 + CCharFormatLayer* aBasedOn,CParaAttribs* aParaAttribs)
1.1209 + {
1.1210 + SplitPhraseL(iPos.iPhraseElement,iPos.iPhraseElementOffset,aParaAttribs);
1.1211 + CCharFormatLayer* layer=CCharFormatLayer::NewL();
1.1212 + layer->SetBase(aBasedOn); // must be done before the SetL().
1.1213 + CleanupStack::PushL(layer);
1.1214 + layer->SetL(aFormat,aMask);
1.1215 + RPhraseAttribsEntry pendingNewPhrase(layer);
1.1216 + TInt pendingNewPhraseElement=(FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0)
1.1217 + ?iPos.iParaBasePhraseElement:iPos.iPhraseElement+1;
1.1218 + iPhraseIx->InsertL(pendingNewPhraseElement,pendingNewPhrase);
1.1219 + CleanupStack::Pop();
1.1220 + aParaAttribs->iPhraseCount++;
1.1221 + }
1.1222 +
1.1223 +
1.1224 +void CRichTextIndex::RebalanceIndex()
1.1225 +// Returns the index to a good state, by releasing the extra share taken on the paraAttribs
1.1226 +//
1.1227 + {
1.1228 + if (iRollbackParaAttribsHandle)
1.1229 + {
1.1230 + // ASSERT: The specified para attribs is indeed in the share list.
1.1231 + if (!iRollbackParaAttribsHandle->IsShared())
1.1232 + {
1.1233 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_REBALANCEINDEX, "EParaAttribsNotInSharedList" );
1.1234 + }
1.1235 + __ASSERT_ALWAYS(iRollbackParaAttribsHandle->IsShared(),Panic(EParaAttribsNotInSharedList));
1.1236 + iRollbackParaAttribsHandle->Release();
1.1237 + iRollbackParaAttribsHandle=NULL;
1.1238 + }
1.1239 + }
1.1240 +
1.1241 +/** Cancels the transitory state where a specified character format is applied
1.1242 +on top of any inherited formatting. eg, when bold is on. Cancel when: (1) the
1.1243 +text position is altered. (2) the first character (or picture) has been
1.1244 +inserted following the setting of this state. If a zero length phrase is
1.1245 +removed OR has content entered into it, the newly abutting phrases are checked
1.1246 +to see if they can be merged. Then a request share of this para is issued.
1.1247 +*/
1.1248 +void CRichTextIndex::CancelInsertCharFormat()
1.1249 + {
1.1250 + if (InsertCharFormatIsActive())
1.1251 + {
1.1252 + TBool isDeleted = DeleteInsertCharFormat();
1.1253 + ConsolidateAt(iPendingNewPhrasePos, isDeleted?
1.1254 + EPositionOnly : EFollowingPhrase);
1.1255 + iPendingNewPhrasePos = EInsertCharFormatReset;
1.1256 + }
1.1257 + }
1.1258 +
1.1259 +/** Attempts to delete a zero-length phrase at the insert character format
1.1260 +position. Does not delete any phrase of non-zero length.
1.1261 +@pre The insert character format must be active
1.1262 +@return ETrue if a zero-length phrase was deleted.
1.1263 +*/
1.1264 +TBool CRichTextIndex::DeleteInsertCharFormat()
1.1265 + {
1.1266 + if (!InsertCharFormatIsActive())
1.1267 + {
1.1268 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_DELETEINSERTCHARFORMAT, "Invariant" );
1.1269 + }
1.1270 + __ASSERT_DEBUG(InsertCharFormatIsActive(), User::Invariant());
1.1271 + ScanToPosition(iPendingNewPhrasePos,EScanToPositionMatchLeft);
1.1272 + TCurrentIndexRecords current;
1.1273 + GetCurrentRecords(current);
1.1274 + if (current.iPhrase && current.iPhrase->Length() == 0)
1.1275 + {
1.1276 + RemoveFromPhraseIx(iPos.iPhraseElement);
1.1277 + current.iParaAttribs->iPhraseCount--; // Para has 1 less phrase in it now.
1.1278 + return ETrue;
1.1279 + }
1.1280 + return EFalse;
1.1281 + }
1.1282 +
1.1283 +/** Attempts to merge phrases and share paragraphs.
1.1284 +@param aPosition
1.1285 + Phrase boundary here is merged if possible, paragraph here is shared if
1.1286 + possible.
1.1287 +@param aPositionOrPhrase
1.1288 + If EPositionOnly the phrases either side of aPosition are considered for merging. If EFollowingPhrase,
1.1289 + the end of the phrase following aPosition is also considered.
1.1290 +*/
1.1291 +void CRichTextIndex::ConsolidateAt(TInt aPosition,
1.1292 + TPositionOrPhrase aPositionOrPhrase)
1.1293 + {
1.1294 + ScanToPosition(aPosition, EScanToPositionAbsolute);
1.1295 + TCurrentIndexRecords current;
1.1296 + GetCurrentRecords(current);
1.1297 + if (!current.iPhrase)
1.1298 + return;
1.1299 +
1.1300 + TInt length = current.iPhrase->Length();
1.1301 + MergePhrases(aPosition);
1.1302 + if (aPositionOrPhrase == EFollowingPhrase)
1.1303 + {
1.1304 + ScanToPosition(aPosition, EScanToPositionAbsolute);
1.1305 + GetCurrentRecords(current);
1.1306 + if (current.iPhrase)
1.1307 + MergePhrases(aPosition + length);
1.1308 + }
1.1309 + Normalize(aPosition);
1.1310 + RebalanceIndex();
1.1311 + }
1.1312 +
1.1313 +TBool CRichTextIndex::DelSetInsertCharFormatL(TInt aPos,TInt aLength)
1.1314 +// Delete aLength characters, commencing at, and including, aPos.
1.1315 +// Adds value by the following behaviour:
1.1316 +// If aPos is on a phrase boundary, then remember temporarily the phrase format.
1.1317 +// This is applied to any content that is immediately inserted.
1.1318 +//
1.1319 + {
1.1320 + __TEST_INVARIANT;
1.1321 +
1.1322 + CancelInsertCharFormat();
1.1323 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.1324 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.1325 + if ((!current.iParaAttribs->IsShared()) && iPos.iPhraseElementOffset==0)
1.1326 + {// aPos is on phrase boundary so SetState.
1.1327 + TCharFormatX format;
1.1328 + TCharFormatXMask mask;
1.1329 + CCharFormatLayer* charBase;
1.1330 + GetPhraseFormat(current,format,mask,charBase);
1.1331 + SetInsertCharFormatL(format,mask,aPos);
1.1332 + }
1.1333 + TIndexDeleteInfo deleteInfo;
1.1334 + SetForDeleteL(deleteInfo,aPos,aLength);
1.1335 + TBool parasMerged=DeleteNow(deleteInfo);
1.1336 +
1.1337 + __TEST_INVARIANT;
1.1338 + return parasMerged;
1.1339 + }
1.1340 +
1.1341 +
1.1342 +void CRichTextIndex::ApplyParaFormatL(const CParaFormat* aFormat,const TParaFormatMask& aMask,TInt aPos,TInt aLength)
1.1343 +// Applies the specified format attributes to the paragraphs covering character position aPos to aPos+aLength-1.
1.1344 +// Preserves any attributes that are currently stored in this layer.
1.1345 +// If the specified para(s) is in the shared list, a new shared para of the desired format must be created,
1.1346 +// and the usage count of the original decremented.
1.1347 +//
1.1348 + {
1.1349 + __TEST_INVARIANT;
1.1350 +
1.1351 + TInt offset=(aLength==0)?0 :-1;
1.1352 + TInt endPara=OwningParagraph(aPos+(aLength+offset));
1.1353 + TInt paraItem=OwningParagraph(aPos);
1.1354 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.1355 + CParaFormat* pf=CParaFormat::NewL(*aFormat); // preserve the desired tablist.
1.1356 + CleanupStack::PushL(pf);
1.1357 + for (;paraItem<=endPara;paraItem++)
1.1358 + {// For each paragraph, apply the specified format.
1.1359 + TParaFormatMask applyMask=aMask;
1.1360 + CParaAttribs* currentParaAttribs=(*iParaIx)[paraItem].iParaAttribs;
1.1361 + TBool shared=currentParaAttribs->IsShared();
1.1362 + if (!shared)
1.1363 + {
1.1364 + currentParaAttribs->iParaFormat->SenseL(pf,applyMask);
1.1365 + currentParaAttribs->iParaFormat->SetL(pf,applyMask);
1.1366 + }
1.1367 + else
1.1368 + {// Must create a new shared para attribs of the specified format
1.1369 + // Make a new para format layer
1.1370 + currentParaAttribs->iParaFormat->SenseL(pf,applyMask);
1.1371 + CParaFormatLayer* newParaLayer=CParaFormatLayer::NewL(pf,applyMask);
1.1372 + newParaLayer->SetBase(currentParaAttribs->iParaFormat->SenseBase());
1.1373 + CleanupStack::PushL(newParaLayer);
1.1374 + // Make a new char format layer
1.1375 + CCharFormatLayer* newCharLayer=CCharFormatLayer::NewL(currentParaAttribs->iCharFormat);
1.1376 + newCharLayer->SetBase(currentParaAttribs->iCharFormat->SenseBase());
1.1377 + CleanupStack::PushL(newCharLayer);
1.1378 + //
1.1379 + CParaAttribs* sharedParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer);
1.1380 + CleanupStack::PopAndDestroy(2);
1.1381 + if (sharedParaAttribs)
1.1382 + (*iParaIx)[paraItem].iParaAttribs=sharedParaAttribs;
1.1383 + currentParaAttribs->Release();
1.1384 + }
1.1385 + }
1.1386 + CleanupStack::PopAndDestroy(); // pf
1.1387 + __TEST_INVARIANT;
1.1388 + }
1.1389 +
1.1390 +
1.1391 +void CRichTextIndex::ApplyParagraphStyleL(const CParagraphStyle& aStyle,TInt aPos,TInt aLength,
1.1392 + const CCharFormatLayer* aCharStyleNormal,CParagraphStyle::TApplyParaStyleMode aMode)
1.1393 +// Applies the specified paragraph style to the paragraphs covering
1.1394 +// character positions aPos to aPos+aLength-1.
1.1395 +// Alters the specific formatting of the covered paragraphs as specified by aMode.
1.1396 +//
1.1397 + {
1.1398 + __TEST_INVARIANT;
1.1399 +
1.1400 + TInt offset=(aLength==0)?0 :-1;
1.1401 + TInt endPara=OwningParagraph(aPos+(aLength+offset));
1.1402 + TInt paraItem=OwningParagraph(aPos);
1.1403 + TInt paragraphBasePhrase=iPos.iParaBasePhraseElement;
1.1404 + TCurrentIndexRecords current;
1.1405 + GetCurrentRecords(current);
1.1406 + for (;paraItem<=endPara;paraItem++)
1.1407 + {// For each paragraph, apply the specified style
1.1408 + CParaAttribs& currentParaAttribs=*(*iParaIx)[paraItem].iParaAttribs;
1.1409 + TBool shared=currentParaAttribs.IsShared();
1.1410 + TUid type=aStyle.Type();
1.1411 + if (!shared)
1.1412 + {
1.1413 + currentParaAttribs.iParaFormat->SetBase(&aStyle);
1.1414 + TInt phraseCount=currentParaAttribs.PhraseCount();
1.1415 + for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++)
1.1416 + {
1.1417 + CCharFormatLayer& charLayer=*(*iPhraseIx)[paragraphBasePhrase+phraseItem].CharFormat();
1.1418 + if (type==KNormalParagraphStyleUid)
1.1419 + charLayer.SetBase(aCharStyleNormal);
1.1420 + else
1.1421 + charLayer.SetBase(aStyle.CharFormatLayer());
1.1422 + ModifySpecificFormatting(*currentParaAttribs.iParaFormat,charLayer,aMode);
1.1423 + }
1.1424 + paragraphBasePhrase+=phraseCount;
1.1425 + }
1.1426 + else
1.1427 + {// Must create a new shared para attribs of the same format, but a different based on link
1.1428 + // Make a new para format layer
1.1429 + CParaFormatLayer* newParaLayer=NULL;
1.1430 + if (aMode==CParagraphStyle::ERetainNoSpecificFormats || aMode==CParagraphStyle::ERetainSpecificCharFormat)
1.1431 + newParaLayer=CParaFormatLayer::NewL();
1.1432 + else
1.1433 + newParaLayer=CParaFormatLayer::NewL(currentParaAttribs.iParaFormat);
1.1434 + newParaLayer->SetBase(&aStyle);
1.1435 + CleanupStack::PushL(newParaLayer);
1.1436 + //
1.1437 + // Make a new char format layer
1.1438 + CCharFormatLayer* newCharLayer=NULL;
1.1439 + if (aMode==CParagraphStyle::ERetainNoSpecificFormats || aMode==CParagraphStyle::ERetainSpecificParaFormat)
1.1440 + newCharLayer=CCharFormatLayer::NewL();
1.1441 + else
1.1442 + newCharLayer=CCharFormatLayer::NewL(currentParaAttribs.iCharFormat);
1.1443 + if (type==KNormalParagraphStyleUid)
1.1444 + newCharLayer->SetBase(aCharStyleNormal);
1.1445 + else
1.1446 + newCharLayer->SetBase(aStyle.CharFormatLayer());
1.1447 + CleanupStack::PushL(newCharLayer);
1.1448 + //
1.1449 + (*iParaIx)[paraItem].iParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer);
1.1450 + CleanupStack::PopAndDestroy(2);
1.1451 + currentParaAttribs.Release();
1.1452 + }
1.1453 + }
1.1454 + }
1.1455 +
1.1456 +
1.1457 +void CRichTextIndex::ModifySpecificFormatting(CParaFormatLayer& aPl,CCharFormatLayer& aCl,CParagraphStyle::TApplyParaStyleMode aMode)
1.1458 +//
1.1459 +//
1.1460 + {
1.1461 + switch(aMode)
1.1462 + {
1.1463 + case(CParagraphStyle::ERetainNoSpecificFormats):
1.1464 + aPl.Reset();
1.1465 + aCl.Reset();
1.1466 + break;
1.1467 + case(CParagraphStyle::ERetainSpecificParaFormat):
1.1468 + aCl.Reset();
1.1469 + break;
1.1470 + case(CParagraphStyle::ERetainSpecificCharFormat):
1.1471 + aPl.Reset();
1.1472 + break;
1.1473 + case(CParagraphStyle::ERetainAllSpecificFormats):
1.1474 + default:
1.1475 + break;
1.1476 + }
1.1477 + }
1.1478 +
1.1479 +
1.1480 +/*
1.1481 +For every paragraph in the document: (i) if it uses the style aFrom, make it use the style aTo,
1.1482 +or the global style if aTo is null; (ii) if any phrase in the paragraph has a character format
1.1483 +based on the character format owned by aFrom, change it so that it is based on the character
1.1484 +format owned by aTo, or the global character format if aTo is null.
1.1485 +
1.1486 +The action described in (ii) should only occur for an 'orphaned' character insertion format; that is
1.1487 +an insertion format left after deletion of a block in a certain style that is itself then deleted.
1.1488 +*/
1.1489 +void CRichTextIndex::NotifyStyleChangedL(const CParagraphStyle* aTo,const CParagraphStyle* aFrom,
1.1490 + const CParaFormatLayer& aGlobalParaFormatLayer,
1.1491 + const CCharFormatLayer& aGlobalCharFormatLayer)
1.1492 + {
1.1493 + __TEST_INVARIANT;
1.1494 +
1.1495 + TInt paraCount=ParagraphCount();
1.1496 + TInt currentPhrase = 0;
1.1497 + const CCharFormatLayer* oldCharFormatLayer = aFrom->CharFormatLayer();
1.1498 + const CParaFormatLayer* newParFormatLayer = aTo ? aTo : &aGlobalParaFormatLayer;
1.1499 + const CCharFormatLayer* newCharFormatLayer = aTo ? aTo->CharFormatLayer() : &aGlobalCharFormatLayer;
1.1500 + for (TInt paraItem = 0;paraItem < paraCount; paraItem++)
1.1501 + {
1.1502 + TParaAttribsEntry* currentPara = &(*iParaIx)[paraItem];
1.1503 + CParaAttribs* currentParaAttribs = currentPara->iParaAttribs;
1.1504 +
1.1505 + TBool changeParStyleBase = currentParaAttribs->iParaFormat->SenseBase() == aFrom;
1.1506 + if (!currentParaAttribs->IsShared())
1.1507 + {
1.1508 + if (changeParStyleBase)
1.1509 + currentParaAttribs->iParaFormat->SetBase(newParFormatLayer);
1.1510 + TInt phraseCount = currentParaAttribs->PhraseCount();
1.1511 + for (TInt phraseItem = currentPhrase; phraseItem < (currentPhrase + phraseCount); phraseItem++)
1.1512 + {
1.1513 + CCharFormatLayer* charFormat = (*iPhraseIx)[phraseItem].CharFormat();
1.1514 + if (charFormat->SenseBase() == oldCharFormatLayer)
1.1515 + charFormat->SetBase(newCharFormatLayer);
1.1516 + }
1.1517 + currentPhrase += phraseCount;
1.1518 + }
1.1519 + else
1.1520 + { // Maintain the shared list reference
1.1521 + CParaAttribs* resultantParaAttribs = CParaAttribs::NewL(currentParaAttribs);
1.1522 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,resultantParaAttribs));
1.1523 + if (changeParStyleBase)
1.1524 + resultantParaAttribs->iParaFormat->SetBase(newParFormatLayer);
1.1525 + if (resultantParaAttribs->iCharFormat->SenseBase() == oldCharFormatLayer)
1.1526 + resultantParaAttribs->iCharFormat->SetBase(newCharFormatLayer);
1.1527 + CParaAttribs* shared = RequestShareL(resultantParaAttribs); // will return a non-NULL handle
1.1528 + __ASSERT_DEBUG(shared,Panic(EDebug));
1.1529 + currentParaAttribs->Release();
1.1530 + iSharedParaQueHead.AddLast(*resultantParaAttribs); // allows correct release of cell.
1.1531 + CleanupStack::PopAndDestroy();
1.1532 + currentPara->iParaAttribs = shared;
1.1533 + }
1.1534 + }
1.1535 +
1.1536 + __TEST_INVARIANT;
1.1537 + }
1.1538 +
1.1539 +
1.1540 +const CParaFormatLayer* CRichTextIndex::ParagraphStyle(TBool& aStyleChangesOverRange,
1.1541 + TInt aPos,
1.1542 + TInt aLength)const
1.1543 +// Return the handle of the first paragraph style encountered in the specified range.
1.1544 +// Set aStyleChangesOverRange to ETrue, if different paragraph styles are encountered
1.1545 +// across the specified range, otherwise set it to EFalse.
1.1546 +//
1.1547 + {
1.1548 + __TEST_INVARIANT;
1.1549 +
1.1550 + aStyleChangesOverRange=EFalse;
1.1551 + CParaFormatLayer* style=NULL;
1.1552 + TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos);
1.1553 + TInt offset=(aLength==0)?0 :-1;
1.1554 + TInt endPara=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos+(aLength+offset));
1.1555 + style=(CParaFormatLayer*)(*iParaIx)[para].iParaAttribs->iParaFormat->SenseBase();
1.1556 + ++para;
1.1557 + for (;para<=endPara;para++)
1.1558 + {
1.1559 + CParaFormatLayer* nextStyle=(CParaFormatLayer*)(*iParaIx)[para].iParaAttribs->iParaFormat->SenseBase();
1.1560 + if (nextStyle!=style)
1.1561 + aStyleChangesOverRange=ETrue;
1.1562 + }
1.1563 +
1.1564 + __TEST_INVARIANT;
1.1565 + return style;
1.1566 + }
1.1567 +
1.1568 +
1.1569 +void CRichTextIndex::SplitPhraseL(TInt aPhrase,TInt anOffset,RPhraseAttribsEntry& aPhraseAttribs,CParaAttribs& aParaAttribs)
1.1570 + {
1.1571 + if (anOffset<=0 || anOffset>=aPhraseAttribs.Length())
1.1572 + {
1.1573 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_SPLITPHRASEL, "Invariant" );
1.1574 + }
1.1575 + __ASSERT_DEBUG(anOffset>0 && anOffset<aPhraseAttribs.Length(),User::Invariant());
1.1576 +//
1.1577 + CCharFormatLayer* charLayer=CCharFormatLayer::NewCopyBaseL(aPhraseAttribs.CharFormat());
1.1578 + CleanupStack::PushL(charLayer);
1.1579 + iPhraseIx->InsertL(aPhrase+1,RPhraseAttribsEntry(charLayer,aPhraseAttribs.Length()-anOffset));
1.1580 + CleanupStack::Pop();
1.1581 + //
1.1582 + // InsertL() has invalidated the phrase index.
1.1583 + iPhraseIx->At(aPhrase).SetLength(anOffset); // Adjust the length of the orginal phrase
1.1584 + aParaAttribs.iPhraseCount++;
1.1585 + }
1.1586 +
1.1587 +
1.1588 +TBool CRichTextIndex::MergePhrases(TInt aPhrase,RPhraseAttribsEntry& aPhraseAttribs,CParaAttribs& aParaAttribs)
1.1589 + {
1.1590 + RPhraseAttribsEntry& prevPhrase=iPhraseIx->At(aPhrase-1);
1.1591 + if (!aPhraseAttribs.IsIdentical(prevPhrase))
1.1592 + return EFalse;
1.1593 + // Merge the abutting phrases together.
1.1594 + prevPhrase.AdjustLength(aPhraseAttribs.Length()); // Extend the remaining phrase
1.1595 + RemoveFromPhraseIx(aPhrase); // Free the resources taken by the redundant phrase
1.1596 + aParaAttribs.iPhraseCount--;
1.1597 + return ETrue;
1.1598 + }
1.1599 +
1.1600 +
1.1601 +void CRichTextIndex::Share(TParaAttribsEntry& aParaEntry,TInt aPhrase)
1.1602 +//
1.1603 +// aParaEntry is not shared and can be (phrase count 1), aPhrase is the single phrase element
1.1604 +//
1.1605 + {
1.1606 + CParaAttribs* paraAttribs=aParaEntry.iParaAttribs;
1.1607 + if (paraAttribs->iPhraseCount!=1)
1.1608 + {
1.1609 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_SHARE, "Invariant" );
1.1610 + }
1.1611 + __ASSERT_DEBUG(paraAttribs->iPhraseCount==1,User::Invariant());
1.1612 +
1.1613 + RPhraseAttribsEntry& phraseAttribs=iPhraseIx->At(aPhrase);
1.1614 + if (phraseAttribs.IsPicturePhrase())
1.1615 + {
1.1616 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_SHARE, "Invariant" );
1.1617 + }
1.1618 + __ASSERT_DEBUG(!phraseAttribs.IsPicturePhrase(),User::Invariant());
1.1619 +
1.1620 + CParaAttribs* share=GetParaAttribs(paraAttribs,*phraseAttribs.CharFormat());
1.1621 + if (share!=paraAttribs)
1.1622 + { // re-use an existing share, so release the current attribs
1.1623 + paraAttribs->Release();
1.1624 + phraseAttribs.Discard();
1.1625 + aParaEntry.iParaAttribs=share;
1.1626 + }
1.1627 + iPhraseIx->Delete(aPhrase);
1.1628 + }
1.1629 +
1.1630 +
1.1631 +void CRichTextIndex::ApplyCharFormatCleanup(TAny* aPtr)
1.1632 +// CLeanup function for ApplyCharFormatL()
1.1633 +//
1.1634 + {REINTERPRET_CAST(CRichTextIndex*,aPtr)->ApplyCharFormatRollback();}
1.1635 +
1.1636 +
1.1637 +void CRichTextIndex::ApplyCharFormatRollback()
1.1638 +// Paragraph and phrase we were working on are stored in iPos
1.1639 +// Return them the canonical form
1.1640 +//
1.1641 + {
1.1642 + TParaAttribsEntry& paraEntry=iParaIx->At(iPos.iParaElement);
1.1643 + CParaAttribs* paraAttribs=paraEntry.iParaAttribs;
1.1644 +
1.1645 + if (paraAttribs->IsShared())
1.1646 + return;
1.1647 +
1.1648 + TInt phrase=iPos.iPhraseElement;
1.1649 + TInt base=iPos.iParaBasePhraseElement;
1.1650 + if (phrase<base || phrase>=base+paraAttribs->iPhraseCount)
1.1651 + {
1.1652 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_APPLYCHARFORMATROLLBACK, "Invariant" );
1.1653 + }
1.1654 + __ASSERT_DEBUG(phrase>=base && phrase<base+paraAttribs->iPhraseCount,User::Invariant());
1.1655 + if (phrase<base+paraAttribs->iPhraseCount-1) // merge to the right
1.1656 + MergePhrases(phrase+1,iPhraseIx->At(phrase+1),*paraAttribs);
1.1657 + if (phrase>base) // merge to the left
1.1658 + MergePhrases(phrase,iPhraseIx->At(phrase),*paraAttribs);
1.1659 + if (paraAttribs->iPhraseCount==1) // Share the paragraph
1.1660 + Share(paraEntry,base);
1.1661 + }
1.1662 +
1.1663 +
1.1664 +void CRichTextIndex::ApplyCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos,TInt aLength,TBool aRemoveSpecific)
1.1665 +// Applies the specified character formatting to the characters contained within the range
1.1666 +// aPos to aPos+(aLength-1).
1.1667 +//
1.1668 + {
1.1669 + if (aLength<0)
1.1670 + {
1.1671 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1672 + }
1.1673 + __ASSERT_DEBUG(aLength>=0,User::Invariant());
1.1674 + __TEST_INVARIANT;
1.1675 +
1.1676 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.1677 + TInt paraOffset=iPos.iParaElementOffset;
1.1678 + TInt phraseOffset=iPos.iPhraseElementOffset;
1.1679 + TInt phrase=iPos.iPhraseElement;
1.1680 +
1.1681 +// prepare for failure
1.1682 + CleanupStack::PushL(TCleanupItem(ApplyCharFormatCleanup,this));
1.1683 +
1.1684 + for (;;)
1.1685 + { // a paragraph at a time
1.1686 + TParaAttribsEntry& paraEntry=iParaIx->At(iPos.iParaElement);
1.1687 + CParaAttribs* paraAttribs=paraEntry.iParaAttribs;
1.1688 + TInt charsToFormat=Min(aLength,paraEntry.iLength-paraOffset);
1.1689 + aLength-=charsToFormat;
1.1690 +#ifdef _DEBUG
1.1691 + aPos+=charsToFormat;
1.1692 +#endif
1.1693 +
1.1694 +// STEP 1. Reclaim any shared paragraph into non shared form. Re-use the object if possible
1.1695 +
1.1696 + if (paraAttribs->IsShared())
1.1697 + {
1.1698 + CCharFormatLayer* charLayer=paraAttribs->iCharFormat;
1.1699 + if (paraAttribs->iRefCount==CParaAttribs::EPrimeSharedCount)
1.1700 + { // we are the sole user of this attribute
1.1701 + iPhraseIx->InsertL(phrase,RPhraseAttribsEntry(charLayer,paraEntry.iLength));
1.1702 + // adjust attribute to be non-shared
1.1703 + paraAttribs->link.Deque();
1.1704 + paraAttribs->iRefCount=CParaAttribs::EPrimeNonSharedCount;
1.1705 + paraAttribs->iPhraseCount=1;
1.1706 + }
1.1707 + else
1.1708 + { // create a new para attribs object
1.1709 + CParaAttribs* newAttribs=CParaAttribs::NewL(paraAttribs->iParaFormat);
1.1710 + CleanupReleasePushL(*newAttribs);
1.1711 + charLayer=CCharFormatLayer::NewCopyBaseL(charLayer);
1.1712 + CleanupStack::PushL(charLayer);
1.1713 + iPhraseIx->InsertL(phrase,RPhraseAttribsEntry(charLayer,paraEntry.iLength));
1.1714 + CleanupStack::Pop(2); // charlayer, newAttribs
1.1715 + paraAttribs->Release(); // lose a share on the old attribs
1.1716 + paraEntry.iParaAttribs=paraAttribs=newAttribs;
1.1717 + }
1.1718 + phraseOffset=paraOffset; // we are now in the current position
1.1719 + }
1.1720 +
1.1721 +// STEP 2. Walk through all affected phrases in this paragraph
1.1722 +// For each one, we may need to split it, and then apply the new format
1.1723 +
1.1724 + do
1.1725 + {
1.1726 + if (phrase>=iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount)
1.1727 + {
1.1728 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1729 + }
1.1730 + __ASSERT_DEBUG(phrase<iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount,User::Invariant());
1.1731 +//
1.1732 + RPhraseAttribsEntry* phraseAttribs=&iPhraseIx->At(phrase);
1.1733 + TInt len=phraseAttribs->Length();
1.1734 +
1.1735 +// STEP 2.1 Split the phrase at the beginning of the range?
1.1736 +
1.1737 + if (phraseOffset>0)
1.1738 + { // can only happen for the first phrase
1.1739 + /*
1.1740 + * The pointer paraAttribs is also stored in
1.1741 + * 'paraEntry.iParaAttribs'. The memory pointed to by this
1.1742 + * pointer will be released in CRichTextIndex's destructor.
1.1743 + */
1.1744 + // coverity[leave_without_push]
1.1745 + SplitPhraseL(phrase,phraseOffset,*phraseAttribs,*paraAttribs); // inserts new phrase at correct position
1.1746 + len-=phraseOffset;
1.1747 + phraseOffset=0;
1.1748 + iPos.iPhraseElement=++phrase;
1.1749 + phraseAttribs=&iPhraseIx->At(phrase);
1.1750 + }
1.1751 +
1.1752 +// STEP 2.2 Split the phrase at the end of the range?
1.1753 +
1.1754 + if (len>charsToFormat)
1.1755 + { // phrase is longer than required format, so split it
1.1756 + /*
1.1757 + * The pointer paraAttribs is also stored in
1.1758 + * 'paraEntry.iParaAttribs'. The memory pointed to by this
1.1759 + * pointer will be released in CRichTextIndex's destructor.
1.1760 + */
1.1761 + // coverity[leave_without_push]
1.1762 + SplitPhraseL(phrase,charsToFormat,*phraseAttribs,*paraAttribs);
1.1763 + len=charsToFormat;
1.1764 + phraseAttribs=&iPhraseIx->At(phrase); // SplitPhraseL modifies the index array, we must do this!
1.1765 + }
1.1766 +
1.1767 + if (phraseAttribs->Length()!=len)
1.1768 + {
1.1769 + OstTrace0( TRACE_DUMP, DUP2_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1770 + }
1.1771 + __ASSERT_DEBUG(phraseAttribs->Length()==len,User::Invariant());
1.1772 +
1.1773 +// STEP 2.3 Change the format of the current phrase layer
1.1774 +
1.1775 + TCharFormatX format=aFormat;
1.1776 + TCharFormatXMask mask=aMask;
1.1777 + CCharFormatLayer* charLayer=phraseAttribs->CharFormat();
1.1778 + if (!aRemoveSpecific)
1.1779 + charLayer->Sense(format,mask); // preserve current specific character formatting
1.1780 + charLayer->SetL(format,mask);
1.1781 +
1.1782 +// STEP 2.4 Check for merging with previous phrase
1.1783 +
1.1784 + if (phrase==iPos.iParaBasePhraseElement || !MergePhrases(phrase,*phraseAttribs,*paraAttribs))
1.1785 + // if we don't merge this phrase, move on to the next one
1.1786 + iPos.iPhraseElement=++phrase;
1.1787 +
1.1788 + charsToFormat-=len;
1.1789 + } while (charsToFormat);
1.1790 +
1.1791 + if (phrase!=iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount && aLength!=0)
1.1792 + {
1.1793 + OstTrace0( TRACE_DUMP, DUP3_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1794 + }
1.1795 + __ASSERT_DEBUG(phrase==iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount || aLength==0,User::Invariant());
1.1796 +
1.1797 +// STEP 3 Reduce the paragraph attributes back to canonical form
1.1798 +
1.1799 +// STEP 3.1 Check for merging at the end of the changes
1.1800 +
1.1801 + if (phrase>iPos.iParaBasePhraseElement && phrase<iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount)
1.1802 + MergePhrases(phrase,iPhraseIx->At(phrase),*paraAttribs); // mustn't adjust phrase index to follow merge
1.1803 +
1.1804 +// STEP 3.2 See if we can re-share the paragraph
1.1805 +
1.1806 + if (paraAttribs->iPhraseCount==1)
1.1807 + { // This para has constant character formatting - can be shared.
1.1808 + iPos.iPhraseElement=--phrase;
1.1809 + Share(paraEntry,phrase);
1.1810 + }
1.1811 +
1.1812 +// loop into next paragraph
1.1813 + if (aLength==0)
1.1814 + break;
1.1815 + iPos.iParaElement++;
1.1816 + paraOffset=0;
1.1817 + iPos.iParaBasePhraseElement=phrase;
1.1818 +#ifdef _DEBUG
1.1819 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.1820 + if (iPos.iDocPos!=aPos)
1.1821 + {
1.1822 + OstTrace0( TRACE_DUMP, DUP4_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1823 + }
1.1824 + __ASSERT_DEBUG(iPos.iDocPos==aPos,User::Invariant());
1.1825 + if (iPos.iPhraseElement!=phrase)
1.1826 + {
1.1827 + OstTrace0( TRACE_DUMP, DUP5_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1828 + }
1.1829 + __ASSERT_DEBUG(iPos.iPhraseElement==phrase,User::Invariant());
1.1830 + if (iPos.iParaElementOffset!=paraOffset)
1.1831 + {
1.1832 + OstTrace0( TRACE_DUMP, DUP6_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1833 + }
1.1834 + __ASSERT_DEBUG(iPos.iParaElementOffset==paraOffset,User::Invariant());
1.1835 + if (iPos.iPhraseElementOffset!=phraseOffset)
1.1836 + {
1.1837 + OstTrace0( TRACE_DUMP, DUP7_CRICHTEXTINDEX_APPLYCHARFORMATL, "Invariant" );
1.1838 + }
1.1839 + __ASSERT_DEBUG(iPos.iPhraseElementOffset==phraseOffset,User::Invariant());
1.1840 + __TEST_INVARIANT;
1.1841 +#endif
1.1842 + }
1.1843 +
1.1844 + CleanupStack::Pop(); // rollback item
1.1845 +
1.1846 + __TEST_INVARIANT;
1.1847 + }
1.1848 +
1.1849 +
1.1850 +void CRichTextIndex::RemoveSpecificParaFormatL(TInt aPos,TInt aLength)
1.1851 +// Removes all specific paragraph formatting from the specified region.
1.1852 +// For each paragraph covered by the range, check if its para attribs is in the
1.1853 +// shared list, or not.
1.1854 +// If its not shared, then simply reset the para format layer.
1.1855 +// If it is in the shared list, then a new shared para attribs must be created,
1.1856 +// and the reference count of the original decremented.
1.1857 +//
1.1858 + {
1.1859 + __TEST_INVARIANT;
1.1860 +
1.1861 + TInt endPara=OwningParagraph(aPos+aLength);
1.1862 + TInt currentPara=OwningParagraph(aPos);
1.1863 + CParaAttribs* currentParaAttribs=NULL;
1.1864 + while (currentPara<=endPara)
1.1865 + {
1.1866 + currentParaAttribs=(*iParaIx)[currentPara].iParaAttribs;
1.1867 + if (!currentParaAttribs->IsShared())
1.1868 + {// Reset specific paragraph format layer to be empty.
1.1869 + currentParaAttribs->iParaFormat->Reset(); // remove specific formatting.
1.1870 + }
1.1871 + else
1.1872 + {// Maintain the shared list reference
1.1873 + CParaAttribs* resultantParaAttribs=CParaAttribs::NewL(currentParaAttribs);
1.1874 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,resultantParaAttribs));
1.1875 + resultantParaAttribs->iParaFormat->Reset(); // remove specific formatting
1.1876 + CParaAttribs* shared=RequestShareL(resultantParaAttribs); // Will return a non-NULL handle.
1.1877 + __ASSERT_DEBUG(shared,Panic(EDebug));
1.1878 + currentParaAttribs->Release();
1.1879 + iSharedParaQueHead.AddLast(*resultantParaAttribs); // Allows correct release of cell.
1.1880 + CleanupStack::PopAndDestroy();
1.1881 + (*iParaIx)[currentPara].iParaAttribs=shared;
1.1882 + }
1.1883 + currentPara++;
1.1884 + }
1.1885 +
1.1886 +
1.1887 + __TEST_INVARIANT;
1.1888 + }
1.1889 +
1.1890 +
1.1891 +void CRichTextIndex::RemoveSpecificCharFormatL(TInt aPos,TInt aLength)
1.1892 +// Removes all specific character formatting from the specified region.
1.1893 +// For each paragraph covered by the range, check if its para attribs is in the
1.1894 +// shared list, or not.
1.1895 +// If its not shared, then simply reset the para format layer.
1.1896 +// If it is in the shared list, then a new shared para attribs must be created,
1.1897 +// and the reference count of the original decremented.
1.1898 +//
1.1899 + {
1.1900 + __TEST_INVARIANT;
1.1901 +
1.1902 + TCharFormatX format; // dummy format
1.1903 + TCharFormatXMask mask;
1.1904 + mask.ClearAll();
1.1905 + ApplyCharFormatL(format,mask,aPos,aLength,ETrue);
1.1906 +
1.1907 + __TEST_INVARIANT;
1.1908 + }
1.1909 +
1.1910 +
1.1911 +TBool CRichTextIndex::MergePhrases(TInt aPos)
1.1912 +// Checks if the specified character position aPos is a phrase boundary.
1.1913 +// If so, then examines the two abutting phrases at aPos to see if they
1.1914 +// are identical; in which case they are merged into one phrase that covers
1.1915 +// the sum of their lengths.
1.1916 +//
1.1917 + {
1.1918 + ScanToPosition(aPos,EScanToPositionAbsolute);
1.1919 + return MergePhrases(iPos);
1.1920 + }
1.1921 +
1.1922 +
1.1923 +TBool CRichTextIndex::MergePhrases(const TLogicalPosition& aPos)
1.1924 +// Checks if the specified character position record is a phrase boundary.
1.1925 +// If so, then examines the two abutting phrases at aPos to see if they
1.1926 +// are identical; in which case they are merged into one phrase that covers
1.1927 +// the sum of their lengths.
1.1928 +//
1.1929 + {
1.1930 + TCurrentIndexRecords current;
1.1931 + GetCurrentRecords(current);
1.1932 + TBool phrasesMerged=EFalse;
1.1933 + if (!FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0)
1.1934 + {// Check if the 2 abutting phrases can be merged together.
1.1935 + TInt rightPhraseElement=iPos.iPhraseElement;
1.1936 + RPhraseAttribsEntry* rightPhrase=&(*iPhraseIx)[rightPhraseElement];
1.1937 + RPhraseAttribsEntry* leftPhrase=&(*iPhraseIx)[rightPhraseElement-1];
1.1938 + if (rightPhrase->IsIdentical(*leftPhrase))
1.1939 + {// Merge the abutting phrases together. Cannot merge picture/non-picture/z.l.p. phrase combinations.
1.1940 + rightPhrase->AdjustLength(leftPhrase->Length()); // Extend the right phrase length
1.1941 + RemoveFromPhraseIx(rightPhraseElement-1); // Free the resources taken by the left phrase - redundant
1.1942 + (*iParaIx)[iPos.iParaElement].iParaAttribs->iPhraseCount--; // Update phrase count of owning CParaAttribs
1.1943 + ScanToPosition(aPos.iDocPos,EScanToPositionAbsolute); // Pick up new phrase index.
1.1944 + phrasesMerged=ETrue;
1.1945 + }
1.1946 + }
1.1947 + return phrasesMerged;
1.1948 + }
1.1949 +
1.1950 +
1.1951 +/** Remove phrases from the containing object. This includes
1.1952 +freeing referenced resources. (pictures etc.)
1.1953 +@param aPhraseIndex The first phrase to be deleted
1.1954 +@param aCount The number of phrases to be deleted
1.1955 +*/
1.1956 +void CRichTextIndex::RemoveFromPhraseIx(TInt aPhraseIndex,TInt aCount)
1.1957 + {
1.1958 + // if the phrase being deleted is <= iLastPos
1.1959 + // then iLastPos will become invalid so should be reset
1.1960 + if (aPhraseIndex <= iLastUsed.iPhraseElement )
1.1961 + iLastUsed.Clear();
1.1962 +
1.1963 + for (TInt offset=aPhraseIndex;offset<(aPhraseIndex+aCount);offset++)
1.1964 + {
1.1965 + // discard phrases & book-keep the picture count
1.1966 + RPhraseAttribsEntry& phrase=(*iPhraseIx)[offset];
1.1967 + phrase.Discard();
1.1968 + if (phrase.IsPicturePhrase())
1.1969 + iPictureCount--;
1.1970 + }
1.1971 + iPhraseIx->Delete(aPhraseIndex,aCount);
1.1972 + }
1.1973 +
1.1974 +void CRichTextIndex::GetParagraphFormatL(CParaFormat* aFormat,TInt aPos)const
1.1975 +// Fills aFormat with the effective Paragraph format attributes for the paragraph
1.1976 +// in which character position aPos is contained.
1.1977 +//
1.1978 + {
1.1979 + __TEST_INVARIANT;
1.1980 +
1.1981 + TLogicalPosition cachePos(iLastUsed);
1.1982 + TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos,&cachePos);
1.1983 + (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(aFormat);
1.1984 + }
1.1985 +
1.1986 +void CRichTextIndex::GetSpecificParagraphFormatL(CParaFormat* aFormat,
1.1987 + TParaFormatMask& aMask,
1.1988 + TInt aPos)const
1.1989 + {
1.1990 + __TEST_INVARIANT;
1.1991 +
1.1992 + TLogicalPosition cachePos(iLastUsed);
1.1993 + TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos,&cachePos);
1.1994 + CParaFormatLayer* pLayer = (*iParaIx)[para].iParaAttribs->iParaFormat;
1.1995 + pLayer->SenseL(aFormat, aMask);
1.1996 + }
1.1997 +
1.1998 +TInt CRichTextIndex::GetChars(TCharFormatX& aFormat,TInt aPos) const
1.1999 +// Returns the number of characters, commencing at aStartPos, that occupy the same phrase, and
1.2000 +// modifies aFormat, to hold the effective format of that phrase.
1.2001 +//
1.2002 + {
1.2003 + __TEST_INVARIANT;
1.2004 +
1.2005 + CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed));
1.2006 + TCurrentIndexRecords current;
1.2007 + GetCurrentRecords(current);
1.2008 + TInt phraseLength;
1.2009 + CCharFormatLayer* charFormatLayer;
1.2010 + if (current.iPhrase)
1.2011 + {// Specific character formatting held in phrase index.
1.2012 + charFormatLayer=current.iPhrase->CharFormat();
1.2013 + phraseLength=(current.iPhrase->Length())-(iPos.iPhraseElementOffset);
1.2014 + }
1.2015 + else
1.2016 + {// Constant character formatting held in the para attribs
1.2017 + charFormatLayer=current.iParaAttribs->iCharFormat;
1.2018 + phraseLength=current.iParaEntry->iLength-iPos.iParaElementOffset;
1.2019 + }
1.2020 + charFormatLayer->SenseEffective(aFormat);
1.2021 + return phraseLength;
1.2022 + }
1.2023 +
1.2024 +
1.2025 +TInt CRichTextIndex::GetPictureSizeInTwips(TSize& aSize,TInt aPos)const
1.2026 +// Get the size of the specified picture into aSize. The picture is specified by its
1.2027 +// character position. Return KErrNotFound if there is no picture at the specified
1.2028 +// document position.
1.2029 +//
1.2030 + {
1.2031 + __TEST_INVARIANT;
1.2032 +
1.2033 + CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed));
1.2034 + TCurrentIndexRecords current;
1.2035 + GetCurrentRecords(current);
1.2036 +
1.2037 + return (current.iPhrase)
1.2038 + ? current.iPhrase->GetPictureSizeInTwips(aSize)
1.2039 + : KErrNotFound;
1.2040 + }
1.2041 +
1.2042 +TPictureHeader* CRichTextIndex::PictureHeaderPtr(TInt aPos)
1.2043 + {
1.2044 + __TEST_INVARIANT;
1.2045 +
1.2046 + CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute);
1.2047 + TCurrentIndexRecords current;
1.2048 + GetCurrentRecords(current);
1.2049 + return current.iPhrase? current.iPhrase->PictureHeaderPtr() : 0;
1.2050 + }
1.2051 +
1.2052 +TPictureHeader CRichTextIndex::PictureHeader(TInt aPos) const
1.2053 +// Return the picture header describing the picture at character position aPos.
1.2054 +// If there is no picture at character position aPos, a default picture header is returned.
1.2055 +//
1.2056 + {
1.2057 + const TPictureHeader* p = const_cast<CRichTextIndex*>(this)->PictureHeaderPtr(aPos);
1.2058 + return p? *p : TPictureHeader();
1.2059 + }
1.2060 +
1.2061 +
1.2062 +CPicture* CRichTextIndex::PictureHandleL(TInt aPos,MLayDoc::TForcePictureLoad aForceLoad)const
1.2063 +// Returns the handle of the concrete picture at character position aPos, if one exists;
1.2064 +// otherwise returns NULL.
1.2065 +//
1.2066 + {
1.2067 + __TEST_INVARIANT;
1.2068 +
1.2069 + CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed));
1.2070 + TCurrentIndexRecords current;
1.2071 + GetCurrentRecords(current);
1.2072 + return (current.iPhrase)
1.2073 + ? (CPicture*)current.iPhrase->PictureHandleL(iText.PictureFactory(),iText.StoreResolver(),aPos,aForceLoad)
1.2074 + : NULL;
1.2075 + }
1.2076 +
1.2077 +
1.2078 +void CRichTextIndex::GetParaFormatL(CParaFormat* aFormat,TParaFormatMask& aVaries,TInt aPos,TInt aLength,CParaFormat::TParaFormatGetMode aMode)const
1.2079 +// Senses the paragraph format of para(s) covered by the region aPos to aPos+aLength-1.
1.2080 +// aFormat takes the values of all attributes, and the mask aMask indicates those values that change
1.2081 +// over the selected region, and are therefore *indeterminate*.
1.2082 +// Application: seeding paragraph formatting dialogs.
1.2083 +//
1.2084 + {
1.2085 + __TEST_INVARIANT;
1.2086 +
1.2087 + TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos);
1.2088 + TInt offset=(aLength==0)?0 :-1;
1.2089 + TInt endPara=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos+(aLength+offset));
1.2090 + aVaries.ClearAll();
1.2091 + (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(aFormat,aMode); // Sense 1st paras' format.
1.2092 + ++para;
1.2093 + CParaFormat* format=CParaFormat::NewLC();
1.2094 + for (;para<=endPara;para++)
1.2095 + {
1.2096 + (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(format,aMode);
1.2097 + if (format->iLanguage!=aFormat->iLanguage)
1.2098 + aVaries.SetAttrib(EAttParaLanguage);
1.2099 + if (format->iFillColor!=aFormat->iFillColor)
1.2100 + aVaries.SetAttrib(EAttFillColor);
1.2101 + if (format->iLeftMarginInTwips!=aFormat->iLeftMarginInTwips)
1.2102 + aVaries.SetAttrib(EAttLeftMargin);
1.2103 + if (format->iRightMarginInTwips!=aFormat->iRightMarginInTwips)
1.2104 + aVaries.SetAttrib(EAttRightMargin);
1.2105 + if (format->iIndentInTwips!=aFormat->iIndentInTwips)
1.2106 + aVaries.SetAttrib(EAttIndent);
1.2107 + if (format->iHorizontalAlignment!=aFormat->iHorizontalAlignment)
1.2108 + aVaries.SetAttrib(EAttAlignment);
1.2109 + if (format->iVerticalAlignment!=aFormat->iVerticalAlignment)
1.2110 + aVaries.SetAttrib(EAttVerticalAlignment);
1.2111 + if (format->iLineSpacingInTwips!=aFormat->iLineSpacingInTwips)
1.2112 + aVaries.SetAttrib(EAttLineSpacing);
1.2113 + if (format->iLineSpacingControl!=aFormat->iLineSpacingControl)
1.2114 + aVaries.SetAttrib(EAttLineSpacingControl);
1.2115 + if (format->iSpaceBeforeInTwips!=aFormat->iSpaceBeforeInTwips)
1.2116 + aVaries.SetAttrib(EAttSpaceBefore);
1.2117 + if (format->iSpaceAfterInTwips!=aFormat->iSpaceAfterInTwips)
1.2118 + aVaries.SetAttrib(EAttSpaceAfter);
1.2119 + if (format->iKeepTogether!=aFormat->iKeepTogether)
1.2120 + aVaries.SetAttrib(EAttKeepTogether);
1.2121 + if (format->iKeepWithNext!=aFormat->iKeepWithNext)
1.2122 + aVaries.SetAttrib(EAttKeepWithNext);
1.2123 + if (format->iWidowOrphan!=aFormat->iWidowOrphan)
1.2124 + aVaries.SetAttrib(EAttWidowOrphan);
1.2125 + if (format->iWrap!=aFormat->iWrap)
1.2126 + aVaries.SetAttrib(EAttWrap);
1.2127 + if (format->iBorderMarginInTwips!=aFormat->iBorderMarginInTwips)
1.2128 + aVaries.SetAttrib(EAttBorderMargin);
1.2129 + if (format->iDefaultTabWidthInTwips!=aFormat->iDefaultTabWidthInTwips)
1.2130 + aVaries.SetAttrib(EAttDefaultTabWidth);
1.2131 + if (aMode==CParaFormat::EAllAttributes)
1.2132 + {
1.2133 + // Borders
1.2134 + for (TInt border=0;border<CParaFormat::EMaxParaBorder;border++)
1.2135 + {// Check each para border individually. Assumes border format attributes run consecutively.
1.2136 + if (!format->IsBorderEqual((CParaFormat::TParaBorderSide)border,*aFormat))
1.2137 + aVaries.SetAttrib((TTextFormatAttribute)(EAttTopBorder+border));
1.2138 + }
1.2139 + // Bullet
1.2140 + if (!format->iBullet && !aFormat->iBullet)
1.2141 + { /* neither para has bullet, so no variation */ }
1.2142 + else if (!format->iBullet || !aFormat->iBullet
1.2143 + || *format->iBullet!=*aFormat->iBullet)
1.2144 + aVaries.SetAttrib(EAttBullet);
1.2145 + // The Tab-List
1.2146 + if (format->TabCount()!=aFormat->TabCount())
1.2147 + aVaries.SetAttrib(EAttTabStop); // TabLists are different.
1.2148 + else
1.2149 + {// The 2 tablists have the same number of tab stops - but are not necessarily the same.
1.2150 + TBool matched=ETrue;
1.2151 + TInt tabCount=format->TabCount();
1.2152 + for (TInt tabItem=0;tabItem<tabCount;tabItem++)
1.2153 + {// Compare the 2 tabs.
1.2154 + TTabStop comp1,comp2;
1.2155 + comp1=format->TabStop(tabItem);
1.2156 + comp2=aFormat->TabStop(tabItem);
1.2157 + if (comp1!=comp2)
1.2158 + matched=EFalse;
1.2159 + }
1.2160 + if (!matched)
1.2161 + aVaries.SetAttrib(EAttTabStop);
1.2162 + }
1.2163 + }
1.2164 + }
1.2165 + CleanupStack::PopAndDestroy();
1.2166 + }
1.2167 +
1.2168 +
1.2169 +// Compare all attributes in two formats and where they differ set the appropriate flag in the aVaries mask.
1.2170 +void CRichTextIndex::CheckForUndetermined(const TCharFormatX& aFormatA,const TCharFormatX& aFormatB,
1.2171 + TCharFormatXMask& aVaries) const
1.2172 + {
1.2173 + const TCharFormat& a = aFormatA.iCharFormat;
1.2174 + const TCharFormat& b = aFormatB.iCharFormat;
1.2175 + if (a.iLanguage!=b.iLanguage)
1.2176 + aVaries.SetAttrib(EAttCharLanguage);
1.2177 + if (a.iFontPresentation.iTextColor!=b.iFontPresentation.iTextColor)
1.2178 + aVaries.SetAttrib(EAttColor);
1.2179 + if (a.iFontPresentation.iHighlightColor!=b.iFontPresentation.iHighlightColor)
1.2180 + aVaries.SetAttrib(EAttFontHighlightColor);
1.2181 + if (a.iFontPresentation.iHighlightStyle!=b.iFontPresentation.iHighlightStyle)
1.2182 + aVaries.SetAttrib(EAttFontHighlightStyle);
1.2183 + if (a.iFontPresentation.iStrikethrough!=b.iFontPresentation.iStrikethrough)
1.2184 + aVaries.SetAttrib(EAttFontStrikethrough);
1.2185 + if (a.iFontPresentation.iUnderline!=b.iFontPresentation.iUnderline)
1.2186 + aVaries.SetAttrib(EAttFontUnderline);
1.2187 + if (a.iFontPresentation.iHiddenText!=b.iFontPresentation.iHiddenText)
1.2188 + aVaries.SetAttrib(EAttFontHiddenText);
1.2189 + if (a.iFontPresentation.iPictureAlignment!=b.iFontPresentation.iPictureAlignment)
1.2190 + aVaries.SetAttrib(EAttFontPictureAlignment);
1.2191 + if (a.iFontSpec.iHeight!=b.iFontSpec.iHeight)
1.2192 + aVaries.SetAttrib(EAttFontHeight);
1.2193 + if (!(a.iFontSpec.iTypeface==b.iFontSpec.iTypeface))
1.2194 + aVaries.SetAttrib(EAttFontTypeface);
1.2195 + if (a.iFontSpec.iFontStyle.Posture()!=b.iFontSpec.iFontStyle.Posture())
1.2196 + aVaries.SetAttrib(EAttFontPosture);
1.2197 + if (a.iFontSpec.iFontStyle.StrokeWeight()!=b.iFontSpec.iFontStyle.StrokeWeight())
1.2198 + aVaries.SetAttrib(EAttFontStrokeWeight);
1.2199 + if (a.iFontSpec.iFontStyle.PrintPosition()!=b.iFontSpec.iFontStyle.PrintPosition())
1.2200 + aVaries.SetAttrib(EAttFontPrintPos);
1.2201 + if (aFormatA.iParserTag != aFormatB.iParserTag)
1.2202 + aVaries.SetAttrib(EAttParserTag);
1.2203 + }
1.2204 +
1.2205 +
1.2206 +void CRichTextIndex::GetCharFormat(TCharFormatX& aFormat,TCharFormatXMask& aVaries,TInt aPos,TInt aLength)const
1.2207 +// Senses the character formatting of the phrase(s) covered by the region aPos to aPos+aLength-1.
1.2208 +// aFormat takes the values of all character format attributes, and the mask aMask indicates those
1.2209 +// values that change over the selected region, and are therefore *indeterminate*.
1.2210 +// Application: seeding character formatting dialogs.
1.2211 +// If aLength is zero, the character format sensed is that of the charcter immediatley to the left (behind) the cursor.
1.2212 +//
1.2213 + {
1.2214 + __TEST_INVARIANT;
1.2215 +
1.2216 + aVaries.ClearAll();
1.2217 + if (aLength==0) // Get the format of the character to the left of the cursor.
1.2218 + ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionMatchLeft);
1.2219 + else
1.2220 + ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute);
1.2221 + // Get char format of first phrase
1.2222 + TCurrentIndexRecords current;
1.2223 + GetCurrentRecords(current);
1.2224 + if (current.iPhrase)
1.2225 + current.iPhrase->CharFormat()->SenseEffective(aFormat);
1.2226 + else
1.2227 + current.iParaAttribs->iCharFormat->SenseEffective(aFormat);
1.2228 + // Place pos at start of next phrase
1.2229 + TInt pos=aPos+(CurrentPhraseLength()-CurrentPhraseOffset());
1.2230 + while (pos<=aPos+aLength-1)
1.2231 + {// Get the format of the next phrase and check if attributes change value
1.2232 + ((CRichTextIndex*)this)->ScanToPosition(pos,EScanToPositionAbsolute);
1.2233 + GetCurrentRecords(current);
1.2234 + TCharFormatX format;
1.2235 + if (current.iPhrase)
1.2236 + current.iPhrase->CharFormat()->SenseEffective(format);
1.2237 + else
1.2238 + current.iParaAttribs->iCharFormat->SenseEffective(format);
1.2239 + CheckForUndetermined(format,aFormat,aVaries);
1.2240 + pos+=CurrentPhraseLength();
1.2241 + }
1.2242 + }
1.2243 +
1.2244 +
1.2245 +void CRichTextIndex::GetSpecificCharFormatDirection(TCharFormatX& aFormat,
1.2246 + TCharFormatXMask& aMask,
1.2247 + TInt aPos,
1.2248 + TBool aGetLeft) const
1.2249 + {
1.2250 + __TEST_INVARIANT;
1.2251 +
1.2252 + aMask.ClearAll();
1.2253 + ((CRichTextIndex*)this)->ScanToPosition(aPos,
1.2254 + aGetLeft? EScanToPositionMatchLeft : EScanToPositionAbsolute);
1.2255 + TCurrentIndexRecords current;
1.2256 + GetCurrentRecords(current);
1.2257 + if (current.iPhrase)
1.2258 + current.iPhrase->CharFormat()->Sense(aFormat,aMask);
1.2259 + else
1.2260 + current.iParaAttribs->iCharFormat->Sense(aFormat,aMask);
1.2261 + }
1.2262 +
1.2263 +void CRichTextIndex::GetSpecificCharFormat(TCharFormatX& aFormat,TCharFormatXMask& aMask,TInt aPos)const
1.2264 +// Return the format attributes store in the specific layer only, for the specified document position.
1.2265 +// THIS IS NOT THE EFFECTIVE FORMAT, BUT THE SPECIFIC FORMATTING ONLY.
1.2266 +//
1.2267 + {
1.2268 + GetSpecificCharFormatDirection(aFormat, aMask, aPos, ETrue);
1.2269 + }
1.2270 +
1.2271 +
1.2272 +CParaAttribs* CRichTextIndex::RequestReclaimShareL(CParaAttribs* aParaAttribs,TParaAttribsEntry* aParaEntry)
1.2273 +// If the specified para attribs is currently on the shared list, then
1.2274 +// a specific para attribs is *reclaimed* and returned.
1.2275 +// The current share on the CParaAttribs is not *Released*.
1.2276 +// A new CParaAttribs is created of the same paragraph format as the shared one,
1.2277 +// but with a reference count of zero, (as this now has specific character formatting),
1.2278 +// and 1 phrase that is of the same character format as the shared one.
1.2279 +// The reclaimed specific para attribs is attactched to the specified para entry.
1.2280 +// NOTE:
1.2281 +// If the specified CParaAttribs is not currently on the shared list, NULL
1.2282 +// is returned, and aParaAttribs left unchanged..
1.2283 +// Assumes a previous call to ScanToPosition has correctly set the internal position record.
1.2284 +// This function can be called safely in any situation. (Except that it may *LEAVE*).
1.2285 +//
1.2286 + {
1.2287 + if (!(aParaAttribs->IsShared()))
1.2288 + return NULL; // This para attribs is not currently shared.
1.2289 + // We are dealing with a shared paraAttribs from now on.
1.2290 + CParaAttribs* reclaimedPara=CParaAttribs::NewL(aParaAttribs->iParaFormat); // Create the re-claimed paraAttribs.
1.2291 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimedPara));
1.2292 + CCharFormatLayer* newFormat=CCharFormatLayer::NewCopyBaseL(aParaAttribs->iCharFormat);
1.2293 + CleanupStack::PushL(newFormat);
1.2294 + RPhraseAttribsEntry phrase(newFormat,aParaEntry->iLength);
1.2295 + // Now insert this phrase into the index.
1.2296 + iPhraseIx->InsertL(iPos.iPhraseElement,phrase);
1.2297 + CleanupStack::Pop(2); // newFormat, reclaimedPara
1.2298 + return reclaimedPara;
1.2299 + }
1.2300 +
1.2301 +
1.2302 +CParaAttribs* CRichTextIndex::RequestShareL(CParaAttribs* aParaAttribs,CCharFormatLayer* aCharFormat,CParaAttribs* aReservedCell)
1.2303 +// Attempts to re-use an existing paraAttribs that matches the one specified.
1.2304 +// Returns the handle of a CParaAttribs, or NULL if the specified argument cannot
1.2305 +// be shared.
1.2306 +// aCharFormat may be NULL, as may aReservedCell.
1.2307 +//
1.2308 + {
1.2309 + if (aParaAttribs->iRefCount<=0 && aParaAttribs->iPhraseCount>1)
1.2310 + return NULL; // This para has specific character formatting & multiple phrases and so cannot be shared.
1.2311 + // This para has constant character formatting - can be shared.
1.2312 + CCharFormatLayer* charFormat;
1.2313 + if (aCharFormat)
1.2314 + charFormat=aCharFormat; // Has a phrase index.
1.2315 + else
1.2316 + charFormat=aParaAttribs->iCharFormat; // Has constant char formatting.
1.2317 + return GetParaAttribsL(aParaAttribs->iParaFormat,charFormat,aReservedCell);
1.2318 + }
1.2319 +
1.2320 +
1.2321 +CParaAttribs* CRichTextIndex::RequestShare(const TLogicalPosition& aLogicalPosition)
1.2322 +// Returns a handle to a paraAttribs on the shared list that matches the paragraph at the
1.2323 +// specified position. Returns NULL if the specified paragraph does not have constant
1.2324 +// character formatting.
1.2325 +//
1.2326 + {
1.2327 + CParaAttribs* paraAttribs=(*iParaIx)[aLogicalPosition.iParaElement].iParaAttribs;
1.2328 + if (paraAttribs->iRefCount<=0 && paraAttribs->iPhraseCount>1)
1.2329 + return NULL; // This para has specific character formatting and so cannot be shared.
1.2330 + // This para has constant character formatting - can be shared.
1.2331 + return GetParaAttribs(aLogicalPosition);
1.2332 + }
1.2333 +
1.2334 +
1.2335 +CParaAttribs* CRichTextIndex::GetParaAttribsL(const CParaFormatLayer* aParaFormat,const CCharFormatLayer* aCharFormat,
1.2336 + CParaAttribs* aReservedCell)
1.2337 +// Attempts to match the specified arguments to a CParaAttribs in the shared list.
1.2338 +// If matched, the handle of the matched para attribs is returned, and the reference count
1.2339 +// of that item is incremented.
1.2340 +//
1.2341 +// aReservedCell is a pre-allocated CParaAttribs that has been correctly setup. If no match
1.2342 +// is found, and the reserved cell is specified, this is used in preference to creating a new one.
1.2343 +// If the reserved cell is not specified and there is no match, a new CParaAttribs of the correct
1.2344 +// specification is created and added to the shared list.
1.2345 +//
1.2346 + {
1.2347 + CParaAttribs* handle=FindSharedParaAttribs(*aParaFormat,*aCharFormat);
1.2348 + if (handle)
1.2349 + return handle; // match found already in the shared list.
1.2350 +// There is no match, so create new sharedPara and add to list.
1.2351 + if (!aReservedCell)
1.2352 + aReservedCell=CParaAttribs::NewL(aParaFormat,aCharFormat); // Reusing aReservedCell saves an automatic.
1.2353 + iSharedParaQueHead.AddLast(*aReservedCell);
1.2354 + return aReservedCell;
1.2355 + }
1.2356 +
1.2357 +
1.2358 +CParaAttribs* CRichTextIndex::GetParaAttribs(CParaAttribs* aParaAttribs,CCharFormatLayer& aCharFormatLayer)
1.2359 +// Called by Reset.
1.2360 +//
1.2361 + {
1.2362 + CParaAttribs* handle=FindSharedParaAttribs(*aParaAttribs->iParaFormat,aCharFormatLayer);
1.2363 + if (handle)
1.2364 + return handle;
1.2365 + else
1.2366 + {// No match, so piece together new shared paraAttribs and add to shared para list.
1.2367 + aParaAttribs->iRefCount=1;
1.2368 + aParaAttribs->iCharFormat=&aCharFormatLayer;
1.2369 + iSharedParaQueHead.AddLast(*aParaAttribs);
1.2370 + return aParaAttribs;
1.2371 + }
1.2372 + }
1.2373 +
1.2374 +
1.2375 +CParaAttribs* CRichTextIndex::GetParaAttribs(const TLogicalPosition& aLogicalPosition)
1.2376 +// Attempts to match the specified arguments to a CParaAttribs in the shared list.
1.2377 +// If matched, the handle of the matched para attribs is returned, and the reference count
1.2378 +// of that item is incremented. If no match is found, the current para attribs is
1.2379 +// transformed into one that is placed in the shared list.
1.2380 +//
1.2381 + {
1.2382 + CParaAttribs* sourceParaAttribs=(*iParaIx)[aLogicalPosition.iParaElement].iParaAttribs;
1.2383 + RPhraseAttribsEntry* sourcePhrase=&(*iPhraseIx)[aLogicalPosition.iPhraseElement];
1.2384 + //
1.2385 + CParaAttribs* handle=FindSharedParaAttribs(*sourceParaAttribs->iParaFormat,*sourcePhrase->CharFormat());
1.2386 + if (handle)
1.2387 + return handle;
1.2388 + else
1.2389 + {// No match, so piece together new shared paraAttribs and add to shared para list
1.2390 + sourceParaAttribs->iRefCount=1;
1.2391 + if (sourcePhrase->IsPicturePhrase())
1.2392 + {
1.2393 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_GETPARAATTRIBS, "EReleasCharFormatLayerOwnershipCalledOnPicturePhrase" );
1.2394 + }
1.2395 + __ASSERT_ALWAYS(!sourcePhrase->IsPicturePhrase(),Panic(EReleasCharFormatLayerOwnershipCalledOnPicturePhrase));
1.2396 + sourceParaAttribs->iCharFormat=sourcePhrase->ReleaseCharFormatLayerOwnership();
1.2397 + sourcePhrase->Discard();
1.2398 + iPhraseIx->Delete(aLogicalPosition.iPhraseElement); // remove the deleted phrase from the phrase index.
1.2399 + iSharedParaQueHead.AddLast(*sourceParaAttribs);
1.2400 + return sourceParaAttribs;
1.2401 + }
1.2402 + }
1.2403 +
1.2404 +
1.2405 +CParaAttribs* CRichTextIndex::FindSharedParaAttribs(const CParaFormatLayer& aParaFormatLayer,const CCharFormatLayer& aCharFormatLayer)
1.2406 +// Attempts to match the specified arguments to an item in the shared para list.
1.2407 +// If found, the handle of the matched para attribs is returned, and the reference count
1.2408 +// of that item is incremented.
1.2409 +// If no match is made NULL is returned.
1.2410 +//
1.2411 + {
1.2412 + CParaAttribs* currentSharedPara=NULL;
1.2413 + TBool matched=EFalse;
1.2414 + if (!iSharedParaQueHead.IsEmpty())
1.2415 + {
1.2416 + TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead);
1.2417 + while ((currentSharedPara=iterator++)!=NULL)
1.2418 + {// Try and match each item in the shared para list.
1.2419 + matched=aParaFormatLayer.IsIdentical(currentSharedPara->iParaFormat);
1.2420 + if (!matched)
1.2421 + continue;
1.2422 + matched=aCharFormatLayer.IsIdentical(currentSharedPara->iCharFormat);
1.2423 + if (!matched)
1.2424 + continue;
1.2425 + // We have a match, so adjust reference count.
1.2426 + currentSharedPara->iRefCount++;
1.2427 + return currentSharedPara;
1.2428 + }
1.2429 + }
1.2430 + return currentSharedPara;
1.2431 + }
1.2432 +
1.2433 +
1.2434 +void CRichTextIndex::ScanToPosition(TInt aCharPos,TScanToPositionMode aMode,TLogicalPosition* aLastUsed/*=NULL*/)
1.2435 +// Move the internal position record to that indicated by the specified character position, aCharPos.
1.2436 +// Behaviour follows:
1.2437 +// aCharPos is considered to be goverened by the phrase covering aCharPos-1,
1.2438 +// except when aCharPos is the fist character of a paragraph, when
1.2439 +// aCharPos is goverened by the phrase coverng aCharPos.
1.2440 +// (If nothing else, aCharPos will be a paragraph delimiter or the end-of-document
1.2441 +// character.
1.2442 +// The implementation below matches to the right as standard, then checks if a left
1.2443 +// phrase match is available.
1.2444 +//
1.2445 + {
1.2446 + if (!aLastUsed || aLastUsed->iDocPos-aLastUsed->iParaElementOffset>aCharPos)
1.2447 + iPos.Clear(); // Reset the internal position record.
1.2448 + else
1.2449 + {
1.2450 + iPos=*aLastUsed;
1.2451 + if (iPos.iDocPos>aCharPos || (aMode==EScanToPositionMatchLeft && iPos.iDocPos==aCharPos))
1.2452 + {// reset to the start of paragraph if aPos < cache pos or aPos==chache Pos whilst matching left
1.2453 + iPos.iDocPos-=iPos.iParaElementOffset;
1.2454 + iPos.iParaElementOffset=iPos.iPhraseElementOffset=0;
1.2455 + iPos.iPhraseElement=iPos.iParaBasePhraseElement;
1.2456 + }
1.2457 + }
1.2458 +
1.2459 + TInt phraseElement=iPos.iPhraseElement;
1.2460 + TInt startOfPara=iPos.iDocPos-iPos.iParaElementOffset;
1.2461 + TInt paraElement=iPos.iParaElement;
1.2462 + const CArrayFix<TParaAttribsEntry>& paraIx=*iParaIx;
1.2463 + const TParaAttribsEntry* para=¶Ix[paraElement];
1.2464 + TInt len=para->iLength;
1.2465 + if (aCharPos>=(startOfPara+len))
1.2466 + {
1.2467 + iPos.iParaElementOffset=iPos.iPhraseElementOffset=0;
1.2468 + phraseElement=iPos.iParaBasePhraseElement;
1.2469 + const TParaAttribsEntry* end=paraIx.End(paraElement);
1.2470 + do
1.2471 + {// Find the paragraph...
1.2472 + startOfPara+=len;
1.2473 + if (!(para->iParaAttribs->IsShared())) // Adjust position within phrase index
1.2474 + phraseElement+=para->iParaAttribs->iPhraseCount;
1.2475 + ++paraElement;
1.2476 + if (++para==end)
1.2477 + {
1.2478 + para=¶Ix[paraElement];
1.2479 + end=paraIx.End(paraElement);
1.2480 + }
1.2481 + len=para->iLength;
1.2482 + }
1.2483 + while (aCharPos>=(startOfPara+len) && (paraElement+1) < paraIx.Count());
1.2484 + iPos.iParaBasePhraseElement=phraseElement;
1.2485 + iPos.iParaElement=paraElement;
1.2486 + }
1.2487 + TInt startOfPhrase=iPos.iParaElementOffset-iPos.iPhraseElementOffset;
1.2488 +// the offset within the paragraph.
1.2489 + TInt paraElementOffset=aCharPos-startOfPara;
1.2490 + iPos.iParaElementOffset=paraElementOffset;
1.2491 +
1.2492 + if (!(para->iParaAttribs->IsShared()))
1.2493 + {// Find phrase & offset within it.
1.2494 + TInt lastPhraseLength=-1; // Record phrase length in case left match required.
1.2495 + const CArrayFix<RPhraseAttribsEntry>& phraseIx=*iPhraseIx;
1.2496 + const RPhraseAttribsEntry* phrase=&phraseIx[phraseElement];
1.2497 + const RPhraseAttribsEntry* end=NULL;
1.2498 + for (;;)
1.2499 + { // Find the phrase in the paragraph...
1.2500 + len=phrase->Length();
1.2501 + if (paraElementOffset<(startOfPhrase+len))
1.2502 + break;
1.2503 + startOfPhrase+=len;
1.2504 + lastPhraseLength=len;
1.2505 + if (end==NULL)
1.2506 + end=phraseIx.End(phraseElement);
1.2507 + phraseElement++;
1.2508 + if (++phrase<end)
1.2509 + continue;
1.2510 + phrase=&phraseIx[phraseElement];
1.2511 + end=phraseIx.End(phraseElement);
1.2512 + }//...and the offset within this.
1.2513 + // Check now for match left.
1.2514 + if ((aMode==EScanToPositionMatchLeft) && lastPhraseLength>=0 && paraElementOffset==startOfPhrase)
1.2515 + {// Match to the left most phrase if at the start of a phrase.
1.2516 + phraseElement--;
1.2517 + iPos.iPhraseElementOffset=lastPhraseLength;
1.2518 + }
1.2519 + else
1.2520 + iPos.iPhraseElementOffset=paraElementOffset-startOfPhrase;
1.2521 + }
1.2522 + else
1.2523 + {
1.2524 + if (iPos.iParaBasePhraseElement!=phraseElement)
1.2525 + {
1.2526 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_SCANTOPOSITION, "EDebug" );
1.2527 + }
1.2528 + __ASSERT_DEBUG(iPos.iParaBasePhraseElement==phraseElement,Panic(EDebug));
1.2529 + }
1.2530 + iPos.iPhraseElement=phraseElement;
1.2531 + iPos.iDocPos=aCharPos;
1.2532 + if (aLastUsed)
1.2533 + *aLastUsed=iPos;
1.2534 + }
1.2535 +
1.2536 +
1.2537 +TBool CRichTextIndex::FirstPhraseOfParagraph()const
1.2538 +// Interogates the current internal position record.
1.2539 +// Return ETrue if the current phrase element is the first phrase
1.2540 +// of specific character format in the current paragraph;
1.2541 +// Otherwise return EFalse.
1.2542 +//
1.2543 + {return iPos.iPhraseElement==iPos.iParaBasePhraseElement;}
1.2544 +
1.2545 +
1.2546 +TInt CRichTextIndex::CurrentPhraseLength()const
1.2547 +// Return the length of the current phrase, where the current
1.2548 +// phrase is specified by the state of the internal position record.
1.2549 +//
1.2550 + {
1.2551 + if ((*iParaIx)[iPos.iParaElement].iParaAttribs->IsShared())
1.2552 + return (*iParaIx)[iPos.iParaElement].iLength;
1.2553 + else
1.2554 + return (*iPhraseIx)[iPos.iPhraseElement].Length();
1.2555 + }
1.2556 +
1.2557 +
1.2558 +TInt CRichTextIndex::CurrentPhraseOffset()const
1.2559 +// Returns the offset within the current phrase, where the current
1.2560 +// phrase is specified by the state of the internal position record.
1.2561 +//
1.2562 + {
1.2563 + if ((*iParaIx)[iPos.iParaElement].iParaAttribs->IsShared())
1.2564 + return iPos.iParaElementOffset; // only 1 phrase in para.
1.2565 + else
1.2566 + return iPos.iPhraseElementOffset;
1.2567 + }
1.2568 +
1.2569 +
1.2570 +void CRichTextIndex::GetCurrentRecords(TCurrentIndexRecords& aRecord)const
1.2571 +// Package the phrase and paragraph index records that apply to the
1.2572 +// current paragraph and return this package. It is assumed that
1.2573 +// the caller has already set the internal position record to a valid state.
1.2574 +//
1.2575 + {
1.2576 + aRecord.iParaEntry=&(*iParaIx)[iPos.iParaElement];
1.2577 + aRecord.iParaAttribs=aRecord.iParaEntry->iParaAttribs;
1.2578 + if (aRecord.iParaAttribs->IsShared())
1.2579 + aRecord.iPhrase=NULL;
1.2580 + else
1.2581 + aRecord.iPhrase=&((*iPhraseIx)[iPos.iPhraseElement]);
1.2582 + }
1.2583 +
1.2584 +
1.2585 +void CRichTextIndex::GetPhraseFormat(TCurrentIndexRecords& aCurrent,TCharFormatX& aFormat,TCharFormatXMask& aMask,
1.2586 + CCharFormatLayer*& aCharBase)const
1.2587 +// Fills aFormat and aMask with the character formatting information of the current record.
1.2588 +// aCharBase is set to the basedOn link if present.
1.2589 +// Encapsulates the concepts of the specific phrase index, and the constant character format.
1.2590 +// Only senses the format in the layer, does *NOT* perform a SenseEffective.
1.2591 +//
1.2592 + {
1.2593 + CCharFormatLayer* charFormatLayer=NULL;
1.2594 + if (aCurrent.iPhrase)
1.2595 + {// Specific character formatting held by phrase index.
1.2596 + charFormatLayer=aCurrent.iPhrase->CharFormat();
1.2597 + }
1.2598 + else
1.2599 + {// Constant character formatting held in the para attribs
1.2600 + charFormatLayer=aCurrent.iParaAttribs->iCharFormat;
1.2601 + }
1.2602 + charFormatLayer->Sense(aFormat,aMask);
1.2603 + aCharBase=(CCharFormatLayer*)(charFormatLayer->SenseBase());
1.2604 + }
1.2605 +
1.2606 +
1.2607 +TInt CRichTextIndex::OwningParagraph(TInt aPos,TLogicalPosition* aLastUsed/*=NULL*/)const
1.2608 +// Return the paragraph element number that contains character position aPos.
1.2609 +// Assumes the caller has validated aPos. Alters the internal record position.
1.2610 +//
1.2611 + {
1.2612 + ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionMatchLeft,aLastUsed);
1.2613 + return iPos.iParaElement;
1.2614 + }
1.2615 +
1.2616 +
1.2617 +void CRichTextIndex::SplitPhraseL(TInt aSplitPos)
1.2618 +// Splits the phrase at the offset aSplitPos, creating a new phrase
1.2619 +// which is filled with the split part of the current phrase, includig aSplitPos.
1.2620 +// The character format applied to the new phrase is the format of the phrase from which it has been split.
1.2621 +// The resulting new phrase is inserted into the phrase index immediately following the
1.2622 +// current element. If aSplitPos is already at a phrase boundary, then no split is performed.
1.2623 +// (This means that a picture phrase in effect can never be split).
1.2624 +//
1.2625 + {
1.2626 + SetPhraseSplit(EFalse);
1.2627 + ScanToPosition(aSplitPos,EScanToPositionAbsolute);
1.2628 + if (iPos.iPhraseElementOffset==0)
1.2629 + return; // aSplitPos on a phrase boundary; urgo no split.
1.2630 + TCurrentIndexRecords current; GetCurrentRecords(current);
1.2631 +// ASSERT: This function set can only be called on CParaAttribs that specific char format.
1.2632 + if (current.iPhrase==NULL)
1.2633 + {
1.2634 + OstTrace0( TRACE_FATAL, DUP1_CRICHTEXTINDEX_SPLITPHRASEL, "ESplitPhraseCalledOnSharedPara" );
1.2635 + }
1.2636 + __ASSERT_ALWAYS(current.iPhrase!=NULL,Panic(ESplitPhraseCalledOnSharedPara));
1.2637 + DoSplitPhraseL(*current.iPhrase,iPos.iPhraseElementOffset,current.iParaAttribs);
1.2638 + }
1.2639 +
1.2640 +
1.2641 +void CRichTextIndex::SplitPhraseL(TInt aPhraseElement,TInt aPhraseOffset,CParaAttribs* aParaAttribs)
1.2642 +// Splits the specified phrase at the offset aOffsetInPhrase, creating a new phrase
1.2643 +// which is filled with the split part of the current phrase, includig the split pos.
1.2644 +// The character format applied to the new phrase is the format of the phrase from which it has been split.
1.2645 +// The resulting new phrase is inserted into the phrase index immediately following the
1.2646 +// current element. If the split pos is already at a phrase boundary, then no split is performed.
1.2647 +// (This means that a picture phrase in effect can never be split).
1.2648 +//
1.2649 + {
1.2650 + SetPhraseSplit(EFalse);
1.2651 + RPhraseAttribsEntry& phrase=(*iPhraseIx)[aPhraseElement];
1.2652 + if ((aPhraseOffset>0) && (aPhraseOffset<phrase.Length()))
1.2653 + {// Not at a phrase boundary so split the current phrase.
1.2654 + DoSplitPhraseL(phrase,aPhraseOffset,aParaAttribs);
1.2655 + }
1.2656 + }
1.2657 +
1.2658 +
1.2659 +void CRichTextIndex::DoSplitPhraseL(RPhraseAttribsEntry& aCurrentPhrase,TInt aPhraseOffset,CParaAttribs* aParaAttribs)
1.2660 +// Splits the specified phrase, creating a new phrase of the same character format.
1.2661 +// This new phrase is inserted into the phrase index immediately following the current one.
1.2662 +//
1.2663 + {
1.2664 +// ASSERT: Cannot split a picture phrase.
1.2665 + if (aCurrentPhrase.IsPicturePhrase())
1.2666 + {
1.2667 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_DOSPLITPHRASEL, "ESplitPhraseCalledOnPicturePhrase" );
1.2668 + }
1.2669 + __ASSERT_DEBUG(!aCurrentPhrase.IsPicturePhrase(),Panic(ESplitPhraseCalledOnPicturePhrase));
1.2670 + CCharFormatLayer* layer=CCharFormatLayer::NewCopyBaseL(aCurrentPhrase.CharFormat());
1.2671 + CleanupStack::PushL(layer);
1.2672 + RPhraseAttribsEntry newPhrase(layer,aCurrentPhrase.Length()-aPhraseOffset);
1.2673 + iPhraseIx->InsertL(iPos.iPhraseElement+1,newPhrase);
1.2674 + CleanupStack::Pop();
1.2675 + //
1.2676 + // InsertL() has invalidated the current internal position record.
1.2677 + iPhraseIx->At(iPos.iPhraseElement).SetLength(aPhraseOffset);
1.2678 + SetPhraseSplit(ETrue);
1.2679 + aParaAttribs->iPhraseCount++;
1.2680 + }
1.2681 +
1.2682 +
1.2683 +TBool CRichTextIndex::HasMarkupData(const CFormatLayer* aGlobalParaFormatLayer)const
1.2684 +// Returns ETure if this rich text instance has any specific markup,
1.2685 +// otherwise returns EFalse.
1.2686 +// The presence of specific markup is indicated by the following...
1.2687 +// 1) Style list is present (if style table is owned by the rich text)
1.2688 +// 2) Any phrase index content
1.2689 +// 3) >1 shared para attribs
1.2690 +// or
1.2691 +// 3) 1 shared para attribs that has specific markup
1.2692 +// 4) any paragraph is based on a style other than normal (the global paraformatlayer)
1.2693 +//
1.2694 + {
1.2695 + TInt phraseCount=PhraseCount();
1.2696 + if (phraseCount>0)
1.2697 + return ETrue;
1.2698 + //
1.2699 + TInt sharedParaCount=SharedParaCount(this);
1.2700 + if (sharedParaCount<1 && (sharedParaCount!=0 || phraseCount<=0))
1.2701 + {
1.2702 + OstTrace0( TRACE_FATAL, CRICHTEXTINDEX_HASMARKUPDATA, "ERichTextIndexIntegrityErr" );
1.2703 + }
1.2704 + __ASSERT_ALWAYS(sharedParaCount>=1 || (sharedParaCount==0 && phraseCount>0),Panic(ERichTextIndexIntegrityErr));
1.2705 + if (sharedParaCount>1)
1.2706 + return ETrue;
1.2707 + const CParaAttribs* paraAttribs=iSharedParaQueHead.First();
1.2708 + if (!paraAttribs->iParaFormat->IsEmpty())
1.2709 + return ETrue;
1.2710 + if (!paraAttribs->iCharFormat->IsEmpty())
1.2711 + return ETrue;
1.2712 + if (paraAttribs->iParaFormat->SenseBase()!=aGlobalParaFormatLayer)
1.2713 + return ETrue;
1.2714 + return EFalse;
1.2715 + }
1.2716 +
1.2717 +
1.2718 +TInt CRichTextIndex::SharedParaCount(const CRichTextIndex* aSource)const
1.2719 +// Return a count of the number of shared paragraph formats present
1.2720 +// in the specified object.
1.2721 +//
1.2722 + {
1.2723 + TInt sharedParaCount = 0;
1.2724 + TDblQueIter<CParaAttribs> iterator( MUTABLE_CAST(TDblQue<CParaAttribs>&, aSource->iSharedParaQueHead) );
1.2725 + while ( iterator++ != NULL )
1.2726 + sharedParaCount++;
1.2727 + return sharedParaCount;
1.2728 + }
1.2729 +
1.2730 +
1.2731 +void CRichTextIndex::AppendTakingSolePictureOwnershipL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo)
1.2732 +// No paragraph style information is appended.
1.2733 +//
1.2734 + {
1.2735 + CancelInsertCharFormat();
1.2736 + CONST_CAST(CRichTextIndex*,aSource)->CancelInsertCharFormat();
1.2737 +
1.2738 + TInt origParaCount=ParagraphCount();
1.2739 + TInt origPhraseCount=iPhraseIx->Count();
1.2740 + TRAPD(ret,
1.2741 + AppendParaIndexL(aSource,aGlobalLayerInfo);
1.2742 + AppendPhraseIndexL(aSource,aGlobalLayerInfo);
1.2743 + );
1.2744 + if (ret!=KErrNone)
1.2745 + {
1.2746 + RemoveFromPhraseIx(origPhraseCount,iPhraseIx->Count()-origPhraseCount); // remove any added phrases etc.
1.2747 + RbRemoveInsertedParaAttribsEntries(origParaCount,ParagraphCount()-origParaCount); // remove any added paragraphs etc.
1.2748 + NormalizeSharedList(); // remove any added shared paragraph attributes
1.2749 + User::Leave(ret);
1.2750 + }
1.2751 +
1.2752 + __TEST_INVARIANT;
1.2753 + }
1.2754 +
1.2755 +
1.2756 +void CRichTextIndex::AppendParaIndexL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo)
1.2757 +//
1.2758 + {
1.2759 + CRichTextStoreMap<CParaAttribs>* map=CRichTextStoreMap<CParaAttribs>::NewLC(SharedParaCount(aSource));
1.2760 +
1.2761 + AppendSharedFormatsL(*map,aSource,aGlobalLayerInfo);
1.2762 +
1.2763 + // Extend para index by required amount
1.2764 + TInt originalParaCount=iParaIx->Count();
1.2765 + TInt requiredParaCount=aSource->iParaIx->Count();
1.2766 + iParaIx->AppendL(TParaAttribsEntry(),requiredParaCount);
1.2767 +
1.2768 + for (TInt ii=0;ii<requiredParaCount;ii++)
1.2769 + {// Copy the paragraph data for each of the appended paragraphs.
1.2770 + const TParaAttribsEntry& sParaEntry=(*aSource->iParaIx)[ii];
1.2771 + const CParaAttribs* sParaAttribs=sParaEntry.iParaAttribs;
1.2772 + CParaAttribs* tParaAttribs;
1.2773 + if (sParaAttribs->IsShared())
1.2774 + {
1.2775 + tParaAttribs=map->Item(sParaAttribs);
1.2776 + if (tParaAttribs==NULL)
1.2777 + {
1.2778 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_APPENDPARAINDEXL, "ESharedFormatsMapIntegrityError" );
1.2779 + }
1.2780 + __ASSERT_DEBUG(tParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError));
1.2781 + tParaAttribs->iRefCount++;
1.2782 + }
1.2783 + else
1.2784 + {// Have to build up the specific para attribs
1.2785 + tParaAttribs=CParaAttribs::NewL(sParaAttribs->iParaFormat); // sets iRefCount=0, copies the format layer
1.2786 + tParaAttribs->iParaFormat->SetBase(aGlobalLayerInfo.iAggParaFormatLayer);
1.2787 + tParaAttribs->iPhraseCount=sParaAttribs->iPhraseCount;
1.2788 + }
1.2789 + TParaAttribsEntry& tParaEntry=(*iParaIx)[originalParaCount+ii];
1.2790 + tParaEntry.iLength=sParaEntry.iLength;
1.2791 + tParaEntry.iParaAttribs=tParaAttribs;
1.2792 +
1.2793 + // tParaAttribs is attached to CRichTextIndex::iParaIx, and will be
1.2794 + // released in destructor CRichTextIndex::~CRichTextIndex().
1.2795 + // To prevent Coverity from reporting defect, add a comment:
1.2796 + // coverity[memory_leak]
1.2797 + }
1.2798 +
1.2799 + CleanupStack::PopAndDestroy(); // map
1.2800 + }
1.2801 +
1.2802 +
1.2803 +void CRichTextIndex::AppendSharedFormatsL(CParaAttribsMap& aMap,const CRichTextIndex* aSource,
1.2804 + const TGlobalLayerInfoAppend& aGlobalLayerInfo)
1.2805 +// A map is kept, that for each original format specifies the corresponding new one that appended
1.2806 +// paragraphs should use.
1.2807 +//
1.2808 + {
1.2809 + TDblQueIter<CParaAttribs> iterator(MUTABLE_CAST(TDblQue<CParaAttribs>&,aSource->iSharedParaQueHead));
1.2810 + CParaAttribs* currentSharedPara;
1.2811 + while ((currentSharedPara=iterator++)!=NULL)
1.2812 + {
1.2813 + if (!currentSharedPara->IsShared())
1.2814 + {
1.2815 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_APPENDSHAREDFORMATSL, "Invariant" );
1.2816 + }
1.2817 + __ASSERT_DEBUG(currentSharedPara->IsShared(),User::Invariant());
1.2818 +
1.2819 + CParaFormatLayer* sPl=currentSharedPara->iParaFormat;
1.2820 + CCharFormatLayer* sCl=currentSharedPara->iCharFormat;
1.2821 + sPl->SetBase(aGlobalLayerInfo.iAggParaFormatLayer); // alter the original so that the following GetParaAttribsL() call will
1.2822 + sCl->SetBase(aGlobalLayerInfo.iAggCharFormatLayer); // match based on our global format layers, not those of aSource's.
1.2823 + CParaAttribs* newParaAttribs=FindSharedParaAttribs(*sPl,*sCl);
1.2824 + sPl->SetBase(aGlobalLayerInfo.iComParaFormatLayer); // set the global format layers back again, cos we don't want to
1.2825 + sCl->SetBase(aGlobalLayerInfo.iComCharFormatLayer); // corrupt aSource.
1.2826 + if (newParaAttribs==NULL)
1.2827 + {
1.2828 + newParaAttribs=CParaAttribs::NewL(currentSharedPara);
1.2829 + // change the based-on links (they are copied in the construction)
1.2830 + newParaAttribs->iParaFormat->SetBase(aGlobalLayerInfo.iAggParaFormatLayer);
1.2831 + newParaAttribs->iCharFormat->SetBase(aGlobalLayerInfo.iAggCharFormatLayer);
1.2832 + iSharedParaQueHead.AddLast(*newParaAttribs);
1.2833 + }
1.2834 + newParaAttribs->iRefCount--; // we have not yet linked incoming para - taken out no shares just yet
1.2835 + aMap.Bind(currentSharedPara,newParaAttribs);
1.2836 + }
1.2837 + }
1.2838 +
1.2839 +void CRichTextIndex::AppendPhraseIndexL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo)
1.2840 +//
1.2841 + {
1.2842 + TInt originalPhraseCount=iPhraseIx->Count();
1.2843 + TInt requiredPhraseCount=aSource->iPhraseIx->Count();
1.2844 +
1.2845 + // Extend phrase index by required amount
1.2846 + iPhraseIx->AppendL(RPhraseAttribsEntry(),requiredPhraseCount);
1.2847 +
1.2848 + CArrayFixFlat<TInt>* pictureMap=new(ELeave) CArrayFixFlat<TInt>(16);
1.2849 + CleanupStack::PushL(pictureMap);
1.2850 +
1.2851 + for (TInt jj=0;jj<requiredPhraseCount;jj++)
1.2852 + {
1.2853 + RPhraseAttribsEntry& sPhrase=(*aSource->iPhraseIx)[jj];
1.2854 + CCharFormatLayer* sCharFormatLayer=sPhrase.CharFormat();
1.2855 + CCharFormatLayer* charLayer=CCharFormatLayer::NewL(sCharFormatLayer);
1.2856 + charLayer->SetBase(aGlobalLayerInfo.iAggCharFormatLayer);
1.2857 + RPhraseAttribsEntry& tPhrase=(*iPhraseIx)[jj+originalPhraseCount];
1.2858 + if (!sPhrase.IsPicturePhrase())
1.2859 + tPhrase=RPhraseAttribsEntry(charLayer,sPhrase.Length());
1.2860 + else
1.2861 + {
1.2862 + TPictureHeader hdr;
1.2863 + hdr=sPhrase.PictureHeader(); // copy the header from the source
1.2864 + if (hdr.iPicture.IsPtr())
1.2865 + hdr.iPicture=NULL; // pic.ownership transferred later.
1.2866 + CleanupStack::PushL(charLayer);
1.2867 + TBool ownershipTaken(EFalse);
1.2868 + CPicturePhrase* picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken);
1.2869 + CleanupStack::Pop(); // charLayer
1.2870 + tPhrase=RPhraseAttribsEntry(picPhrase);
1.2871 + iPictureCount++;
1.2872 + pictureMap->AppendL(jj);
1.2873 + }
1.2874 + }
1.2875 +
1.2876 + // transfer pictures now
1.2877 + for (TInt kk=pictureMap->Count();--kk>=0;)
1.2878 + {
1.2879 + TInt jj=pictureMap->At(kk);
1.2880 + TPictureHeader* sHeader=(*aSource->iPhraseIx)[jj].PictureHeaderPtr();
1.2881 + if (!sHeader)
1.2882 + {
1.2883 + OstTrace0( TRACE_DUMP, CRICHTEXTINDEX_APPENDPHRASEINDEXL, "Invariant" );
1.2884 + }
1.2885 + __ASSERT_DEBUG(sHeader,User::Invariant());
1.2886 + if (sHeader->iPicture.IsPtr())
1.2887 + { // transfer picture to us
1.2888 + TPictureHeader* tHeader=(*iPhraseIx)[jj+originalPhraseCount].PictureHeaderPtr();
1.2889 + if (!tHeader)
1.2890 + {
1.2891 + OstTrace0( TRACE_DUMP, DUP1_CRICHTEXTINDEX_APPENDPHRASEINDEXL, "Invariant" );
1.2892 + }
1.2893 + __ASSERT_DEBUG(tHeader,User::Invariant());
1.2894 + tHeader->iPicture=sHeader->iPicture.AsPtr();
1.2895 + sHeader->iPicture=NULL;
1.2896 + }
1.2897 + }
1.2898 +
1.2899 + CleanupStack::PopAndDestroy(); // pictureMap
1.2900 + }
1.2901 +
1.2902 +
1.2903 +void CRichTextIndex::AppendParagraphL(const CParaFormatLayer* aGlobalParaFormatLayer,
1.2904 + const CCharFormatLayer* aGlobalCharFormatLayer,
1.2905 + TInt aReplicas)
1.2906 +// Append aReplicas empty paragraphs, the format of which is based on the
1.2907 +// global format layers.
1.2908 +//
1.2909 + {
1.2910 + __TEST_INVARIANT;
1.2911 +
1.2912 + // add the shared para format record
1.2913 + CParaAttribs* paraAttribs=CParaAttribs::NewL(aGlobalParaFormatLayer,aGlobalCharFormatLayer);
1.2914 + paraAttribs->iParaFormat->SetBase(aGlobalParaFormatLayer); // reset the base properly
1.2915 + paraAttribs->iCharFormat->SetBase(aGlobalCharFormatLayer); // reset the base properly.
1.2916 + CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,paraAttribs));
1.2917 + CParaAttribs* paUsed=GetParaAttribsL(aGlobalParaFormatLayer,aGlobalCharFormatLayer,paraAttribs);
1.2918 + // guaranteed not to leave as 3rd argument specified.
1.2919 + // The refCount of paUsed is incremented here by one share.
1.2920 + //
1.2921 + // add the paragraph records
1.2922 + TParaAttribsEntry paraEntry(1,paUsed);
1.2923 + iParaIx->AppendL(paraEntry,aReplicas);
1.2924 + if (paUsed!=paraAttribs)
1.2925 + CleanupStack::PopAndDestroy();
1.2926 + else
1.2927 + CleanupStack::Pop();
1.2928 + //
1.2929 + // set the ref count of paUsed
1.2930 + paUsed->iRefCount+=(aReplicas-1); // compensate for already adding 1 share.
1.2931 +
1.2932 + __TEST_INVARIANT;
1.2933 + }
1.2934 +
1.2935 +
1.2936 +TParaAttribsEntry::TParaAttribsEntry():
1.2937 + iLength(0),
1.2938 + iParaAttribs(NULL)
1.2939 + {
1.2940 + }
1.2941 +
1.2942 +
1.2943 +TParaAttribsEntry::TParaAttribsEntry(TInt aLength,CParaAttribs* aParaAttribs):
1.2944 + iLength(aLength),
1.2945 + iParaAttribs(aParaAttribs)
1.2946 + {
1.2947 + }
1.2948 +
1.2949 +
1.2950 +CParaAttribs* CParaAttribs::NewL(const CParaFormatLayer* aParaLayer,const CCharFormatLayer* aCharLayer)
1.2951 +// Returns a handle to a new instance of this class.
1.2952 +// Creates a CParaAttribs with constant character formatting.
1.2953 +//
1.2954 + {
1.2955 + CParaAttribs* self=new(ELeave) CParaAttribs();
1.2956 + CleanupStack::PushL(self);
1.2957 + self->iParaFormat=CParaFormatLayer::NewCopyBaseL(aParaLayer);
1.2958 + // iParaFormat will be released in destructor.
1.2959 + // To prevent Coverity from reporting defect, add a comment:
1.2960 + // coverity[leave_without_push]
1.2961 + self->iCharFormat=CCharFormatLayer::NewCopyBaseL(aCharLayer);
1.2962 + CleanupStack::Pop();
1.2963 + self->iRefCount=EPrimeSharedCount;
1.2964 + return self;
1.2965 + }
1.2966 +
1.2967 +
1.2968 +CParaAttribs* CParaAttribs::NewL(const CParaFormatLayer* aParaLayer)
1.2969 +// Returns a handle to a new instance of this class.
1.2970 +// Creates a CParaAttribs for specific character formatting.
1.2971 +//
1.2972 + {
1.2973 + CParaAttribs* self=new(ELeave) CParaAttribs();
1.2974 + CleanupStack::PushL(self);
1.2975 + self->iParaFormat=CParaFormatLayer::NewCopyBaseL(aParaLayer);
1.2976 + CleanupStack::Pop();
1.2977 + self->iRefCount=EPrimeNonSharedCount;
1.2978 + self->iPhraseCount=1;
1.2979 + return self;
1.2980 + }
1.2981 +
1.2982 +
1.2983 +CParaAttribs* CParaAttribs::NewL(const CParaAttribs* aParaAttribs)
1.2984 + {
1.2985 + return NewL(aParaAttribs->iParaFormat,aParaAttribs->iCharFormat);
1.2986 + }
1.2987 +
1.2988 +
1.2989 +CParaAttribs::CParaAttribs():
1.2990 + iRefCount(-1) // Ensures Destruct works correctly when called on a semi-initialised object.
1.2991 + {
1.2992 + }
1.2993 +
1.2994 +
1.2995 +void CParaAttribs::Release()
1.2996 +// Release a share on this CParaAttribs.
1.2997 +// If after this, no shares remain, destroy this CParaAttribs.
1.2998 +//
1.2999 + {
1.3000 + iRefCount--;
1.3001 + if (iRefCount<=0)
1.3002 + delete this;
1.3003 + }
1.3004 +
1.3005 +
1.3006 +void CParaAttribs::Release(TInt aCount)
1.3007 +// Release aCount number of shares of this CParaAttribs.
1.3008 +// If after this, no shares remain, destroy this CParaAttribs.
1.3009 +//
1.3010 + {
1.3011 + iRefCount-=aCount;
1.3012 + if (iRefCount<=0)
1.3013 + delete this;
1.3014 + }
1.3015 +
1.3016 +
1.3017 +CParaAttribs::~CParaAttribs()
1.3018 +// Release the memory associated with this object.
1.3019 +//
1.3020 + {
1.3021 + delete iParaFormat;
1.3022 + if (iRefCount==0)
1.3023 + {// Constant character formatting - in the shared list.
1.3024 + delete iCharFormat;
1.3025 + link.Deque(); // Remove this para attribs from the shared list.
1.3026 + }
1.3027 + }
1.3028 +
1.3029 +
1.3030 +TInt CParaAttribs::PhraseCount()const
1.3031 +// Return a count of the number of phrases in this para attribs.
1.3032 +//
1.3033 + {return (iRefCount>=1)?1:iPhraseCount;}
1.3034 +
1.3035 +
1.3036 +DLLEXPORT_C void RPhraseAttribsEntry::__DbgTestInvariant()const
1.3037 +// Class invariants.
1.3038 +//
1.3039 + {
1.3040 +#ifdef _DEBUG
1.3041 +// ASSERT: iLength is +ve (applying to character formatting, or is set to indicate a picture phrase.
1.3042 + if (iLength<0 && !IsPicturePhrase())
1.3043 + {
1.3044 + OstTrace0( TRACE_DUMP, RPHRASEATTRIBSENTRY_DBGTESTINVARIANT, "Invariant" );
1.3045 + }
1.3046 + __ASSERT_DEBUG(iLength>=0 || IsPicturePhrase(),User::Invariant());
1.3047 +#endif
1.3048 + }
1.3049 +
1.3050 +
1.3051 +RPhraseAttribsEntry::RPhraseAttribsEntry():
1.3052 + iLength(0),
1.3053 + iCharFormat(NULL)
1.3054 + {
1.3055 + }
1.3056 +
1.3057 +
1.3058 +RPhraseAttribsEntry::RPhraseAttribsEntry(CCharFormatLayer* aCharFormat,TInt aLength):
1.3059 + iLength(aLength),
1.3060 + iCharFormat(aCharFormat)
1.3061 + {
1.3062 + }
1.3063 +
1.3064 +
1.3065 +RPhraseAttribsEntry::RPhraseAttribsEntry(CPicturePhrase* aPicturePhrase):
1.3066 + iLength(EPictureIndicator),
1.3067 + iPicturePhrase(aPicturePhrase)
1.3068 + {
1.3069 + }
1.3070 +
1.3071 +
1.3072 +void RPhraseAttribsEntry::AssignAndRelease(const RPhraseAttribsEntry& aPhrase)
1.3073 +// Assign the state of the specified object to this,
1.3074 +//
1.3075 + {
1.3076 + iLength=aPhrase.iLength;
1.3077 + iCharFormat=aPhrase.iCharFormat; // both union members share the same address space, so this is fine.
1.3078 + }
1.3079 +
1.3080 +
1.3081 +void RPhraseAttribsEntry::Discard()
1.3082 +// Free storage.
1.3083 +//
1.3084 + {
1.3085 + __TEST_INVARIANT;
1.3086 +
1.3087 + if (iLength==EPictureIndicator)
1.3088 + delete iPicturePhrase;
1.3089 + else
1.3090 + delete iCharFormat;
1.3091 + }
1.3092 +
1.3093 +
1.3094 +void RPhraseAttribsEntry::ExternalizeL(RWriteStream& aStream)const
1.3095 +// Save this phrase into aStream.
1.3096 +//
1.3097 + {
1.3098 + TUint8 picIndicator=(TUint8)(IsPicturePhrase()!=EFalse);
1.3099 + aStream.WriteUint8L(picIndicator);
1.3100 + aStream.WriteInt32L(Length());
1.3101 + aStream<< *CharFormat();
1.3102 + if ((TBool)picIndicator)
1.3103 + aStream<< *PictureHeaderPtr();
1.3104 + }
1.3105 +
1.3106 +
1.3107 +CCharFormatLayer* RPhraseAttribsEntry::CharFormat()const
1.3108 + // Returns a pointer the CCharFormatLayer of this phrase.
1.3109 + //
1.3110 + {return (iLength==EPictureIndicator)?iPicturePhrase->iCharFormat:iCharFormat;}
1.3111 +
1.3112 +
1.3113 +void RPhraseAttribsEntry::SetLength(TInt aLength)
1.3114 +// Sets the phrase length.
1.3115 +//
1.3116 + {
1.3117 + __TEST_INVARIANT;
1.3118 +
1.3119 + iLength=aLength;
1.3120 + }
1.3121 +
1.3122 +
1.3123 +void RPhraseAttribsEntry::AdjustLength(TInt aIncrement)
1.3124 +// Adjusts the length of the phrase by the signed value aIncrement.
1.3125 +//
1.3126 + {
1.3127 +// ASSERT: The length of a picture phrase may only be altered by deleting it, in which case
1.3128 +// the only adjustment made will be an increment of -1 (EPictureIndicator).
1.3129 + if (IsPicturePhrase() && (!IsPicturePhrase() || aIncrement!=EPictureIndicator)
1.3130 + && (!IsPicturePhrase() || aIncrement!=0) )
1.3131 + {
1.3132 + OstTrace0( TRACE_DUMP, RPHRASEATTRIBSENTRY_ADJUSTLENGTH, "EModifiedPicturePhraseLength" );
1.3133 + }
1.3134 + __ASSERT_DEBUG(!IsPicturePhrase() || (IsPicturePhrase() && aIncrement==EPictureIndicator)
1.3135 + || (IsPicturePhrase() && aIncrement==0)
1.3136 + ,Panic(EModifiedPicturePhraseLength));
1.3137 + TInt len=iLength;
1.3138 + iLength=(len==EPictureIndicator)
1.3139 + ? len-aIncrement
1.3140 + : len+aIncrement;
1.3141 + }
1.3142 +
1.3143 +
1.3144 +TInt RPhraseAttribsEntry::GetPictureSizeInTwips(TSize& aSize)const
1.3145 +// If this is a picture phrase, write the size of the picture to aSize,
1.3146 +// otherwise return KErrNotFound.
1.3147 +//
1.3148 + {
1.3149 + if (!IsPicturePhrase())
1.3150 + return KErrNotFound;
1.3151 + if (iPicturePhrase->iPicHdr.iPicture.IsPtr() && iPicturePhrase->iPicHdr.iPicture.AsPtr())
1.3152 + iPicturePhrase->iPicHdr.iPicture->GetSizeInTwips(aSize);
1.3153 + else
1.3154 + aSize=iPicturePhrase->iPicHdr.iSize;
1.3155 + return KErrNone;
1.3156 + }
1.3157 +
1.3158 +
1.3159 +TPictureHeader RPhraseAttribsEntry::PictureHeader()const
1.3160 +// Return the picture header describing the picture at character position aPos.
1.3161 +// If there is no picture at character position aPos, a default picture header is returned.
1.3162 +//
1.3163 + {
1.3164 + return (IsPicturePhrase())
1.3165 + ? iPicturePhrase->iPicHdr
1.3166 + : TPictureHeader();
1.3167 + }
1.3168 +
1.3169 +
1.3170 +const CPicture* RPhraseAttribsEntry::PictureHandleL(const MPictureFactory* aFactory,
1.3171 + const MRichTextStoreResolver* aResolver,
1.3172 + TInt aPos,
1.3173 + MLayDoc::TForcePictureLoad aForceLoad)const
1.3174 +// For a text phrase returns NULL.
1.3175 +// For a picture phrase returns a pointer to the picture object itself.
1.3176 +// May leave since loading of pictures is deferred until this point,
1.3177 +// ie, when the picture is required.
1.3178 +// Also returns NULL if the picture is not in memory *and* TForcePictureLoad is false.
1.3179 +//
1.3180 + {
1.3181 + if (iLength!=EPictureIndicator)
1.3182 + return NULL;
1.3183 + else
1.3184 + {// Check if the picture is in memory
1.3185 + CPicture* handle=NULL;
1.3186 + if (iPicturePhrase->iPicHdr.iPicture.IsPtr())
1.3187 + handle=iPicturePhrase->iPicHdr.iPicture;
1.3188 + else
1.3189 + {// Check if the picture should be loaded from persistent storage
1.3190 + if (aForceLoad==MLayDoc::EForceLoadTrue) // picture not in memory, so load it.
1.3191 + {
1.3192 + if (aResolver==NULL || aFactory==NULL)
1.3193 + return NULL;
1.3194 + const CStreamStore& store=aResolver->StreamStoreL(aPos);
1.3195 + aFactory->NewPictureL(iPicturePhrase->iPicHdr,store);
1.3196 + handle=iPicturePhrase->iPicHdr.iPicture;
1.3197 + }
1.3198 + }
1.3199 + return handle;
1.3200 + }
1.3201 + }
1.3202 +
1.3203 +
1.3204 +TPictureHeader* RPhraseAttribsEntry::PictureHeaderPtr()const
1.3205 +// For a [text] phrase returns NULL.
1.3206 +// For a picture phrase returns a pointer to the picture header.
1.3207 +//
1.3208 + {return (iLength==EPictureIndicator)? &iPicturePhrase->iPicHdr:NULL;}
1.3209 +
1.3210 +
1.3211 +CCharFormatLayer* RPhraseAttribsEntry::ReleaseCharFormatLayerOwnership()
1.3212 +// Return a handle to the character format layer, then set this handle to it to NULL.
1.3213 +// thus giving up ownership of the object.
1.3214 +//
1.3215 + {
1.3216 + CCharFormatLayer*& layer=(iLength==EPictureIndicator)?iPicturePhrase->iCharFormat:iCharFormat;
1.3217 + CCharFormatLayer* charFormatLayer=layer;
1.3218 + layer=NULL;
1.3219 + return charFormatLayer;
1.3220 + }
1.3221 +
1.3222 +
1.3223 +TBool RPhraseAttribsEntry::IsIdentical(const RPhraseAttribsEntry& aPhrase)const
1.3224 +// Returns ETrue if this phrase is identical to the specified phrase.
1.3225 +// otherwise returns EFalse.
1.3226 +// The 2 are equal only if they are both non-zero length text phrases, and of identical character format.
1.3227 +//
1.3228 + {
1.3229 + if (iLength<=0) // picture or zero-length
1.3230 + return EFalse;
1.3231 + if (aPhrase.iLength<=0) // picture or zero-length
1.3232 + return EFalse;
1.3233 + return iCharFormat->IsIdentical(aPhrase.iCharFormat,EFalse); // EFalse=do not compare based-on link
1.3234 + }
1.3235 +
1.3236 +
1.3237 +CPicturePhrase* CPicturePhrase::NewL(const TPictureHeader& aPicHdr,TCharFormatX& aFormat,
1.3238 + TCharFormatXMask& aMask,CCharFormatLayer* aCharBase,
1.3239 + TBool& aPictureOwnershipTaken)
1.3240 + {
1.3241 + CPicturePhrase* self=new(ELeave) CPicturePhrase(aPicHdr,aPictureOwnershipTaken);
1.3242 + CleanupStack::PushL(self);
1.3243 + self->ConstructL(aFormat,aMask,aCharBase);
1.3244 + CleanupStack::Pop();
1.3245 + return self;
1.3246 + }
1.3247 +
1.3248 +
1.3249 +// The charLayer is assumed to have a valid based-on link already set.
1.3250 +// Called as part of the rich text index Internalize only.
1.3251 +CPicturePhrase* CPicturePhrase::NewL(const TPictureHeader& aPicHdr,
1.3252 + CCharFormatLayer* aCharLayer,
1.3253 + TBool& aPictureOwnershipTaken)
1.3254 + {
1.3255 + return new(ELeave) CPicturePhrase(aPicHdr,aCharLayer,aPictureOwnershipTaken);
1.3256 + }
1.3257 +
1.3258 +
1.3259 +CPicturePhrase::CPicturePhrase(const TPictureHeader& aPicHdr,TBool& aPictureOwnershipTaken):
1.3260 + iPicHdr(aPicHdr)
1.3261 + {
1.3262 + aPictureOwnershipTaken=ETrue;
1.3263 + }
1.3264 +
1.3265 +
1.3266 +CPicturePhrase::CPicturePhrase(const TPictureHeader& aPicHdr,
1.3267 + CCharFormatLayer* aCharLayer,
1.3268 + TBool& aPictureOwnershipTaken):
1.3269 + iCharFormat(aCharLayer),
1.3270 + iPicHdr(aPicHdr)
1.3271 + {
1.3272 + aPictureOwnershipTaken=ETrue;
1.3273 + }
1.3274 +
1.3275 +
1.3276 +void CPicturePhrase::ConstructL(TCharFormatX& aFormat,TCharFormatXMask& aMask,CCharFormatLayer* aCharBase)
1.3277 + {
1.3278 + iCharFormat=CCharFormatLayer::NewL(aFormat,aMask);
1.3279 + iCharFormat->SetBase(aCharBase);
1.3280 + }
1.3281 +
1.3282 +
1.3283 +CPicturePhrase::~CPicturePhrase()
1.3284 + {
1.3285 + iPicHdr.DeletePicture();
1.3286 + delete iCharFormat;
1.3287 + }
1.3288 +
1.3289 +TLogicalPosition::TLogicalPosition():
1.3290 + iDocPos(0),
1.3291 + iParaElement(0),
1.3292 + iParaElementOffset(0),
1.3293 + iPhraseElement(0),
1.3294 + iPhraseElementOffset(0)
1.3295 + {
1.3296 + }
1.3297 +
1.3298 +
1.3299 +void TLogicalPosition::Clear()
1.3300 +// Reset this logical position record.
1.3301 +//
1.3302 + {
1.3303 + *this=TLogicalPosition();
1.3304 + iParaBasePhraseElement=0;
1.3305 + }