|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32std.h> |
|
20 #include <e32base.h> |
|
21 |
|
22 #include <gdi.h> |
|
23 #include <s32stor.h> |
|
24 #include "TXTFMLYR.H" |
|
25 #include "TXTETEXT.H" |
|
26 #include "TXTLAYDC.H" |
|
27 #include "TXTSTYLE.H" |
|
28 #include "TXTINDEX.H" |
|
29 |
|
30 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
31 #include "TXTFMLYR_INTERNAL.H" |
|
32 #include "TXTSTYLE_INTERNAL.H" |
|
33 #endif |
|
34 |
|
35 TGlobalLayerInfoAppend::TGlobalLayerInfoAppend() |
|
36 : iAggParaFormatLayer(NULL),iAggCharFormatLayer(NULL),iComParaFormatLayer(NULL),iComCharFormatLayer(NULL) |
|
37 {} |
|
38 |
|
39 TGlobalLayerInfoAppend::TGlobalLayerInfoAppend(const CParaFormatLayer* aAggParaFormatLayer,const CCharFormatLayer* aAggCharFormatLayer, |
|
40 const CParaFormatLayer* aComParaFormatLayer,const CCharFormatLayer* aComCharFormatLayer) |
|
41 : iAggParaFormatLayer(aAggParaFormatLayer),iAggCharFormatLayer(aAggCharFormatLayer), |
|
42 iComParaFormatLayer(aComParaFormatLayer),iComCharFormatLayer(aComCharFormatLayer) |
|
43 {} |
|
44 |
|
45 |
|
46 TTextFragment::TTextFragment(): |
|
47 iLength(0), |
|
48 iPhraseCount(0) |
|
49 { |
|
50 } |
|
51 |
|
52 |
|
53 TCurrentIndexRecords::TCurrentIndexRecords() |
|
54 { |
|
55 } |
|
56 |
|
57 |
|
58 DLLEXPORT_C void CRichTextIndex::__DbgTestInvariant()const |
|
59 // Provides class invariants. Explanations below: |
|
60 // |
|
61 { |
|
62 #ifdef _DEBUG |
|
63 // ASSERT: Every phrase index is consistent with its corresponding paragraph. |
|
64 TInt zeroLengthPhraseCount=0; |
|
65 TInt maxPara=iParaIx->Count(); |
|
66 TInt numberOfReferencesToSharedList=0; |
|
67 TInt currentPhraseElement=0; |
|
68 for (TInt para=0;para<maxPara;para++) |
|
69 { |
|
70 // ASSERT: The basedOn link is valid. |
|
71 CFormatLayer* thisLayer=(*iParaIx)[para].iParaAttribs->iParaFormat; |
|
72 CFormatLayer* base=CONST_CAST(CFormatLayer*,thisLayer->SenseBase()); |
|
73 __ASSERT_DEBUG(base!=NULL,User::Invariant()); |
|
74 if ((*iParaIx)[para].iParaAttribs->iRefCount>0) |
|
75 numberOfReferencesToSharedList++; |
|
76 TInt paragraphLength=(*iParaIx)[para].iLength; |
|
77 TInt sumOfPhraseLengths=0; |
|
78 TInt maxPhrase=(*iParaIx)[para].iParaAttribs->PhraseCount(); |
|
79 for (TInt phrase=0;phrase<maxPhrase;phrase++) |
|
80 { |
|
81 if (maxPhrase>1) |
|
82 { |
|
83 const RPhraseAttribsEntry* phrase=&(*iPhraseIx)[currentPhraseElement]; |
|
84 CCharFormatLayer* charFormatLayer=phrase->CharFormat(); |
|
85 // ASSERT: The basedOn link is valid. |
|
86 __ASSERT_DEBUG(charFormatLayer->SenseBase()!=NULL,User::Invariant()); |
|
87 __ASSERT_DEBUG(TInt(charFormatLayer->SenseBase())>0x1000,User::Invariant()); |
|
88 sumOfPhraseLengths+=(*iPhraseIx)[currentPhraseElement].Length(); |
|
89 if ((*iPhraseIx)[currentPhraseElement].Length()==0) |
|
90 zeroLengthPhraseCount++; |
|
91 currentPhraseElement++; |
|
92 } |
|
93 else |
|
94 { |
|
95 CCharFormatLayer* charFormatLayer=(*iParaIx)[para].iParaAttribs->iCharFormat; |
|
96 // ASSERT: The basedOn link is valid. |
|
97 __ASSERT_DEBUG(charFormatLayer->SenseBase()!=NULL,User::Invariant()); |
|
98 sumOfPhraseLengths+=(*iParaIx)[para].iLength; |
|
99 } |
|
100 } |
|
101 __ASSERT_DEBUG(sumOfPhraseLengths==paragraphLength,User::Invariant()); |
|
102 } |
|
103 // ASSERT: We have no unexpected phrases left over |
|
104 __ASSERT_DEBUG(currentPhraseElement==-1 || |
|
105 currentPhraseElement==iPhraseIx->Count(),User::Invariant()); |
|
106 // ASSERT: There is either zero(0) or one(1) zero length phrase in the whole index |
|
107 __ASSERT_DEBUG( (zeroLengthPhraseCount==0) || |
|
108 (zeroLengthPhraseCount==1 && iPendingNewPhrasePos!=EInsertCharFormatReset), |
|
109 User::Invariant()); |
|
110 // ASSERT: the number of paraEntries with paraAttribs of refCount>0 == the sum of refCounts in the shared list. |
|
111 // or is only one less - as is set when SetInsertCharFormat is called on a shared paraAttribs. |
|
112 TInt totalReferenceCount=0; |
|
113 if (!iSharedParaQueHead.IsEmpty()) |
|
114 { |
|
115 CParaAttribs* currentSharedPara; |
|
116 TDblQueIter<CParaAttribs> iterator(((CRichTextIndex*)this)->iSharedParaQueHead); |
|
117 while ((currentSharedPara=iterator++)!=NULL) |
|
118 totalReferenceCount+=currentSharedPara->iRefCount; |
|
119 } |
|
120 __ASSERT_DEBUG((numberOfReferencesToSharedList==totalReferenceCount) || |
|
121 (numberOfReferencesToSharedList==totalReferenceCount-1),User::Invariant()); |
|
122 // ASSERT: iPictureCount corresponds to the number of pictures in the stored in the index. |
|
123 TInt picCount=0; |
|
124 TInt phraseCount=(iPhraseIx) ? iPhraseIx->Count() : 0; |
|
125 for (TInt item=0;item<phraseCount;item++) |
|
126 picCount+=((*iPhraseIx)[item].IsPicturePhrase()) |
|
127 ? 1 |
|
128 : 0; |
|
129 __ASSERT_DEBUG(iPictureCount==picCount,User::Invariant()); |
|
130 #endif |
|
131 } |
|
132 |
|
133 |
|
134 CRichTextIndex* CRichTextIndex::NewL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer, |
|
135 const CRichText& aText,TInt aParaGran,TInt aPhraseGran) |
|
136 // Return a handle to a new instance of this class. |
|
137 // Requires the global format layer handles on which to base the first content. |
|
138 // |
|
139 { |
|
140 CRichTextIndex* self=new(ELeave) CRichTextIndex(aText); |
|
141 CleanupStack::PushL(self); |
|
142 self->ConstructL(aGlobalParaLayer,aGlobalCharLayer,aParaGran,aPhraseGran); |
|
143 CleanupStack::Pop(); |
|
144 return self; |
|
145 } |
|
146 |
|
147 |
|
148 CRichTextIndex::CRichTextIndex(const CRichText& aText): |
|
149 iText(aText), |
|
150 iPendingNewPhrasePos(EInsertCharFormatReset), |
|
151 iSharedParaQueHead(_FOFF(CParaAttribs,link)) |
|
152 { |
|
153 } |
|
154 |
|
155 |
|
156 void CRichTextIndex::ConstructL(const CParaFormatLayer* aGlobalParaLayer,const CCharFormatLayer* aGlobalCharLayer,TInt aParaGran,TInt aPhraseGran) |
|
157 // Provides a fully initialised rich text index. |
|
158 // Upon construction, the index contains a single paragraph of length 1 (para.terminator). |
|
159 // This first paragraph initially has constant character formatting, ie the shared para list |
|
160 // must have one item in it. |
|
161 // |
|
162 { |
|
163 CParaFormatLayer* paraLayer=CParaFormatLayer::NewL(); // Creates empty layer. |
|
164 paraLayer->SetBase(aGlobalParaLayer); // Sets basedOn to global default. |
|
165 CleanupStack::PushL(paraLayer); |
|
166 CCharFormatLayer* charLayer=CCharFormatLayer::NewL(); // Creates empty layer. |
|
167 charLayer->SetBase(aGlobalCharLayer); // Sets basedOn to global default. |
|
168 CleanupStack::PushL(charLayer); |
|
169 CParaAttribs* paraAttribs=GetParaAttribsL(paraLayer,charLayer); |
|
170 CleanupStack::PopAndDestroy(2); |
|
171 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,paraAttribs)); |
|
172 iParaIx=new(ELeave) CArrayFixSeg<TParaAttribsEntry>(aParaGran); |
|
173 TParaAttribsEntry para(1,paraAttribs); |
|
174 iParaIx->AppendL(para); |
|
175 CleanupStack::Pop(); |
|
176 iPhraseIx=new(ELeave) CArrayFixSeg<RPhraseAttribsEntry>(aPhraseGran); |
|
177 |
|
178 __TEST_INVARIANT; |
|
179 } |
|
180 |
|
181 |
|
182 CRichTextIndex::~CRichTextIndex() |
|
183 // Free up all storage allocated in the rich text index. |
|
184 // |
|
185 { |
|
186 TInt count; |
|
187 if (iPhraseIx) |
|
188 {// Destroy the phrase index and its contents. |
|
189 __ASSERT_ALWAYS(iParaIx,Panic(EPhraseIxPresentWithNoParaIx)); |
|
190 count=iPhraseIx->Count(); |
|
191 for (TInt offset=0;offset<count;offset++) |
|
192 (*iPhraseIx)[offset].Discard(); |
|
193 } |
|
194 delete iPhraseIx; |
|
195 if (iParaIx) |
|
196 {// Destroy the para index and its contents. |
|
197 count=iParaIx->Count(); |
|
198 for (TInt offset=0;offset<count;offset++) |
|
199 { |
|
200 CParaAttribs* pA=(*iParaIx)[offset].iParaAttribs; |
|
201 if (!pA->IsShared()) |
|
202 pA->Release(); |
|
203 } |
|
204 } |
|
205 delete iParaIx; |
|
206 RebalanceIndex(); |
|
207 // |
|
208 // Clear the shared list. (Will usually be empty by now |
|
209 // unless internalize failed after getting shared list & before getting all para data. |
|
210 CParaAttribs* currentSharedPara; |
|
211 TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead); |
|
212 while ((currentSharedPara=iterator++)!=NULL) |
|
213 currentSharedPara->Release(currentSharedPara->iRefCount); |
|
214 __ASSERT_ALWAYS(iSharedParaQueHead.IsEmpty(),Panic(ERichTextIndexIntegrityErr)); |
|
215 } |
|
216 |
|
217 |
|
218 TInt CRichTextIndex::CharPosOfParagraph(TInt& aLength,TInt aParaOffset)const |
|
219 // Returns the character position of the first character of paragraph aParaOffset, |
|
220 // where aParaOffset specifies the nth paragraph. |
|
221 // The length of this nth paragraph is written to aLength. |
|
222 // |
|
223 // If aParaOffset specifies a paragraph that does not exist, EScanEndOfData is returned. |
|
224 // |
|
225 { |
|
226 __TEST_INVARIANT; |
|
227 |
|
228 if (aParaOffset>=iParaIx->Count()) |
|
229 return CPlainText::EScanEndOfData; |
|
230 TInt pos=0,offset=0; |
|
231 for (offset=0;offset<aParaOffset;offset++) |
|
232 pos+=(*iParaIx)[offset].iLength; |
|
233 aLength=(*iParaIx)[offset].iLength; |
|
234 return pos; |
|
235 } |
|
236 |
|
237 |
|
238 TInt CRichTextIndex::ParagraphNumberForPos(TInt& aPos)const |
|
239 // Returns the paragraph offset for the specified character position aPos. |
|
240 // aPos is in turn modified to hold the character position of the first character |
|
241 // of this paragraph. If aPos is already on a paragraph boundary then do nothing. |
|
242 // |
|
243 { |
|
244 __TEST_INVARIANT; |
|
245 |
|
246 ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute); |
|
247 aPos-=iPos.iParaElementOffset; |
|
248 return iPos.iParaElement; |
|
249 } |
|
250 |
|
251 |
|
252 void CRichTextIndex::DocumentChanged()const |
|
253 { |
|
254 MUTABLE_CAST(TLogicalPosition&,iLastUsed).Clear(); |
|
255 } |
|
256 |
|
257 |
|
258 void CRichTextIndex::DoSoloInsertL(TInt aPos,TInt aLength) |
|
259 // Updates the index following the insertion of content into a single phrase. |
|
260 // First find the phrase record the governs the insert pos. |
|
261 // (1) If the current phrase is a text phrase, then simply extend the length of the phrase record. |
|
262 // (2) If the current phrase is a picture phrase then this cannot be extended. |
|
263 // There is 1 pathological case here: |
|
264 // (i) The [current] picture phrase is the 1st phrase in the paragraph, and the insert pos |
|
265 // is before this phrase. (paragraph insert pos == 0). |
|
266 // In this case we must insert a new text phrase *before* the picture phrase. |
|
267 // (ii) In normal circumstances the inserted text is after the picture phrase. So, if the |
|
268 // following phrase is of the same character format as the picture then we can re-use this phrase. |
|
269 // If it is not of the same character format (or is also a picture phrase), |
|
270 // then we must insert a new text phrase of the correct format immediately following the current picture phrase. |
|
271 // |
|
272 { |
|
273 RebalanceIndex(); |
|
274 if (!((iPendingNewPhrasePos == EInsertCharFormatReset) || (aPos == iPendingNewPhrasePos))) |
|
275 CancelInsertCharFormat(); |
|
276 |
|
277 ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
278 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
279 if (current.iPhrase && current.iPhrase->IsPicturePhrase()) |
|
280 {// Paragraph has specific char format, and current phrase is picture phrase. |
|
281 TInt newPhraseRequired=EFalse; |
|
282 CCharFormatLayer* charLayer=current.iPhrase->CharFormat(); |
|
283 if (FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0) |
|
284 newPhraseRequired=ETrue; // Text is inserted at the start of the para behind the picture. |
|
285 else |
|
286 {// Check for re-use of the next text phrase. |
|
287 iPos.iPhraseElement++; |
|
288 iPos.iPhraseElementOffset=0; |
|
289 const RPhraseAttribsEntry& nextPhrase=(*iPhraseIx)[iPos.iPhraseElement]; |
|
290 if (nextPhrase.IsPicturePhrase() || !nextPhrase.CharFormat()->IsIdentical(charLayer,EFalse)) |
|
291 {// Need a new phrase if the formats don't match OR the next phrase is a picture phrase. |
|
292 newPhraseRequired=ETrue; // Need to create a new phrase to take this insert. |
|
293 } |
|
294 } |
|
295 if (newPhraseRequired) |
|
296 {// Insert new phrase & record this fact |
|
297 CCharFormatLayer* charFormat=CCharFormatLayer::NewCopyBaseL(charLayer); |
|
298 RPhraseAttribsEntry newPhrase(charFormat); |
|
299 CleanupStack::PushL(charFormat); |
|
300 iPhraseIx->InsertL(iPos.iPhraseElement,newPhrase); |
|
301 CleanupStack::Pop(); |
|
302 current.iParaAttribs->iPhraseCount++; |
|
303 } |
|
304 GetCurrentRecords(current); // Update current records, cos used below. |
|
305 } |
|
306 // Extend the lengths in the index. |
|
307 current.iParaEntry->iLength+=aLength; // Increase length of paragraph. |
|
308 if (current.iPhrase) |
|
309 current.iPhrase->AdjustLength(aLength); // Increase the length of this phrase. |
|
310 iPos.iPhraseElementOffset+=aLength; |
|
311 iPos.iParaElementOffset+=aLength; |
|
312 iPos.iDocPos+=aLength; |
|
313 } |
|
314 |
|
315 |
|
316 void CRichTextIndex::InsertL(TInt aPos,const TDesC& aBuf,const CParaFormatLayer& aGlobalParaFormatLayer) |
|
317 // Updates the index following the insertion of a descriptor of text into the document. |
|
318 // Correctly handles embedded paragraph delimiters. |
|
319 // |
|
320 { |
|
321 __TEST_INVARIANT; |
|
322 TInt bufLen=aBuf.Length(); |
|
323 |
|
324 RebalanceIndex(); |
|
325 TInt paragraphCount=0; |
|
326 const TText* start=aBuf.Ptr(); |
|
327 const TText* end=start+bufLen; |
|
328 while (start<end) |
|
329 { |
|
330 if (*start++==CEditableText::EParagraphDelimiter) |
|
331 paragraphCount++; |
|
332 } |
|
333 if (paragraphCount==0) |
|
334 { |
|
335 if (bufLen > 0) |
|
336 { |
|
337 DoSoloInsertL(aPos,bufLen); |
|
338 CancelInsertCharFormat(); |
|
339 } |
|
340 __TEST_INVARIANT; |
|
341 return; |
|
342 } |
|
343 ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
344 TLogicalPosition pastePos=iPos; // Used to adjust paragraph/phrase lengths later |
|
345 |
|
346 if (paragraphCount>1) |
|
347 { |
|
348 TCurrentIndexRecords current; |
|
349 GetCurrentRecords(current); |
|
350 const CParaAttribs& paraAttribs=*current.iParaAttribs; |
|
351 CCharFormatLayer* charLayer=(paraAttribs.IsShared()) |
|
352 ? paraAttribs.iCharFormat |
|
353 : (*iPhraseIx)[iPos.iPhraseElement].CharFormat(); |
|
354 CParaFormatLayer* paraLayer=paraAttribs.iParaFormat; |
|
355 CParaAttribs* theParaAttribs=GetParaAttribsL(paraLayer,charLayer); |
|
356 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,theParaAttribs)); |
|
357 iParaIx->InsertL(pastePos.iParaElement,TParaAttribsEntry(0,theParaAttribs),paragraphCount-1); |
|
358 CleanupStack::Pop(); |
|
359 theParaAttribs->iRefCount+=paragraphCount-2; // add the extra references |
|
360 } |
|
361 TLogicalPosition pos; |
|
362 TRAPD(ret, |
|
363 SplitParagraphAtPastePosL(pastePos,pos,aGlobalParaFormatLayer)); |
|
364 if (ret!=KErrNone) |
|
365 { |
|
366 RbRemoveInsertedParaAttribsEntries(pastePos.iParaElement,paragraphCount-1); |
|
367 User::Leave(ret); |
|
368 } |
|
369 |
|
370 if (paragraphCount>1) |
|
371 { // swap the entries for the split and first inserted paragraph |
|
372 TParaAttribsEntry& paraEntry=(*iParaIx)[pastePos.iParaElement+paragraphCount-1]; |
|
373 TParaAttribsEntry& insertEntry=(*iParaIx)[pastePos.iParaElement]; |
|
374 TParaAttribsEntry temp=paraEntry; |
|
375 paraEntry=insertEntry; |
|
376 insertEntry=temp; |
|
377 }// Cos weve inserted new paragraphs in front of the governing one. |
|
378 |
|
379 // Sort out the front para |
|
380 TParaAttribsEntry& frontPara=(*iParaIx)[pastePos.iParaElement]; |
|
381 TPtrC buf(aBuf); |
|
382 TInt lengthOfFirstPara=ParaLengthFromBuffer(buf); |
|
383 frontPara.iLength+=lengthOfFirstPara; // Adjust the para length |
|
384 buf.Set(aBuf.Right(aBuf.Length()-lengthOfFirstPara-1)); |
|
385 if (!frontPara.iParaAttribs->IsShared() && lengthOfFirstPara != 0) |
|
386 { |
|
387 RPhraseAttribsEntry* phrase=&(*iPhraseIx)[pastePos.iPhraseElement]; |
|
388 if (phrase->IsPicturePhrase()) |
|
389 { // move insertion past any picture phrase |
|
390 pastePos.iPhraseElement++; |
|
391 pastePos.iPhraseElementOffset=0; |
|
392 phrase=&(*iPhraseIx)[pastePos.iPhraseElement]; |
|
393 } |
|
394 phrase->AdjustLength(lengthOfFirstPara); // Adjust the phrase length |
|
395 } |
|
396 for (TInt paraItem=1;paraItem<paragraphCount;paraItem++) |
|
397 {// For each para inserted between the fist and last |
|
398 TParaAttribsEntry& para=(*iParaIx)[pastePos.iParaElement+paraItem]; |
|
399 TInt length=ParaLengthFromBuffer(buf)+1; |
|
400 __ASSERT_DEBUG(length!=KErrNotFound,Panic(EInsertEmbeddedParaErr)); |
|
401 para.iLength=length; |
|
402 buf.Set(buf.Right(buf.Length()-length)); |
|
403 } |
|
404 // For final paragrph |
|
405 TInt trailingTextLen=buf.Length(); |
|
406 if (trailingTextLen>0) |
|
407 { |
|
408 TParaAttribsEntry& backPara=(*iParaIx)[pos.iParaElement]; |
|
409 backPara.iLength+=trailingTextLen; |
|
410 if (!backPara.iParaAttribs->IsShared()) |
|
411 { |
|
412 RPhraseAttribsEntry& phrase=(*iPhraseIx)[pos.iPhraseElement]; |
|
413 phrase.AdjustLength(trailingTextLen); // Adjust phrase length |
|
414 } |
|
415 } |
|
416 // |
|
417 // Now tidy up |
|
418 if (bufLen>1 && iPendingNewPhrasePos!=EInsertCharFormatReset) |
|
419 { |
|
420 iPendingNewPhrasePos=aPos+(bufLen-trailingTextLen); |
|
421 CancelInsertCharFormat(); |
|
422 } |
|
423 |
|
424 __TEST_INVARIANT; |
|
425 } |
|
426 |
|
427 |
|
428 void CRichTextIndex::SplitParagraphAtPastePosL(TLogicalPosition& aPastePos,TLogicalPosition& aNewPos, |
|
429 const CParaFormatLayer& aGlobalParaFormatLayer) |
|
430 // Breaks the paragraph specified by the logical position aPastePos, inserting a paragraph delimiter. |
|
431 // |
|
432 { |
|
433 TInt insertPendingPos = iPendingNewPhrasePos; |
|
434 DoSoloInsertL(aPastePos.iDocPos,1); |
|
435 TBool insertCharFormatDeleted = EFalse; |
|
436 if (InsertCharFormatIsActive()) |
|
437 { |
|
438 insertCharFormatDeleted = DeleteInsertCharFormat(); |
|
439 iPendingNewPhrasePos = EInsertCharFormatReset; |
|
440 } |
|
441 TRAPD(ret, |
|
442 InsertParagraphL(aPastePos.iDocPos+1,aGlobalParaFormatLayer)); // Split the current para (and maybe phrase index). |
|
443 if (ret!=KErrNone) |
|
444 { |
|
445 // locate the character inserted by DoSoloInsertL() above |
|
446 ScanToPosition(aPastePos.iDocPos,EScanToPositionAbsolute); |
|
447 TCurrentIndexRecords current; |
|
448 GetCurrentRecords(current); |
|
449 current.iParaEntry->iLength--; |
|
450 if (current.iPhrase) |
|
451 { |
|
452 current.iPhrase->AdjustLength(-1); // collapse phrase by right amount |
|
453 if (insertPendingPos!=EInsertCharFormatReset) |
|
454 { |
|
455 __ASSERT_DEBUG(current.iPhrase->Length()==0,User::Invariant()); |
|
456 iPendingNewPhrasePos=insertPendingPos; |
|
457 } |
|
458 else if (current.iPhrase->Length()==0) |
|
459 { |
|
460 RemoveFromPhraseIx(iPos.iPhraseElement,1); |
|
461 current.iParaAttribs->iPhraseCount--; |
|
462 __ASSERT_DEBUG(current.iParaAttribs->PhraseCount()>1,User::Invariant()); |
|
463 } |
|
464 } |
|
465 User::Leave(ret); |
|
466 } |
|
467 if (insertPendingPos != EInsertCharFormatReset) |
|
468 ConsolidateAt(insertPendingPos, insertCharFormatDeleted? |
|
469 EPositionOnly : EFollowingPhrase); |
|
470 ScanToPosition(aPastePos.iDocPos+1,EScanToPositionMatchLeft); // Gives us the next para. |
|
471 aNewPos=iPos; |
|
472 } |
|
473 |
|
474 |
|
475 TInt CRichTextIndex::ParaLengthFromBuffer(TDesC& aBuf)const |
|
476 // Returns the length of the first para found in the buffer. |
|
477 // The returned length excludes the paragraph delimiter character. |
|
478 // Returns KNotFound if there is no paragraph delimiter. |
|
479 // |
|
480 {return aBuf.Locate(CEditableText::EParagraphDelimiter);} |
|
481 |
|
482 |
|
483 void CRichTextIndex::InsertL(TInt aPos,const TPictureHeader& aPicHdr, TBool& aPictureOwnershipTaken) |
|
484 // Updates the index following the insertion of a picture header object into the text |
|
485 // component. This is accomplished by creating & inserting a picture phrase at the |
|
486 // relevant place. |
|
487 // |
|
488 { |
|
489 __TEST_INVARIANT; |
|
490 |
|
491 RebalanceIndex(); |
|
492 // ASSERT: A valid picture header, referencing a valid picture has been inserted. |
|
493 __ASSERT_ALWAYS(aPicHdr.iPicture.IsPtr() && aPicHdr.iPicture.AsPtr()!=NULL,Panic(EInsertNullPicHdrData)); |
|
494 // ASSERT: The current insert pos hasn't been changed without cancelling SetInsertCharFormat. |
|
495 __ASSERT_ALWAYS((iPendingNewPhrasePos==EInsertCharFormatReset) || (aPos==iPendingNewPhrasePos), |
|
496 Panic(ESetInsertCharFormatIntegrityErr)); |
|
497 if (iPendingNewPhrasePos!=EInsertCharFormatReset) |
|
498 CancelInsertCharFormat(); // Cancel this state before inserting picture. Rebalances the index. |
|
499 ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
500 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
501 TCharFormatX format; |
|
502 TCharFormatXMask mask; //...and build up its format. |
|
503 CCharFormatLayer* baseChar; |
|
504 GetPhraseFormat(current,format,mask,baseChar); //...inherit format from prev. phrase. |
|
505 // Create the picture phrase. Takes ownership of the aPicHdr.iPicture |
|
506 CPicturePhrase* picture=CPicturePhrase::NewL(aPicHdr,format,mask,baseChar,aPictureOwnershipTaken); |
|
507 CleanupStack::PushL(picture); |
|
508 //New reclaimed CParaAttribs instance |
|
509 CParaAttribs* reclaimed=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry); |
|
510 //Store the old CParaAttribs instance in rollbackParaAttribsHandle |
|
511 CParaAttribs* rollbackParaAttribsHandle=current.iParaAttribs; |
|
512 if (reclaimed) |
|
513 { |
|
514 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed)); |
|
515 current.iParaEntry->iParaAttribs=reclaimed; // Use this reclaimed para attribs (the new CParaAttribs instance) |
|
516 } |
|
517 GetCurrentRecords(current); |
|
518 // ASSERT: The reclaim succeeded. We must always end up with a PhraseIx-not constant char format. |
|
519 __ASSERT_DEBUG(current.iPhrase!=NULL,Panic(EReclaimShareError)); |
|
520 TRAPD(ret1, |
|
521 SplitPhraseL(aPos)); // Phrase may not be split if at boundary. |
|
522 |
|
523 if (ret1!=KErrNone) |
|
524 { |
|
525 RbInsertPicture(rollbackParaAttribsHandle);//Restore the old CParaAttribs instance |
|
526 User::Leave(ret1); |
|
527 } |
|
528 |
|
529 TInt offset=(PhraseSplit())?1:0; // Insert position of new phrase relative to current. |
|
530 RPhraseAttribsEntry newPhrase(picture); |
|
531 TRAPD(ret2, |
|
532 iPhraseIx->InsertL(iPos.iPhraseElement+offset,newPhrase)); |
|
533 if (ret2!=KErrNone) |
|
534 { |
|
535 RbInsertPicture(rollbackParaAttribsHandle);//Restore the old CParaAttribs instance |
|
536 User::Leave(ret2); |
|
537 } |
|
538 |
|
539 if(reclaimed) |
|
540 { |
|
541 CleanupStack::Pop();//"Pop" for CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimed)); |
|
542 } |
|
543 CleanupStack::Pop(picture); |
|
544 // Update counts etc. - cannot leave now. |
|
545 current.iParaEntry->iLength+=RPhraseAttribsEntry::EPicturePhraseLength; |
|
546 current.iParaAttribs->iPhraseCount++; // for the picture phrase |
|
547 iPictureCount++; |
|
548 |
|
549 // Commit |
|
550 if(reclaimed) |
|
551 { |
|
552 rollbackParaAttribsHandle->Release(); // Release hold on original shared paraAttribs. |
|
553 } |
|
554 |
|
555 __TEST_INVARIANT; |
|
556 //coverity[memory_leak] |
|
557 } |
|
558 |
|
559 void CRichTextIndex::RbInsertPicture(CParaAttribs* aGoodParaAttribs) |
|
560 // Reinstate the original good paraAttribs. |
|
561 // Then rollback the SplitPhrase() call if it succeeded. |
|
562 // |
|
563 { |
|
564 (*iParaIx)[iPos.iParaElement].iParaAttribs=aGoodParaAttribs; |
|
565 if (PhraseSplit()) |
|
566 {// Rollback the SplitPhrase() |
|
567 TInt length=(*iPhraseIx)[iPos.iPhraseElement+1].Length(); |
|
568 RemoveFromPhraseIx(iPos.iPhraseElement+1); |
|
569 (*iPhraseIx)[iPos.iPhraseElement].AdjustLength(length); |
|
570 } |
|
571 } |
|
572 |
|
573 |
|
574 // Insert a new paragraph immediately following character position aPos, fixing the length of the preceeding |
|
575 // paragraph. The new paragraph preserves any explicit paragraph/character formatting, and is based on the |
|
576 // global layers. (Do not need to rebalance the index here; a previous call to DoSoloInsertL accomplishes this) |
|
577 |
|
578 void CRichTextIndex::InsertParagraphL(TInt aPos,const CParaFormatLayer& aGlobalParaFormatLayer) |
|
579 { |
|
580 ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
581 TCurrentIndexRecords current; |
|
582 GetCurrentRecords(current); |
|
583 TParaAttribsEntry newPara; |
|
584 CCharFormatLayer* charLayer; |
|
585 if (current.iPhrase) // entry in phrase index |
|
586 charLayer=current.iPhrase->CharFormat(); |
|
587 else |
|
588 charLayer=current.iParaAttribs->iCharFormat; |
|
589 // |
|
590 // New para format layer, based on normal, inheriting specific format |
|
591 CParaFormatLayer* currentParaFormat=current.iParaAttribs->iParaFormat; |
|
592 CParaFormatLayer* newParaLayer=CParaFormatLayer::NewL(currentParaFormat); |
|
593 const CParaFormatLayer& currentStyle=STATIC_CAST(const CParaFormatLayer&,*currentParaFormat->SenseBase()); |
|
594 const TUid currentStyleType=currentStyle.Type(); |
|
595 |
|
596 // !! |
|
597 // Only change to Normal if current style is a built-in one |
|
598 // or we are not at the end of a heading style. |
|
599 TBool useNormal; |
|
600 if (currentStyleType==KNormalParagraphStyleUid) |
|
601 useNormal=ETrue; |
|
602 else if (currentStyleType==KUserDefinedParagraphStyleUid) |
|
603 useNormal=EFalse; |
|
604 else if (iPos.iParaElementOffset<=(current.iParaEntry->iLength-2)) // cos of previous call to DoSoloInsertL() |
|
605 useNormal=EFalse; |
|
606 else |
|
607 useNormal=ETrue; |
|
608 newParaLayer->SetBase((useNormal) |
|
609 ? &aGlobalParaFormatLayer |
|
610 : ¤tStyle); |
|
611 const CCharFormatLayer* newCharBase=(useNormal) |
|
612 ? iText.GlobalCharFormatLayer() |
|
613 : STATIC_CAST(const CParagraphStyle&,currentStyle).CharFormatLayer(); |
|
614 CleanupStack::PushL(newParaLayer); |
|
615 // |
|
616 if (current.iParaAttribs->IsShared()) |
|
617 {// Current para has constant char format - so the new one also has constant char format |
|
618 // New char format layer, based on normal, inheriting specific format |
|
619 CCharFormatLayer* newCharLayer=CCharFormatLayer::NewL(charLayer); |
|
620 newCharLayer->SetBase(newCharBase); |
|
621 CleanupStack::PushL(newCharLayer); |
|
622 newPara.iParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer); |
|
623 CleanupStack::PopAndDestroy(2); // newCharLayer/newParaLayer |
|
624 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,newPara.iParaAttribs)); |
|
625 iParaIx->InsertL(iPos.iParaElement+1,newPara); |
|
626 CleanupStack::Pop(); // paraAttribs cleanup item |
|
627 GetCurrentRecords(current); // could be changed by InsertL() above |
|
628 } |
|
629 else // Do the split myself since this para has specific character formatting. |
|
630 {// Make the new CParaAttribs |
|
631 CParaAttribs* newParaAttribs=CParaAttribs::NewL(newParaLayer); |
|
632 CleanupStack::PopAndDestroy(); // newParaLayer - copy owned by newParaAttribs |
|
633 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,newParaAttribs)); |
|
634 // |
|
635 // Split current phrase & insert if necessary. |
|
636 // Split even when we are at a phrase boundary -> this introduces an z.l.p. for the insertion point |
|
637 RPhraseAttribsEntry& insertPhrase=iPhraseIx->At(iPos.iPhraseElement); |
|
638 TInt insertPendingPos=(iPos.iPhraseElementOffset==insertPhrase.Length()) ? aPos : EInsertCharFormatReset; |
|
639 DoSplitPhraseL(insertPhrase,iPos.iPhraseElementOffset,current.iParaAttribs); // Ups iPhraseCount |
|
640 // |
|
641 // Insert the new paragraph. |
|
642 newPara.iParaAttribs=newParaAttribs; |
|
643 TRAPD(ret, |
|
644 iParaIx->InsertL(iPos.iParaElement+1,newPara)); // Inserts the new paraAttribsEntry record. |
|
645 if (ret!=KErrNone) |
|
646 { |
|
647 RemoveFromPhraseIx(iPos.iPhraseElement+1,1); // inserted by DoSplitPhraseL |
|
648 current.iParaAttribs->iPhraseCount--; |
|
649 User::Leave(ret); |
|
650 } |
|
651 |
|
652 iPendingNewPhrasePos=insertPendingPos; |
|
653 CleanupStack::Pop(); // newParaAttribs. All OK now |
|
654 GetCurrentRecords(current); // could be changed by InsertL() above |
|
655 // |
|
656 // Calculate new paraAttribs phrase counts. |
|
657 TInt remainder=(iPos.iPhraseElement+1)-iPos.iParaBasePhraseElement; |
|
658 TInt newPhraseCount=current.iParaAttribs->iPhraseCount-remainder; |
|
659 newParaAttribs->iPhraseCount=newPhraseCount; |
|
660 current.iParaAttribs->iPhraseCount=remainder; |
|
661 |
|
662 const CArrayFix<RPhraseAttribsEntry>& phraseIx=*iPhraseIx; |
|
663 TInt startPhrase=iPos.iPhraseElement+1; |
|
664 for (TInt ii=startPhrase; ii<startPhrase+newPhraseCount; ii++) |
|
665 { |
|
666 RPhraseAttribsEntry phrase=phraseIx[ii]; |
|
667 phrase.CharFormat()->SetBase(newCharBase); |
|
668 } |
|
669 // |
|
670 // The index now reflects the correct state. |
|
671 // Next, the efficiency thing - see if the new paras can share existing ones. |
|
672 if (newPhraseCount==1) |
|
673 Share(iParaIx->At(iPos.iParaElement+1),iPos.iParaBasePhraseElement+remainder); |
|
674 if (remainder==1) |
|
675 Share(iParaIx->At(iPos.iParaElement),iPos.iParaBasePhraseElement); |
|
676 } |
|
677 // Alter the length of the original paragraph and the new paragraph. |
|
678 TInt currentLength=current.iParaEntry->iLength; |
|
679 current.iParaEntry->iLength=iPos.iParaElementOffset; |
|
680 ((*iParaIx)[iPos.iParaElement+1]).iLength+=currentLength-current.iParaEntry->iLength; // Alters the length of the copy of aNewPara. |
|
681 } |
|
682 |
|
683 |
|
684 void CRichTextIndex::SetForDeleteL(TIndexDeleteInfo& aInfo,TInt aPos,TInt aLength) |
|
685 // |
|
686 { |
|
687 __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete. |
|
688 |
|
689 aInfo.iDeleteLength=aLength; |
|
690 // |
|
691 // Check for simple cases first |
|
692 DocumentChanged(); // clears internal position record. |
|
693 ScanToPosition(aPos,EScanToPositionAbsolute,&iLastUsed); |
|
694 TCurrentIndexRecords current; |
|
695 GetCurrentRecords(current); |
|
696 aInfo.iStartPara=iPos.iParaElement; |
|
697 aInfo.iEndPara=iPos.iParaElement; // default |
|
698 aInfo.iDeletePos=iPos; // default |
|
699 // |
|
700 TInt startParaLength=current.iParaEntry->iLength; |
|
701 TInt lengthRemainingInPara=startParaLength-iPos.iParaElementOffset; |
|
702 if (aLength<lengthRemainingInPara) |
|
703 {// Case is delete-from-paragraph |
|
704 aInfo.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph; |
|
705 return; |
|
706 } |
|
707 // |
|
708 ScanToPosition(aPos+aLength,EScanToPositionMatchLeft,&iLastUsed); // Forces endPara to be next para when just removing a para delimiter. |
|
709 aInfo.iEndPara=iPos.iParaElement; |
|
710 // if (iPos.iParaElementOffset==0) |
|
711 // {// Can use delete-paragraph |
|
712 // aInfo.iDeleteType=TIndexDeleteInfo::EDeleteParagraph; |
|
713 // return; |
|
714 // } |
|
715 // |
|
716 // Set for the general (leaving) delete. |
|
717 GetCurrentRecords(current); |
|
718 CParaAttribs* reclaimedEndPara=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry); // does not release share. |
|
719 TParaAttribsEntry* origEndParaEntry=current.iParaEntry; |
|
720 CParaAttribs* origParaAttribs=current.iParaAttribs; |
|
721 TInt endPosPhrase=iPos.iPhraseElement; |
|
722 if (reclaimedEndPara) |
|
723 origEndParaEntry->iParaAttribs=reclaimedEndPara; |
|
724 // Get start para info. |
|
725 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
726 GetCurrentRecords(current); |
|
727 CParaAttribs* reclaimedStartPara=NULL; |
|
728 TRAPD(ret, |
|
729 reclaimedStartPara=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry)); |
|
730 if (ret!=KErrNone) |
|
731 { |
|
732 if (reclaimedEndPara) |
|
733 { |
|
734 reclaimedEndPara->Release(); |
|
735 RemoveFromPhraseIx(endPosPhrase); |
|
736 origEndParaEntry->iParaAttribs=origParaAttribs; |
|
737 } |
|
738 User::Leave(ret); |
|
739 } |
|
740 if (reclaimedEndPara) |
|
741 origParaAttribs->Release(); // Release share on the original end para attribs |
|
742 if (reclaimedStartPara) |
|
743 {// Use the specific start para |
|
744 current.iParaAttribs->Release(); |
|
745 current.iParaEntry->iParaAttribs=reclaimedStartPara; |
|
746 ScanToPosition(aPos,EScanToPositionAbsolute); // Pick up reclaimed phrase. |
|
747 } |
|
748 aInfo.iDeletePos=iPos; // internal position of aPos after any reclaim |
|
749 // Note: iDeleteType can surely be made obsolete now? TPB 7/11/2000 |
|
750 aInfo.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph; |
|
751 |
|
752 /* |
|
753 * Pointer to memory allocated to 'reclaimedEndPara' is assigned to |
|
754 * 'origEndParaEntry->iParaAttribs' on line 706. The memory will be |
|
755 * released in CRichTextIndex's destructor. |
|
756 */ |
|
757 // coverity[memory_leak] |
|
758 } |
|
759 |
|
760 |
|
761 TBool CRichTextIndex::DeleteParagraph(TInt aPos,TInt aLength) |
|
762 // Remove aCount entire paragraphs from the text. |
|
763 // Leave-safe |
|
764 // Returns EFalse indicating that no paragraphs were merged together, |
|
765 // as a result of the delete action. |
|
766 // Does NOT preserve any zero-length/insert pending state. |
|
767 // |
|
768 { |
|
769 __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete. |
|
770 |
|
771 CancelInsertCharFormat(); |
|
772 ScanToPosition(aPos,EScanToPositionAbsolute,&iLastUsed); |
|
773 |
|
774 __ASSERT_DEBUG(iPos.iParaElementOffset==0,Panic(EDeleteParagraphInvalidStartValue)); |
|
775 |
|
776 TIndexDeleteInfo info; |
|
777 info.iDeleteType=TIndexDeleteInfo::EDeleteParagraph; |
|
778 info.iDeletePos=iPos; |
|
779 info.iStartPara=iPos.iParaElement; |
|
780 // |
|
781 TInt documentLength=iText.DocumentLength(); |
|
782 TInt pos=(aPos+aLength>documentLength |
|
783 ? documentLength |
|
784 : aPos+aLength); |
|
785 ScanToPosition(pos,EScanToPositionMatchLeft,&iLastUsed); // Forces endPara to be next para when just removing a para delimiter. |
|
786 |
|
787 info.iEndPara=iPos.iParaElement; |
|
788 info.iDeleteLength=aLength; |
|
789 |
|
790 DeleteNow(info); |
|
791 // do not want to call TidyAfterDelete() |
|
792 |
|
793 return EFalse; |
|
794 } |
|
795 |
|
796 |
|
797 |
|
798 void CRichTextIndex::DeleteFromParagraph(TInt aPos,TInt aLength) |
|
799 // Special case delete for removing content from within a single paragraph only. |
|
800 // Not to be used for deleting an entire paragraph or paragraphs. |
|
801 // Returns EFalse indicating that no paragraphs were merged together, |
|
802 // as a result of the delete action. |
|
803 // |
|
804 { |
|
805 __TEST_INVARIANT; // Do not need to RebalanceIndex(); part of defined behaviour for delete. |
|
806 |
|
807 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
808 |
|
809 #ifdef _DEBUG |
|
810 { |
|
811 TCurrentIndexRecords current; |
|
812 GetCurrentRecords(current); |
|
813 TInt startParaLength=current.iParaEntry->iLength; |
|
814 TInt lengthRemainingInPara=startParaLength-iPos.iParaElementOffset; |
|
815 |
|
816 __ASSERT_ALWAYS(aLength<lengthRemainingInPara,Panic(EDeleteFromParagraphInvalidRange)); |
|
817 } |
|
818 #endif |
|
819 |
|
820 TIndexDeleteInfo info; |
|
821 info.iDeleteLength=aLength; |
|
822 info.iStartPara=iPos.iParaElement; |
|
823 info.iEndPara=iPos.iParaElement; |
|
824 info.iDeletePos=iPos; |
|
825 info.iDeleteType=TIndexDeleteInfo::EDeleteFromParagraph; |
|
826 |
|
827 DoDeleteFromParagraph(info); |
|
828 |
|
829 __TEST_INVARIANT; |
|
830 } |
|
831 |
|
832 |
|
833 TBool CRichTextIndex::DoDeleteFromParagraph(const TIndexDeleteInfo& aInfo) |
|
834 // Delete content from *within* the boundary of a single paragraph only.0 |
|
835 // Returns EFalse indicating that no paragraphs were merged together, |
|
836 // as a result of the delete action. |
|
837 // |
|
838 { |
|
839 iPos=aInfo.iDeletePos; |
|
840 TInt length=aInfo.iDeleteLength; |
|
841 DeleteParagraphText(length); |
|
842 TidyAfterDelete(aInfo); |
|
843 |
|
844 return EFalse; |
|
845 } |
|
846 |
|
847 |
|
848 TBool CRichTextIndex::DeleteNow(TIndexDeleteInfo& aInfo) |
|
849 // Deletes index data corresponding the info argument. |
|
850 // Returns ETrue is 2 paragraphs are merged as a result of the delete, otherwise returns false. |
|
851 // |
|
852 { |
|
853 iPos=aInfo.iDeletePos; |
|
854 TCurrentIndexRecords current; |
|
855 GetCurrentRecords(current); |
|
856 TInt leftToDelete=aInfo.iDeleteLength; |
|
857 TInt charsLeftInPara=(current.iParaEntry->iLength)-(iPos.iParaElementOffset); |
|
858 TBool doParaMerge=((iPos.iPhraseElement>0 || iPos.iPhraseElementOffset>0) && leftToDelete>=charsLeftInPara); |
|
859 // ETrue if the 1st para has content remaining but no paragraph delimiter. |
|
860 // |
|
861 TBool firstParaRemoved=(FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0 && aInfo.iDeleteLength>=current.iParaEntry->iLength); |
|
862 // ETrue if the 1st para has been *wholly* deleted. |
|
863 // |
|
864 DeleteParagraphText(leftToDelete); // Delete range will be in a minimum of 1 paragraph. |
|
865 if (aInfo.iStartPara<aInfo.iEndPara) |
|
866 {// The delete range crosses paragraph boundaries. |
|
867 for (TInt currentPara=aInfo.iStartPara+1;currentPara<=aInfo.iEndPara;currentPara++) |
|
868 { |
|
869 ScanToPosition(aInfo.iDeletePos.iDocPos,EScanToPositionAbsolute); |
|
870 DeleteParagraphText(leftToDelete); |
|
871 } |
|
872 } |
|
873 // Now tidy up |
|
874 if (doParaMerge && !firstParaRemoved) |
|
875 {// Merge the 2 paras together. |
|
876 TParaAttribsEntry* paraEntry=&(*iParaIx)[aInfo.iStartPara]; |
|
877 TParaAttribsEntry* paraEntryFollowing=&(*iParaIx)[aInfo.iStartPara+1]; |
|
878 paraEntryFollowing->iLength+=paraEntry->iLength; // Extend length of remaining para. |
|
879 paraEntryFollowing->iParaAttribs->iPhraseCount+=paraEntry->iParaAttribs->iPhraseCount; // Extend phrase count |
|
880 paraEntry->iParaAttribs->Release(); |
|
881 iParaIx->Delete(aInfo.iStartPara); |
|
882 } |
|
883 if (aInfo.iDeleteType!=TIndexDeleteInfo::EDeleteParagraph) |
|
884 TidyAfterDelete(aInfo); |
|
885 |
|
886 __TEST_INVARIANT; |
|
887 return doParaMerge; |
|
888 } |
|
889 |
|
890 |
|
891 void CRichTextIndex::TidyAfterDelete(const TIndexDeleteInfo& aInfo) |
|
892 // |
|
893 // |
|
894 { |
|
895 MergePhrases(aInfo.iDeletePos.iDocPos); // Alters internal position record. |
|
896 TCurrentIndexRecords current; |
|
897 GetCurrentRecords(current); // So must get records again. |
|
898 if (!current.iParaAttribs->IsShared()) |
|
899 {// May be able to reclaim a share from this *specific* record |
|
900 CParaAttribs* sharedParaAttribs=RequestShare(iPos); |
|
901 if (sharedParaAttribs!=NULL && current.iParaAttribs!=sharedParaAttribs) |
|
902 {// Use this shared record |
|
903 current.iParaAttribs->Release(); |
|
904 RemoveFromPhraseIx(iPos.iPhraseElement); |
|
905 current.iParaEntry->iParaAttribs=sharedParaAttribs; |
|
906 } |
|
907 } |
|
908 } |
|
909 |
|
910 |
|
911 void CRichTextIndex::Normalize(TInt aPos) |
|
912 // |
|
913 { |
|
914 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
915 NormalizeNow(iPos); |
|
916 |
|
917 __TEST_INVARIANT; |
|
918 } |
|
919 |
|
920 |
|
921 void CRichTextIndex::NormalizeNow(const TLogicalPosition& aNormalizePos) |
|
922 // |
|
923 { |
|
924 CParaAttribs* currentParaAttribs=(*iParaIx)[aNormalizePos.iParaElement].iParaAttribs; |
|
925 if (!currentParaAttribs->IsShared()) |
|
926 { |
|
927 CParaAttribs* sharedParaAttribs=RequestShare(iPos); |
|
928 if (sharedParaAttribs!=NULL && currentParaAttribs!=sharedParaAttribs) |
|
929 {// We must have been given a share on something already in the shared list. Dump current stuff. |
|
930 currentParaAttribs->Release(); |
|
931 (*iParaIx)[aNormalizePos.iParaElement].iParaAttribs=sharedParaAttribs; |
|
932 RemoveFromPhraseIx(aNormalizePos.iParaBasePhraseElement); |
|
933 } |
|
934 } |
|
935 } |
|
936 |
|
937 |
|
938 CParaAttribs* CRichTextIndex::ReserveCellLC() |
|
939 // Returns a handle to a newly created CParaAttribs object. This may be used |
|
940 // during a call to GetParaAttribsL() as a pre-allocated cell, thus ensuring |
|
941 // that the call cannot possibly leave. |
|
942 // ASSUMES: that the internal position record has been set correctly. |
|
943 // |
|
944 { |
|
945 CParaAttribs* reservedCell=ReserveCellL(); |
|
946 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reservedCell)); |
|
947 return reservedCell; |
|
948 } |
|
949 |
|
950 |
|
951 CParaAttribs* CRichTextIndex::ReserveCellL() |
|
952 // Returns a handle to a newly created CParaAttribs object. This may be used |
|
953 // during a call to GetParaAttribsL() as a pre-allocated cell, thus ensuring |
|
954 // that the call cannot possibly leave. |
|
955 // ASSUMES: that the internal position record has been set correctly. |
|
956 // |
|
957 { |
|
958 TCurrentIndexRecords current; |
|
959 GetCurrentRecords(current); |
|
960 const CParaAttribs& paraAttribs=*current.iParaAttribs; |
|
961 CParaFormatLayer* paraLayer=paraAttribs.iParaFormat; |
|
962 CCharFormatLayer* charLayer=(paraAttribs.IsShared()) |
|
963 ? paraAttribs.iCharFormat |
|
964 : (*iPhraseIx)[iPos.iPhraseElement].CharFormat(); |
|
965 CParaAttribs* reservedCell=CParaAttribs::NewL(paraLayer,charLayer); |
|
966 return reservedCell; |
|
967 } |
|
968 |
|
969 |
|
970 TBool CRichTextIndex::DeleteParagraphText(TInt& aLength) |
|
971 // Called once for each paragraph that's included in the delete range. |
|
972 // Assumes the internal position record has already been set correctly. |
|
973 // The delete range may cover: (1) The entire paragraph - so just destroy the paragraph, |
|
974 // (2i) At least a portion of a single phrase, and possibly |
|
975 // (2ii) 0..n whole contiguous phrases, and possibly |
|
976 // (2iii) a trailing partial phrase. |
|
977 // Returns ETrue if the full paragraph is deleted, otherwise returns EFalase. |
|
978 // |
|
979 { |
|
980 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
981 if (FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0 && aLength>=current.iParaEntry->iLength) |
|
982 {// The entire paragraph needs to be deleted. |
|
983 aLength-=current.iParaEntry->iLength; |
|
984 if (!current.iParaAttribs->IsShared()) |
|
985 RemoveFromPhraseIx(iPos.iParaBasePhraseElement,current.iParaAttribs->iPhraseCount); |
|
986 current.iParaAttribs->Release(); |
|
987 iParaIx->Delete(iPos.iParaElement); |
|
988 return ETrue; |
|
989 } |
|
990 TInt deleteFromPhrase=CurrentPhraseLength()-iPos.iPhraseElementOffset; |
|
991 TInt maxPhrase=current.iParaAttribs->PhraseCount(); |
|
992 TInt currentPhrase=(iPos.iPhraseElement-iPos.iParaBasePhraseElement); |
|
993 while (currentPhrase<maxPhrase) |
|
994 { |
|
995 TInt deletable=Min(deleteFromPhrase,aLength); |
|
996 current.iParaEntry->iLength-=deletable; // Adjust the paragraph length. |
|
997 if (current.iPhrase && deletable>=CurrentPhraseLength()) |
|
998 {// Remove the now empty phrase from the phrase index. |
|
999 RemoveFromPhraseIx(iPos.iPhraseElement); |
|
1000 current.iParaAttribs->iPhraseCount--; |
|
1001 } |
|
1002 else if (current.iPhrase) |
|
1003 {// Adjust phrase length and move onto the next phrase. |
|
1004 current.iPhrase->AdjustLength(-deletable); |
|
1005 iPos.iPhraseElement++; |
|
1006 iPos.iPhraseElementOffset=0; |
|
1007 } |
|
1008 currentPhrase++; |
|
1009 aLength-=deletable; |
|
1010 if(aLength==0) |
|
1011 break; // Nothing left to delete in this paragraph. |
|
1012 // Get the data for the next phrase. |
|
1013 GetCurrentRecords(current); |
|
1014 deleteFromPhrase=CurrentPhraseLength(); |
|
1015 } |
|
1016 return EFalse; |
|
1017 } |
|
1018 |
|
1019 TBool CRichTextIndex::InsertCharFormatIsActive() |
|
1020 { |
|
1021 return iPendingNewPhrasePos != EInsertCharFormatReset; |
|
1022 } |
|
1023 |
|
1024 /** Sets an *InsertPending* state, where format has been inserted into the |
|
1025 text, but no content has yet been inserted. This *state* is cancelled by cursor |
|
1026 movement etc. Split the current phrase at aPos (if necessary) and insert a zero |
|
1027 length phrase, ready to accept the pending content of the specified format. |
|
1028 */ |
|
1029 void CRichTextIndex::SetInsertCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos) |
|
1030 { |
|
1031 __ASSERT_ALWAYS(!InsertCharFormatIsActive() || aPos==iPendingNewPhrasePos, |
|
1032 Panic(ESetInsertCharFormatIntegrityErr)); |
|
1033 if (InsertCharFormatIsActive()) |
|
1034 UpdateInsertCharFormatL(aFormat, aMask); |
|
1035 else |
|
1036 NewInsertCharFormatL(aFormat, aMask, aPos); |
|
1037 } |
|
1038 |
|
1039 void CRichTextIndex::NewInsertCharFormatL(const TCharFormatX& aFormat, |
|
1040 const TCharFormatXMask& aMask, TInt aPos) |
|
1041 { |
|
1042 __ASSERT_ALWAYS(!InsertCharFormatIsActive(), |
|
1043 Panic(ESetInsertCharFormatIntegrityErr)); |
|
1044 ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
1045 TCurrentIndexRecords current; |
|
1046 GetCurrentRecords(current); |
|
1047 CCharFormatLayer* basedOn; |
|
1048 TCharFormatX applyFormat=aFormat; |
|
1049 TCharFormatXMask applyMask=aMask; |
|
1050 GetPhraseFormat(current,applyFormat,applyMask,basedOn); // Inherit phrase attributes to the left, over what is present. |
|
1051 TBool origParaAttribsShared=current.iParaAttribs->IsShared(); |
|
1052 if (origParaAttribsShared) |
|
1053 {// Current paraAttribs is shared. |
|
1054 iRollbackParaAttribsHandle=current.iParaAttribs; |
|
1055 current.iParaEntry->iParaAttribs=RequestReclaimShareL(current.iParaAttribs,current.iParaEntry); // Does not release share. |
|
1056 ScanToPosition(aPos,EScanToPositionMatchLeft); // Pick up reclaimed phrase. |
|
1057 } // Now current.iParaAttribs has specific character formatting - guaranteed. |
|
1058 GetCurrentRecords(current); |
|
1059 TRAPD(ret, DoNewInsertCharFormatL(applyFormat, applyMask, |
|
1060 basedOn, current.iParaAttribs)); |
|
1061 if (ret!=KErrNone) |
|
1062 {// Rollback as if this function call never happened. |
|
1063 if (origParaAttribsShared) |
|
1064 {// Revert back to sharing the original. |
|
1065 current.iParaAttribs->Release(); |
|
1066 RemoveFromPhraseIx(iPos.iPhraseElement); |
|
1067 current.iParaEntry->iParaAttribs=iRollbackParaAttribsHandle; |
|
1068 } |
|
1069 else |
|
1070 {// Restore the original phrase index. |
|
1071 if (PhraseSplit()) |
|
1072 MergePhrases(aPos); |
|
1073 } |
|
1074 User::LeaveNoMemory(); |
|
1075 } |
|
1076 iPendingNewPhrasePos=aPos; |
|
1077 } |
|
1078 |
|
1079 void CRichTextIndex::UpdateInsertCharFormatL(const TCharFormatX& aFormat, |
|
1080 const TCharFormatXMask& aMask) |
|
1081 { |
|
1082 CCharFormatLayer* currentLayer = GetCurrentInsertCharFormat(); |
|
1083 CCharFormatLayer* newLayer = CCharFormatLayer::NewCopyBaseL(currentLayer); |
|
1084 CleanupStack::PushL(newLayer); |
|
1085 newLayer->SetL(aFormat, aMask); |
|
1086 currentLayer->Swap(*newLayer); |
|
1087 CleanupStack::PopAndDestroy(newLayer); |
|
1088 } |
|
1089 |
|
1090 CCharFormatLayer* CRichTextIndex::GetCurrentInsertCharFormat() |
|
1091 { |
|
1092 __ASSERT_DEBUG(InsertCharFormatIsActive(), |
|
1093 Panic(ESetInsertCharFormatIntegrityErr)); |
|
1094 ScanToPosition(iPendingNewPhrasePos,EScanToPositionMatchLeft); |
|
1095 TCurrentIndexRecords current; |
|
1096 GetCurrentRecords(current); |
|
1097 __ASSERT_DEBUG((*iPhraseIx)[iPos.iPhraseElement].Length() == 0, |
|
1098 Panic(ESetInsertCharFormatIntegrityErr)); |
|
1099 return (*iPhraseIx)[iPos.iPhraseElement].CharFormat(); |
|
1100 } |
|
1101 |
|
1102 void CRichTextIndex::DoNewInsertCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask, |
|
1103 CCharFormatLayer* aBasedOn,CParaAttribs* aParaAttribs) |
|
1104 { |
|
1105 SplitPhraseL(iPos.iPhraseElement,iPos.iPhraseElementOffset,aParaAttribs); |
|
1106 CCharFormatLayer* layer=CCharFormatLayer::NewL(); |
|
1107 layer->SetBase(aBasedOn); // must be done before the SetL(). |
|
1108 CleanupStack::PushL(layer); |
|
1109 layer->SetL(aFormat,aMask); |
|
1110 RPhraseAttribsEntry pendingNewPhrase(layer); |
|
1111 TInt pendingNewPhraseElement=(FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0) |
|
1112 ?iPos.iParaBasePhraseElement:iPos.iPhraseElement+1; |
|
1113 iPhraseIx->InsertL(pendingNewPhraseElement,pendingNewPhrase); |
|
1114 CleanupStack::Pop(); |
|
1115 aParaAttribs->iPhraseCount++; |
|
1116 } |
|
1117 |
|
1118 |
|
1119 void CRichTextIndex::RebalanceIndex() |
|
1120 // Returns the index to a good state, by releasing the extra share taken on the paraAttribs |
|
1121 // |
|
1122 { |
|
1123 if (iRollbackParaAttribsHandle) |
|
1124 { |
|
1125 // ASSERT: The specified para attribs is indeed in the share list. |
|
1126 __ASSERT_ALWAYS(iRollbackParaAttribsHandle->IsShared(),Panic(EParaAttribsNotInSharedList)); |
|
1127 iRollbackParaAttribsHandle->Release(); |
|
1128 iRollbackParaAttribsHandle=NULL; |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 /** Cancels the transitory state where a specified character format is applied |
|
1133 on top of any inherited formatting. eg, when bold is on. Cancel when: (1) the |
|
1134 text position is altered. (2) the first character (or picture) has been |
|
1135 inserted following the setting of this state. If a zero length phrase is |
|
1136 removed OR has content entered into it, the newly abutting phrases are checked |
|
1137 to see if they can be merged. Then a request share of this para is issued. |
|
1138 */ |
|
1139 void CRichTextIndex::CancelInsertCharFormat() |
|
1140 { |
|
1141 if (InsertCharFormatIsActive()) |
|
1142 { |
|
1143 TBool isDeleted = DeleteInsertCharFormat(); |
|
1144 ConsolidateAt(iPendingNewPhrasePos, isDeleted? |
|
1145 EPositionOnly : EFollowingPhrase); |
|
1146 iPendingNewPhrasePos = EInsertCharFormatReset; |
|
1147 } |
|
1148 } |
|
1149 |
|
1150 /** Attempts to delete a zero-length phrase at the insert character format |
|
1151 position. Does not delete any phrase of non-zero length. |
|
1152 @pre The insert character format must be active |
|
1153 @return ETrue if a zero-length phrase was deleted. |
|
1154 */ |
|
1155 TBool CRichTextIndex::DeleteInsertCharFormat() |
|
1156 { |
|
1157 __ASSERT_DEBUG(InsertCharFormatIsActive(), User::Invariant()); |
|
1158 ScanToPosition(iPendingNewPhrasePos,EScanToPositionMatchLeft); |
|
1159 TCurrentIndexRecords current; |
|
1160 GetCurrentRecords(current); |
|
1161 if (current.iPhrase && current.iPhrase->Length() == 0) |
|
1162 { |
|
1163 RemoveFromPhraseIx(iPos.iPhraseElement); |
|
1164 current.iParaAttribs->iPhraseCount--; // Para has 1 less phrase in it now. |
|
1165 return ETrue; |
|
1166 } |
|
1167 return EFalse; |
|
1168 } |
|
1169 |
|
1170 /** Attempts to merge phrases and share paragraphs. |
|
1171 @param aPosition |
|
1172 Phrase boundary here is merged if possible, paragraph here is shared if |
|
1173 possible. |
|
1174 @param aPositionOrPhrase |
|
1175 If EPositionOnly the phrases either side of aPosition are considered for merging. If EFollowingPhrase, |
|
1176 the end of the phrase following aPosition is also considered. |
|
1177 */ |
|
1178 void CRichTextIndex::ConsolidateAt(TInt aPosition, |
|
1179 TPositionOrPhrase aPositionOrPhrase) |
|
1180 { |
|
1181 ScanToPosition(aPosition, EScanToPositionAbsolute); |
|
1182 TCurrentIndexRecords current; |
|
1183 GetCurrentRecords(current); |
|
1184 if (!current.iPhrase) |
|
1185 return; |
|
1186 |
|
1187 TInt length = current.iPhrase->Length(); |
|
1188 MergePhrases(aPosition); |
|
1189 if (aPositionOrPhrase == EFollowingPhrase) |
|
1190 { |
|
1191 ScanToPosition(aPosition, EScanToPositionAbsolute); |
|
1192 GetCurrentRecords(current); |
|
1193 if (current.iPhrase) |
|
1194 MergePhrases(aPosition + length); |
|
1195 } |
|
1196 Normalize(aPosition); |
|
1197 RebalanceIndex(); |
|
1198 } |
|
1199 |
|
1200 TBool CRichTextIndex::DelSetInsertCharFormatL(TInt aPos,TInt aLength) |
|
1201 // Delete aLength characters, commencing at, and including, aPos. |
|
1202 // Adds value by the following behaviour: |
|
1203 // If aPos is on a phrase boundary, then remember temporarily the phrase format. |
|
1204 // This is applied to any content that is immediately inserted. |
|
1205 // |
|
1206 { |
|
1207 __TEST_INVARIANT; |
|
1208 |
|
1209 CancelInsertCharFormat(); |
|
1210 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
1211 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
1212 if ((!current.iParaAttribs->IsShared()) && iPos.iPhraseElementOffset==0) |
|
1213 {// aPos is on phrase boundary so SetState. |
|
1214 TCharFormatX format; |
|
1215 TCharFormatXMask mask; |
|
1216 CCharFormatLayer* charBase; |
|
1217 GetPhraseFormat(current,format,mask,charBase); |
|
1218 SetInsertCharFormatL(format,mask,aPos); |
|
1219 } |
|
1220 TIndexDeleteInfo deleteInfo; |
|
1221 SetForDeleteL(deleteInfo,aPos,aLength); |
|
1222 TBool parasMerged=DeleteNow(deleteInfo); |
|
1223 |
|
1224 __TEST_INVARIANT; |
|
1225 return parasMerged; |
|
1226 } |
|
1227 |
|
1228 |
|
1229 void CRichTextIndex::ApplyParaFormatL(const CParaFormat* aFormat,const TParaFormatMask& aMask,TInt aPos,TInt aLength) |
|
1230 // Applies the specified format attributes to the paragraphs covering character position aPos to aPos+aLength-1. |
|
1231 // Preserves any attributes that are currently stored in this layer. |
|
1232 // If the specified para(s) is in the shared list, a new shared para of the desired format must be created, |
|
1233 // and the usage count of the original decremented. |
|
1234 // |
|
1235 { |
|
1236 __TEST_INVARIANT; |
|
1237 |
|
1238 TInt offset=(aLength==0)?0 :-1; |
|
1239 TInt endPara=OwningParagraph(aPos+(aLength+offset)); |
|
1240 TInt paraItem=OwningParagraph(aPos); |
|
1241 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
1242 CParaFormat* pf=CParaFormat::NewL(*aFormat); // preserve the desired tablist. |
|
1243 CleanupStack::PushL(pf); |
|
1244 for (;paraItem<=endPara;paraItem++) |
|
1245 {// For each paragraph, apply the specified format. |
|
1246 TParaFormatMask applyMask=aMask; |
|
1247 CParaAttribs* currentParaAttribs=(*iParaIx)[paraItem].iParaAttribs; |
|
1248 TBool shared=currentParaAttribs->IsShared(); |
|
1249 if (!shared) |
|
1250 { |
|
1251 currentParaAttribs->iParaFormat->SenseL(pf,applyMask); |
|
1252 currentParaAttribs->iParaFormat->SetL(pf,applyMask); |
|
1253 } |
|
1254 else |
|
1255 {// Must create a new shared para attribs of the specified format |
|
1256 // Make a new para format layer |
|
1257 currentParaAttribs->iParaFormat->SenseL(pf,applyMask); |
|
1258 CParaFormatLayer* newParaLayer=CParaFormatLayer::NewL(pf,applyMask); |
|
1259 newParaLayer->SetBase(currentParaAttribs->iParaFormat->SenseBase()); |
|
1260 CleanupStack::PushL(newParaLayer); |
|
1261 // Make a new char format layer |
|
1262 CCharFormatLayer* newCharLayer=CCharFormatLayer::NewL(currentParaAttribs->iCharFormat); |
|
1263 newCharLayer->SetBase(currentParaAttribs->iCharFormat->SenseBase()); |
|
1264 CleanupStack::PushL(newCharLayer); |
|
1265 // |
|
1266 CParaAttribs* sharedParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer); |
|
1267 CleanupStack::PopAndDestroy(2); |
|
1268 if (sharedParaAttribs) |
|
1269 (*iParaIx)[paraItem].iParaAttribs=sharedParaAttribs; |
|
1270 currentParaAttribs->Release(); |
|
1271 } |
|
1272 } |
|
1273 CleanupStack::PopAndDestroy(); // pf |
|
1274 __TEST_INVARIANT; |
|
1275 } |
|
1276 |
|
1277 |
|
1278 void CRichTextIndex::ApplyParagraphStyleL(const CParagraphStyle& aStyle,TInt aPos,TInt aLength, |
|
1279 const CCharFormatLayer* aCharStyleNormal,CParagraphStyle::TApplyParaStyleMode aMode) |
|
1280 // Applies the specified paragraph style to the paragraphs covering |
|
1281 // character positions aPos to aPos+aLength-1. |
|
1282 // Alters the specific formatting of the covered paragraphs as specified by aMode. |
|
1283 // |
|
1284 { |
|
1285 __TEST_INVARIANT; |
|
1286 |
|
1287 TInt offset=(aLength==0)?0 :-1; |
|
1288 TInt endPara=OwningParagraph(aPos+(aLength+offset)); |
|
1289 TInt paraItem=OwningParagraph(aPos); |
|
1290 TInt paragraphBasePhrase=iPos.iParaBasePhraseElement; |
|
1291 TCurrentIndexRecords current; |
|
1292 GetCurrentRecords(current); |
|
1293 for (;paraItem<=endPara;paraItem++) |
|
1294 {// For each paragraph, apply the specified style |
|
1295 CParaAttribs& currentParaAttribs=*(*iParaIx)[paraItem].iParaAttribs; |
|
1296 TBool shared=currentParaAttribs.IsShared(); |
|
1297 TUid type=aStyle.Type(); |
|
1298 if (!shared) |
|
1299 { |
|
1300 currentParaAttribs.iParaFormat->SetBase(&aStyle); |
|
1301 TInt phraseCount=currentParaAttribs.PhraseCount(); |
|
1302 for (TInt phraseItem=0;phraseItem<phraseCount;phraseItem++) |
|
1303 { |
|
1304 CCharFormatLayer& charLayer=*(*iPhraseIx)[paragraphBasePhrase+phraseItem].CharFormat(); |
|
1305 if (type==KNormalParagraphStyleUid) |
|
1306 charLayer.SetBase(aCharStyleNormal); |
|
1307 else |
|
1308 charLayer.SetBase(aStyle.CharFormatLayer()); |
|
1309 ModifySpecificFormatting(*currentParaAttribs.iParaFormat,charLayer,aMode); |
|
1310 } |
|
1311 paragraphBasePhrase+=phraseCount; |
|
1312 } |
|
1313 else |
|
1314 {// Must create a new shared para attribs of the same format, but a different based on link |
|
1315 // Make a new para format layer |
|
1316 CParaFormatLayer* newParaLayer=NULL; |
|
1317 if (aMode==CParagraphStyle::ERetainNoSpecificFormats || aMode==CParagraphStyle::ERetainSpecificCharFormat) |
|
1318 newParaLayer=CParaFormatLayer::NewL(); |
|
1319 else |
|
1320 newParaLayer=CParaFormatLayer::NewL(currentParaAttribs.iParaFormat); |
|
1321 newParaLayer->SetBase(&aStyle); |
|
1322 CleanupStack::PushL(newParaLayer); |
|
1323 // |
|
1324 // Make a new char format layer |
|
1325 CCharFormatLayer* newCharLayer=NULL; |
|
1326 if (aMode==CParagraphStyle::ERetainNoSpecificFormats || aMode==CParagraphStyle::ERetainSpecificParaFormat) |
|
1327 newCharLayer=CCharFormatLayer::NewL(); |
|
1328 else |
|
1329 newCharLayer=CCharFormatLayer::NewL(currentParaAttribs.iCharFormat); |
|
1330 if (type==KNormalParagraphStyleUid) |
|
1331 newCharLayer->SetBase(aCharStyleNormal); |
|
1332 else |
|
1333 newCharLayer->SetBase(aStyle.CharFormatLayer()); |
|
1334 CleanupStack::PushL(newCharLayer); |
|
1335 // |
|
1336 (*iParaIx)[paraItem].iParaAttribs=GetParaAttribsL(newParaLayer,newCharLayer); |
|
1337 CleanupStack::PopAndDestroy(2); |
|
1338 currentParaAttribs.Release(); |
|
1339 } |
|
1340 } |
|
1341 } |
|
1342 |
|
1343 |
|
1344 void CRichTextIndex::ModifySpecificFormatting(CParaFormatLayer& aPl,CCharFormatLayer& aCl,CParagraphStyle::TApplyParaStyleMode aMode) |
|
1345 // |
|
1346 // |
|
1347 { |
|
1348 switch(aMode) |
|
1349 { |
|
1350 case(CParagraphStyle::ERetainNoSpecificFormats): |
|
1351 aPl.Reset(); |
|
1352 aCl.Reset(); |
|
1353 break; |
|
1354 case(CParagraphStyle::ERetainSpecificParaFormat): |
|
1355 aCl.Reset(); |
|
1356 break; |
|
1357 case(CParagraphStyle::ERetainSpecificCharFormat): |
|
1358 aPl.Reset(); |
|
1359 break; |
|
1360 case(CParagraphStyle::ERetainAllSpecificFormats): |
|
1361 default: |
|
1362 break; |
|
1363 } |
|
1364 } |
|
1365 |
|
1366 |
|
1367 /* |
|
1368 For every paragraph in the document: (i) if it uses the style aFrom, make it use the style aTo, |
|
1369 or the global style if aTo is null; (ii) if any phrase in the paragraph has a character format |
|
1370 based on the character format owned by aFrom, change it so that it is based on the character |
|
1371 format owned by aTo, or the global character format if aTo is null. |
|
1372 |
|
1373 The action described in (ii) should only occur for an 'orphaned' character insertion format; that is |
|
1374 an insertion format left after deletion of a block in a certain style that is itself then deleted. |
|
1375 */ |
|
1376 void CRichTextIndex::NotifyStyleChangedL(const CParagraphStyle* aTo,const CParagraphStyle* aFrom, |
|
1377 const CParaFormatLayer& aGlobalParaFormatLayer, |
|
1378 const CCharFormatLayer& aGlobalCharFormatLayer) |
|
1379 { |
|
1380 __TEST_INVARIANT; |
|
1381 |
|
1382 TInt paraCount=ParagraphCount(); |
|
1383 TInt currentPhrase = 0; |
|
1384 const CCharFormatLayer* oldCharFormatLayer = aFrom->CharFormatLayer(); |
|
1385 const CParaFormatLayer* newParFormatLayer = aTo ? aTo : &aGlobalParaFormatLayer; |
|
1386 const CCharFormatLayer* newCharFormatLayer = aTo ? aTo->CharFormatLayer() : &aGlobalCharFormatLayer; |
|
1387 for (TInt paraItem = 0;paraItem < paraCount; paraItem++) |
|
1388 { |
|
1389 TParaAttribsEntry* currentPara = &(*iParaIx)[paraItem]; |
|
1390 CParaAttribs* currentParaAttribs = currentPara->iParaAttribs; |
|
1391 |
|
1392 TBool changeParStyleBase = currentParaAttribs->iParaFormat->SenseBase() == aFrom; |
|
1393 if (!currentParaAttribs->IsShared()) |
|
1394 { |
|
1395 if (changeParStyleBase) |
|
1396 currentParaAttribs->iParaFormat->SetBase(newParFormatLayer); |
|
1397 TInt phraseCount = currentParaAttribs->PhraseCount(); |
|
1398 for (TInt phraseItem = currentPhrase; phraseItem < (currentPhrase + phraseCount); phraseItem++) |
|
1399 { |
|
1400 CCharFormatLayer* charFormat = (*iPhraseIx)[phraseItem].CharFormat(); |
|
1401 if (charFormat->SenseBase() == oldCharFormatLayer) |
|
1402 charFormat->SetBase(newCharFormatLayer); |
|
1403 } |
|
1404 currentPhrase += phraseCount; |
|
1405 } |
|
1406 else |
|
1407 { // Maintain the shared list reference |
|
1408 CParaAttribs* resultantParaAttribs = CParaAttribs::NewL(currentParaAttribs); |
|
1409 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,resultantParaAttribs)); |
|
1410 if (changeParStyleBase) |
|
1411 resultantParaAttribs->iParaFormat->SetBase(newParFormatLayer); |
|
1412 if (resultantParaAttribs->iCharFormat->SenseBase() == oldCharFormatLayer) |
|
1413 resultantParaAttribs->iCharFormat->SetBase(newCharFormatLayer); |
|
1414 CParaAttribs* shared = RequestShareL(resultantParaAttribs); // will return a non-NULL handle |
|
1415 __ASSERT_DEBUG(shared,Panic(EDebug)); |
|
1416 currentParaAttribs->Release(); |
|
1417 iSharedParaQueHead.AddLast(*resultantParaAttribs); // allows correct release of cell. |
|
1418 CleanupStack::PopAndDestroy(); |
|
1419 currentPara->iParaAttribs = shared; |
|
1420 } |
|
1421 } |
|
1422 |
|
1423 __TEST_INVARIANT; |
|
1424 } |
|
1425 |
|
1426 |
|
1427 const CParaFormatLayer* CRichTextIndex::ParagraphStyle(TBool& aStyleChangesOverRange, |
|
1428 TInt aPos, |
|
1429 TInt aLength)const |
|
1430 // Return the handle of the first paragraph style encountered in the specified range. |
|
1431 // Set aStyleChangesOverRange to ETrue, if different paragraph styles are encountered |
|
1432 // across the specified range, otherwise set it to EFalse. |
|
1433 // |
|
1434 { |
|
1435 __TEST_INVARIANT; |
|
1436 |
|
1437 aStyleChangesOverRange=EFalse; |
|
1438 CParaFormatLayer* style=NULL; |
|
1439 TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos); |
|
1440 TInt offset=(aLength==0)?0 :-1; |
|
1441 TInt endPara=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos+(aLength+offset)); |
|
1442 style=(CParaFormatLayer*)(*iParaIx)[para].iParaAttribs->iParaFormat->SenseBase(); |
|
1443 ++para; |
|
1444 for (;para<=endPara;para++) |
|
1445 { |
|
1446 CParaFormatLayer* nextStyle=(CParaFormatLayer*)(*iParaIx)[para].iParaAttribs->iParaFormat->SenseBase(); |
|
1447 if (nextStyle!=style) |
|
1448 aStyleChangesOverRange=ETrue; |
|
1449 } |
|
1450 |
|
1451 __TEST_INVARIANT; |
|
1452 return style; |
|
1453 } |
|
1454 |
|
1455 |
|
1456 void CRichTextIndex::SplitPhraseL(TInt aPhrase,TInt anOffset,RPhraseAttribsEntry& aPhraseAttribs,CParaAttribs& aParaAttribs) |
|
1457 { |
|
1458 __ASSERT_DEBUG(anOffset>0 && anOffset<aPhraseAttribs.Length(),User::Invariant()); |
|
1459 // |
|
1460 CCharFormatLayer* charLayer=CCharFormatLayer::NewCopyBaseL(aPhraseAttribs.CharFormat()); |
|
1461 CleanupStack::PushL(charLayer); |
|
1462 iPhraseIx->InsertL(aPhrase+1,RPhraseAttribsEntry(charLayer,aPhraseAttribs.Length()-anOffset)); |
|
1463 CleanupStack::Pop(); |
|
1464 // |
|
1465 // InsertL() has invalidated the phrase index. |
|
1466 iPhraseIx->At(aPhrase).SetLength(anOffset); // Adjust the length of the orginal phrase |
|
1467 aParaAttribs.iPhraseCount++; |
|
1468 } |
|
1469 |
|
1470 |
|
1471 TBool CRichTextIndex::MergePhrases(TInt aPhrase,RPhraseAttribsEntry& aPhraseAttribs,CParaAttribs& aParaAttribs) |
|
1472 { |
|
1473 RPhraseAttribsEntry& prevPhrase=iPhraseIx->At(aPhrase-1); |
|
1474 if (!aPhraseAttribs.IsIdentical(prevPhrase)) |
|
1475 return EFalse; |
|
1476 // Merge the abutting phrases together. |
|
1477 prevPhrase.AdjustLength(aPhraseAttribs.Length()); // Extend the remaining phrase |
|
1478 RemoveFromPhraseIx(aPhrase); // Free the resources taken by the redundant phrase |
|
1479 aParaAttribs.iPhraseCount--; |
|
1480 return ETrue; |
|
1481 } |
|
1482 |
|
1483 |
|
1484 void CRichTextIndex::Share(TParaAttribsEntry& aParaEntry,TInt aPhrase) |
|
1485 // |
|
1486 // aParaEntry is not shared and can be (phrase count 1), aPhrase is the single phrase element |
|
1487 // |
|
1488 { |
|
1489 CParaAttribs* paraAttribs=aParaEntry.iParaAttribs; |
|
1490 __ASSERT_DEBUG(paraAttribs->iPhraseCount==1,User::Invariant()); |
|
1491 |
|
1492 RPhraseAttribsEntry& phraseAttribs=iPhraseIx->At(aPhrase); |
|
1493 __ASSERT_DEBUG(!phraseAttribs.IsPicturePhrase(),User::Invariant()); |
|
1494 |
|
1495 CParaAttribs* share=GetParaAttribs(paraAttribs,*phraseAttribs.CharFormat()); |
|
1496 if (share!=paraAttribs) |
|
1497 { // re-use an existing share, so release the current attribs |
|
1498 paraAttribs->Release(); |
|
1499 phraseAttribs.Discard(); |
|
1500 aParaEntry.iParaAttribs=share; |
|
1501 } |
|
1502 iPhraseIx->Delete(aPhrase); |
|
1503 } |
|
1504 |
|
1505 |
|
1506 void CRichTextIndex::ApplyCharFormatCleanup(TAny* aPtr) |
|
1507 // CLeanup function for ApplyCharFormatL() |
|
1508 // |
|
1509 {REINTERPRET_CAST(CRichTextIndex*,aPtr)->ApplyCharFormatRollback();} |
|
1510 |
|
1511 |
|
1512 void CRichTextIndex::ApplyCharFormatRollback() |
|
1513 // Paragraph and phrase we were working on are stored in iPos |
|
1514 // Return them the canonical form |
|
1515 // |
|
1516 { |
|
1517 TParaAttribsEntry& paraEntry=iParaIx->At(iPos.iParaElement); |
|
1518 CParaAttribs* paraAttribs=paraEntry.iParaAttribs; |
|
1519 |
|
1520 if (paraAttribs->IsShared()) |
|
1521 return; |
|
1522 |
|
1523 TInt phrase=iPos.iPhraseElement; |
|
1524 TInt base=iPos.iParaBasePhraseElement; |
|
1525 __ASSERT_DEBUG(phrase>=base && phrase<base+paraAttribs->iPhraseCount,User::Invariant()); |
|
1526 if (phrase<base+paraAttribs->iPhraseCount-1) // merge to the right |
|
1527 MergePhrases(phrase+1,iPhraseIx->At(phrase+1),*paraAttribs); |
|
1528 if (phrase>base) // merge to the left |
|
1529 MergePhrases(phrase,iPhraseIx->At(phrase),*paraAttribs); |
|
1530 if (paraAttribs->iPhraseCount==1) // Share the paragraph |
|
1531 Share(paraEntry,base); |
|
1532 } |
|
1533 |
|
1534 |
|
1535 void CRichTextIndex::ApplyCharFormatL(const TCharFormatX& aFormat,const TCharFormatXMask& aMask,TInt aPos,TInt aLength,TBool aRemoveSpecific) |
|
1536 // Applies the specified character formatting to the characters contained within the range |
|
1537 // aPos to aPos+(aLength-1). |
|
1538 // |
|
1539 { |
|
1540 __ASSERT_DEBUG(aLength>=0,User::Invariant()); |
|
1541 __TEST_INVARIANT; |
|
1542 |
|
1543 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
1544 TInt paraOffset=iPos.iParaElementOffset; |
|
1545 TInt phraseOffset=iPos.iPhraseElementOffset; |
|
1546 TInt phrase=iPos.iPhraseElement; |
|
1547 |
|
1548 // prepare for failure |
|
1549 CleanupStack::PushL(TCleanupItem(ApplyCharFormatCleanup,this)); |
|
1550 |
|
1551 for (;;) |
|
1552 { // a paragraph at a time |
|
1553 TParaAttribsEntry& paraEntry=iParaIx->At(iPos.iParaElement); |
|
1554 CParaAttribs* paraAttribs=paraEntry.iParaAttribs; |
|
1555 TInt charsToFormat=Min(aLength,paraEntry.iLength-paraOffset); |
|
1556 aLength-=charsToFormat; |
|
1557 #ifdef _DEBUG |
|
1558 aPos+=charsToFormat; |
|
1559 #endif |
|
1560 |
|
1561 // STEP 1. Reclaim any shared paragraph into non shared form. Re-use the object if possible |
|
1562 |
|
1563 if (paraAttribs->IsShared()) |
|
1564 { |
|
1565 CCharFormatLayer* charLayer=paraAttribs->iCharFormat; |
|
1566 if (paraAttribs->iRefCount==CParaAttribs::EPrimeSharedCount) |
|
1567 { // we are the sole user of this attribute |
|
1568 iPhraseIx->InsertL(phrase,RPhraseAttribsEntry(charLayer,paraEntry.iLength)); |
|
1569 // adjust attribute to be non-shared |
|
1570 paraAttribs->link.Deque(); |
|
1571 paraAttribs->iRefCount=CParaAttribs::EPrimeNonSharedCount; |
|
1572 paraAttribs->iPhraseCount=1; |
|
1573 } |
|
1574 else |
|
1575 { // create a new para attribs object |
|
1576 CParaAttribs* newAttribs=CParaAttribs::NewL(paraAttribs->iParaFormat); |
|
1577 CleanupReleasePushL(*newAttribs); |
|
1578 charLayer=CCharFormatLayer::NewCopyBaseL(charLayer); |
|
1579 CleanupStack::PushL(charLayer); |
|
1580 iPhraseIx->InsertL(phrase,RPhraseAttribsEntry(charLayer,paraEntry.iLength)); |
|
1581 CleanupStack::Pop(2); // charlayer, newAttribs |
|
1582 paraAttribs->Release(); // lose a share on the old attribs |
|
1583 paraEntry.iParaAttribs=paraAttribs=newAttribs; |
|
1584 } |
|
1585 phraseOffset=paraOffset; // we are now in the current position |
|
1586 } |
|
1587 |
|
1588 // STEP 2. Walk through all affected phrases in this paragraph |
|
1589 // For each one, we may need to split it, and then apply the new format |
|
1590 |
|
1591 do |
|
1592 { |
|
1593 __ASSERT_DEBUG(phrase<iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount,User::Invariant()); |
|
1594 // |
|
1595 RPhraseAttribsEntry* phraseAttribs=&iPhraseIx->At(phrase); |
|
1596 TInt len=phraseAttribs->Length(); |
|
1597 |
|
1598 // STEP 2.1 Split the phrase at the beginning of the range? |
|
1599 |
|
1600 if (phraseOffset>0) |
|
1601 { // can only happen for the first phrase |
|
1602 /* |
|
1603 * The pointer paraAttribs is also stored in |
|
1604 * 'paraEntry.iParaAttribs'. The memory pointed to by this |
|
1605 * pointer will be released in CRichTextIndex's destructor. |
|
1606 */ |
|
1607 // coverity[leave_without_push] |
|
1608 SplitPhraseL(phrase,phraseOffset,*phraseAttribs,*paraAttribs); // inserts new phrase at correct position |
|
1609 len-=phraseOffset; |
|
1610 phraseOffset=0; |
|
1611 iPos.iPhraseElement=++phrase; |
|
1612 phraseAttribs=&iPhraseIx->At(phrase); |
|
1613 } |
|
1614 |
|
1615 // STEP 2.2 Split the phrase at the end of the range? |
|
1616 |
|
1617 if (len>charsToFormat) |
|
1618 { // phrase is longer than required format, so split it |
|
1619 /* |
|
1620 * The pointer paraAttribs is also stored in |
|
1621 * 'paraEntry.iParaAttribs'. The memory pointed to by this |
|
1622 * pointer will be released in CRichTextIndex's destructor. |
|
1623 */ |
|
1624 // coverity[leave_without_push] |
|
1625 SplitPhraseL(phrase,charsToFormat,*phraseAttribs,*paraAttribs); |
|
1626 len=charsToFormat; |
|
1627 phraseAttribs=&iPhraseIx->At(phrase); // SplitPhraseL modifies the index array, we must do this! |
|
1628 } |
|
1629 |
|
1630 __ASSERT_DEBUG(phraseAttribs->Length()==len,User::Invariant()); |
|
1631 |
|
1632 // STEP 2.3 Change the format of the current phrase layer |
|
1633 |
|
1634 TCharFormatX format=aFormat; |
|
1635 TCharFormatXMask mask=aMask; |
|
1636 CCharFormatLayer* charLayer=phraseAttribs->CharFormat(); |
|
1637 if (!aRemoveSpecific) |
|
1638 charLayer->Sense(format,mask); // preserve current specific character formatting |
|
1639 charLayer->SetL(format,mask); |
|
1640 |
|
1641 // STEP 2.4 Check for merging with previous phrase |
|
1642 |
|
1643 if (phrase==iPos.iParaBasePhraseElement || !MergePhrases(phrase,*phraseAttribs,*paraAttribs)) |
|
1644 // if we don't merge this phrase, move on to the next one |
|
1645 iPos.iPhraseElement=++phrase; |
|
1646 |
|
1647 charsToFormat-=len; |
|
1648 } while (charsToFormat); |
|
1649 |
|
1650 __ASSERT_DEBUG(phrase==iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount || aLength==0,User::Invariant()); |
|
1651 |
|
1652 // STEP 3 Reduce the paragraph attributes back to canonical form |
|
1653 |
|
1654 // STEP 3.1 Check for merging at the end of the changes |
|
1655 |
|
1656 if (phrase>iPos.iParaBasePhraseElement && phrase<iPos.iParaBasePhraseElement+paraAttribs->iPhraseCount) |
|
1657 MergePhrases(phrase,iPhraseIx->At(phrase),*paraAttribs); // mustn't adjust phrase index to follow merge |
|
1658 |
|
1659 // STEP 3.2 See if we can re-share the paragraph |
|
1660 |
|
1661 if (paraAttribs->iPhraseCount==1) |
|
1662 { // This para has constant character formatting - can be shared. |
|
1663 iPos.iPhraseElement=--phrase; |
|
1664 Share(paraEntry,phrase); |
|
1665 } |
|
1666 |
|
1667 // loop into next paragraph |
|
1668 if (aLength==0) |
|
1669 break; |
|
1670 iPos.iParaElement++; |
|
1671 paraOffset=0; |
|
1672 iPos.iParaBasePhraseElement=phrase; |
|
1673 #ifdef _DEBUG |
|
1674 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
1675 __ASSERT_DEBUG(iPos.iDocPos==aPos,User::Invariant()); |
|
1676 __ASSERT_DEBUG(iPos.iPhraseElement==phrase,User::Invariant()); |
|
1677 __ASSERT_DEBUG(iPos.iParaElementOffset==paraOffset,User::Invariant()); |
|
1678 __ASSERT_DEBUG(iPos.iPhraseElementOffset==phraseOffset,User::Invariant()); |
|
1679 __TEST_INVARIANT; |
|
1680 #endif |
|
1681 } |
|
1682 |
|
1683 CleanupStack::Pop(); // rollback item |
|
1684 |
|
1685 __TEST_INVARIANT; |
|
1686 } |
|
1687 |
|
1688 |
|
1689 void CRichTextIndex::RemoveSpecificParaFormatL(TInt aPos,TInt aLength) |
|
1690 // Removes all specific paragraph formatting from the specified region. |
|
1691 // For each paragraph covered by the range, check if its para attribs is in the |
|
1692 // shared list, or not. |
|
1693 // If its not shared, then simply reset the para format layer. |
|
1694 // If it is in the shared list, then a new shared para attribs must be created, |
|
1695 // and the reference count of the original decremented. |
|
1696 // |
|
1697 { |
|
1698 __TEST_INVARIANT; |
|
1699 |
|
1700 TInt endPara=OwningParagraph(aPos+aLength); |
|
1701 TInt currentPara=OwningParagraph(aPos); |
|
1702 CParaAttribs* currentParaAttribs=NULL; |
|
1703 while (currentPara<=endPara) |
|
1704 { |
|
1705 currentParaAttribs=(*iParaIx)[currentPara].iParaAttribs; |
|
1706 if (!currentParaAttribs->IsShared()) |
|
1707 {// Reset specific paragraph format layer to be empty. |
|
1708 currentParaAttribs->iParaFormat->Reset(); // remove specific formatting. |
|
1709 } |
|
1710 else |
|
1711 {// Maintain the shared list reference |
|
1712 CParaAttribs* resultantParaAttribs=CParaAttribs::NewL(currentParaAttribs); |
|
1713 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,resultantParaAttribs)); |
|
1714 resultantParaAttribs->iParaFormat->Reset(); // remove specific formatting |
|
1715 CParaAttribs* shared=RequestShareL(resultantParaAttribs); // Will return a non-NULL handle. |
|
1716 __ASSERT_DEBUG(shared,Panic(EDebug)); |
|
1717 currentParaAttribs->Release(); |
|
1718 iSharedParaQueHead.AddLast(*resultantParaAttribs); // Allows correct release of cell. |
|
1719 CleanupStack::PopAndDestroy(); |
|
1720 (*iParaIx)[currentPara].iParaAttribs=shared; |
|
1721 } |
|
1722 currentPara++; |
|
1723 } |
|
1724 |
|
1725 |
|
1726 __TEST_INVARIANT; |
|
1727 } |
|
1728 |
|
1729 |
|
1730 void CRichTextIndex::RemoveSpecificCharFormatL(TInt aPos,TInt aLength) |
|
1731 // Removes all specific character formatting from the specified region. |
|
1732 // For each paragraph covered by the range, check if its para attribs is in the |
|
1733 // shared list, or not. |
|
1734 // If its not shared, then simply reset the para format layer. |
|
1735 // If it is in the shared list, then a new shared para attribs must be created, |
|
1736 // and the reference count of the original decremented. |
|
1737 // |
|
1738 { |
|
1739 __TEST_INVARIANT; |
|
1740 |
|
1741 TCharFormatX format; // dummy format |
|
1742 TCharFormatXMask mask; |
|
1743 mask.ClearAll(); |
|
1744 ApplyCharFormatL(format,mask,aPos,aLength,ETrue); |
|
1745 |
|
1746 __TEST_INVARIANT; |
|
1747 } |
|
1748 |
|
1749 |
|
1750 TBool CRichTextIndex::MergePhrases(TInt aPos) |
|
1751 // Checks if the specified character position aPos is a phrase boundary. |
|
1752 // If so, then examines the two abutting phrases at aPos to see if they |
|
1753 // are identical; in which case they are merged into one phrase that covers |
|
1754 // the sum of their lengths. |
|
1755 // |
|
1756 { |
|
1757 ScanToPosition(aPos,EScanToPositionAbsolute); |
|
1758 return MergePhrases(iPos); |
|
1759 } |
|
1760 |
|
1761 |
|
1762 TBool CRichTextIndex::MergePhrases(const TLogicalPosition& aPos) |
|
1763 // Checks if the specified character position record is a phrase boundary. |
|
1764 // If so, then examines the two abutting phrases at aPos to see if they |
|
1765 // are identical; in which case they are merged into one phrase that covers |
|
1766 // the sum of their lengths. |
|
1767 // |
|
1768 { |
|
1769 TCurrentIndexRecords current; |
|
1770 GetCurrentRecords(current); |
|
1771 TBool phrasesMerged=EFalse; |
|
1772 if (!FirstPhraseOfParagraph() && iPos.iPhraseElementOffset==0) |
|
1773 {// Check if the 2 abutting phrases can be merged together. |
|
1774 TInt rightPhraseElement=iPos.iPhraseElement; |
|
1775 RPhraseAttribsEntry* rightPhrase=&(*iPhraseIx)[rightPhraseElement]; |
|
1776 RPhraseAttribsEntry* leftPhrase=&(*iPhraseIx)[rightPhraseElement-1]; |
|
1777 if (rightPhrase->IsIdentical(*leftPhrase)) |
|
1778 {// Merge the abutting phrases together. Cannot merge picture/non-picture/z.l.p. phrase combinations. |
|
1779 rightPhrase->AdjustLength(leftPhrase->Length()); // Extend the right phrase length |
|
1780 RemoveFromPhraseIx(rightPhraseElement-1); // Free the resources taken by the left phrase - redundant |
|
1781 (*iParaIx)[iPos.iParaElement].iParaAttribs->iPhraseCount--; // Update phrase count of owning CParaAttribs |
|
1782 ScanToPosition(aPos.iDocPos,EScanToPositionAbsolute); // Pick up new phrase index. |
|
1783 phrasesMerged=ETrue; |
|
1784 } |
|
1785 } |
|
1786 return phrasesMerged; |
|
1787 } |
|
1788 |
|
1789 |
|
1790 /** Remove phrases from the containing object. This includes |
|
1791 freeing referenced resources. (pictures etc.) |
|
1792 @param aPhraseIndex The first phrase to be deleted |
|
1793 @param aCount The number of phrases to be deleted |
|
1794 */ |
|
1795 void CRichTextIndex::RemoveFromPhraseIx(TInt aPhraseIndex,TInt aCount) |
|
1796 { |
|
1797 // if the phrase being deleted is <= iLastPos |
|
1798 // then iLastPos will become invalid so should be reset |
|
1799 if (aPhraseIndex <= iLastUsed.iPhraseElement ) |
|
1800 iLastUsed.Clear(); |
|
1801 |
|
1802 for (TInt offset=aPhraseIndex;offset<(aPhraseIndex+aCount);offset++) |
|
1803 { |
|
1804 // discard phrases & book-keep the picture count |
|
1805 RPhraseAttribsEntry& phrase=(*iPhraseIx)[offset]; |
|
1806 phrase.Discard(); |
|
1807 if (phrase.IsPicturePhrase()) |
|
1808 iPictureCount--; |
|
1809 } |
|
1810 iPhraseIx->Delete(aPhraseIndex,aCount); |
|
1811 } |
|
1812 |
|
1813 void CRichTextIndex::GetParagraphFormatL(CParaFormat* aFormat,TInt aPos)const |
|
1814 // Fills aFormat with the effective Paragraph format attributes for the paragraph |
|
1815 // in which character position aPos is contained. |
|
1816 // |
|
1817 { |
|
1818 __TEST_INVARIANT; |
|
1819 |
|
1820 TLogicalPosition cachePos(iLastUsed); |
|
1821 TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos,&cachePos); |
|
1822 (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(aFormat); |
|
1823 } |
|
1824 |
|
1825 void CRichTextIndex::GetSpecificParagraphFormatL(CParaFormat* aFormat, |
|
1826 TParaFormatMask& aMask, |
|
1827 TInt aPos)const |
|
1828 { |
|
1829 __TEST_INVARIANT; |
|
1830 |
|
1831 TLogicalPosition cachePos(iLastUsed); |
|
1832 TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos,&cachePos); |
|
1833 CParaFormatLayer* pLayer = (*iParaIx)[para].iParaAttribs->iParaFormat; |
|
1834 pLayer->SenseL(aFormat, aMask); |
|
1835 } |
|
1836 |
|
1837 TInt CRichTextIndex::GetChars(TCharFormatX& aFormat,TInt aPos) const |
|
1838 // Returns the number of characters, commencing at aStartPos, that occupy the same phrase, and |
|
1839 // modifies aFormat, to hold the effective format of that phrase. |
|
1840 // |
|
1841 { |
|
1842 __TEST_INVARIANT; |
|
1843 |
|
1844 CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed)); |
|
1845 TCurrentIndexRecords current; |
|
1846 GetCurrentRecords(current); |
|
1847 TInt phraseLength; |
|
1848 CCharFormatLayer* charFormatLayer; |
|
1849 if (current.iPhrase) |
|
1850 {// Specific character formatting held in phrase index. |
|
1851 charFormatLayer=current.iPhrase->CharFormat(); |
|
1852 phraseLength=(current.iPhrase->Length())-(iPos.iPhraseElementOffset); |
|
1853 } |
|
1854 else |
|
1855 {// Constant character formatting held in the para attribs |
|
1856 charFormatLayer=current.iParaAttribs->iCharFormat; |
|
1857 phraseLength=current.iParaEntry->iLength-iPos.iParaElementOffset; |
|
1858 } |
|
1859 charFormatLayer->SenseEffective(aFormat); |
|
1860 return phraseLength; |
|
1861 } |
|
1862 |
|
1863 |
|
1864 TInt CRichTextIndex::GetPictureSizeInTwips(TSize& aSize,TInt aPos)const |
|
1865 // Get the size of the specified picture into aSize. The picture is specified by its |
|
1866 // character position. Return KErrNotFound if there is no picture at the specified |
|
1867 // document position. |
|
1868 // |
|
1869 { |
|
1870 __TEST_INVARIANT; |
|
1871 |
|
1872 CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed)); |
|
1873 TCurrentIndexRecords current; |
|
1874 GetCurrentRecords(current); |
|
1875 |
|
1876 return (current.iPhrase) |
|
1877 ? current.iPhrase->GetPictureSizeInTwips(aSize) |
|
1878 : KErrNotFound; |
|
1879 } |
|
1880 |
|
1881 TPictureHeader* CRichTextIndex::PictureHeaderPtr(TInt aPos) |
|
1882 { |
|
1883 __TEST_INVARIANT; |
|
1884 |
|
1885 CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute); |
|
1886 TCurrentIndexRecords current; |
|
1887 GetCurrentRecords(current); |
|
1888 return current.iPhrase? current.iPhrase->PictureHeaderPtr() : 0; |
|
1889 } |
|
1890 |
|
1891 TPictureHeader CRichTextIndex::PictureHeader(TInt aPos) const |
|
1892 // Return the picture header describing the picture at character position aPos. |
|
1893 // If there is no picture at character position aPos, a default picture header is returned. |
|
1894 // |
|
1895 { |
|
1896 const TPictureHeader* p = const_cast<CRichTextIndex*>(this)->PictureHeaderPtr(aPos); |
|
1897 return p? *p : TPictureHeader(); |
|
1898 } |
|
1899 |
|
1900 |
|
1901 CPicture* CRichTextIndex::PictureHandleL(TInt aPos,MLayDoc::TForcePictureLoad aForceLoad)const |
|
1902 // Returns the handle of the concrete picture at character position aPos, if one exists; |
|
1903 // otherwise returns NULL. |
|
1904 // |
|
1905 { |
|
1906 __TEST_INVARIANT; |
|
1907 |
|
1908 CONST_CAST(CRichTextIndex*,this)->ScanToPosition(aPos,EScanToPositionAbsolute,&MUTABLE_CAST(TLogicalPosition&,iLastUsed)); |
|
1909 TCurrentIndexRecords current; |
|
1910 GetCurrentRecords(current); |
|
1911 return (current.iPhrase) |
|
1912 ? (CPicture*)current.iPhrase->PictureHandleL(iText.PictureFactory(),iText.StoreResolver(),aPos,aForceLoad) |
|
1913 : NULL; |
|
1914 } |
|
1915 |
|
1916 |
|
1917 void CRichTextIndex::GetParaFormatL(CParaFormat* aFormat,TParaFormatMask& aVaries,TInt aPos,TInt aLength,CParaFormat::TParaFormatGetMode aMode)const |
|
1918 // Senses the paragraph format of para(s) covered by the region aPos to aPos+aLength-1. |
|
1919 // aFormat takes the values of all attributes, and the mask aMask indicates those values that change |
|
1920 // over the selected region, and are therefore *indeterminate*. |
|
1921 // Application: seeding paragraph formatting dialogs. |
|
1922 // |
|
1923 { |
|
1924 __TEST_INVARIANT; |
|
1925 |
|
1926 TInt para=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos); |
|
1927 TInt offset=(aLength==0)?0 :-1; |
|
1928 TInt endPara=CONST_CAST(CRichTextIndex*,this)->OwningParagraph(aPos+(aLength+offset)); |
|
1929 aVaries.ClearAll(); |
|
1930 (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(aFormat,aMode); // Sense 1st paras' format. |
|
1931 ++para; |
|
1932 CParaFormat* format=CParaFormat::NewLC(); |
|
1933 for (;para<=endPara;para++) |
|
1934 { |
|
1935 (*iParaIx)[para].iParaAttribs->iParaFormat->SenseEffectiveL(format,aMode); |
|
1936 if (format->iLanguage!=aFormat->iLanguage) |
|
1937 aVaries.SetAttrib(EAttParaLanguage); |
|
1938 if (format->iFillColor!=aFormat->iFillColor) |
|
1939 aVaries.SetAttrib(EAttFillColor); |
|
1940 if (format->iLeftMarginInTwips!=aFormat->iLeftMarginInTwips) |
|
1941 aVaries.SetAttrib(EAttLeftMargin); |
|
1942 if (format->iRightMarginInTwips!=aFormat->iRightMarginInTwips) |
|
1943 aVaries.SetAttrib(EAttRightMargin); |
|
1944 if (format->iIndentInTwips!=aFormat->iIndentInTwips) |
|
1945 aVaries.SetAttrib(EAttIndent); |
|
1946 if (format->iHorizontalAlignment!=aFormat->iHorizontalAlignment) |
|
1947 aVaries.SetAttrib(EAttAlignment); |
|
1948 if (format->iVerticalAlignment!=aFormat->iVerticalAlignment) |
|
1949 aVaries.SetAttrib(EAttVerticalAlignment); |
|
1950 if (format->iLineSpacingInTwips!=aFormat->iLineSpacingInTwips) |
|
1951 aVaries.SetAttrib(EAttLineSpacing); |
|
1952 if (format->iLineSpacingControl!=aFormat->iLineSpacingControl) |
|
1953 aVaries.SetAttrib(EAttLineSpacingControl); |
|
1954 if (format->iSpaceBeforeInTwips!=aFormat->iSpaceBeforeInTwips) |
|
1955 aVaries.SetAttrib(EAttSpaceBefore); |
|
1956 if (format->iSpaceAfterInTwips!=aFormat->iSpaceAfterInTwips) |
|
1957 aVaries.SetAttrib(EAttSpaceAfter); |
|
1958 if (format->iKeepTogether!=aFormat->iKeepTogether) |
|
1959 aVaries.SetAttrib(EAttKeepTogether); |
|
1960 if (format->iKeepWithNext!=aFormat->iKeepWithNext) |
|
1961 aVaries.SetAttrib(EAttKeepWithNext); |
|
1962 if (format->iWidowOrphan!=aFormat->iWidowOrphan) |
|
1963 aVaries.SetAttrib(EAttWidowOrphan); |
|
1964 if (format->iWrap!=aFormat->iWrap) |
|
1965 aVaries.SetAttrib(EAttWrap); |
|
1966 if (format->iBorderMarginInTwips!=aFormat->iBorderMarginInTwips) |
|
1967 aVaries.SetAttrib(EAttBorderMargin); |
|
1968 if (format->iDefaultTabWidthInTwips!=aFormat->iDefaultTabWidthInTwips) |
|
1969 aVaries.SetAttrib(EAttDefaultTabWidth); |
|
1970 if (aMode==CParaFormat::EAllAttributes) |
|
1971 { |
|
1972 // Borders |
|
1973 for (TInt border=0;border<CParaFormat::EMaxParaBorder;border++) |
|
1974 {// Check each para border individually. Assumes border format attributes run consecutively. |
|
1975 if (!format->IsBorderEqual((CParaFormat::TParaBorderSide)border,*aFormat)) |
|
1976 aVaries.SetAttrib((TTextFormatAttribute)(EAttTopBorder+border)); |
|
1977 } |
|
1978 // Bullet |
|
1979 if (!format->iBullet && !aFormat->iBullet) |
|
1980 { /* neither para has bullet, so no variation */ } |
|
1981 else if (!format->iBullet || !aFormat->iBullet |
|
1982 || *format->iBullet!=*aFormat->iBullet) |
|
1983 aVaries.SetAttrib(EAttBullet); |
|
1984 // The Tab-List |
|
1985 if (format->TabCount()!=aFormat->TabCount()) |
|
1986 aVaries.SetAttrib(EAttTabStop); // TabLists are different. |
|
1987 else |
|
1988 {// The 2 tablists have the same number of tab stops - but are not necessarily the same. |
|
1989 TBool matched=ETrue; |
|
1990 TInt tabCount=format->TabCount(); |
|
1991 for (TInt tabItem=0;tabItem<tabCount;tabItem++) |
|
1992 {// Compare the 2 tabs. |
|
1993 TTabStop comp1,comp2; |
|
1994 comp1=format->TabStop(tabItem); |
|
1995 comp2=aFormat->TabStop(tabItem); |
|
1996 if (comp1!=comp2) |
|
1997 matched=EFalse; |
|
1998 } |
|
1999 if (!matched) |
|
2000 aVaries.SetAttrib(EAttTabStop); |
|
2001 } |
|
2002 } |
|
2003 } |
|
2004 CleanupStack::PopAndDestroy(); |
|
2005 } |
|
2006 |
|
2007 |
|
2008 // Compare all attributes in two formats and where they differ set the appropriate flag in the aVaries mask. |
|
2009 void CRichTextIndex::CheckForUndetermined(const TCharFormatX& aFormatA,const TCharFormatX& aFormatB, |
|
2010 TCharFormatXMask& aVaries) const |
|
2011 { |
|
2012 const TCharFormat& a = aFormatA.iCharFormat; |
|
2013 const TCharFormat& b = aFormatB.iCharFormat; |
|
2014 if (a.iLanguage!=b.iLanguage) |
|
2015 aVaries.SetAttrib(EAttCharLanguage); |
|
2016 if (a.iFontPresentation.iTextColor!=b.iFontPresentation.iTextColor) |
|
2017 aVaries.SetAttrib(EAttColor); |
|
2018 if (a.iFontPresentation.iHighlightColor!=b.iFontPresentation.iHighlightColor) |
|
2019 aVaries.SetAttrib(EAttFontHighlightColor); |
|
2020 if (a.iFontPresentation.iHighlightStyle!=b.iFontPresentation.iHighlightStyle) |
|
2021 aVaries.SetAttrib(EAttFontHighlightStyle); |
|
2022 if (a.iFontPresentation.iStrikethrough!=b.iFontPresentation.iStrikethrough) |
|
2023 aVaries.SetAttrib(EAttFontStrikethrough); |
|
2024 if (a.iFontPresentation.iUnderline!=b.iFontPresentation.iUnderline) |
|
2025 aVaries.SetAttrib(EAttFontUnderline); |
|
2026 if (a.iFontPresentation.iHiddenText!=b.iFontPresentation.iHiddenText) |
|
2027 aVaries.SetAttrib(EAttFontHiddenText); |
|
2028 if (a.iFontPresentation.iPictureAlignment!=b.iFontPresentation.iPictureAlignment) |
|
2029 aVaries.SetAttrib(EAttFontPictureAlignment); |
|
2030 if (a.iFontSpec.iHeight!=b.iFontSpec.iHeight) |
|
2031 aVaries.SetAttrib(EAttFontHeight); |
|
2032 if (!(a.iFontSpec.iTypeface==b.iFontSpec.iTypeface)) |
|
2033 aVaries.SetAttrib(EAttFontTypeface); |
|
2034 if (a.iFontSpec.iFontStyle.Posture()!=b.iFontSpec.iFontStyle.Posture()) |
|
2035 aVaries.SetAttrib(EAttFontPosture); |
|
2036 if (a.iFontSpec.iFontStyle.StrokeWeight()!=b.iFontSpec.iFontStyle.StrokeWeight()) |
|
2037 aVaries.SetAttrib(EAttFontStrokeWeight); |
|
2038 if (a.iFontSpec.iFontStyle.PrintPosition()!=b.iFontSpec.iFontStyle.PrintPosition()) |
|
2039 aVaries.SetAttrib(EAttFontPrintPos); |
|
2040 if (aFormatA.iParserTag != aFormatB.iParserTag) |
|
2041 aVaries.SetAttrib(EAttParserTag); |
|
2042 } |
|
2043 |
|
2044 |
|
2045 void CRichTextIndex::GetCharFormat(TCharFormatX& aFormat,TCharFormatXMask& aVaries,TInt aPos,TInt aLength)const |
|
2046 // Senses the character formatting of the phrase(s) covered by the region aPos to aPos+aLength-1. |
|
2047 // aFormat takes the values of all character format attributes, and the mask aMask indicates those |
|
2048 // values that change over the selected region, and are therefore *indeterminate*. |
|
2049 // Application: seeding character formatting dialogs. |
|
2050 // If aLength is zero, the character format sensed is that of the charcter immediatley to the left (behind) the cursor. |
|
2051 // |
|
2052 { |
|
2053 __TEST_INVARIANT; |
|
2054 |
|
2055 aVaries.ClearAll(); |
|
2056 if (aLength==0) // Get the format of the character to the left of the cursor. |
|
2057 ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionMatchLeft); |
|
2058 else |
|
2059 ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionAbsolute); |
|
2060 // Get char format of first phrase |
|
2061 TCurrentIndexRecords current; |
|
2062 GetCurrentRecords(current); |
|
2063 if (current.iPhrase) |
|
2064 current.iPhrase->CharFormat()->SenseEffective(aFormat); |
|
2065 else |
|
2066 current.iParaAttribs->iCharFormat->SenseEffective(aFormat); |
|
2067 // Place pos at start of next phrase |
|
2068 TInt pos=aPos+(CurrentPhraseLength()-CurrentPhraseOffset()); |
|
2069 while (pos<=aPos+aLength-1) |
|
2070 {// Get the format of the next phrase and check if attributes change value |
|
2071 ((CRichTextIndex*)this)->ScanToPosition(pos,EScanToPositionAbsolute); |
|
2072 GetCurrentRecords(current); |
|
2073 TCharFormatX format; |
|
2074 if (current.iPhrase) |
|
2075 current.iPhrase->CharFormat()->SenseEffective(format); |
|
2076 else |
|
2077 current.iParaAttribs->iCharFormat->SenseEffective(format); |
|
2078 CheckForUndetermined(format,aFormat,aVaries); |
|
2079 pos+=CurrentPhraseLength(); |
|
2080 } |
|
2081 } |
|
2082 |
|
2083 |
|
2084 void CRichTextIndex::GetSpecificCharFormatDirection(TCharFormatX& aFormat, |
|
2085 TCharFormatXMask& aMask, |
|
2086 TInt aPos, |
|
2087 TBool aGetLeft) const |
|
2088 { |
|
2089 __TEST_INVARIANT; |
|
2090 |
|
2091 aMask.ClearAll(); |
|
2092 ((CRichTextIndex*)this)->ScanToPosition(aPos, |
|
2093 aGetLeft? EScanToPositionMatchLeft : EScanToPositionAbsolute); |
|
2094 TCurrentIndexRecords current; |
|
2095 GetCurrentRecords(current); |
|
2096 if (current.iPhrase) |
|
2097 current.iPhrase->CharFormat()->Sense(aFormat,aMask); |
|
2098 else |
|
2099 current.iParaAttribs->iCharFormat->Sense(aFormat,aMask); |
|
2100 } |
|
2101 |
|
2102 void CRichTextIndex::GetSpecificCharFormat(TCharFormatX& aFormat,TCharFormatXMask& aMask,TInt aPos)const |
|
2103 // Return the format attributes store in the specific layer only, for the specified document position. |
|
2104 // THIS IS NOT THE EFFECTIVE FORMAT, BUT THE SPECIFIC FORMATTING ONLY. |
|
2105 // |
|
2106 { |
|
2107 GetSpecificCharFormatDirection(aFormat, aMask, aPos, ETrue); |
|
2108 } |
|
2109 |
|
2110 |
|
2111 CParaAttribs* CRichTextIndex::RequestReclaimShareL(CParaAttribs* aParaAttribs,TParaAttribsEntry* aParaEntry) |
|
2112 // If the specified para attribs is currently on the shared list, then |
|
2113 // a specific para attribs is *reclaimed* and returned. |
|
2114 // The current share on the CParaAttribs is not *Released*. |
|
2115 // A new CParaAttribs is created of the same paragraph format as the shared one, |
|
2116 // but with a reference count of zero, (as this now has specific character formatting), |
|
2117 // and 1 phrase that is of the same character format as the shared one. |
|
2118 // The reclaimed specific para attribs is attactched to the specified para entry. |
|
2119 // NOTE: |
|
2120 // If the specified CParaAttribs is not currently on the shared list, NULL |
|
2121 // is returned, and aParaAttribs left unchanged.. |
|
2122 // Assumes a previous call to ScanToPosition has correctly set the internal position record. |
|
2123 // This function can be called safely in any situation. (Except that it may *LEAVE*). |
|
2124 // |
|
2125 { |
|
2126 if (!(aParaAttribs->IsShared())) |
|
2127 return NULL; // This para attribs is not currently shared. |
|
2128 // We are dealing with a shared paraAttribs from now on. |
|
2129 CParaAttribs* reclaimedPara=CParaAttribs::NewL(aParaAttribs->iParaFormat); // Create the re-claimed paraAttribs. |
|
2130 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,reclaimedPara)); |
|
2131 CCharFormatLayer* newFormat=CCharFormatLayer::NewCopyBaseL(aParaAttribs->iCharFormat); |
|
2132 CleanupStack::PushL(newFormat); |
|
2133 RPhraseAttribsEntry phrase(newFormat,aParaEntry->iLength); |
|
2134 // Now insert this phrase into the index. |
|
2135 iPhraseIx->InsertL(iPos.iPhraseElement,phrase); |
|
2136 CleanupStack::Pop(2); // newFormat, reclaimedPara |
|
2137 return reclaimedPara; |
|
2138 } |
|
2139 |
|
2140 |
|
2141 CParaAttribs* CRichTextIndex::RequestShareL(CParaAttribs* aParaAttribs,CCharFormatLayer* aCharFormat,CParaAttribs* aReservedCell) |
|
2142 // Attempts to re-use an existing paraAttribs that matches the one specified. |
|
2143 // Returns the handle of a CParaAttribs, or NULL if the specified argument cannot |
|
2144 // be shared. |
|
2145 // aCharFormat may be NULL, as may aReservedCell. |
|
2146 // |
|
2147 { |
|
2148 if (aParaAttribs->iRefCount<=0 && aParaAttribs->iPhraseCount>1) |
|
2149 return NULL; // This para has specific character formatting & multiple phrases and so cannot be shared. |
|
2150 // This para has constant character formatting - can be shared. |
|
2151 CCharFormatLayer* charFormat; |
|
2152 if (aCharFormat) |
|
2153 charFormat=aCharFormat; // Has a phrase index. |
|
2154 else |
|
2155 charFormat=aParaAttribs->iCharFormat; // Has constant char formatting. |
|
2156 return GetParaAttribsL(aParaAttribs->iParaFormat,charFormat,aReservedCell); |
|
2157 } |
|
2158 |
|
2159 |
|
2160 CParaAttribs* CRichTextIndex::RequestShare(const TLogicalPosition& aLogicalPosition) |
|
2161 // Returns a handle to a paraAttribs on the shared list that matches the paragraph at the |
|
2162 // specified position. Returns NULL if the specified paragraph does not have constant |
|
2163 // character formatting. |
|
2164 // |
|
2165 { |
|
2166 CParaAttribs* paraAttribs=(*iParaIx)[aLogicalPosition.iParaElement].iParaAttribs; |
|
2167 if (paraAttribs->iRefCount<=0 && paraAttribs->iPhraseCount>1) |
|
2168 return NULL; // This para has specific character formatting and so cannot be shared. |
|
2169 // This para has constant character formatting - can be shared. |
|
2170 return GetParaAttribs(aLogicalPosition); |
|
2171 } |
|
2172 |
|
2173 |
|
2174 CParaAttribs* CRichTextIndex::GetParaAttribsL(const CParaFormatLayer* aParaFormat,const CCharFormatLayer* aCharFormat, |
|
2175 CParaAttribs* aReservedCell) |
|
2176 // Attempts to match the specified arguments to a CParaAttribs in the shared list. |
|
2177 // If matched, the handle of the matched para attribs is returned, and the reference count |
|
2178 // of that item is incremented. |
|
2179 // |
|
2180 // aReservedCell is a pre-allocated CParaAttribs that has been correctly setup. If no match |
|
2181 // is found, and the reserved cell is specified, this is used in preference to creating a new one. |
|
2182 // If the reserved cell is not specified and there is no match, a new CParaAttribs of the correct |
|
2183 // specification is created and added to the shared list. |
|
2184 // |
|
2185 { |
|
2186 CParaAttribs* handle=FindSharedParaAttribs(*aParaFormat,*aCharFormat); |
|
2187 if (handle) |
|
2188 return handle; // match found already in the shared list. |
|
2189 // There is no match, so create new sharedPara and add to list. |
|
2190 if (!aReservedCell) |
|
2191 aReservedCell=CParaAttribs::NewL(aParaFormat,aCharFormat); // Reusing aReservedCell saves an automatic. |
|
2192 iSharedParaQueHead.AddLast(*aReservedCell); |
|
2193 return aReservedCell; |
|
2194 } |
|
2195 |
|
2196 |
|
2197 CParaAttribs* CRichTextIndex::GetParaAttribs(CParaAttribs* aParaAttribs,CCharFormatLayer& aCharFormatLayer) |
|
2198 // Called by Reset. |
|
2199 // |
|
2200 { |
|
2201 CParaAttribs* handle=FindSharedParaAttribs(*aParaAttribs->iParaFormat,aCharFormatLayer); |
|
2202 if (handle) |
|
2203 return handle; |
|
2204 else |
|
2205 {// No match, so piece together new shared paraAttribs and add to shared para list. |
|
2206 aParaAttribs->iRefCount=1; |
|
2207 aParaAttribs->iCharFormat=&aCharFormatLayer; |
|
2208 iSharedParaQueHead.AddLast(*aParaAttribs); |
|
2209 return aParaAttribs; |
|
2210 } |
|
2211 } |
|
2212 |
|
2213 |
|
2214 CParaAttribs* CRichTextIndex::GetParaAttribs(const TLogicalPosition& aLogicalPosition) |
|
2215 // Attempts to match the specified arguments to a CParaAttribs in the shared list. |
|
2216 // If matched, the handle of the matched para attribs is returned, and the reference count |
|
2217 // of that item is incremented. If no match is found, the current para attribs is |
|
2218 // transformed into one that is placed in the shared list. |
|
2219 // |
|
2220 { |
|
2221 CParaAttribs* sourceParaAttribs=(*iParaIx)[aLogicalPosition.iParaElement].iParaAttribs; |
|
2222 RPhraseAttribsEntry* sourcePhrase=&(*iPhraseIx)[aLogicalPosition.iPhraseElement]; |
|
2223 // |
|
2224 CParaAttribs* handle=FindSharedParaAttribs(*sourceParaAttribs->iParaFormat,*sourcePhrase->CharFormat()); |
|
2225 if (handle) |
|
2226 return handle; |
|
2227 else |
|
2228 {// No match, so piece together new shared paraAttribs and add to shared para list |
|
2229 sourceParaAttribs->iRefCount=1; |
|
2230 __ASSERT_ALWAYS(!sourcePhrase->IsPicturePhrase(),Panic(EReleasCharFormatLayerOwnershipCalledOnPicturePhrase)); |
|
2231 sourceParaAttribs->iCharFormat=sourcePhrase->ReleaseCharFormatLayerOwnership(); |
|
2232 sourcePhrase->Discard(); |
|
2233 iPhraseIx->Delete(aLogicalPosition.iPhraseElement); // remove the deleted phrase from the phrase index. |
|
2234 iSharedParaQueHead.AddLast(*sourceParaAttribs); |
|
2235 return sourceParaAttribs; |
|
2236 } |
|
2237 } |
|
2238 |
|
2239 |
|
2240 CParaAttribs* CRichTextIndex::FindSharedParaAttribs(const CParaFormatLayer& aParaFormatLayer,const CCharFormatLayer& aCharFormatLayer) |
|
2241 // Attempts to match the specified arguments to an item in the shared para list. |
|
2242 // If found, the handle of the matched para attribs is returned, and the reference count |
|
2243 // of that item is incremented. |
|
2244 // If no match is made NULL is returned. |
|
2245 // |
|
2246 { |
|
2247 CParaAttribs* currentSharedPara=NULL; |
|
2248 TBool matched=EFalse; |
|
2249 if (!iSharedParaQueHead.IsEmpty()) |
|
2250 { |
|
2251 TDblQueIter<CParaAttribs> iterator(iSharedParaQueHead); |
|
2252 while ((currentSharedPara=iterator++)!=NULL) |
|
2253 {// Try and match each item in the shared para list. |
|
2254 matched=aParaFormatLayer.IsIdentical(currentSharedPara->iParaFormat); |
|
2255 if (!matched) |
|
2256 continue; |
|
2257 matched=aCharFormatLayer.IsIdentical(currentSharedPara->iCharFormat); |
|
2258 if (!matched) |
|
2259 continue; |
|
2260 // We have a match, so adjust reference count. |
|
2261 currentSharedPara->iRefCount++; |
|
2262 return currentSharedPara; |
|
2263 } |
|
2264 } |
|
2265 return currentSharedPara; |
|
2266 } |
|
2267 |
|
2268 |
|
2269 void CRichTextIndex::ScanToPosition(TInt aCharPos,TScanToPositionMode aMode,TLogicalPosition* aLastUsed/*=NULL*/) |
|
2270 // Move the internal position record to that indicated by the specified character position, aCharPos. |
|
2271 // Behaviour follows: |
|
2272 // aCharPos is considered to be goverened by the phrase covering aCharPos-1, |
|
2273 // except when aCharPos is the fist character of a paragraph, when |
|
2274 // aCharPos is goverened by the phrase coverng aCharPos. |
|
2275 // (If nothing else, aCharPos will be a paragraph delimiter or the end-of-document |
|
2276 // character. |
|
2277 // The implementation below matches to the right as standard, then checks if a left |
|
2278 // phrase match is available. |
|
2279 // |
|
2280 { |
|
2281 if (!aLastUsed || aLastUsed->iDocPos-aLastUsed->iParaElementOffset>aCharPos) |
|
2282 iPos.Clear(); // Reset the internal position record. |
|
2283 else |
|
2284 { |
|
2285 iPos=*aLastUsed; |
|
2286 if (iPos.iDocPos>aCharPos || (aMode==EScanToPositionMatchLeft && iPos.iDocPos==aCharPos)) |
|
2287 {// reset to the start of paragraph if aPos < cache pos or aPos==chache Pos whilst matching left |
|
2288 iPos.iDocPos-=iPos.iParaElementOffset; |
|
2289 iPos.iParaElementOffset=iPos.iPhraseElementOffset=0; |
|
2290 iPos.iPhraseElement=iPos.iParaBasePhraseElement; |
|
2291 } |
|
2292 } |
|
2293 |
|
2294 TInt phraseElement=iPos.iPhraseElement; |
|
2295 TInt startOfPara=iPos.iDocPos-iPos.iParaElementOffset; |
|
2296 TInt paraElement=iPos.iParaElement; |
|
2297 const CArrayFix<TParaAttribsEntry>& paraIx=*iParaIx; |
|
2298 const TParaAttribsEntry* para=¶Ix[paraElement]; |
|
2299 TInt len=para->iLength; |
|
2300 if (aCharPos>=(startOfPara+len)) |
|
2301 { |
|
2302 iPos.iParaElementOffset=iPos.iPhraseElementOffset=0; |
|
2303 phraseElement=iPos.iParaBasePhraseElement; |
|
2304 const TParaAttribsEntry* end=paraIx.End(paraElement); |
|
2305 do |
|
2306 {// Find the paragraph... |
|
2307 startOfPara+=len; |
|
2308 if (!(para->iParaAttribs->IsShared())) // Adjust position within phrase index |
|
2309 phraseElement+=para->iParaAttribs->iPhraseCount; |
|
2310 ++paraElement; |
|
2311 if (++para==end) |
|
2312 { |
|
2313 para=¶Ix[paraElement]; |
|
2314 end=paraIx.End(paraElement); |
|
2315 } |
|
2316 len=para->iLength; |
|
2317 } |
|
2318 while (aCharPos>=(startOfPara+len) && (paraElement+1) < paraIx.Count()); |
|
2319 iPos.iParaBasePhraseElement=phraseElement; |
|
2320 iPos.iParaElement=paraElement; |
|
2321 } |
|
2322 TInt startOfPhrase=iPos.iParaElementOffset-iPos.iPhraseElementOffset; |
|
2323 // the offset within the paragraph. |
|
2324 TInt paraElementOffset=aCharPos-startOfPara; |
|
2325 iPos.iParaElementOffset=paraElementOffset; |
|
2326 |
|
2327 if (!(para->iParaAttribs->IsShared())) |
|
2328 {// Find phrase & offset within it. |
|
2329 TInt lastPhraseLength=-1; // Record phrase length in case left match required. |
|
2330 const CArrayFix<RPhraseAttribsEntry>& phraseIx=*iPhraseIx; |
|
2331 const RPhraseAttribsEntry* phrase=&phraseIx[phraseElement]; |
|
2332 const RPhraseAttribsEntry* end=NULL; |
|
2333 for (;;) |
|
2334 { // Find the phrase in the paragraph... |
|
2335 len=phrase->Length(); |
|
2336 if (paraElementOffset<(startOfPhrase+len)) |
|
2337 break; |
|
2338 startOfPhrase+=len; |
|
2339 lastPhraseLength=len; |
|
2340 if (end==NULL) |
|
2341 end=phraseIx.End(phraseElement); |
|
2342 phraseElement++; |
|
2343 if (++phrase<end) |
|
2344 continue; |
|
2345 phrase=&phraseIx[phraseElement]; |
|
2346 end=phraseIx.End(phraseElement); |
|
2347 }//...and the offset within this. |
|
2348 // Check now for match left. |
|
2349 if ((aMode==EScanToPositionMatchLeft) && lastPhraseLength>=0 && paraElementOffset==startOfPhrase) |
|
2350 {// Match to the left most phrase if at the start of a phrase. |
|
2351 phraseElement--; |
|
2352 iPos.iPhraseElementOffset=lastPhraseLength; |
|
2353 } |
|
2354 else |
|
2355 iPos.iPhraseElementOffset=paraElementOffset-startOfPhrase; |
|
2356 } |
|
2357 else |
|
2358 { |
|
2359 __ASSERT_DEBUG(iPos.iParaBasePhraseElement==phraseElement,Panic(EDebug)); |
|
2360 } |
|
2361 iPos.iPhraseElement=phraseElement; |
|
2362 iPos.iDocPos=aCharPos; |
|
2363 if (aLastUsed) |
|
2364 *aLastUsed=iPos; |
|
2365 } |
|
2366 |
|
2367 |
|
2368 TBool CRichTextIndex::FirstPhraseOfParagraph()const |
|
2369 // Interogates the current internal position record. |
|
2370 // Return ETrue if the current phrase element is the first phrase |
|
2371 // of specific character format in the current paragraph; |
|
2372 // Otherwise return EFalse. |
|
2373 // |
|
2374 {return iPos.iPhraseElement==iPos.iParaBasePhraseElement;} |
|
2375 |
|
2376 |
|
2377 TInt CRichTextIndex::CurrentPhraseLength()const |
|
2378 // Return the length of the current phrase, where the current |
|
2379 // phrase is specified by the state of the internal position record. |
|
2380 // |
|
2381 { |
|
2382 if ((*iParaIx)[iPos.iParaElement].iParaAttribs->IsShared()) |
|
2383 return (*iParaIx)[iPos.iParaElement].iLength; |
|
2384 else |
|
2385 return (*iPhraseIx)[iPos.iPhraseElement].Length(); |
|
2386 } |
|
2387 |
|
2388 |
|
2389 TInt CRichTextIndex::CurrentPhraseOffset()const |
|
2390 // Returns the offset within the current phrase, where the current |
|
2391 // phrase is specified by the state of the internal position record. |
|
2392 // |
|
2393 { |
|
2394 if ((*iParaIx)[iPos.iParaElement].iParaAttribs->IsShared()) |
|
2395 return iPos.iParaElementOffset; // only 1 phrase in para. |
|
2396 else |
|
2397 return iPos.iPhraseElementOffset; |
|
2398 } |
|
2399 |
|
2400 |
|
2401 void CRichTextIndex::GetCurrentRecords(TCurrentIndexRecords& aRecord)const |
|
2402 // Package the phrase and paragraph index records that apply to the |
|
2403 // current paragraph and return this package. It is assumed that |
|
2404 // the caller has already set the internal position record to a valid state. |
|
2405 // |
|
2406 { |
|
2407 aRecord.iParaEntry=&(*iParaIx)[iPos.iParaElement]; |
|
2408 aRecord.iParaAttribs=aRecord.iParaEntry->iParaAttribs; |
|
2409 if (aRecord.iParaAttribs->IsShared()) |
|
2410 aRecord.iPhrase=NULL; |
|
2411 else |
|
2412 aRecord.iPhrase=&((*iPhraseIx)[iPos.iPhraseElement]); |
|
2413 } |
|
2414 |
|
2415 |
|
2416 void CRichTextIndex::GetPhraseFormat(TCurrentIndexRecords& aCurrent,TCharFormatX& aFormat,TCharFormatXMask& aMask, |
|
2417 CCharFormatLayer*& aCharBase)const |
|
2418 // Fills aFormat and aMask with the character formatting information of the current record. |
|
2419 // aCharBase is set to the basedOn link if present. |
|
2420 // Encapsulates the concepts of the specific phrase index, and the constant character format. |
|
2421 // Only senses the format in the layer, does *NOT* perform a SenseEffective. |
|
2422 // |
|
2423 { |
|
2424 CCharFormatLayer* charFormatLayer=NULL; |
|
2425 if (aCurrent.iPhrase) |
|
2426 {// Specific character formatting held by phrase index. |
|
2427 charFormatLayer=aCurrent.iPhrase->CharFormat(); |
|
2428 } |
|
2429 else |
|
2430 {// Constant character formatting held in the para attribs |
|
2431 charFormatLayer=aCurrent.iParaAttribs->iCharFormat; |
|
2432 } |
|
2433 charFormatLayer->Sense(aFormat,aMask); |
|
2434 aCharBase=(CCharFormatLayer*)(charFormatLayer->SenseBase()); |
|
2435 } |
|
2436 |
|
2437 |
|
2438 TInt CRichTextIndex::OwningParagraph(TInt aPos,TLogicalPosition* aLastUsed/*=NULL*/)const |
|
2439 // Return the paragraph element number that contains character position aPos. |
|
2440 // Assumes the caller has validated aPos. Alters the internal record position. |
|
2441 // |
|
2442 { |
|
2443 ((CRichTextIndex*)this)->ScanToPosition(aPos,EScanToPositionMatchLeft,aLastUsed); |
|
2444 return iPos.iParaElement; |
|
2445 } |
|
2446 |
|
2447 |
|
2448 void CRichTextIndex::SplitPhraseL(TInt aSplitPos) |
|
2449 // Splits the phrase at the offset aSplitPos, creating a new phrase |
|
2450 // which is filled with the split part of the current phrase, includig aSplitPos. |
|
2451 // The character format applied to the new phrase is the format of the phrase from which it has been split. |
|
2452 // The resulting new phrase is inserted into the phrase index immediately following the |
|
2453 // current element. If aSplitPos is already at a phrase boundary, then no split is performed. |
|
2454 // (This means that a picture phrase in effect can never be split). |
|
2455 // |
|
2456 { |
|
2457 SetPhraseSplit(EFalse); |
|
2458 ScanToPosition(aSplitPos,EScanToPositionAbsolute); |
|
2459 if (iPos.iPhraseElementOffset==0) |
|
2460 return; // aSplitPos on a phrase boundary; urgo no split. |
|
2461 TCurrentIndexRecords current; GetCurrentRecords(current); |
|
2462 // ASSERT: This function set can only be called on CParaAttribs that specific char format. |
|
2463 __ASSERT_ALWAYS(current.iPhrase!=NULL,Panic(ESplitPhraseCalledOnSharedPara)); |
|
2464 DoSplitPhraseL(*current.iPhrase,iPos.iPhraseElementOffset,current.iParaAttribs); |
|
2465 } |
|
2466 |
|
2467 |
|
2468 void CRichTextIndex::SplitPhraseL(TInt aPhraseElement,TInt aPhraseOffset,CParaAttribs* aParaAttribs) |
|
2469 // Splits the specified phrase at the offset aOffsetInPhrase, creating a new phrase |
|
2470 // which is filled with the split part of the current phrase, includig the split pos. |
|
2471 // The character format applied to the new phrase is the format of the phrase from which it has been split. |
|
2472 // The resulting new phrase is inserted into the phrase index immediately following the |
|
2473 // current element. If the split pos is already at a phrase boundary, then no split is performed. |
|
2474 // (This means that a picture phrase in effect can never be split). |
|
2475 // |
|
2476 { |
|
2477 SetPhraseSplit(EFalse); |
|
2478 RPhraseAttribsEntry& phrase=(*iPhraseIx)[aPhraseElement]; |
|
2479 if ((aPhraseOffset>0) && (aPhraseOffset<phrase.Length())) |
|
2480 {// Not at a phrase boundary so split the current phrase. |
|
2481 DoSplitPhraseL(phrase,aPhraseOffset,aParaAttribs); |
|
2482 } |
|
2483 } |
|
2484 |
|
2485 |
|
2486 void CRichTextIndex::DoSplitPhraseL(RPhraseAttribsEntry& aCurrentPhrase,TInt aPhraseOffset,CParaAttribs* aParaAttribs) |
|
2487 // Splits the specified phrase, creating a new phrase of the same character format. |
|
2488 // This new phrase is inserted into the phrase index immediately following the current one. |
|
2489 // |
|
2490 { |
|
2491 // ASSERT: Cannot split a picture phrase. |
|
2492 __ASSERT_DEBUG(!aCurrentPhrase.IsPicturePhrase(),Panic(ESplitPhraseCalledOnPicturePhrase)); |
|
2493 CCharFormatLayer* layer=CCharFormatLayer::NewCopyBaseL(aCurrentPhrase.CharFormat()); |
|
2494 CleanupStack::PushL(layer); |
|
2495 RPhraseAttribsEntry newPhrase(layer,aCurrentPhrase.Length()-aPhraseOffset); |
|
2496 iPhraseIx->InsertL(iPos.iPhraseElement+1,newPhrase); |
|
2497 CleanupStack::Pop(); |
|
2498 // |
|
2499 // InsertL() has invalidated the current internal position record. |
|
2500 iPhraseIx->At(iPos.iPhraseElement).SetLength(aPhraseOffset); |
|
2501 SetPhraseSplit(ETrue); |
|
2502 aParaAttribs->iPhraseCount++; |
|
2503 } |
|
2504 |
|
2505 |
|
2506 TBool CRichTextIndex::HasMarkupData(const CFormatLayer* aGlobalParaFormatLayer)const |
|
2507 // Returns ETure if this rich text instance has any specific markup, |
|
2508 // otherwise returns EFalse. |
|
2509 // The presence of specific markup is indicated by the following... |
|
2510 // 1) Style list is present (if style table is owned by the rich text) |
|
2511 // 2) Any phrase index content |
|
2512 // 3) >1 shared para attribs |
|
2513 // or |
|
2514 // 3) 1 shared para attribs that has specific markup |
|
2515 // 4) any paragraph is based on a style other than normal (the global paraformatlayer) |
|
2516 // |
|
2517 { |
|
2518 TInt phraseCount=PhraseCount(); |
|
2519 if (phraseCount>0) |
|
2520 return ETrue; |
|
2521 // |
|
2522 TInt sharedParaCount=SharedParaCount(this); |
|
2523 __ASSERT_ALWAYS(sharedParaCount>=1 || (sharedParaCount==0 && phraseCount>0),Panic(ERichTextIndexIntegrityErr)); |
|
2524 if (sharedParaCount>1) |
|
2525 return ETrue; |
|
2526 const CParaAttribs* paraAttribs=iSharedParaQueHead.First(); |
|
2527 if (!paraAttribs->iParaFormat->IsEmpty()) |
|
2528 return ETrue; |
|
2529 if (!paraAttribs->iCharFormat->IsEmpty()) |
|
2530 return ETrue; |
|
2531 if (paraAttribs->iParaFormat->SenseBase()!=aGlobalParaFormatLayer) |
|
2532 return ETrue; |
|
2533 return EFalse; |
|
2534 } |
|
2535 |
|
2536 |
|
2537 TInt CRichTextIndex::SharedParaCount(const CRichTextIndex* aSource)const |
|
2538 // Return a count of the number of shared paragraph formats present |
|
2539 // in the specified object. |
|
2540 // |
|
2541 { |
|
2542 TInt sharedParaCount = 0; |
|
2543 TDblQueIter<CParaAttribs> iterator( MUTABLE_CAST(TDblQue<CParaAttribs>&, aSource->iSharedParaQueHead) ); |
|
2544 while ( iterator++ != NULL ) |
|
2545 sharedParaCount++; |
|
2546 return sharedParaCount; |
|
2547 } |
|
2548 |
|
2549 |
|
2550 void CRichTextIndex::AppendTakingSolePictureOwnershipL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo) |
|
2551 // No paragraph style information is appended. |
|
2552 // |
|
2553 { |
|
2554 CancelInsertCharFormat(); |
|
2555 CONST_CAST(CRichTextIndex*,aSource)->CancelInsertCharFormat(); |
|
2556 |
|
2557 TInt origParaCount=ParagraphCount(); |
|
2558 TInt origPhraseCount=iPhraseIx->Count(); |
|
2559 TRAPD(ret, |
|
2560 AppendParaIndexL(aSource,aGlobalLayerInfo); |
|
2561 AppendPhraseIndexL(aSource,aGlobalLayerInfo); |
|
2562 ); |
|
2563 if (ret!=KErrNone) |
|
2564 { |
|
2565 RemoveFromPhraseIx(origPhraseCount,iPhraseIx->Count()-origPhraseCount); // remove any added phrases etc. |
|
2566 RbRemoveInsertedParaAttribsEntries(origParaCount,ParagraphCount()-origParaCount); // remove any added paragraphs etc. |
|
2567 NormalizeSharedList(); // remove any added shared paragraph attributes |
|
2568 User::Leave(ret); |
|
2569 } |
|
2570 |
|
2571 __TEST_INVARIANT; |
|
2572 } |
|
2573 |
|
2574 |
|
2575 void CRichTextIndex::AppendParaIndexL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo) |
|
2576 // |
|
2577 { |
|
2578 CRichTextStoreMap<CParaAttribs>* map=CRichTextStoreMap<CParaAttribs>::NewLC(SharedParaCount(aSource)); |
|
2579 |
|
2580 AppendSharedFormatsL(*map,aSource,aGlobalLayerInfo); |
|
2581 |
|
2582 // Extend para index by required amount |
|
2583 TInt originalParaCount=iParaIx->Count(); |
|
2584 TInt requiredParaCount=aSource->iParaIx->Count(); |
|
2585 iParaIx->AppendL(TParaAttribsEntry(),requiredParaCount); |
|
2586 |
|
2587 for (TInt ii=0;ii<requiredParaCount;ii++) |
|
2588 {// Copy the paragraph data for each of the appended paragraphs. |
|
2589 const TParaAttribsEntry& sParaEntry=(*aSource->iParaIx)[ii]; |
|
2590 const CParaAttribs* sParaAttribs=sParaEntry.iParaAttribs; |
|
2591 CParaAttribs* tParaAttribs; |
|
2592 if (sParaAttribs->IsShared()) |
|
2593 { |
|
2594 tParaAttribs=map->Item(sParaAttribs); |
|
2595 __ASSERT_DEBUG(tParaAttribs!=NULL,Panic(ESharedFormatsMapIntegrityError)); |
|
2596 tParaAttribs->iRefCount++; |
|
2597 } |
|
2598 else |
|
2599 {// Have to build up the specific para attribs |
|
2600 tParaAttribs=CParaAttribs::NewL(sParaAttribs->iParaFormat); // sets iRefCount=0, copies the format layer |
|
2601 tParaAttribs->iParaFormat->SetBase(aGlobalLayerInfo.iAggParaFormatLayer); |
|
2602 tParaAttribs->iPhraseCount=sParaAttribs->iPhraseCount; |
|
2603 } |
|
2604 TParaAttribsEntry& tParaEntry=(*iParaIx)[originalParaCount+ii]; |
|
2605 tParaEntry.iLength=sParaEntry.iLength; |
|
2606 tParaEntry.iParaAttribs=tParaAttribs; |
|
2607 |
|
2608 // tParaAttribs is attached to CRichTextIndex::iParaIx, and will be |
|
2609 // released in destructor CRichTextIndex::~CRichTextIndex(). |
|
2610 // To prevent Coverity from reporting defect, add a comment: |
|
2611 // coverity[memory_leak] |
|
2612 } |
|
2613 |
|
2614 CleanupStack::PopAndDestroy(); // map |
|
2615 } |
|
2616 |
|
2617 |
|
2618 void CRichTextIndex::AppendSharedFormatsL(CParaAttribsMap& aMap,const CRichTextIndex* aSource, |
|
2619 const TGlobalLayerInfoAppend& aGlobalLayerInfo) |
|
2620 // A map is kept, that for each original format specifies the corresponding new one that appended |
|
2621 // paragraphs should use. |
|
2622 // |
|
2623 { |
|
2624 TDblQueIter<CParaAttribs> iterator(MUTABLE_CAST(TDblQue<CParaAttribs>&,aSource->iSharedParaQueHead)); |
|
2625 CParaAttribs* currentSharedPara; |
|
2626 while ((currentSharedPara=iterator++)!=NULL) |
|
2627 { |
|
2628 __ASSERT_DEBUG(currentSharedPara->IsShared(),User::Invariant()); |
|
2629 |
|
2630 CParaFormatLayer* sPl=currentSharedPara->iParaFormat; |
|
2631 CCharFormatLayer* sCl=currentSharedPara->iCharFormat; |
|
2632 sPl->SetBase(aGlobalLayerInfo.iAggParaFormatLayer); // alter the original so that the following GetParaAttribsL() call will |
|
2633 sCl->SetBase(aGlobalLayerInfo.iAggCharFormatLayer); // match based on our global format layers, not those of aSource's. |
|
2634 CParaAttribs* newParaAttribs=FindSharedParaAttribs(*sPl,*sCl); |
|
2635 sPl->SetBase(aGlobalLayerInfo.iComParaFormatLayer); // set the global format layers back again, cos we don't want to |
|
2636 sCl->SetBase(aGlobalLayerInfo.iComCharFormatLayer); // corrupt aSource. |
|
2637 if (newParaAttribs==NULL) |
|
2638 { |
|
2639 newParaAttribs=CParaAttribs::NewL(currentSharedPara); |
|
2640 // change the based-on links (they are copied in the construction) |
|
2641 newParaAttribs->iParaFormat->SetBase(aGlobalLayerInfo.iAggParaFormatLayer); |
|
2642 newParaAttribs->iCharFormat->SetBase(aGlobalLayerInfo.iAggCharFormatLayer); |
|
2643 iSharedParaQueHead.AddLast(*newParaAttribs); |
|
2644 } |
|
2645 newParaAttribs->iRefCount--; // we have not yet linked incoming para - taken out no shares just yet |
|
2646 aMap.Bind(currentSharedPara,newParaAttribs); |
|
2647 } |
|
2648 } |
|
2649 |
|
2650 void CRichTextIndex::AppendPhraseIndexL(const CRichTextIndex* aSource,const TGlobalLayerInfoAppend& aGlobalLayerInfo) |
|
2651 // |
|
2652 { |
|
2653 TInt originalPhraseCount=iPhraseIx->Count(); |
|
2654 TInt requiredPhraseCount=aSource->iPhraseIx->Count(); |
|
2655 |
|
2656 // Extend phrase index by required amount |
|
2657 iPhraseIx->AppendL(RPhraseAttribsEntry(),requiredPhraseCount); |
|
2658 |
|
2659 CArrayFixFlat<TInt>* pictureMap=new(ELeave) CArrayFixFlat<TInt>(16); |
|
2660 CleanupStack::PushL(pictureMap); |
|
2661 |
|
2662 for (TInt jj=0;jj<requiredPhraseCount;jj++) |
|
2663 { |
|
2664 RPhraseAttribsEntry& sPhrase=(*aSource->iPhraseIx)[jj]; |
|
2665 CCharFormatLayer* sCharFormatLayer=sPhrase.CharFormat(); |
|
2666 CCharFormatLayer* charLayer=CCharFormatLayer::NewL(sCharFormatLayer); |
|
2667 charLayer->SetBase(aGlobalLayerInfo.iAggCharFormatLayer); |
|
2668 RPhraseAttribsEntry& tPhrase=(*iPhraseIx)[jj+originalPhraseCount]; |
|
2669 if (!sPhrase.IsPicturePhrase()) |
|
2670 tPhrase=RPhraseAttribsEntry(charLayer,sPhrase.Length()); |
|
2671 else |
|
2672 { |
|
2673 TPictureHeader hdr; |
|
2674 hdr=sPhrase.PictureHeader(); // copy the header from the source |
|
2675 if (hdr.iPicture.IsPtr()) |
|
2676 hdr.iPicture=NULL; // pic.ownership transferred later. |
|
2677 CleanupStack::PushL(charLayer); |
|
2678 TBool ownershipTaken(EFalse); |
|
2679 CPicturePhrase* picPhrase=CPicturePhrase::NewL(hdr,charLayer,ownershipTaken); |
|
2680 CleanupStack::Pop(); // charLayer |
|
2681 tPhrase=RPhraseAttribsEntry(picPhrase); |
|
2682 iPictureCount++; |
|
2683 pictureMap->AppendL(jj); |
|
2684 } |
|
2685 } |
|
2686 |
|
2687 // transfer pictures now |
|
2688 for (TInt kk=pictureMap->Count();--kk>=0;) |
|
2689 { |
|
2690 TInt jj=pictureMap->At(kk); |
|
2691 TPictureHeader* sHeader=(*aSource->iPhraseIx)[jj].PictureHeaderPtr(); |
|
2692 __ASSERT_DEBUG(sHeader,User::Invariant()); |
|
2693 if (sHeader->iPicture.IsPtr()) |
|
2694 { // transfer picture to us |
|
2695 TPictureHeader* tHeader=(*iPhraseIx)[jj+originalPhraseCount].PictureHeaderPtr(); |
|
2696 __ASSERT_DEBUG(tHeader,User::Invariant()); |
|
2697 tHeader->iPicture=sHeader->iPicture.AsPtr(); |
|
2698 sHeader->iPicture=NULL; |
|
2699 } |
|
2700 } |
|
2701 |
|
2702 CleanupStack::PopAndDestroy(); // pictureMap |
|
2703 } |
|
2704 |
|
2705 |
|
2706 void CRichTextIndex::AppendParagraphL(const CParaFormatLayer* aGlobalParaFormatLayer, |
|
2707 const CCharFormatLayer* aGlobalCharFormatLayer, |
|
2708 TInt aReplicas) |
|
2709 // Append aReplicas empty paragraphs, the format of which is based on the |
|
2710 // global format layers. |
|
2711 // |
|
2712 { |
|
2713 __TEST_INVARIANT; |
|
2714 |
|
2715 // add the shared para format record |
|
2716 CParaAttribs* paraAttribs=CParaAttribs::NewL(aGlobalParaFormatLayer,aGlobalCharFormatLayer); |
|
2717 paraAttribs->iParaFormat->SetBase(aGlobalParaFormatLayer); // reset the base properly |
|
2718 paraAttribs->iCharFormat->SetBase(aGlobalCharFormatLayer); // reset the base properly. |
|
2719 CleanupStack::PushL(TCleanupItem(ReleaseOnCleanup,paraAttribs)); |
|
2720 CParaAttribs* paUsed=GetParaAttribsL(aGlobalParaFormatLayer,aGlobalCharFormatLayer,paraAttribs); |
|
2721 // guaranteed not to leave as 3rd argument specified. |
|
2722 // The refCount of paUsed is incremented here by one share. |
|
2723 // |
|
2724 // add the paragraph records |
|
2725 TParaAttribsEntry paraEntry(1,paUsed); |
|
2726 iParaIx->AppendL(paraEntry,aReplicas); |
|
2727 if (paUsed!=paraAttribs) |
|
2728 CleanupStack::PopAndDestroy(); |
|
2729 else |
|
2730 CleanupStack::Pop(); |
|
2731 // |
|
2732 // set the ref count of paUsed |
|
2733 paUsed->iRefCount+=(aReplicas-1); // compensate for already adding 1 share. |
|
2734 |
|
2735 __TEST_INVARIANT; |
|
2736 } |
|
2737 |
|
2738 |
|
2739 TParaAttribsEntry::TParaAttribsEntry(): |
|
2740 iLength(0), |
|
2741 iParaAttribs(NULL) |
|
2742 { |
|
2743 } |
|
2744 |
|
2745 |
|
2746 TParaAttribsEntry::TParaAttribsEntry(TInt aLength,CParaAttribs* aParaAttribs): |
|
2747 iLength(aLength), |
|
2748 iParaAttribs(aParaAttribs) |
|
2749 { |
|
2750 } |
|
2751 |
|
2752 |
|
2753 CParaAttribs* CParaAttribs::NewL(const CParaFormatLayer* aParaLayer,const CCharFormatLayer* aCharLayer) |
|
2754 // Returns a handle to a new instance of this class. |
|
2755 // Creates a CParaAttribs with constant character formatting. |
|
2756 // |
|
2757 { |
|
2758 CParaAttribs* self=new(ELeave) CParaAttribs(); |
|
2759 CleanupStack::PushL(self); |
|
2760 self->iParaFormat=CParaFormatLayer::NewCopyBaseL(aParaLayer); |
|
2761 // iParaFormat will be released in destructor. |
|
2762 // To prevent Coverity from reporting defect, add a comment: |
|
2763 // coverity[leave_without_push] |
|
2764 self->iCharFormat=CCharFormatLayer::NewCopyBaseL(aCharLayer); |
|
2765 CleanupStack::Pop(); |
|
2766 self->iRefCount=EPrimeSharedCount; |
|
2767 return self; |
|
2768 } |
|
2769 |
|
2770 |
|
2771 CParaAttribs* CParaAttribs::NewL(const CParaFormatLayer* aParaLayer) |
|
2772 // Returns a handle to a new instance of this class. |
|
2773 // Creates a CParaAttribs for specific character formatting. |
|
2774 // |
|
2775 { |
|
2776 CParaAttribs* self=new(ELeave) CParaAttribs(); |
|
2777 CleanupStack::PushL(self); |
|
2778 self->iParaFormat=CParaFormatLayer::NewCopyBaseL(aParaLayer); |
|
2779 CleanupStack::Pop(); |
|
2780 self->iRefCount=EPrimeNonSharedCount; |
|
2781 self->iPhraseCount=1; |
|
2782 return self; |
|
2783 } |
|
2784 |
|
2785 |
|
2786 CParaAttribs* CParaAttribs::NewL(const CParaAttribs* aParaAttribs) |
|
2787 { |
|
2788 return NewL(aParaAttribs->iParaFormat,aParaAttribs->iCharFormat); |
|
2789 } |
|
2790 |
|
2791 |
|
2792 CParaAttribs::CParaAttribs(): |
|
2793 iRefCount(-1) // Ensures Destruct works correctly when called on a semi-initialised object. |
|
2794 { |
|
2795 } |
|
2796 |
|
2797 |
|
2798 void CParaAttribs::Release() |
|
2799 // Release a share on this CParaAttribs. |
|
2800 // If after this, no shares remain, destroy this CParaAttribs. |
|
2801 // |
|
2802 { |
|
2803 iRefCount--; |
|
2804 if (iRefCount<=0) |
|
2805 delete this; |
|
2806 } |
|
2807 |
|
2808 |
|
2809 void CParaAttribs::Release(TInt aCount) |
|
2810 // Release aCount number of shares of this CParaAttribs. |
|
2811 // If after this, no shares remain, destroy this CParaAttribs. |
|
2812 // |
|
2813 { |
|
2814 iRefCount-=aCount; |
|
2815 if (iRefCount<=0) |
|
2816 delete this; |
|
2817 } |
|
2818 |
|
2819 |
|
2820 CParaAttribs::~CParaAttribs() |
|
2821 // Release the memory associated with this object. |
|
2822 // |
|
2823 { |
|
2824 delete iParaFormat; |
|
2825 if (iRefCount==0) |
|
2826 {// Constant character formatting - in the shared list. |
|
2827 delete iCharFormat; |
|
2828 link.Deque(); // Remove this para attribs from the shared list. |
|
2829 } |
|
2830 } |
|
2831 |
|
2832 |
|
2833 TInt CParaAttribs::PhraseCount()const |
|
2834 // Return a count of the number of phrases in this para attribs. |
|
2835 // |
|
2836 {return (iRefCount>=1)?1:iPhraseCount;} |
|
2837 |
|
2838 |
|
2839 DLLEXPORT_C void RPhraseAttribsEntry::__DbgTestInvariant()const |
|
2840 // Class invariants. |
|
2841 // |
|
2842 { |
|
2843 #ifdef _DEBUG |
|
2844 // ASSERT: iLength is +ve (applying to character formatting, or is set to indicate a picture phrase. |
|
2845 __ASSERT_DEBUG(iLength>=0 || IsPicturePhrase(),User::Invariant()); |
|
2846 #endif |
|
2847 } |
|
2848 |
|
2849 |
|
2850 RPhraseAttribsEntry::RPhraseAttribsEntry(): |
|
2851 iLength(0), |
|
2852 iCharFormat(NULL) |
|
2853 { |
|
2854 } |
|
2855 |
|
2856 |
|
2857 RPhraseAttribsEntry::RPhraseAttribsEntry(CCharFormatLayer* aCharFormat,TInt aLength): |
|
2858 iLength(aLength), |
|
2859 iCharFormat(aCharFormat) |
|
2860 { |
|
2861 } |
|
2862 |
|
2863 |
|
2864 RPhraseAttribsEntry::RPhraseAttribsEntry(CPicturePhrase* aPicturePhrase): |
|
2865 iLength(EPictureIndicator), |
|
2866 iPicturePhrase(aPicturePhrase) |
|
2867 { |
|
2868 } |
|
2869 |
|
2870 |
|
2871 void RPhraseAttribsEntry::AssignAndRelease(const RPhraseAttribsEntry& aPhrase) |
|
2872 // Assign the state of the specified object to this, |
|
2873 // |
|
2874 { |
|
2875 iLength=aPhrase.iLength; |
|
2876 iCharFormat=aPhrase.iCharFormat; // both union members share the same address space, so this is fine. |
|
2877 } |
|
2878 |
|
2879 |
|
2880 void RPhraseAttribsEntry::Discard() |
|
2881 // Free storage. |
|
2882 // |
|
2883 { |
|
2884 __TEST_INVARIANT; |
|
2885 |
|
2886 if (iLength==EPictureIndicator) |
|
2887 delete iPicturePhrase; |
|
2888 else |
|
2889 delete iCharFormat; |
|
2890 } |
|
2891 |
|
2892 |
|
2893 void RPhraseAttribsEntry::ExternalizeL(RWriteStream& aStream)const |
|
2894 // Save this phrase into aStream. |
|
2895 // |
|
2896 { |
|
2897 TUint8 picIndicator=(TUint8)(IsPicturePhrase()!=EFalse); |
|
2898 aStream.WriteUint8L(picIndicator); |
|
2899 aStream.WriteInt32L(Length()); |
|
2900 aStream<< *CharFormat(); |
|
2901 if ((TBool)picIndicator) |
|
2902 aStream<< *PictureHeaderPtr(); |
|
2903 } |
|
2904 |
|
2905 |
|
2906 CCharFormatLayer* RPhraseAttribsEntry::CharFormat()const |
|
2907 // Returns a pointer the CCharFormatLayer of this phrase. |
|
2908 // |
|
2909 {return (iLength==EPictureIndicator)?iPicturePhrase->iCharFormat:iCharFormat;} |
|
2910 |
|
2911 |
|
2912 void RPhraseAttribsEntry::SetLength(TInt aLength) |
|
2913 // Sets the phrase length. |
|
2914 // |
|
2915 { |
|
2916 __TEST_INVARIANT; |
|
2917 |
|
2918 iLength=aLength; |
|
2919 } |
|
2920 |
|
2921 |
|
2922 void RPhraseAttribsEntry::AdjustLength(TInt aIncrement) |
|
2923 // Adjusts the length of the phrase by the signed value aIncrement. |
|
2924 // |
|
2925 { |
|
2926 // ASSERT: The length of a picture phrase may only be altered by deleting it, in which case |
|
2927 // the only adjustment made will be an increment of -1 (EPictureIndicator). |
|
2928 __ASSERT_DEBUG(!IsPicturePhrase() || (IsPicturePhrase() && aIncrement==EPictureIndicator) |
|
2929 || (IsPicturePhrase() && aIncrement==0) |
|
2930 ,Panic(EModifiedPicturePhraseLength)); |
|
2931 TInt len=iLength; |
|
2932 iLength=(len==EPictureIndicator) |
|
2933 ? len-aIncrement |
|
2934 : len+aIncrement; |
|
2935 } |
|
2936 |
|
2937 |
|
2938 TInt RPhraseAttribsEntry::GetPictureSizeInTwips(TSize& aSize)const |
|
2939 // If this is a picture phrase, write the size of the picture to aSize, |
|
2940 // otherwise return KErrNotFound. |
|
2941 // |
|
2942 { |
|
2943 if (!IsPicturePhrase()) |
|
2944 return KErrNotFound; |
|
2945 if (iPicturePhrase->iPicHdr.iPicture.IsPtr() && iPicturePhrase->iPicHdr.iPicture.AsPtr()) |
|
2946 iPicturePhrase->iPicHdr.iPicture->GetSizeInTwips(aSize); |
|
2947 else |
|
2948 aSize=iPicturePhrase->iPicHdr.iSize; |
|
2949 return KErrNone; |
|
2950 } |
|
2951 |
|
2952 |
|
2953 TPictureHeader RPhraseAttribsEntry::PictureHeader()const |
|
2954 // Return the picture header describing the picture at character position aPos. |
|
2955 // If there is no picture at character position aPos, a default picture header is returned. |
|
2956 // |
|
2957 { |
|
2958 return (IsPicturePhrase()) |
|
2959 ? iPicturePhrase->iPicHdr |
|
2960 : TPictureHeader(); |
|
2961 } |
|
2962 |
|
2963 |
|
2964 const CPicture* RPhraseAttribsEntry::PictureHandleL(const MPictureFactory* aFactory, |
|
2965 const MRichTextStoreResolver* aResolver, |
|
2966 TInt aPos, |
|
2967 MLayDoc::TForcePictureLoad aForceLoad)const |
|
2968 // For a text phrase returns NULL. |
|
2969 // For a picture phrase returns a pointer to the picture object itself. |
|
2970 // May leave since loading of pictures is deferred until this point, |
|
2971 // ie, when the picture is required. |
|
2972 // Also returns NULL if the picture is not in memory *and* TForcePictureLoad is false. |
|
2973 // |
|
2974 { |
|
2975 if (iLength!=EPictureIndicator) |
|
2976 return NULL; |
|
2977 else |
|
2978 {// Check if the picture is in memory |
|
2979 CPicture* handle=NULL; |
|
2980 if (iPicturePhrase->iPicHdr.iPicture.IsPtr()) |
|
2981 handle=iPicturePhrase->iPicHdr.iPicture; |
|
2982 else |
|
2983 {// Check if the picture should be loaded from persistent storage |
|
2984 if (aForceLoad==MLayDoc::EForceLoadTrue) // picture not in memory, so load it. |
|
2985 { |
|
2986 if (aResolver==NULL || aFactory==NULL) |
|
2987 return NULL; |
|
2988 const CStreamStore& store=aResolver->StreamStoreL(aPos); |
|
2989 aFactory->NewPictureL(iPicturePhrase->iPicHdr,store); |
|
2990 handle=iPicturePhrase->iPicHdr.iPicture; |
|
2991 } |
|
2992 } |
|
2993 return handle; |
|
2994 } |
|
2995 } |
|
2996 |
|
2997 |
|
2998 TPictureHeader* RPhraseAttribsEntry::PictureHeaderPtr()const |
|
2999 // For a [text] phrase returns NULL. |
|
3000 // For a picture phrase returns a pointer to the picture header. |
|
3001 // |
|
3002 {return (iLength==EPictureIndicator)? &iPicturePhrase->iPicHdr:NULL;} |
|
3003 |
|
3004 |
|
3005 CCharFormatLayer* RPhraseAttribsEntry::ReleaseCharFormatLayerOwnership() |
|
3006 // Return a handle to the character format layer, then set this handle to it to NULL. |
|
3007 // thus giving up ownership of the object. |
|
3008 // |
|
3009 { |
|
3010 CCharFormatLayer*& layer=(iLength==EPictureIndicator)?iPicturePhrase->iCharFormat:iCharFormat; |
|
3011 CCharFormatLayer* charFormatLayer=layer; |
|
3012 layer=NULL; |
|
3013 return charFormatLayer; |
|
3014 } |
|
3015 |
|
3016 |
|
3017 TBool RPhraseAttribsEntry::IsIdentical(const RPhraseAttribsEntry& aPhrase)const |
|
3018 // Returns ETrue if this phrase is identical to the specified phrase. |
|
3019 // otherwise returns EFalse. |
|
3020 // The 2 are equal only if they are both non-zero length text phrases, and of identical character format. |
|
3021 // |
|
3022 { |
|
3023 if (iLength<=0) // picture or zero-length |
|
3024 return EFalse; |
|
3025 if (aPhrase.iLength<=0) // picture or zero-length |
|
3026 return EFalse; |
|
3027 return iCharFormat->IsIdentical(aPhrase.iCharFormat,EFalse); // EFalse=do not compare based-on link |
|
3028 } |
|
3029 |
|
3030 |
|
3031 CPicturePhrase* CPicturePhrase::NewL(const TPictureHeader& aPicHdr,TCharFormatX& aFormat, |
|
3032 TCharFormatXMask& aMask,CCharFormatLayer* aCharBase, |
|
3033 TBool& aPictureOwnershipTaken) |
|
3034 { |
|
3035 CPicturePhrase* self=new(ELeave) CPicturePhrase(aPicHdr,aPictureOwnershipTaken); |
|
3036 CleanupStack::PushL(self); |
|
3037 self->ConstructL(aFormat,aMask,aCharBase); |
|
3038 CleanupStack::Pop(); |
|
3039 return self; |
|
3040 } |
|
3041 |
|
3042 |
|
3043 // The charLayer is assumed to have a valid based-on link already set. |
|
3044 // Called as part of the rich text index Internalize only. |
|
3045 CPicturePhrase* CPicturePhrase::NewL(const TPictureHeader& aPicHdr, |
|
3046 CCharFormatLayer* aCharLayer, |
|
3047 TBool& aPictureOwnershipTaken) |
|
3048 { |
|
3049 return new(ELeave) CPicturePhrase(aPicHdr,aCharLayer,aPictureOwnershipTaken); |
|
3050 } |
|
3051 |
|
3052 |
|
3053 CPicturePhrase::CPicturePhrase(const TPictureHeader& aPicHdr,TBool& aPictureOwnershipTaken): |
|
3054 iPicHdr(aPicHdr) |
|
3055 { |
|
3056 aPictureOwnershipTaken=ETrue; |
|
3057 } |
|
3058 |
|
3059 |
|
3060 CPicturePhrase::CPicturePhrase(const TPictureHeader& aPicHdr, |
|
3061 CCharFormatLayer* aCharLayer, |
|
3062 TBool& aPictureOwnershipTaken): |
|
3063 iCharFormat(aCharLayer), |
|
3064 iPicHdr(aPicHdr) |
|
3065 { |
|
3066 aPictureOwnershipTaken=ETrue; |
|
3067 } |
|
3068 |
|
3069 |
|
3070 void CPicturePhrase::ConstructL(TCharFormatX& aFormat,TCharFormatXMask& aMask,CCharFormatLayer* aCharBase) |
|
3071 { |
|
3072 iCharFormat=CCharFormatLayer::NewL(aFormat,aMask); |
|
3073 iCharFormat->SetBase(aCharBase); |
|
3074 } |
|
3075 |
|
3076 |
|
3077 CPicturePhrase::~CPicturePhrase() |
|
3078 { |
|
3079 iPicHdr.DeletePicture(); |
|
3080 delete iCharFormat; |
|
3081 } |
|
3082 |
|
3083 TLogicalPosition::TLogicalPosition(): |
|
3084 iDocPos(0), |
|
3085 iParaElement(0), |
|
3086 iParaElementOffset(0), |
|
3087 iPhraseElement(0), |
|
3088 iPhraseElementOffset(0) |
|
3089 { |
|
3090 } |
|
3091 |
|
3092 |
|
3093 void TLogicalPosition::Clear() |
|
3094 // Reset this logical position record. |
|
3095 // |
|
3096 { |
|
3097 *this=TLogicalPosition(); |
|
3098 iParaBasePhraseElement=0; |
|
3099 } |