|
1 /* |
|
2 * Copyright (c) 1999-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 * TAGMA's bytecode interpreter classes. These convert between document positions and x-y coordinates, |
|
16 * draw the text, find the bytecode for some text, and supply information about lines. |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 #include "TMSTD.H" |
|
22 #include "TMINTERP.H" |
|
23 #include "TmHighlightSource.h" |
|
24 #include <s32mem.h> |
|
25 #include <frmtlay.h> |
|
26 |
|
27 TTmInterpreterParam::TTmInterpreterParam(const CTmTextLayout& aTextLayout): |
|
28 iByteCode(&aTextLayout.Code()), |
|
29 iCodeStart(0), |
|
30 iCodeEnd(aTextLayout.Code().Size()), |
|
31 iTextStart(aTextLayout.StartChar()), |
|
32 iWidth(aTextLayout.LayoutWidth()), |
|
33 iDrawingInterpFlags(aTextLayout.GetDrawingInterpFlags()) |
|
34 { |
|
35 } |
|
36 |
|
37 TTmInterpreterParam::TTmInterpreterParam(const CTmCode& aByteCode): |
|
38 iByteCode(&aByteCode), |
|
39 iCodeStart(0), |
|
40 iCodeEnd(aByteCode.Size()), |
|
41 iTextStart(0), |
|
42 iWidth(0), |
|
43 iDrawingInterpFlags(0) |
|
44 { |
|
45 } |
|
46 |
|
47 TTmInterpreter::TTmInterpreter(const TTmInterpreterParam& aParam,const TPoint* aTopLeft): |
|
48 iReader(*aParam.iByteCode,aParam.iCodeStart,aParam.iCodeEnd), |
|
49 iTextPos(aParam.iTextStart), |
|
50 iOp(0), |
|
51 iOpMod(0), |
|
52 iOpStartCode(0), |
|
53 iOpEndCode(0), |
|
54 iOpSubscript(0), |
|
55 iVisualEndOfLineIsAmbiguous(ETrue), |
|
56 iVisualStartOfLineIsAmbiguous(ETrue), |
|
57 iInlineTextFormat(0), |
|
58 iLabelType(MTmSource::ENoLabel), |
|
59 iBdState(NULL) |
|
60 { |
|
61 iOpStartChar = iOpEndChar = iTextPos; |
|
62 iTextLayoutWidth = aParam.iWidth; |
|
63 if (aTopLeft) |
|
64 iTextLayoutTopLeft = *aTopLeft; |
|
65 iNextLineTop = iTextLayoutTopLeft.iY; |
|
66 iNextLineStartChar = iTextPos; |
|
67 iLineInfo.iLineNumber = -1; |
|
68 iLineInfo.iParNumber = -1; |
|
69 iLineInfo.iLineInPar = -1; |
|
70 iLineInfo.iFlags = 0; |
|
71 if (0 == aParam.iTextStart) |
|
72 { |
|
73 iLineInfo.iFlags = TTmLineInfo::ELineEndsInForcedLineBreak; |
|
74 iVisualEndOfLineIsAmbiguous = EFalse; |
|
75 } |
|
76 } |
|
77 |
|
78 /** |
|
79 * Returns ETrue if the document position is within the current line. |
|
80 * @internalComponent |
|
81 */ |
|
82 TBool TTmInterpreter::PosIsInLine(const TTmDocPos& aDocPos) const |
|
83 { |
|
84 if (aDocPos.iPos < iOpStartChar || iOpEndChar < aDocPos.iPos) |
|
85 return EFalse; |
|
86 if (iOpStartChar < aDocPos.iPos && aDocPos.iPos < iOpEndChar) |
|
87 return ETrue; |
|
88 if (aDocPos.iPos == iOpStartChar) |
|
89 return aDocPos.iLeadingEdge || !iVisualStartOfLineIsAmbiguous; |
|
90 // aDocPos.iPos == iOpEndChar |
|
91 return !aDocPos.iLeadingEdge && iVisualEndOfLineIsAmbiguous; |
|
92 } |
|
93 |
|
94 /** |
|
95 * Read an operator EOpLine and its arguments from the bytecode, updating the |
|
96 * member variables accordingly. |
|
97 * @param aChars Number of characters in the line. |
|
98 * @return Number of bytes in the byte code for the line. |
|
99 * @internalComponent |
|
100 */ |
|
101 TInt TTmInterpreter::ReadOpLine(TInt aChars) |
|
102 { |
|
103 iVisualStartOfLineIsAmbiguous = iVisualEndOfLineIsAmbiguous; |
|
104 iLineInfo.iLineNumber++; |
|
105 iLineInfo.iLineInPar++; |
|
106 iLineInfo.iFlags = 0; |
|
107 if (iOpMod & EModParStart) |
|
108 { |
|
109 iVisualStartOfLineIsAmbiguous = EFalse; |
|
110 iLineInfo.iParNumber++; |
|
111 iLineInfo.iLineInPar = 0; |
|
112 iLineInfo.iParTop = iNextLineTop; |
|
113 iLineInfo.iFlags |= TTmLineInfo::EParStart; |
|
114 } |
|
115 if (iOpMod & EModParEnd) |
|
116 iLineInfo.iFlags |= TTmLineInfo::EParEnd; |
|
117 TInt flags = 0; |
|
118 if (iOpMod & EModLineFlags) |
|
119 flags = iReader.ReadNumber(); // <F> (flags) |
|
120 if (flags & ELineFlagLineEndsInForcedLineBreak) |
|
121 iLineInfo.iFlags |= TTmLineInfo::ELineEndsInForcedLineBreak; |
|
122 iVisualEndOfLineIsAmbiguous = flags & ELineFlagVisualEndOfLineIsAmbiguous; |
|
123 if (iOpMod & EModRightToLeft) |
|
124 iLineInfo.iFlags |= TTmLineInfo::EParRightToLeft; |
|
125 |
|
126 TInt extra_bytes = iReader.ReadNumber(); // <B> (bytecode size) |
|
127 |
|
128 // Set line information; read height <H> and inner rect <I> and make band-relative |
|
129 iLineInfo.iStart = iOpStartChar = iNextLineStartChar; |
|
130 iLineInfo.iEnd = iOpEndChar = iNextLineStartChar = iOpStartChar + aChars; |
|
131 iLineInfo.iOuterRect.iTl.iX = iTextLayoutTopLeft.iX; |
|
132 iLineInfo.iOuterRect.iBr.iX = iTextLayoutTopLeft.iX + iTextLayoutWidth; |
|
133 iLineInfo.iOuterRect.iTl.iY = iNextLineTop; |
|
134 iNextLineTop += iReader.ReadNumber(); // <H> (height) |
|
135 iLineInfo.iOuterRect.iBr.iY = iNextLineTop; |
|
136 iLineInfo.iInnerRect = iReader.ReadRect(); // <I> (inner rectangle) |
|
137 iLineInfo.iInnerRect.Move(iLineInfo.iOuterRect.iTl); |
|
138 iLineInfo.iBaseline = iLineInfo.iInnerRect.iTl.iY + iReader.ReadNumber(); // <A> (ascent) |
|
139 |
|
140 // Set the start and end pen positions |
|
141 iOpStartPen = iLineInfo.iInnerRect.iTl; |
|
142 iOpStartPen.iY = iLineInfo.iBaseline; |
|
143 iOpEndPen = iLineInfo.iInnerRect.iBr; |
|
144 iOpEndPen.iY = iLineInfo.iBaseline; |
|
145 |
|
146 // Read the bidirectional state immediately if it is present and is wanted (iBdState is non-null) |
|
147 //first reset the bidirectional state pointer - if the state is not present in the |
|
148 //bytecode that means that it's the default state |
|
149 if(iBdState) |
|
150 { |
|
151 iBdState->Reset(); |
|
152 } |
|
153 while (iBdState && iReader.CodePos() < iReader.CodeEndPos() |
|
154 && iReader.PeekByte() == EOpParam) |
|
155 { |
|
156 TInt end_code = iReader.CodePos() + extra_bytes; |
|
157 iReader.ReadByte(); // skip EOpParam |
|
158 TUint8 id = iReader.ReadByte(); |
|
159 TInt bytes = iReader.ReadNumber(); |
|
160 if (id == EParamBdState) |
|
161 { |
|
162 RBufReadStream stream(*iReader.Code().Buffer(),iReader.CodePos()); |
|
163 TRAPD(error,iBdState->InternalizeL(stream)); |
|
164 if (error) |
|
165 Panic(ECorrupt); |
|
166 stream.Close(); |
|
167 } |
|
168 Skip(iReader.CodePos() + bytes,iOpStartChar); |
|
169 extra_bytes = end_code - iReader.CodePos(); |
|
170 } |
|
171 |
|
172 // Set the interpreter text and pen positions. |
|
173 iPen = iOpStartPen; |
|
174 iTextPos = iOpStartChar; |
|
175 |
|
176 return extra_bytes; |
|
177 } |
|
178 |
|
179 /** Read an operator and its arguments from the bytecode, updating the member |
|
180 variables accordingly. Note that the current position in the byte code is |
|
181 not necessarily brought up to the next operator. |
|
182 @pre The current position in the byte code is at an operator. |
|
183 @return EFalse if there was insufficient byte code to read. |
|
184 @internalComponent */ |
|
185 TBool TTmInterpreter::Next() |
|
186 { |
|
187 if (iReader.CodePos() >= iReader.CodeEndPos()) |
|
188 return FALSE; |
|
189 |
|
190 // Initialise start character, pen position and code position. |
|
191 iOpStartChar = iTextPos; |
|
192 iOpStartPen = iPen; |
|
193 iOpStartCode = iReader.CodePos(); |
|
194 |
|
195 // Unpack the operator. |
|
196 iOp = iOpMod = iReader.ReadByte(); |
|
197 iOp &= KMaskOpcode; // top three bits |
|
198 iOpMod &= KMaskModifiers; // low five bits |
|
199 |
|
200 TInt chars = 1; |
|
201 iOpSubscript = 0; |
|
202 if (iOp == EOpLine) |
|
203 { |
|
204 chars = iReader.ReadNumber(); |
|
205 iLineContextChar = iReader.ReadNumber(); // Read the context for this line |
|
206 } |
|
207 |
|
208 else |
|
209 { |
|
210 // Read optional arguments <P>, <N> and <Y> |
|
211 if (iOpMod & EModPos) |
|
212 iOpStartChar += iReader.ReadNumber(); |
|
213 if (iOpMod & EModCount) |
|
214 chars = iReader.ReadNumber(); |
|
215 if (iOpMod & EModSubscript) |
|
216 iOpSubscript = iReader.ReadNumber(); |
|
217 } |
|
218 iOpEndChar = iOpStartChar + chars; |
|
219 iOpEndPen = iOpStartPen; |
|
220 |
|
221 TInt extra_bytes = 0; |
|
222 switch (iOp) |
|
223 { |
|
224 case EOpLine: |
|
225 extra_bytes = ReadOpLine(chars); |
|
226 break; |
|
227 |
|
228 case EOpText: |
|
229 case EOpSpecialChar: |
|
230 { |
|
231 TInt deltaX = iReader.ReadNumber(); |
|
232 if (0 <= deltaX) |
|
233 iOpEndPen.iX += deltaX; |
|
234 else |
|
235 iOpStartPen.iX += deltaX; |
|
236 } |
|
237 iContextChar = iReader.ReadNumber(); // Read the context for this chunk. |
|
238 iTextPos = iOpEndChar; |
|
239 iPen.iX = iOpEndPen.iX; |
|
240 break; |
|
241 |
|
242 case EOpInlineText: |
|
243 iOpEndPen.iX += iReader.ReadNumber(); |
|
244 iInlineTextFormat = iReader.ReadNumber(); |
|
245 { |
|
246 iInlineText.SetLength(chars + 2); |
|
247 iInlineText[0] = 0xFFFF; |
|
248 for (int i = 0; i < chars; i++) |
|
249 iInlineText[i+1] = (TText)iReader.ReadNumber(); |
|
250 iInlineText[chars+1] = 0xFFFF; |
|
251 } |
|
252 iOpEndChar = iOpStartChar; |
|
253 iTextPos = iOpEndChar; |
|
254 iPen.iX = iOpEndPen.iX; |
|
255 break; |
|
256 |
|
257 case EOpRule: |
|
258 iBounds = iReader.ReadRect(); |
|
259 iBounds.Move(iOpStartPen); |
|
260 iRuleColour = TRgb(iReader.ReadNumber()); |
|
261 break; |
|
262 |
|
263 case EOpDoc: |
|
264 extra_bytes = iReader.ReadNumber(); // <B> (bytecode size) |
|
265 iBounds = iReader.ReadRect(); // <R> (bounds) |
|
266 iBounds.Move(iOpStartPen); |
|
267 iOpEndPen.iX = iBounds.iBr.iX; |
|
268 break; |
|
269 |
|
270 case EOpLabel: |
|
271 extra_bytes = iReader.ReadNumber(); // <B> (bytecode size) |
|
272 iBounds = iReader.ReadRect(); // <R> (bounds) |
|
273 iLabelType = (MTmSource::TLabelType)iReader.ReadNumber(); // <L> (label type) |
|
274 break; |
|
275 |
|
276 case EOpParam: |
|
277 iParamId = iReader.ReadByte(); |
|
278 iOpEndChar = iOpStartChar; // parameters consume no text |
|
279 extra_bytes = iReader.ReadNumber(); // <B> (bytecode size) |
|
280 break; |
|
281 |
|
282 default: |
|
283 Panic(ECorrupt); |
|
284 break; |
|
285 } |
|
286 |
|
287 iOpEndCode = iReader.CodePos() + extra_bytes; |
|
288 |
|
289 return TRUE; |
|
290 } |
|
291 |
|
292 /** |
|
293 * Sets the position within the byte code. |
|
294 * @param aCodePos The position within the byte code to go to. |
|
295 * @param aTextPos The document position that corresponds to aCodePos. |
|
296 * @internalComponent |
|
297 */ |
|
298 void TTmInterpreter::Skip(TInt aCodePos,TInt aTextPos) |
|
299 { |
|
300 iReader.SetCodePos(aCodePos); |
|
301 iTextPos = aTextPos; |
|
302 } |
|
303 |
|
304 /** Returns the picture subscript value */ |
|
305 TInt TTmInterpreter::Subscript() |
|
306 { |
|
307 return iOpSubscript; |
|
308 } |
|
309 |
|
310 /** |
|
311 @internalComponent |
|
312 */ |
|
313 RTmGeneralInterpreter::RTmGeneralInterpreter(MTmSource& aSource, |
|
314 const TTmInterpreterParam& aParam, const TPoint* aTopLeft) |
|
315 : TTmInterpreter(aParam,aTopLeft), |
|
316 iTextCache(aSource,aSource.InterpretDevice()) |
|
317 { |
|
318 iCopyFit = &aSource.InterpretDevice() != &aSource.FormatDevice(); |
|
319 iTmTextDrawExt = reinterpret_cast <MTmTextDrawExt*> (Source().GetExtendedInterface(KTmTextDrawExtId)); |
|
320 if(!iTmTextDrawExt) |
|
321 { |
|
322 iTmTextDrawExt = &iTmTextDrawExtDefault; |
|
323 } |
|
324 __ASSERT_ALWAYS(iTmTextDrawExt != NULL, Panic(ENotImplemented)); |
|
325 } |
|
326 |
|
327 /** |
|
328 * Get source text starting at aPos and not more than (aEndChar - aPos) |
|
329 * characters. |
|
330 * @param aPos The start position for the text to be returned. |
|
331 * @param aEndChar The maximum position to be returned plus one. |
|
332 * @param aText Returns a view of the text. |
|
333 * @param aFormat |
|
334 * If non-null, returns the format of this text. All the text returned is |
|
335 * in this format. |
|
336 * @param aFont If aFont is not null, on return contains a pointer to an opened CTmTextFontCache* |
|
337 The caller must call Close on aFont when finished with the font. |
|
338 * @internalComponent |
|
339 */ |
|
340 void RTmGeneralInterpreter::GetText(TInt aPos,TInt aEndChar,TPtrC& aText,TTmCharFormat* aFormat,CTmTextFontCache** aFont) |
|
341 { |
|
342 iTextCache.GetText(aPos,aEndChar,aText,aFormat,aFont); |
|
343 } |
|
344 |
|
345 /** |
|
346 * Gets the inline text inserted by the formatter in the current position. |
|
347 * @param aText Returns the inline text. Valid until the position is moved. |
|
348 * @param aFormat If non-null, returns the format of the inline text. |
|
349 * @param aFont If aFont is not null, on return contains a pointer to an opened CTmTextFontCache* |
|
350 The caller must call Close on aFont when finished with the font. |
|
351 * @internalComponent |
|
352 */ |
|
353 void RTmGeneralInterpreter::GetInlineText(TPtrC& aText,TTmCharFormat* aFormat,CTmTextFontCache** aFont) |
|
354 { |
|
355 TPtrC p; |
|
356 TInt inlineTextFormatPos = InlineTextFormat() + LineInfo().iStart; |
|
357 //InlineTextFormat(): the offset position in current line |
|
358 //LineInfo().iStart : start position of current line |
|
359 //inlineTextFormatPos : position in the whole document |
|
360 |
|
361 iTextCache.GetText(inlineTextFormatPos,KMaxTInt,p,aFormat,aFont); |
|
362 aText.Set(InlineText()); |
|
363 } |
|
364 |
|
365 /** |
|
366 * Returns the number of lines in the band. |
|
367 * @return Number of lines formatted. |
|
368 * @internalComponent |
|
369 */ |
|
370 TInt TTmInterpreter::Lines() |
|
371 { |
|
372 while (Next()) |
|
373 { |
|
374 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
375 Skip(); |
|
376 } |
|
377 return iLineInfo.iLineNumber + 1; |
|
378 } |
|
379 |
|
380 /** |
|
381 * Returns the number of paragraphs in the band. |
|
382 * @return Number of paragraphs formatted. |
|
383 * @internalComponent |
|
384 */ |
|
385 TInt TTmInterpreter::Paragraphs() |
|
386 { |
|
387 while (Next()) |
|
388 { |
|
389 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
390 Skip(); |
|
391 } |
|
392 return iLineInfo.iParNumber + 1; |
|
393 } |
|
394 |
|
395 /** |
|
396 * Iterates to the line containing the document position if any. Any position |
|
397 * from CTmTextLayout::StartChar() to CTmTextLayout::EndChar() inclusive can be |
|
398 * found. |
|
399 * @param aDocPos The document position to be found. |
|
400 * @return ETrue if it was found. |
|
401 * @internalComponent |
|
402 */ |
|
403 TBool TTmInterpreter::DocPosToLine(const TTmDocPosSpec& aDocPos) |
|
404 { |
|
405 /* |
|
406 Convert to a document position. Treat positions specified using directionality as |
|
407 trailing, then correct to the following line if necessary. |
|
408 */ |
|
409 TTmDocPos doc_pos(aDocPos.iPos,aDocPos.iType == TTmDocPosSpec::ELeading); |
|
410 |
|
411 if (!Next()) |
|
412 return EFalse; |
|
413 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
414 while (!PosIsInLine(doc_pos)) |
|
415 { |
|
416 Skip(); |
|
417 if (!Next()) |
|
418 return EFalse; |
|
419 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
420 } |
|
421 |
|
422 /* |
|
423 If the position is at the end of the line and was sought by direction it might not be in the line; |
|
424 if not it will be in the next line if any. Read operators and check for the position until it is |
|
425 found or we get to the next line. |
|
426 */ |
|
427 if (aDocPos.iPos == EndChar() |
|
428 && aDocPos.iType != TTmDocPosSpec::ETrailing |
|
429 && aDocPos.iType != TTmDocPosSpec::ELeading |
|
430 && !AtEndOfTextLayout()) |
|
431 { |
|
432 TBool rightToLeft = (aDocPos.iType == TTmDocPosSpec::ERightToLeft); |
|
433 while (Next() && Op() != EOpLine) |
|
434 { |
|
435 TBool sameDirectionality = rightToLeft? |
|
436 RightToLeft() : !RightToLeft(); |
|
437 if (aDocPos.iPos == EndChar() && sameDirectionality) |
|
438 return ETrue; |
|
439 } |
|
440 } |
|
441 |
|
442 return ETrue; |
|
443 } |
|
444 |
|
445 /** |
|
446 * Iterates to the line with the specified line number if any. |
|
447 * @param aLineNumber The line number to find. |
|
448 * @return ETrue if the line was found (i.e. if it is formatted). |
|
449 * @internalComponent |
|
450 */ |
|
451 TBool TTmInterpreter::LineNumberToLine(TInt aLineNumber) |
|
452 { |
|
453 while (Next()) |
|
454 { |
|
455 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
456 if (iLineInfo.iLineNumber == aLineNumber) |
|
457 return TRUE; |
|
458 else |
|
459 Skip(); |
|
460 } |
|
461 return EFalse; |
|
462 } |
|
463 |
|
464 /** |
|
465 * Iterates to the specified line of the specified paragraph. This function |
|
466 * will always return ETrue if the paragraph is formatted. If the line number |
|
467 * is out of range it will be camped to the correct range; thus if aLineInPar |
|
468 * is KMaxTInt the last line of the paragraph is found. |
|
469 * @param aParNumber Paragraph number to be found. |
|
470 * @param aLineInPar Line number within paragraph to be found. |
|
471 * @return |
|
472 * ETrue if the operation is successful. This will be the case if the |
|
473 * applicable line is formatted. |
|
474 * @internalComponent |
|
475 */ |
|
476 TBool TTmInterpreter::ParNumberToLine(TInt aParNumber,TInt aLineInPar) |
|
477 { |
|
478 while (Next()) |
|
479 { |
|
480 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
481 if (iLineInfo.iParNumber == aParNumber) |
|
482 { |
|
483 if (iLineInfo.iLineInPar >= aLineInPar || ParEnd()) |
|
484 return TRUE; |
|
485 } |
|
486 Skip(); |
|
487 } |
|
488 return EFalse; |
|
489 } |
|
490 |
|
491 /** |
|
492 * Iterates to the line containing the specified Y position number if any. |
|
493 * @param aYPos The Y position to find. |
|
494 * @return ETrue if the line was found (i.e. if it is formatted). |
|
495 * @internalComponent |
|
496 */ |
|
497 TBool TTmInterpreter::YPosToLine(TInt aYPos) |
|
498 { |
|
499 while (Next()) |
|
500 { |
|
501 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
502 if (iLineInfo.iOuterRect.iTl.iY <= aYPos && iLineInfo.iOuterRect.iBr.iY > aYPos) |
|
503 return TRUE; |
|
504 else |
|
505 Skip(); |
|
506 } |
|
507 return EFalse; |
|
508 } |
|
509 |
|
510 /** |
|
511 * Iterates to the width of the widest line in the specified vertical range |
|
512 * that is formatted, returning its width. |
|
513 * @param aTop Line number of the top line that is to be considered. |
|
514 * @param aBottom |
|
515 * Line number of the first line below aTop that should not be considered. |
|
516 * @return |
|
517 * The width found, or 0 if the entire range is not formatted. |
|
518 * @internalComponent |
|
519 */ |
|
520 TInt TTmInterpreter::WidthOfWidestLine(TInt aTop,TInt aBottom) |
|
521 { |
|
522 int width = 0; |
|
523 while (Next()) |
|
524 { |
|
525 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
526 // Quit if below the range. |
|
527 if (iLineInfo.iOuterRect.iTl.iY >= aBottom) |
|
528 break; |
|
529 // If the line overlaps the range check its width. |
|
530 if (iLineInfo.iOuterRect.iBr.iY > aTop) |
|
531 { |
|
532 int cur_width = iLineInfo.iInnerRect.iBr.iX - iLineInfo.iInnerRect.iTl.iX; |
|
533 if (cur_width > width) |
|
534 width = cur_width; |
|
535 } |
|
536 Skip(); |
|
537 } |
|
538 return width; |
|
539 } |
|
540 |
|
541 /** |
|
542 Finds the leftmost left bound and the rightmost right bound within the |
|
543 specified y co-ordinate range |
|
544 @param aTopY |
|
545 The top of the range to check. |
|
546 @param aBottomY |
|
547 The bottom of the range to check. |
|
548 @param aLeft |
|
549 The left most X-coordinate found. KMaxTInt if there was nothing in the |
|
550 range at all. |
|
551 @param aRight |
|
552 The right most X-coordinate found. KMinTInt if there was nothing in the |
|
553 range at all. |
|
554 @internalComponent |
|
555 */ |
|
556 void TTmInterpreter::HorizontalExtremes(TInt &aLeft, TInt &aRight, |
|
557 TInt aTopY, TInt aBottomY) |
|
558 { |
|
559 aLeft = KMaxTInt; |
|
560 aRight = KMinTInt; |
|
561 if (!Next()) |
|
562 return; |
|
563 while (iLineInfo.iOuterRect.iBr.iY < aTopY) |
|
564 { |
|
565 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
566 Skip(); |
|
567 if (!Next()) |
|
568 return; |
|
569 } |
|
570 while (iLineInfo.iOuterRect.iTl.iY <= aBottomY) |
|
571 { |
|
572 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
573 if (iLineInfo.iInnerRect.iTl.iX < aLeft) |
|
574 aLeft = iLineInfo.iInnerRect.iTl.iX; |
|
575 if (aRight < iLineInfo.iInnerRect.iBr.iX) |
|
576 aRight = iLineInfo.iInnerRect.iBr.iX; |
|
577 Skip(); |
|
578 if (!Next()) |
|
579 return; |
|
580 } |
|
581 } |
|
582 |
|
583 /** |
|
584 * Finds the smallest rectangle that needs to be redrawn after reformatting |
|
585 * some text. |
|
586 * @param aNewCode Code representing the formatting of the changed text. |
|
587 * @param aStartChar The first character that has changed. |
|
588 * @param aOldLength The length of the text that was changed. |
|
589 * @param aNewLength The new length of the changed text. |
|
590 * @param aRedrawRect The rectangle that needs redrawing. |
|
591 * @internalComponent |
|
592 */ |
|
593 void TTmInterpreter::CalculateRedrawRect(TTmInterpreter& aNewCode,TInt aStartChar,TInt aOldLength,TInt aNewLength, |
|
594 TRect& aRedrawRect) |
|
595 { |
|
596 /* |
|
597 Strip leading identical lines before the reformatted range and set aRedrawRect to the bounds of |
|
598 the first line to be redrawn. |
|
599 */ |
|
600 TBool have_old_line = Next(); |
|
601 TBool have_new_line = aNewCode.Next(); |
|
602 while (have_old_line && have_new_line) |
|
603 { |
|
604 aRedrawRect = LineInfo().iOuterRect; |
|
605 if (EndChar() > aStartChar || |
|
606 StartChar() != aNewCode.StartChar() || EndChar() != aNewCode.EndChar()) |
|
607 break; |
|
608 Skip(); |
|
609 have_old_line = Next(); |
|
610 aNewCode.Skip(); |
|
611 have_new_line = aNewCode.Next(); |
|
612 } |
|
613 |
|
614 // Move after the reformatted range. |
|
615 while (have_old_line && StartChar() < aStartChar + aOldLength) |
|
616 { |
|
617 Skip(); |
|
618 have_old_line = Next(); |
|
619 } |
|
620 while (have_new_line && aNewCode.StartChar() < aStartChar + aNewLength) |
|
621 { |
|
622 aRedrawRect.iBr.iY = aNewCode.LineInfo().iOuterRect.iBr.iY; |
|
623 aNewCode.Skip(); |
|
624 have_new_line = aNewCode.Next(); |
|
625 } |
|
626 |
|
627 // Compare lines after the reformatted range. |
|
628 int length_change = aNewLength - aOldLength; |
|
629 while (have_old_line && have_new_line) |
|
630 { |
|
631 if (StartChar() + length_change == aNewCode.StartChar() && EndChar() + length_change == aNewCode.EndChar()) |
|
632 { |
|
633 /* |
|
634 These lines are identical so don't need to be redrawn, so remove the new line's rectangle from |
|
635 the redraw rectangle, and stop comparing, because subsequent lines will all be identical. |
|
636 */ |
|
637 aRedrawRect.iBr.iY = aNewCode.LineInfo().iOuterRect.iTl.iY; |
|
638 break; |
|
639 } |
|
640 |
|
641 // Add the current new line to the redraw rectangle. |
|
642 aRedrawRect.iBr.iY = aNewCode.LineInfo().iOuterRect.iBr.iY; |
|
643 |
|
644 // Attempt to synchronise. |
|
645 if (EndChar() + length_change < aNewCode.EndChar()) |
|
646 { |
|
647 Skip(); |
|
648 have_old_line = Next(); |
|
649 } |
|
650 else |
|
651 { |
|
652 aNewCode.Skip(); |
|
653 have_new_line = aNewCode.Next(); |
|
654 } |
|
655 } |
|
656 |
|
657 // If the old text has run out, extend the redraw rect to cover any remaining text. |
|
658 while (have_new_line && !have_old_line) |
|
659 { |
|
660 aRedrawRect.iBr.iY = aNewCode.LineInfo().iOuterRect.iBr.iY; |
|
661 aNewCode.Skip(); |
|
662 have_new_line = aNewCode.Next(); |
|
663 } |
|
664 } |
|
665 |
|
666 /** |
|
667 Resets so that will return ETrue for AtEnd(). |
|
668 */ |
|
669 void RTmGraphemeInTextChunkIterator::Reset() |
|
670 { |
|
671 iPosition.iPosInText = 0; |
|
672 iLength = 0; |
|
673 } |
|
674 |
|
675 /** |
|
676 Constructs an iterator that will return ETrue for AtEnd(). |
|
677 */ |
|
678 RTmGraphemeInTextChunkIterator::RTmGraphemeInTextChunkIterator() |
|
679 : iFont(NULL) |
|
680 { |
|
681 Reset(); |
|
682 } |
|
683 |
|
684 void RTmGraphemeInTextChunkIterator::Close() |
|
685 { |
|
686 if (iFont) |
|
687 { |
|
688 iFont->Close(); |
|
689 iFont = NULL; |
|
690 } |
|
691 |
|
692 if (iShapeInfo.IsOpen()) |
|
693 iShapeInfo.Close(); |
|
694 } |
|
695 |
|
696 /** |
|
697 Begins the iteration. |
|
698 @param aByteCodeIterator |
|
699 The interpreter with the information about the formatting being traversed. |
|
700 Must be set to the start of the text chunk to be iterated over. The |
|
701 interpreter is not advanced by this function. |
|
702 @param aCache |
|
703 A pointer to a two-byte cache in which to store the results of the |
|
704 iteration. |
|
705 */ |
|
706 void RTmGraphemeInTextChunkIterator::Begin( |
|
707 RTmGeneralInterpreter& aByteCodeIterator, |
|
708 TTmGraphemeEdgeInfo (*aCache)[2]) |
|
709 { |
|
710 if (iShapeInfo.IsOpen()) |
|
711 iShapeInfo.Close(); |
|
712 iCache = aCache; |
|
713 iReverse = aByteCodeIterator.RightToLeft()? |
|
714 RTmTextCache::EVisualRightToLeft : RTmTextCache::ELeftToRight; |
|
715 iIgnorePosition = -1; |
|
716 if (!aByteCodeIterator.VisualEndOfLineIsAmbiguous()) |
|
717 iIgnorePosition = aByteCodeIterator.LineInfo().iEnd; |
|
718 |
|
719 __ASSERT_DEBUG(aByteCodeIterator.Op() == TTmInterpreter::EOpText, TmPanic(EInvariant)); |
|
720 |
|
721 if (iFont) |
|
722 { |
|
723 iFont->Close(); |
|
724 iFont = NULL; |
|
725 } |
|
726 iEndChar = aByteCodeIterator.EndChar(); |
|
727 iStartChar = aByteCodeIterator.StartChar(); |
|
728 iLength = iEndChar - aByteCodeIterator.StartChar(); |
|
729 if (KMaxTextChunkSize < iLength) |
|
730 { |
|
731 iLength = KMaxTextChunkSize; |
|
732 iEndChar = iStartChar + iLength; |
|
733 } |
|
734 |
|
735 // If a custom interface to draw the text in context exists, then get the Displayed Text within context. |
|
736 if (aByteCodeIterator.TextCache().Source().GetExtendedInterface(KTmCustomExtensionUid)) |
|
737 { |
|
738 aByteCodeIterator.TextCache().GetDisplayedText(iStartChar,iEndChar,iReverse,iBuffer,aByteCodeIterator.ContextCharChar(),0, |
|
739 &iFont); |
|
740 } |
|
741 else |
|
742 { |
|
743 aByteCodeIterator.TextCache().GetDisplayedText(iStartChar,iEndChar,iReverse,iBuffer,0,0,&iFont); |
|
744 } |
|
745 |
|
746 if (!iFont) |
|
747 { |
|
748 iPosition.iPosInText = 0; |
|
749 iLength = 0; |
|
750 return; |
|
751 } |
|
752 |
|
753 // start_char and end_char need to be adjusted to take account of |
|
754 // the extra context supplied by GetDisplayedText. |
|
755 --iStartChar; |
|
756 ++iEndChar; |
|
757 ++iLength; |
|
758 iPosition.iText.Set(iBuffer, iLength + 1); |
|
759 iPosition.iPosInText = 1; |
|
760 iPosition.iPen = aByteCodeIterator.StartPen(); |
|
761 |
|
762 iStartPenX = iPosition.iPen.iX; |
|
763 iEndPenX = aByteCodeIterator.EndPen().iX; |
|
764 } |
|
765 |
|
766 /** Find any protruding left side-bearing. |
|
767 @return Maximum of aStartOfChunk - left bound of each glyph. |
|
768 @internalComponent */ |
|
769 TInt LeftSideBearing(const TInt aStartOfChunk, const CFont::TPositionParam& aPos) |
|
770 { |
|
771 TInt bearing(aStartOfChunk); |
|
772 TInt glyph(aPos.iOutputGlyphs); |
|
773 while (glyph != 0) |
|
774 { |
|
775 --glyph; |
|
776 TInt left(aPos.iOutput[glyph].iBounds.iTl.iX); |
|
777 if (left < bearing) |
|
778 bearing = left; |
|
779 } |
|
780 return aStartOfChunk - bearing; |
|
781 } |
|
782 |
|
783 /** |
|
784 Advances the iteration to the next character. The aCache array as passed to |
|
785 Begin will be overwritten with the results. |
|
786 @return |
|
787 The number of characters found; 1 or 2. |
|
788 */ |
|
789 TInt RTmGraphemeInTextChunkIterator::Next() |
|
790 { |
|
791 __ASSERT_DEBUG(!AtEnd(), TmPanic(EBadArg)); |
|
792 TInt previousPositionInBuffer = iPosition.iPosInText; |
|
793 TInt previousPosition = iReverse? |
|
794 iEndChar - iPosition.iPosInText : iStartChar + iPosition.iPosInText; |
|
795 TPoint previousPen = iPosition.iPen; |
|
796 |
|
797 //The return value of GetCharacterPosition2() is not used here |
|
798 //form and gdi has had correct behavior when GetCharacterPosition2() return EFalse |
|
799 //And that was done by changing iPosInText inside GetCharacterPosition2() |
|
800 TBool isGlyphGenerated = iFont->Font().GetCharacterPosition2(iPosition, iShapeInfo); |
|
801 |
|
802 // Move the pen (cursor position) to the right if the cluster just seen |
|
803 // has a negative side-bearing. This corrects for the fact that |
|
804 // DrawText() pushes text with left side-bearings to the right. |
|
805 iPosition.iPen.iX += LeftSideBearing(iStartPenX, iPosition); |
|
806 TInt numCodePoints = iPosition.iPosInText - previousPositionInBuffer; |
|
807 TInt currentPosition = iReverse? |
|
808 iEndChar - iPosition.iPosInText : iStartChar + iPosition.iPosInText; |
|
809 __ASSERT_DEBUG(currentPosition != previousPosition, TmPanic(EInvariant)); |
|
810 |
|
811 TInt cachePos = 0; |
|
812 // Report the left hand edge of the character. |
|
813 if (iIgnorePosition != previousPosition) |
|
814 { |
|
815 (*iCache)[0].iPos.iRightToLeft = iReverse; |
|
816 (*iCache)[0].iPos.iDocPos.iLeadingEdge = !iReverse; |
|
817 (*iCache)[0].iPos.iDocPos.iPos = previousPosition; |
|
818 (*iCache)[0].iPos.iEdge = previousPen; |
|
819 (*iCache)[0].iCodePoints = numCodePoints; |
|
820 cachePos = 1; |
|
821 } |
|
822 // Report the right hand edge of the character. |
|
823 if (iIgnorePosition != currentPosition) |
|
824 { |
|
825 (*iCache)[cachePos].iPos.iRightToLeft = iReverse; |
|
826 (*iCache)[cachePos].iPos.iDocPos.iLeadingEdge = iReverse; |
|
827 (*iCache)[cachePos].iPos.iDocPos.iPos = currentPosition; |
|
828 (*iCache)[cachePos].iPos.iEdge = iPosition.iPen; |
|
829 (*iCache)[cachePos].iCodePoints = numCodePoints; |
|
830 if (iPosition.iPosInText == iLength) |
|
831 { |
|
832 // We are probably moving over a chunk, so its right edge |
|
833 // will be the end of the chunk, not where the renderer |
|
834 // thinks it is. |
|
835 if ((*iCache)[cachePos].iPos.iEdge.iX < iEndPenX) |
|
836 (*iCache)[cachePos].iPos.iEdge.iX = iEndPenX; |
|
837 } |
|
838 ++cachePos; |
|
839 } |
|
840 __ASSERT_DEBUG(0 < cachePos, TmPanic(EInvariant)); |
|
841 return cachePos; |
|
842 } |
|
843 |
|
844 /** |
|
845 Begins the iteration. |
|
846 @param aByteCodeIterator |
|
847 The interpreter with the information about the formatting being traversed. |
|
848 Must be set to the start of the text chunk to be iterated over. The |
|
849 interpreter is not advanced by this function. |
|
850 */ |
|
851 RTmGraphemeInTextChunkIteratorNice::RTmGraphemeInTextChunkIteratorNice( |
|
852 RTmGeneralInterpreter& aByteCodeIterator) |
|
853 { |
|
854 iBase.Begin(aByteCodeIterator, &iCache); |
|
855 iCurrent = iCache; |
|
856 iEnd = iCache; |
|
857 if (!iBase.AtEnd()) |
|
858 iEnd += iBase.Next(); |
|
859 } |
|
860 |
|
861 void RTmGraphemeInTextChunkIteratorNice::Close() |
|
862 { |
|
863 iBase.Close(); |
|
864 } |
|
865 |
|
866 /** |
|
867 Advances the iteration to the next edge. |
|
868 */ |
|
869 void RTmGraphemeInTextChunkIteratorNice::Next() |
|
870 { |
|
871 __ASSERT_DEBUG(!AtEnd(), TmPanic(EBadArg)); |
|
872 // Return if we have not finished moving through the cache. |
|
873 if (++iCurrent != iEnd) |
|
874 return; |
|
875 // Return if there are no more characters. |
|
876 if (iBase.AtEnd()) |
|
877 return; |
|
878 iCurrent = iCache; |
|
879 iEnd = iCache + iBase.Next(); |
|
880 } |
|
881 |
|
882 /** |
|
883 Returns a pointer to the current element. |
|
884 @return |
|
885 The current element in the iteration. Will be undefined if AtEnd is |
|
886 returning ETrue. |
|
887 */ |
|
888 const TTmGraphemeEdgeInfo* RTmGraphemeInTextChunkIteratorNice::Get() const |
|
889 { |
|
890 return iCurrent; |
|
891 } |
|
892 |
|
893 /** |
|
894 Reports whether the iteration has finished. |
|
895 @return |
|
896 EFalse if the iteration has not finished. If ETrue is returned, Get will |
|
897 return a defined value. |
|
898 */ |
|
899 TBool RTmGraphemeInTextChunkIteratorNice::AtEnd() const |
|
900 { |
|
901 return iCurrent == iEnd? ETrue : EFalse; |
|
902 } |
|
903 |
|
904 /** |
|
905 Advances to the position specified. Behaviour is undefined if the position does |
|
906 not exist in the chunk. The position is considered to exist if it is within a |
|
907 grapheme cluster in the chunk, even if the specific edge does not exist. |
|
908 @param aDocPos |
|
909 Position to advance to. |
|
910 */ |
|
911 void RTmGraphemeInTextChunkIteratorNice::FindEdge(const TTmDocPos& aDocPos) |
|
912 { |
|
913 __ASSERT_DEBUG(!AtEnd(), TmPanic(EBadArg)); |
|
914 while (RTmGraphemeEdgeIterator::ETotalMatch != |
|
915 RTmGraphemeEdgeIterator::DocPosMatches(aDocPos, *Get())) |
|
916 { |
|
917 Next(); |
|
918 __ASSERT_DEBUG(!AtEnd(), TmPanic(EBadArg)); |
|
919 } |
|
920 } |
|
921 |
|
922 void TTmVisualDocPos::Reset() |
|
923 { |
|
924 iAmbiguity = ENotFound; |
|
925 } |
|
926 |
|
927 TTmVisualDocPos::TTmVisualDocPos() |
|
928 { |
|
929 Reset(); |
|
930 } |
|
931 |
|
932 void TTmVisualDocPos::SetAsUnambiguous(const TTmPosInfo2& aPos) |
|
933 { |
|
934 iLeft = iRight = aPos; |
|
935 iAmbiguity = EUnambiguous; |
|
936 } |
|
937 |
|
938 void TTmVisualDocPos::SetIfAmbiguous( |
|
939 const TTmPosInfo2& aLeft, const TTmPosInfo2& aRight) |
|
940 { |
|
941 if (aLeft.iDocPos.iPos == aRight.iDocPos.iPos |
|
942 && aLeft.iEdge.iX == aRight.iEdge.iX) |
|
943 // These edges do meet. |
|
944 return; |
|
945 |
|
946 // There is an ambiguity, but which edges are involved? |
|
947 TBool leftIsRightHandEdge = aLeft.iRightToLeft? |
|
948 aLeft.iDocPos.iLeadingEdge : !aLeft.iDocPos.iLeadingEdge; |
|
949 TBool rightIsLeftHandEdge = aRight.iRightToLeft? |
|
950 !aRight.iDocPos.iLeadingEdge : aRight.iDocPos.iLeadingEdge; |
|
951 |
|
952 if (leftIsRightHandEdge) |
|
953 { |
|
954 iLeft = aLeft; |
|
955 if (rightIsLeftHandEdge) |
|
956 { |
|
957 iRight = aRight; |
|
958 iAmbiguity = EAmbiguous; |
|
959 } |
|
960 else |
|
961 { |
|
962 iRight = aLeft; |
|
963 iAmbiguity = ELeftOnly; |
|
964 } |
|
965 } |
|
966 else if (rightIsLeftHandEdge) |
|
967 { |
|
968 iLeft = iRight = aRight; |
|
969 iAmbiguity = ERightOnly; |
|
970 } |
|
971 } |
|
972 |
|
973 /** |
|
974 Return the position that best matches the X co-ordinate specified by aX. |
|
975 @param aX X coordinate sought. |
|
976 @return |
|
977 0 if no value was found. A pointer to the result if a value was found. |
|
978 */ |
|
979 const TTmPosInfo2* TTmVisualDocPos::NearestToX(TInt aX) const |
|
980 { |
|
981 if (iAmbiguity == ENotFound) |
|
982 return 0; |
|
983 TInt leftDistance = iLeft.iEdge.iX < aX? |
|
984 aX - iLeft.iEdge.iX : iLeft.iEdge.iX - aX; |
|
985 TInt rightDistance = iRight.iEdge.iX < aX? |
|
986 aX - iRight.iEdge.iX : iRight.iEdge.iX - aX; |
|
987 if (leftDistance < rightDistance) |
|
988 return &iLeft; |
|
989 else |
|
990 return &iRight; |
|
991 } |
|
992 |
|
993 /** Restarts the checker for a new line. */ |
|
994 void TTmAmbiguityChecker::Reset() |
|
995 { |
|
996 iPrev.iEdge.iX = KMinTInt; |
|
997 iPrev.iRightToLeft = EFalse; |
|
998 iPrev.iDocPos.iPos = KMinTInt; |
|
999 iPrev.iDocPos.iLeadingEdge = ETrue; |
|
1000 iLastAmbiguousPos.Reset(); |
|
1001 } |
|
1002 |
|
1003 /** Constructs a checker ready to check a line. */ |
|
1004 TTmAmbiguityChecker::TTmAmbiguityChecker() |
|
1005 { |
|
1006 Reset(); |
|
1007 } |
|
1008 |
|
1009 /** |
|
1010 Checks an edge for ambiguity against the last edge added. |
|
1011 @param aEdge The edge to check and store. |
|
1012 */ |
|
1013 void TTmAmbiguityChecker::AddEdge(const TTmPosInfo2& aEdge) |
|
1014 { |
|
1015 iLastAmbiguousPos.SetIfAmbiguous(iPrev, aEdge); |
|
1016 iPrev = aEdge; |
|
1017 } |
|
1018 |
|
1019 /** |
|
1020 Checks whether the last edge added is ambiguous if there are no more edges in |
|
1021 the line. |
|
1022 */ |
|
1023 void TTmAmbiguityChecker::EndLine() |
|
1024 { |
|
1025 TTmPosInfo2 dummyEdge; |
|
1026 dummyEdge.iEdge.iX = KMaxTInt; |
|
1027 dummyEdge.iRightToLeft = EFalse; |
|
1028 dummyEdge.iDocPos.iLeadingEdge = EFalse; |
|
1029 dummyEdge.iDocPos.iPos = KMaxTInt; |
|
1030 AddEdge(dummyEdge); |
|
1031 } |
|
1032 |
|
1033 /** |
|
1034 Reports whether the iteration is over. |
|
1035 @return ETrue if Next may no longer be called as there is no more information. |
|
1036 */ |
|
1037 TBool RTmGraphemeInTextChunkIterator::AtEnd() const |
|
1038 { |
|
1039 return iLength <= iPosition.iPosInText; |
|
1040 } |
|
1041 |
|
1042 /** |
|
1043 Releases all resources |
|
1044 */ |
|
1045 void RTmGraphemeEdgeIterator::Close() |
|
1046 { |
|
1047 iTextChunkIterator.Close(); |
|
1048 } |
|
1049 |
|
1050 /** |
|
1051 Advances the iteration to the next character edge. Note that this one may be in |
|
1052 the same place as the last. |
|
1053 |
|
1054 Begin must be called before this function can be used. |
|
1055 @see Begin |
|
1056 */ |
|
1057 void RTmGraphemeEdgeIterator::Next() |
|
1058 { |
|
1059 __ASSERT_DEBUG(!AtEnd(), TmPanic(EBadArg)); |
|
1060 --iCacheSize; |
|
1061 if (0 != iCacheSize) |
|
1062 { |
|
1063 ++iCachePos; |
|
1064 return; |
|
1065 } |
|
1066 |
|
1067 iCachePos = 0; |
|
1068 |
|
1069 // more positions within this text chunk? |
|
1070 if (!iTextChunkIterator.AtEnd()) |
|
1071 { |
|
1072 iCacheSize = iTextChunkIterator.Next(); |
|
1073 return; |
|
1074 } |
|
1075 |
|
1076 // Get the next position in this line |
|
1077 while (iByteCodeIterator->CodePos() < iEndLineCodePos) |
|
1078 { |
|
1079 // The WHILE loop assures that there is always sufficientByteCode avaliable. |
|
1080 TBool haveSufficientByteCode = iByteCodeIterator->Next(); |
|
1081 __ASSERT_DEBUG(haveSufficientByteCode, TmPanic(EBadArg)); |
|
1082 |
|
1083 iByteCodeIterator->Skip(); |
|
1084 TInt op = iByteCodeIterator->Op(); |
|
1085 if (op == TTmInterpreter::EOpSpecialChar) |
|
1086 { |
|
1087 TBool reverse = iByteCodeIterator->RightToLeft(); |
|
1088 TInt endChar = iByteCodeIterator->EndChar(); |
|
1089 TInt startChar = iByteCodeIterator->StartChar(); |
|
1090 TInt actualEndChar = reverse? startChar : endChar; // Based on direction of text |
|
1091 TInt actualStartChar = reverse? endChar : startChar; // Based on direction of text |
|
1092 iPosInfoCache[0].iPos.iDocPos.iPos = reverse? endChar : startChar; |
|
1093 iPosInfoCache[0].iPos.iDocPos.iLeadingEdge = !reverse; |
|
1094 iPosInfoCache[0].iPos.iRightToLeft = reverse; |
|
1095 iPosInfoCache[0].iPos.iEdge = iByteCodeIterator->StartPen(); |
|
1096 iPosInfoCache[0].iCodePoints = 1; |
|
1097 /** If we have reached the end edge (for LTR text), do not cache the next character in the bytecode. |
|
1098 Simply return.*/ |
|
1099 if (actualEndChar == iIgnorePosition) |
|
1100 { |
|
1101 iCacheSize = 1; |
|
1102 return; |
|
1103 } |
|
1104 iPosInfoCache[1].iPos.iDocPos.iPos = reverse? startChar : endChar; |
|
1105 iPosInfoCache[1].iPos.iDocPos.iLeadingEdge = reverse; |
|
1106 iPosInfoCache[1].iPos.iRightToLeft = reverse; |
|
1107 iPosInfoCache[1].iPos.iEdge = iByteCodeIterator->EndPen(); |
|
1108 iPosInfoCache[1].iCodePoints = 1; |
|
1109 iCacheSize = 2; |
|
1110 /** If we have reached the start edge (for RTL text), do not cache the next character in the bytecode. |
|
1111 Simply return.*/ |
|
1112 if (actualStartChar == iIgnorePosition) |
|
1113 { |
|
1114 iCacheSize = 1; |
|
1115 iCachePos = 1; |
|
1116 return; |
|
1117 } |
|
1118 // Otherwise, simply return with both cache positions set, cache size of 2, and position in cache 0 |
|
1119 return; |
|
1120 } |
|
1121 else if (op == TTmInterpreter::EOpText) |
|
1122 { |
|
1123 iTextChunkIterator.Begin(*iByteCodeIterator, &iPosInfoCache); |
|
1124 if (!iTextChunkIterator.AtEnd()) |
|
1125 { |
|
1126 iCacheSize = iTextChunkIterator.Next(); |
|
1127 return; |
|
1128 } |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 // No more positions within the line. |
|
1133 if (!iTrailingEdgeOfUnambiguousLineEndAdded |
|
1134 && iByteCodeIterator->TrailingEdgeOfUnambiguousLineEnd( |
|
1135 iPosInfoCache[0].iPos, ETrue)) |
|
1136 { |
|
1137 // Got the trailing edge of the previous line's last character. |
|
1138 iPosInfoCache[0].iCodePoints = 1; |
|
1139 iCacheSize = 1; |
|
1140 iTrailingEdgeOfUnambiguousLineEndAdded = ETrue; |
|
1141 return; |
|
1142 } |
|
1143 } |
|
1144 |
|
1145 /** |
|
1146 Gets the current edge, if the iteration is not at an end. |
|
1147 |
|
1148 Begin must be called before this function can be used. |
|
1149 @see Begin |
|
1150 @see AtEnd |
|
1151 |
|
1152 @return |
|
1153 The current edge co-ordinates in formatting space, the character |
|
1154 index that the position is just before and whether the edge is the trailing |
|
1155 edge of the previous character or the leading edge of the next character. |
|
1156 Undefined if the iteration is at an end. Call AtEnd to see if this is the |
|
1157 case. |
|
1158 */ |
|
1159 const TTmGraphemeEdgeInfo& RTmGraphemeEdgeIterator::Get() const |
|
1160 { |
|
1161 return iPosInfoCache[iCachePos]; |
|
1162 } |
|
1163 |
|
1164 /** |
|
1165 Gets the current edge, if the iteration is not at an end. A shortcut for |
|
1166 Get().iPos. |
|
1167 |
|
1168 Begin must be called before this function can be used. |
|
1169 @see Begin |
|
1170 @see Get |
|
1171 @see AtEnd |
|
1172 |
|
1173 @return |
|
1174 The current edge co-ordinates in formatting space, the character index that |
|
1175 the position is just before and whether the edge is the trailing edge of |
|
1176 the previous character or the leading edge of the next character. Undefined |
|
1177 if the iteration is at an end. Call AtEnd to see if this is the case. |
|
1178 */ |
|
1179 const TTmPosInfo2& RTmGraphemeEdgeIterator::GetInfo() const |
|
1180 { |
|
1181 return iPosInfoCache[iCachePos].iPos; |
|
1182 } |
|
1183 |
|
1184 /** |
|
1185 Determines if the iteration has finished the line or not. |
|
1186 @return ETrue if the iteration is at an end. |
|
1187 */ |
|
1188 TBool RTmGraphemeEdgeIterator::AtEnd() const |
|
1189 { |
|
1190 return iCacheSize == 0? ETrue : EFalse; |
|
1191 } |
|
1192 |
|
1193 /** |
|
1194 Begins the iteration again from the start of the line. The iterator passed in |
|
1195 will not be advanced beyond the current line. |
|
1196 @param aByteCodeIterator |
|
1197 Iterator to the formatting which should be set to the start of the |
|
1198 formatting to be traversed. It will be advanced during the use of this |
|
1199 iterator. It should not be used by any other code while this |
|
1200 RTmGraphemeEdgeIterator is being used. |
|
1201 */ |
|
1202 void RTmGraphemeEdgeIterator::Begin( |
|
1203 RTmGeneralInterpreter& aByteCodeIterator) |
|
1204 { |
|
1205 /** Set the position of the edge of the line to stop at when iterating through the edges */ |
|
1206 if (!aByteCodeIterator.VisualEndOfLineIsAmbiguous()) |
|
1207 iIgnorePosition = aByteCodeIterator.LineInfo().iEnd; |
|
1208 iByteCodeIterator = &aByteCodeIterator; |
|
1209 iEndLineCodePos = iByteCodeIterator->EndCodePos(); |
|
1210 iTextChunkIterator.Reset(); |
|
1211 iCachePos = 0; |
|
1212 iCacheSize = 1; |
|
1213 // Get the first value if there is one |
|
1214 if (iByteCodeIterator->TrailingEdgeOfUnambiguousLineEnd( |
|
1215 iPosInfoCache[0].iPos, EFalse)) |
|
1216 { |
|
1217 // Got the trailing edge of the previous line's last character. |
|
1218 iPosInfoCache[0].iCodePoints = 1; |
|
1219 iTrailingEdgeOfUnambiguousLineEndAdded = ETrue; |
|
1220 return; |
|
1221 } |
|
1222 iTrailingEdgeOfUnambiguousLineEndAdded = EFalse; |
|
1223 Next(); |
|
1224 } |
|
1225 |
|
1226 /** |
|
1227 Finds the nearest edge to the x position specified. The iterator should be |
|
1228 initialised to the start of the line to be searched. |
|
1229 @param aX The X position to search for (in formatting coordinates). |
|
1230 @param aNearest The result. |
|
1231 */ |
|
1232 void RTmGraphemeEdgeIterator::FindXPos(TInt aX, TTmVisualDocPos& aNearest) |
|
1233 { |
|
1234 TTmPosInfo2 nearest; |
|
1235 if (!FindEdgeByX(aX, nearest, aNearest)) |
|
1236 aNearest.Reset(); |
|
1237 else if (aNearest.Ambiguity() == TTmVisualDocPos::ENotFound) |
|
1238 aNearest.SetAsUnambiguous(nearest); |
|
1239 } |
|
1240 |
|
1241 /** |
|
1242 Finds the nearest edge to the x position specified. The iterator should be |
|
1243 initialised to the start of the line to be searched. |
|
1244 @param aX The position to find (in formatting coordinates). |
|
1245 @param aNearest |
|
1246 The nearest position to aX, if ETrue is returned. |
|
1247 @param aAmbiguity |
|
1248 Any ambiguity visually coincident with aNearest if ETrue is returned. |
|
1249 @return |
|
1250 ETrue if there is any position there at all. If EFalse, aNearest and |
|
1251 aAmbiguity are undefined. |
|
1252 */ |
|
1253 TBool RTmGraphemeEdgeIterator::FindEdgeByX(TInt aX, TTmPosInfo2& aNearest, |
|
1254 TTmVisualDocPos& aAmbiguity) |
|
1255 { |
|
1256 TInt lastX = KMinTInt; |
|
1257 TInt distance = KMaxTInt; |
|
1258 TTmAmbiguityChecker checker; |
|
1259 TTmPosInfo2 found; |
|
1260 // Find the last edge before aX |
|
1261 while (!AtEnd() && GetInfo().iEdge.iX <= aX) |
|
1262 { |
|
1263 found = GetInfo(); |
|
1264 if (lastX != found.iEdge.iX) |
|
1265 { |
|
1266 lastX = found.iEdge.iX; |
|
1267 distance = aX - lastX; |
|
1268 checker.Reset(); |
|
1269 } |
|
1270 checker.AddEdge(found); |
|
1271 Next(); |
|
1272 } |
|
1273 // Find the first edge after aX if it is closer. |
|
1274 if (!AtEnd() && GetInfo().iEdge.iX - aX < distance) |
|
1275 { |
|
1276 checker.Reset(); |
|
1277 found = GetInfo(); |
|
1278 lastX = found.iEdge.iX; |
|
1279 checker.AddEdge(found); |
|
1280 Next(); |
|
1281 while (!AtEnd() && GetInfo().iEdge.iX == lastX) |
|
1282 { |
|
1283 checker.AddEdge(GetInfo()); |
|
1284 Next(); |
|
1285 } |
|
1286 } |
|
1287 if (AtEnd()) |
|
1288 checker.EndLine(); |
|
1289 aAmbiguity = checker.LastAmbiguity(); |
|
1290 if (lastX == KMinTInt) |
|
1291 return EFalse; |
|
1292 aNearest = found; |
|
1293 return ETrue; |
|
1294 } |
|
1295 |
|
1296 /** |
|
1297 Determines if aDocPos matches the grapheme edge defined by aEdgeInfo. |
|
1298 @param aDocPos The document position specification to match. |
|
1299 @param aEdgeInfo The grapheme edge to match. |
|
1300 @return |
|
1301 ENoMatch if the document position does not match the grapheme edge. |
|
1302 EPositionOnly if the document position edge specification is ERightToLeft |
|
1303 or ELeftToRight and the document position matches but not the |
|
1304 directionality. ETotalMatch if the document position and edge |
|
1305 specifications match. |
|
1306 */ |
|
1307 RTmGraphemeEdgeIterator::TGraphemeMatch |
|
1308 RTmGraphemeEdgeIterator::DocPosMatches(const TTmDocPosSpec& aDocPos, |
|
1309 const TTmGraphemeEdgeInfo& aEdgeInfo) |
|
1310 { |
|
1311 TInt startOfGrapheme = aEdgeInfo.iPos.iDocPos.iPos - |
|
1312 (aEdgeInfo.iPos.iDocPos.iLeadingEdge? 0 : aEdgeInfo.iCodePoints - 1); |
|
1313 if (startOfGrapheme <= aDocPos.iPos |
|
1314 && aDocPos.iPos < startOfGrapheme + aEdgeInfo.iCodePoints) |
|
1315 { |
|
1316 // Found a grapheme that matches the document position. |
|
1317 // Does it match the rest of the spec? |
|
1318 switch (aDocPos.iType) |
|
1319 { |
|
1320 case TTmDocPosSpec::ELeftToRight: |
|
1321 return aEdgeInfo.iPos.iRightToLeft? |
|
1322 EPositionOnly : ETotalMatch; |
|
1323 case TTmDocPosSpec::ERightToLeft: |
|
1324 return aEdgeInfo.iPos.iRightToLeft? |
|
1325 ETotalMatch : EPositionOnly; |
|
1326 case TTmDocPosSpec::ELeading: |
|
1327 return aEdgeInfo.iPos.iDocPos.iLeadingEdge? |
|
1328 ETotalMatch : ENoMatch; |
|
1329 case TTmDocPosSpec::ETrailing: |
|
1330 return aEdgeInfo.iPos.iDocPos.iLeadingEdge? |
|
1331 ENoMatch : ETotalMatch; |
|
1332 default: |
|
1333 return ENoMatch; |
|
1334 } |
|
1335 } |
|
1336 return ENoMatch; |
|
1337 } |
|
1338 |
|
1339 /** |
|
1340 Finds the edge specified. If a Right-to-Left or Left-to-Right edge is demanded, |
|
1341 an edge with the wrong directionality will be returned if the right one does |
|
1342 not exist, but one or two with the wrong one does. The iterator should be |
|
1343 initialised to the start of the line to be searched. |
|
1344 @param aDocPos The position to be found. |
|
1345 @param aInfo The result. |
|
1346 @return ETrue if a result could be found. |
|
1347 */ |
|
1348 TBool RTmGraphemeEdgeIterator::FindEdge(const TTmDocPosSpec& aDocPos, |
|
1349 TTmPosInfo2& aInfo) |
|
1350 { |
|
1351 TInt matches = 0; |
|
1352 while (!AtEnd()) |
|
1353 { |
|
1354 TTmGraphemeEdgeInfo info = Get(); |
|
1355 TInt match = static_cast<TInt>(DocPosMatches(aDocPos, info)); |
|
1356 if (0 != match) |
|
1357 { |
|
1358 matches += match; |
|
1359 aInfo = info.iPos; |
|
1360 if (2 <= matches) |
|
1361 return ETrue; |
|
1362 } |
|
1363 Next(); |
|
1364 } |
|
1365 return matches; |
|
1366 } |
|
1367 |
|
1368 /** |
|
1369 Finds the rightmost edge that is to the left of aDocPos in this line. |
|
1370 @param aDocPos Document position that the result must be to the left of. |
|
1371 @param aNext Result. Undefined if 0 or 1 is returned. |
|
1372 @param aNearest Information about aDocPos itself. Undefined if 0 is returned. |
|
1373 @return |
|
1374 2 if both aNearest and aNext have a result, 1 if only aNearest does and 0 |
|
1375 if neither were found. |
|
1376 */ |
|
1377 RTmGraphemeEdgeIterator::TEdgesFound |
|
1378 RTmGraphemeEdgeIterator::FindEdgeLeftwards(const TTmDocPosSpec& aDocPos, |
|
1379 TTmPosInfo2& aNearest, TTmVisualDocPos& aNext) |
|
1380 { |
|
1381 TInt matches = 0; |
|
1382 TTmPosInfo2 last; |
|
1383 last = GetInfo(); |
|
1384 TTmAmbiguityChecker checker; |
|
1385 TTmVisualDocPos lastXVisualPosition; |
|
1386 while (!AtEnd() && matches < 2) |
|
1387 { |
|
1388 if (last.iEdge.iX != GetInfo().iEdge.iX) |
|
1389 { |
|
1390 lastXVisualPosition = checker.LastAmbiguity(); |
|
1391 if (lastXVisualPosition.Ambiguity() == TTmVisualDocPos::ENotFound) |
|
1392 lastXVisualPosition.SetAsUnambiguous(last); |
|
1393 checker.Reset(); |
|
1394 } |
|
1395 last = GetInfo(); |
|
1396 checker.AddEdge(last); |
|
1397 TInt match = static_cast<TInt>(DocPosMatches(aDocPos, Get())); |
|
1398 if (match != 0) |
|
1399 { |
|
1400 aNearest = last; |
|
1401 aNext = lastXVisualPosition; |
|
1402 matches += match; |
|
1403 } |
|
1404 Next(); |
|
1405 } |
|
1406 if (matches == 0) |
|
1407 return ENone; |
|
1408 return (aNext.Ambiguity() == TTmVisualDocPos::ENotFound)? |
|
1409 ENearestOnly : ENearestAndNext; |
|
1410 } |
|
1411 |
|
1412 /** |
|
1413 Finds the leftmost edge that is to the right of aDocPos in this line. |
|
1414 @param aDocPos Document position that the result must be to the right of. |
|
1415 @param aNext Result. Undefined if 0 or 1 is returned. |
|
1416 @param aNearest Information about aDocPos itself. Undefined if 0 is returned. |
|
1417 @return |
|
1418 2 if both aNearest and aNext have a result, 1 if only aNearest does and 0 |
|
1419 if neither were found. |
|
1420 */ |
|
1421 RTmGraphemeEdgeIterator::TEdgesFound |
|
1422 RTmGraphemeEdgeIterator::FindEdgeRightwards(const TTmDocPosSpec& aDocPos, |
|
1423 TTmPosInfo2& aNearest, TTmVisualDocPos& aNext) |
|
1424 { |
|
1425 if (AtEnd()) |
|
1426 return ENone; |
|
1427 |
|
1428 RTmGraphemeEdgeIterator::TEdgesFound result = ENone; |
|
1429 TTmAmbiguityChecker checker; |
|
1430 TTmGraphemeEdgeInfo info = Get(); |
|
1431 TTmPosInfo2 firstOfLastX = info.iPos; |
|
1432 TInt lastX = info.iPos.iEdge.iX; |
|
1433 TInt nearestPositionX = KMinTInt; |
|
1434 TInt nextPositionX = KMinTInt; |
|
1435 TInt matches = 0; |
|
1436 while (!AtEnd()) |
|
1437 { |
|
1438 info = Get(); |
|
1439 TInt x = info.iPos.iEdge.iX; |
|
1440 |
|
1441 //Are we moving to a new postion? |
|
1442 if (x != lastX) |
|
1443 { |
|
1444 if (lastX == nearestPositionX) |
|
1445 { |
|
1446 // Moving from nearest position to next position. |
|
1447 // Need to start checking for ambiguity. |
|
1448 nextPositionX = x; |
|
1449 checker.Reset(); |
|
1450 } |
|
1451 else if (lastX == nextPositionX) |
|
1452 { |
|
1453 // Moving off next position. Possibly we have finished. |
|
1454 aNext = checker.LastAmbiguity(); |
|
1455 if (aNext.Ambiguity() == TTmVisualDocPos::ENotFound) |
|
1456 aNext.SetAsUnambiguous(firstOfLastX); |
|
1457 result = ENearestAndNext; |
|
1458 if (1 < matches) |
|
1459 return result; |
|
1460 } |
|
1461 lastX = x; |
|
1462 firstOfLastX = info.iPos; |
|
1463 } |
|
1464 |
|
1465 // If we are in the "next" position (one to the right of the |
|
1466 // "nearest" position) we need to check for ambiguity. |
|
1467 if (x == nextPositionX) |
|
1468 checker.AddEdge(info.iPos); |
|
1469 |
|
1470 // Find out if we are or may be in the "nearest" position. |
|
1471 TInt match = static_cast<TInt>(DocPosMatches(aDocPos, info)); |
|
1472 if (0 != match && matches < 2) |
|
1473 { |
|
1474 // We are in the nearest position, or are in a half-match |
|
1475 // where the position matches but the directionality does not. |
|
1476 matches += match; |
|
1477 aNearest = info.iPos; |
|
1478 result = ENearestOnly; |
|
1479 nearestPositionX = x; |
|
1480 nextPositionX = KMinTInt; |
|
1481 } |
|
1482 |
|
1483 Next(); |
|
1484 } |
|
1485 |
|
1486 if (lastX == nextPositionX) |
|
1487 { |
|
1488 // We reached the end of the line at the "next" position, |
|
1489 // so we need to finish the ambiguity checking. |
|
1490 checker.EndLine(); |
|
1491 aNext = checker.LastAmbiguity(); |
|
1492 if (aNext.Ambiguity() == TTmVisualDocPos::ENotFound) |
|
1493 aNext.SetAsUnambiguous(firstOfLastX); |
|
1494 return ENearestAndNext; |
|
1495 } |
|
1496 |
|
1497 return result; |
|
1498 } |
|
1499 |
|
1500 /** |
|
1501 Returns the first trailing edge beyond aDocPos not visually coincident with the |
|
1502 leading edge at aDocPos in this line. |
|
1503 @param aDocPos |
|
1504 The starting document index. |
|
1505 @return |
|
1506 The document position found, or KErrNotFound if none was found in this |
|
1507 line. |
|
1508 */ |
|
1509 TInt RTmGraphemeEdgeIterator::NextPosition(TInt aDocPos) |
|
1510 { |
|
1511 TBool currentXIsForbidden = EFalse; |
|
1512 TInt currentX = KMinTInt; |
|
1513 TInt lastXBestPos = KMaxTInt; |
|
1514 TInt currentXBestPos = KMaxTInt; |
|
1515 while (!AtEnd()) |
|
1516 { |
|
1517 TInt x = GetInfo().iEdge.iX; |
|
1518 const TTmDocPos &docPos = GetInfo().iDocPos; |
|
1519 if (x != currentX) |
|
1520 { |
|
1521 currentX = x; |
|
1522 if (!currentXIsForbidden && currentXBestPos < lastXBestPos) |
|
1523 lastXBestPos = currentXBestPos; |
|
1524 currentXBestPos = KMaxTInt; |
|
1525 currentXIsForbidden = EFalse; |
|
1526 } |
|
1527 if (docPos.iLeadingEdge) |
|
1528 { |
|
1529 if (docPos.iPos == aDocPos) |
|
1530 currentXIsForbidden = ETrue; |
|
1531 } |
|
1532 else |
|
1533 { |
|
1534 if (aDocPos < docPos.iPos && docPos.iPos < currentXBestPos) |
|
1535 currentXBestPos = docPos.iPos; |
|
1536 } |
|
1537 Next(); |
|
1538 } |
|
1539 if (!currentXIsForbidden && currentXBestPos < lastXBestPos) |
|
1540 lastXBestPos = currentXBestPos; |
|
1541 return lastXBestPos == KMaxTInt? KErrNotFound : lastXBestPos; |
|
1542 } |
|
1543 |
|
1544 /** |
|
1545 Returns the last leading edge before aDocPos not visually coincident with the |
|
1546 trailing edge at aDocPos in this line. |
|
1547 @param aDocPos |
|
1548 The starting document index. |
|
1549 @return |
|
1550 The document position found, or KErrNotFound if none was found in this |
|
1551 line. |
|
1552 */ |
|
1553 TInt RTmGraphemeEdgeIterator::PreviousPosition(TInt aDocPos) |
|
1554 { |
|
1555 TBool currentXIsForbidden = EFalse; |
|
1556 TInt currentX = KMinTInt; |
|
1557 TInt lastXBestPos = KMinTInt; |
|
1558 TInt currentXBestPos = KMinTInt; |
|
1559 while (!AtEnd()) |
|
1560 { |
|
1561 TInt x = GetInfo().iEdge.iX; |
|
1562 const TTmDocPos &docPos = GetInfo().iDocPos; |
|
1563 if (x != currentX) |
|
1564 { |
|
1565 currentX = x; |
|
1566 if (!currentXIsForbidden && lastXBestPos < currentXBestPos) |
|
1567 lastXBestPos = currentXBestPos; |
|
1568 currentXBestPos = KMinTInt; |
|
1569 currentXIsForbidden = EFalse; |
|
1570 } |
|
1571 if (!docPos.iLeadingEdge) |
|
1572 { |
|
1573 if (docPos.iPos == aDocPos) |
|
1574 currentXIsForbidden = ETrue; |
|
1575 } |
|
1576 else |
|
1577 { |
|
1578 if (currentXBestPos < docPos.iPos && docPos.iPos < aDocPos) |
|
1579 currentXBestPos = docPos.iPos; |
|
1580 } |
|
1581 Next(); |
|
1582 } |
|
1583 if (!currentXIsForbidden && lastXBestPos < currentXBestPos) |
|
1584 lastXBestPos = currentXBestPos; |
|
1585 return lastXBestPos == KMinTInt? KErrNotFound : lastXBestPos; |
|
1586 } |
|
1587 |
|
1588 /** |
|
1589 * Gets a line of text as displayed, after bidirectional formatting, conversion |
|
1590 * of invisible characters to visible forms, and conversion of glyphs to |
|
1591 * context-dependent forms. |
|
1592 * @param aLineNumber Line to be retrieved. |
|
1593 * @param aText Buffer for output. |
|
1594 * @param aNeeded |
|
1595 * Length of buffer required for the output. This will be greater than |
|
1596 * aText.MaxLength() if aText was not big enough. |
|
1597 * @internalComponent |
|
1598 */ |
|
1599 TBool RTmGeneralInterpreter::GetDisplayedTextL(TInt aLineNumber,TDes& aText,TUint aContextChar,TInt& aNeeded) |
|
1600 { |
|
1601 aText.SetLength(0); |
|
1602 aNeeded = 0; |
|
1603 TBool found = LineNumberToLine(aLineNumber); |
|
1604 if (!found) |
|
1605 return FALSE; |
|
1606 |
|
1607 int i = 0; |
|
1608 while (Next() && Op() != EOpLine) |
|
1609 switch (Op()) |
|
1610 { |
|
1611 case EOpText: |
|
1612 case EOpSpecialChar: |
|
1613 { |
|
1614 TText buffer[KMaxTextChunkSize + 2]; |
|
1615 CTmTextFontCache* font = 0; |
|
1616 RTmTextCache::TDisplayedTextDirectionality directionality = |
|
1617 RightToLeft()? |
|
1618 RTmTextCache::EVisualRightToLeft |
|
1619 : RTmTextCache::ELeftToRight; |
|
1620 User::LeaveIfError(iTextCache.GetDisplayedText(StartChar(), EndChar(), |
|
1621 directionality, buffer,aContextChar, 0, &font)); |
|
1622 __ASSERT_DEBUG(font, TmPanic(EInvariant)); |
|
1623 CFont::TPositionParam p; |
|
1624 int length = EndChar() - StartChar() + 1; |
|
1625 p.iText.Set(buffer, length + 1); |
|
1626 p.iPosInText = 1; |
|
1627 TInt textMaxLength = aText.MaxLength(); |
|
1628 RShapeInfo shapeInfo; |
|
1629 while (p.iPosInText < length) |
|
1630 { |
|
1631 if(!font->Font().GetCharacterPosition2(p, shapeInfo)) |
|
1632 { |
|
1633 //The iPosInText changed after calling the GetCharacterPosition2() |
|
1634 continue; |
|
1635 } |
|
1636 |
|
1637 aNeeded += p.iOutputGlyphs; |
|
1638 for (i = 0; i < p.iOutputGlyphs; i++) |
|
1639 { |
|
1640 TInt code = p.iOutput[i].iCode; |
|
1641 if (code <= 0xFFFF) |
|
1642 { |
|
1643 // non-surrogate character |
|
1644 if (aText.Length() < textMaxLength) |
|
1645 aText.Append(code); |
|
1646 } |
|
1647 else if (code <= 0x10FFFF) |
|
1648 { |
|
1649 // surrogate pair |
|
1650 ++aNeeded; |
|
1651 if (aText.Length() < textMaxLength) |
|
1652 aText.Append(0xD7C0 + (code >> 10)); |
|
1653 if (aText.Length() < textMaxLength) |
|
1654 aText.Append(0xDC00 | (code & 0x3FF)); |
|
1655 } |
|
1656 else |
|
1657 { |
|
1658 // Glyph code; cannot be specified as Unicode. |
|
1659 // Instead add 0xFFFD the Unicode Replacement |
|
1660 // Character |
|
1661 if (aText.Length() < textMaxLength) |
|
1662 aText.Append(0xFFFD); |
|
1663 } |
|
1664 } |
|
1665 } |
|
1666 font->Close(); |
|
1667 if (shapeInfo.IsOpen()) |
|
1668 shapeInfo.Close(); |
|
1669 } |
|
1670 break; |
|
1671 |
|
1672 case EOpInlineText: |
|
1673 for (i = 0; i < InlineText().Length(); i++) |
|
1674 { |
|
1675 aNeeded++; |
|
1676 if (aText.Length() < aText.MaxLength()) |
|
1677 aText.Append(InlineText()[i]); |
|
1678 } |
|
1679 break; |
|
1680 |
|
1681 default: |
|
1682 Skip(); |
|
1683 break; |
|
1684 } |
|
1685 |
|
1686 return TRUE; |
|
1687 } |
|
1688 |
|
1689 /** |
|
1690 * Iterates past an X-Y position and returns the position information for |
|
1691 * the nearest edge to that point. |
|
1692 * @param aXyPos The point to find. |
|
1693 * @param aInfo Returns information about the edge found. |
|
1694 * @return |
|
1695 * ETrue if the operation was successful. It will succeed if the line |
|
1696 * containing aXyPos is formatted. |
|
1697 * @internalComponent |
|
1698 */ |
|
1699 TBool RTmGeneralInterpreter::FindXyPos(const TPoint& aXyPos,TTmPosInfo2& aInfo) |
|
1700 { |
|
1701 if (!YPosToLine(aXyPos.iY)) |
|
1702 return EFalse; |
|
1703 |
|
1704 aInfo.iDocPos = StartDocPos(); |
|
1705 aInfo.iEdge = StartPen(); |
|
1706 |
|
1707 RTmGraphemeEdgeIterator edgeIterator; |
|
1708 edgeIterator.Begin(*this); |
|
1709 TTmVisualDocPos dummy; |
|
1710 if (!edgeIterator.FindEdgeByX(aXyPos.iX, aInfo, dummy)) |
|
1711 return EFalse; |
|
1712 edgeIterator.Close(); |
|
1713 return ETrue; |
|
1714 } |
|
1715 |
|
1716 /** |
|
1717 * Iterates to a document position and returns information about it. |
|
1718 * @param aDocPos The position to find. |
|
1719 * @param aInfo Returns information about the position found. |
|
1720 * @return |
|
1721 * ETrue if the operation was successful. It will succeed if the line |
|
1722 * containing aDocPos is formatted. |
|
1723 * @internalComponent |
|
1724 */ |
|
1725 TBool RTmGeneralInterpreter::FindDocPos(const TTmDocPosSpec& aDocPos,TTmPosInfo2& aInfo) |
|
1726 { |
|
1727 if (!DocPosToLine(aDocPos)) |
|
1728 return FALSE; |
|
1729 |
|
1730 aInfo.iDocPos = StartDocPos(); |
|
1731 aInfo.iEdge = StartPen(); |
|
1732 |
|
1733 RTmGraphemeEdgeIterator edgeIterator; |
|
1734 edgeIterator.Begin(*this); |
|
1735 edgeIterator.FindEdge(aDocPos, aInfo); |
|
1736 edgeIterator.Close(); |
|
1737 return TRUE; |
|
1738 } |
|
1739 |
|
1740 /** |
|
1741 Gets the trailing edge of the previous line's last character, if this position |
|
1742 is unambiguous and if the current position is at the visual start of the line. |
|
1743 Which end the visual start of the line is depends on the paragraph |
|
1744 directionality of the current paragraph. |
|
1745 @param aPosOut The position found, if any. |
|
1746 @param aOnRight Are we currently on the right hand extreme of the line? |
|
1747 @return ETrue if there is such a position at the specified end. |
|
1748 @internalComponent |
|
1749 */ |
|
1750 TBool RTmGeneralInterpreter::TrailingEdgeOfUnambiguousLineEnd( |
|
1751 TTmPosInfo2& aPosOut, TBool aOnRight) const |
|
1752 { |
|
1753 if (VisualStartOfLineIsAmbiguous()) |
|
1754 return EFalse; |
|
1755 TBool atStart = LineInfo().iFlags & TTmLineInfo::EParRightToLeft? |
|
1756 aOnRight : !aOnRight; |
|
1757 if (!atStart) |
|
1758 return EFalse; |
|
1759 aPosOut.iDocPos.iLeadingEdge = EFalse; |
|
1760 aPosOut.iDocPos.iPos = LineInfo().iStart; |
|
1761 aPosOut.iEdge.iY = LineInfo().iBaseline; |
|
1762 aPosOut.iEdge.iX = aOnRight? |
|
1763 LineInfo().iInnerRect.iBr.iX : LineInfo().iInnerRect.iTl.iX; |
|
1764 aPosOut.iRightToLeft = aOnRight; |
|
1765 return ETrue; |
|
1766 } |
|
1767 |
|
1768 RTmDrawingInterpreter::RTmDrawingInterpreter(MTmSource& aSource,CGraphicsContext& aGc, |
|
1769 const TTmInterpreterParam& aParam,const TPoint& aTopLeft, |
|
1770 const TRect& aClipRect,const TLogicalRgb* aDocBackground, |
|
1771 TUint aFlags,const TCursorSelection* aHighlight, |
|
1772 const TTmHighlightExtensions* aHighlightExtensions, |
|
1773 TBool aDrawInvertedHighlight): |
|
1774 RTmGeneralInterpreter(aSource,aParam,&aTopLeft), |
|
1775 iGc(aGc), |
|
1776 iClipRect(aClipRect), |
|
1777 iFirstLine(TRUE), |
|
1778 iLabelled(FALSE), |
|
1779 iLabelLeft(KMaxTInt), |
|
1780 iLabelRight(KMinTInt), |
|
1781 iDocBackground(aDocBackground), |
|
1782 iFlags(aFlags | aParam.iDrawingInterpFlags), |
|
1783 iHighlightStartPos(0), |
|
1784 iHighlightEndPos(0), |
|
1785 iHighlightExtensions(NULL), |
|
1786 iHighlightedLineRect(), |
|
1787 iHighlightedLineRgn(4), // granularity = 4 |
|
1788 iSource(aSource), |
|
1789 iParam(aParam), |
|
1790 iDrawInvertedHighlight(EFalse), |
|
1791 iHighlightXorColor() |
|
1792 { |
|
1793 iHighlightStartPos = 0; |
|
1794 iHighlightEndPos = 0; |
|
1795 if (aHighlight) |
|
1796 { |
|
1797 if (aHighlight->iAnchorPos < aHighlight->iCursorPos) |
|
1798 { |
|
1799 iHighlightStartPos = aHighlight->iAnchorPos; |
|
1800 iHighlightEndPos = aHighlight->iCursorPos; |
|
1801 } |
|
1802 else |
|
1803 { |
|
1804 iHighlightStartPos = aHighlight->iCursorPos; |
|
1805 iHighlightEndPos = aHighlight->iAnchorPos; |
|
1806 } |
|
1807 } |
|
1808 |
|
1809 if (NULL != aHighlightExtensions && ! aHighlightExtensions->IsNull()) |
|
1810 { |
|
1811 iHighlightExtensions = aHighlightExtensions; |
|
1812 } |
|
1813 |
|
1814 TTmHighlightSource highlightSource(aSource); |
|
1815 iDrawInvertedHighlight = aDrawInvertedHighlight || ! highlightSource.HighlightVisible(); |
|
1816 if (iDrawInvertedHighlight) |
|
1817 { |
|
1818 // Explicit construction of the 2nd parameter for SystemColor, TRgb, ensuring opaque alpha blending. |
|
1819 // FF is opaque alpha channel value. |
|
1820 TRgb defaultColorOfBackground(static_cast<TUint32>(TLogicalRgb::ESystemBackgroundColor), 0xFF); |
|
1821 TRgb backgroundColor = aSource.SystemColor(TLogicalRgb::ESystemBackgroundIndex,defaultColorOfBackground); |
|
1822 |
|
1823 // Explicit construction of the 2nd parameter for SystemColor, TRgb, ensuring opaque alpha blending. |
|
1824 // FF is opaque alpha channel value. |
|
1825 TRgb defaultColorOfXorColor(static_cast<TUint32>(TLogicalRgb::ESystemSelectionBackgroundColor), 0xFF); |
|
1826 TRgb xorColor = aSource.SystemColor(TLogicalRgb::ESystemSelectionBackgroundIndex,defaultColorOfXorColor); |
|
1827 |
|
1828 iHighlightXorColor = backgroundColor ^ xorColor; |
|
1829 } |
|
1830 } |
|
1831 |
|
1832 RTmDrawingInterpreter::~RTmDrawingInterpreter() |
|
1833 { |
|
1834 iHighlightedLineRgn.Close(); |
|
1835 } |
|
1836 |
|
1837 TBool RTmDrawingInterpreter::GetHighlightPos(TInt& aHighlightStartPos, TInt& aHighlightEndPos) const |
|
1838 { |
|
1839 aHighlightStartPos = aHighlightEndPos = 0; |
|
1840 |
|
1841 if (iHighlightEndPos > iHighlightStartPos) |
|
1842 { |
|
1843 aHighlightStartPos = iHighlightStartPos; |
|
1844 if (StartDocPos().iPos > iHighlightStartPos) |
|
1845 { |
|
1846 aHighlightStartPos = StartDocPos().iPos; |
|
1847 } |
|
1848 |
|
1849 aHighlightEndPos = iHighlightEndPos; |
|
1850 if (EndDocPos().iPos < iHighlightEndPos) |
|
1851 { |
|
1852 aHighlightEndPos = EndDocPos().iPos; |
|
1853 } |
|
1854 } |
|
1855 |
|
1856 return (aHighlightEndPos > aHighlightStartPos); |
|
1857 } |
|
1858 |
|
1859 TBool RTmDrawingInterpreter::GetHighlightClipRegion(const TRect& aClipRect, RRegion& aHighlightRegion) const |
|
1860 { |
|
1861 if (UsesAdjustedHighlight()) |
|
1862 { |
|
1863 return GetAdjustedHighlightClipRegion(aClipRect, aHighlightRegion); |
|
1864 } |
|
1865 |
|
1866 aHighlightRegion.Clear(); |
|
1867 |
|
1868 TInt highlightStartPos = 0; |
|
1869 TInt highlightEndPos = 0; |
|
1870 if (GetHighlightPos(highlightStartPos, highlightEndPos)) |
|
1871 { |
|
1872 TRect rect(TRect::EUninitialized); |
|
1873 TTmDocPos start(highlightStartPos, ETrue); |
|
1874 TTmDocPos end(highlightEndPos, EFalse); |
|
1875 RTmBoundingRectInterpreter interpreter(iSource, iParam); |
|
1876 TBool found = interpreter.FirstRect(start.iPos, end.iPos, rect); |
|
1877 while (found) |
|
1878 { |
|
1879 if (!rect.IsEmpty()) |
|
1880 { |
|
1881 rect.Move(TextLayoutTopLeft()); |
|
1882 aHighlightRegion.AddRect(rect); |
|
1883 |
|
1884 if (aHighlightRegion.CheckError()) |
|
1885 { |
|
1886 break; |
|
1887 } |
|
1888 else |
|
1889 { |
|
1890 aHighlightRegion.Tidy(); |
|
1891 } |
|
1892 } |
|
1893 |
|
1894 found = interpreter.NextRect(rect); |
|
1895 } |
|
1896 |
|
1897 interpreter.Close(); |
|
1898 return ! aHighlightRegion.CheckError(); |
|
1899 } |
|
1900 else |
|
1901 { |
|
1902 return ETrue; |
|
1903 } |
|
1904 } |
|
1905 |
|
1906 TBool RTmDrawingInterpreter::GetFirstHighlightClipRect(RTmBoundingRectInterpreter& aInterpreter, |
|
1907 const TRect& aClipRect, TRect& aRect) const |
|
1908 { |
|
1909 if (UsesAdjustedHighlight()) |
|
1910 { |
|
1911 return GetFirstAdjustedHighlightClipRect(aInterpreter, aClipRect, aRect); |
|
1912 } |
|
1913 |
|
1914 TInt highlightStartPos = 0; |
|
1915 TInt highlightEndPos = 0; |
|
1916 if (GetHighlightPos(highlightStartPos, highlightEndPos)) |
|
1917 { |
|
1918 TTmDocPos start(highlightStartPos, ETrue); |
|
1919 TTmDocPos end(highlightEndPos, EFalse); |
|
1920 TBool found = aInterpreter.FirstRect(start.iPos, end.iPos, aRect); |
|
1921 while (found) |
|
1922 { |
|
1923 aRect.Move(TextLayoutTopLeft()); |
|
1924 aRect.Intersection(aClipRect); |
|
1925 if (aRect.IsEmpty()) |
|
1926 { |
|
1927 found = aInterpreter.NextRect(aRect); |
|
1928 } |
|
1929 else |
|
1930 { |
|
1931 return ETrue; |
|
1932 } |
|
1933 } |
|
1934 } |
|
1935 |
|
1936 aRect = TRect(TRect::EUninitialized); |
|
1937 return EFalse; |
|
1938 } |
|
1939 |
|
1940 TBool RTmDrawingInterpreter::GetNextHighlightClipRect(RTmBoundingRectInterpreter& aInterpreter, |
|
1941 const TRect& aClipRect, TRect& aRect) const |
|
1942 { |
|
1943 if (UsesAdjustedHighlight()) |
|
1944 { |
|
1945 return GetNextAdjustedHighlightClipRect(aInterpreter, aClipRect, aRect); |
|
1946 } |
|
1947 |
|
1948 TBool found = aInterpreter.NextRect(aRect); |
|
1949 while (found) |
|
1950 { |
|
1951 aRect.Move(TextLayoutTopLeft()); |
|
1952 aRect.Intersection(aClipRect); |
|
1953 if (aRect.IsEmpty()) |
|
1954 { |
|
1955 found = aInterpreter.NextRect(aRect); |
|
1956 } |
|
1957 else |
|
1958 { |
|
1959 return ETrue; |
|
1960 } |
|
1961 } |
|
1962 |
|
1963 aRect = TRect(TRect::EUninitialized); |
|
1964 return EFalse; |
|
1965 } |
|
1966 |
|
1967 TBool RTmDrawingInterpreter::GetAdjustedHighlightClipRegion(const TRect& aClipRect, RRegion& aHighlightRegion) const |
|
1968 { |
|
1969 __ASSERT_DEBUG(NULL != iHighlightExtensions, TmPanic(EInvariant)); |
|
1970 |
|
1971 aHighlightRegion.Clear(); |
|
1972 |
|
1973 if (iHighlightEndPos > iHighlightStartPos) |
|
1974 { |
|
1975 RTmBoundingRectInterpreter interpreter(iSource, iParam); |
|
1976 |
|
1977 TRect rect(TRect::EUninitialized); |
|
1978 TBool found = interpreter.FirstRect(iHighlightStartPos, iHighlightEndPos, rect); |
|
1979 while (found) |
|
1980 { |
|
1981 if (! rect.IsEmpty()) |
|
1982 { |
|
1983 rect.Move(TextLayoutTopLeft()); |
|
1984 iHighlightExtensions->AdjustRect(rect); |
|
1985 if (rect.iBr.iY < aClipRect.iTl.iY) |
|
1986 { |
|
1987 // ignore it |
|
1988 } |
|
1989 else if (rect.iTl.iY > aClipRect.iBr.iY) |
|
1990 { |
|
1991 break; |
|
1992 } |
|
1993 else |
|
1994 { |
|
1995 aHighlightRegion.AddRect(rect); |
|
1996 if (aHighlightRegion.CheckError()) |
|
1997 { |
|
1998 break; |
|
1999 } |
|
2000 else |
|
2001 { |
|
2002 aHighlightRegion.Tidy(); |
|
2003 } |
|
2004 } |
|
2005 } |
|
2006 |
|
2007 found = interpreter.NextRect(rect); |
|
2008 } |
|
2009 |
|
2010 interpreter.Close(); |
|
2011 |
|
2012 if (aHighlightRegion.CheckError()) |
|
2013 { |
|
2014 return EFalse; |
|
2015 } |
|
2016 |
|
2017 aHighlightRegion.ClipRect(aClipRect); |
|
2018 } |
|
2019 |
|
2020 return ETrue; |
|
2021 } |
|
2022 |
|
2023 TBool RTmDrawingInterpreter::GetFirstAdjustedHighlightClipRect(RTmBoundingRectInterpreter& aInterpreter, |
|
2024 const TRect& aClipRect, TRect& aRect) const |
|
2025 { |
|
2026 __ASSERT_DEBUG(NULL != iHighlightExtensions, TmPanic(EInvariant)); |
|
2027 |
|
2028 if (iHighlightEndPos > iHighlightStartPos) |
|
2029 { |
|
2030 TBool found = aInterpreter.FirstRect(iHighlightStartPos, iHighlightEndPos, aRect); |
|
2031 while (found) |
|
2032 { |
|
2033 if (! aRect.IsEmpty()) |
|
2034 { |
|
2035 aRect.Move(TextLayoutTopLeft()); |
|
2036 iHighlightExtensions->AdjustRect(aRect); |
|
2037 if (aRect.iBr.iY < aClipRect.iTl.iY) |
|
2038 { |
|
2039 // ignore it |
|
2040 } |
|
2041 else if (aRect.iTl.iY > aClipRect.iBr.iY) |
|
2042 { |
|
2043 break; |
|
2044 } |
|
2045 else |
|
2046 { |
|
2047 aRect.Intersection(aClipRect); |
|
2048 if (! aRect.IsEmpty()) |
|
2049 { |
|
2050 return ETrue; |
|
2051 } |
|
2052 } |
|
2053 } |
|
2054 |
|
2055 found = aInterpreter.NextRect(aRect); |
|
2056 } |
|
2057 } |
|
2058 |
|
2059 aRect = TRect(TRect::EUninitialized); |
|
2060 return EFalse; |
|
2061 } |
|
2062 |
|
2063 TBool RTmDrawingInterpreter::GetNextAdjustedHighlightClipRect(RTmBoundingRectInterpreter& aInterpreter, |
|
2064 const TRect& aClipRect, TRect& aRect) const |
|
2065 { |
|
2066 __ASSERT_DEBUG(NULL != iHighlightExtensions, TmPanic(EInvariant)); |
|
2067 __ASSERT_DEBUG(iHighlightEndPos > iHighlightStartPos, TmPanic(EInvariant)); |
|
2068 |
|
2069 TBool found = aInterpreter.NextRect(aRect); |
|
2070 while (found) |
|
2071 { |
|
2072 if (! aRect.IsEmpty()) |
|
2073 { |
|
2074 aRect.Move(TextLayoutTopLeft()); |
|
2075 iHighlightExtensions->AdjustRect(aRect); |
|
2076 |
|
2077 if (aRect.iBr.iY < aClipRect.iTl.iY) |
|
2078 { |
|
2079 // ignore it |
|
2080 } |
|
2081 else if (aRect.iTl.iY > aClipRect.iBr.iY) |
|
2082 { |
|
2083 break; |
|
2084 } |
|
2085 else |
|
2086 { |
|
2087 aRect.Intersection(aClipRect); |
|
2088 if (! aRect.IsEmpty()) |
|
2089 { |
|
2090 return ETrue; |
|
2091 } |
|
2092 } |
|
2093 } |
|
2094 |
|
2095 found = aInterpreter.NextRect(aRect); |
|
2096 } |
|
2097 |
|
2098 aRect = TRect(TRect::EUninitialized); |
|
2099 return EFalse; |
|
2100 } |
|
2101 |
|
2102 TBool RTmDrawingInterpreter::IsCurrentOpCompletelyHighlighted() const |
|
2103 { |
|
2104 if (iHighlightEndPos > iHighlightStartPos) |
|
2105 { |
|
2106 return iHighlightStartPos <= StartDocPos().iPos && |
|
2107 iHighlightEndPos >= EndDocPos().iPos; |
|
2108 } |
|
2109 else |
|
2110 { |
|
2111 return EFalse; |
|
2112 } |
|
2113 } |
|
2114 |
|
2115 TBool RTmDrawingInterpreter::UsesExtendedHighlight() const |
|
2116 { |
|
2117 return NULL != iHighlightExtensions && iHighlightExtensions->Extends(); |
|
2118 } |
|
2119 |
|
2120 TBool RTmDrawingInterpreter::UsesAdjustedHighlight() const |
|
2121 { |
|
2122 return NULL != iHighlightExtensions && ! iHighlightExtensions->IsNull(); |
|
2123 } |
|
2124 |
|
2125 void RTmDrawingInterpreter::Draw() |
|
2126 { |
|
2127 if (iClipRect.iBr.iY < TextLayoutTopLeft().iY |
|
2128 || (iFlags & EInvisible)) |
|
2129 return; |
|
2130 |
|
2131 iGc.Reset(); |
|
2132 InitGraphicsContext(); |
|
2133 TRect drawn = iClipRect; |
|
2134 drawn.iTl.iY = drawn.iBr.iY = TextLayoutTopLeft().iY; |
|
2135 int error; |
|
2136 |
|
2137 TBool done = FALSE; |
|
2138 while (Next() && !done) |
|
2139 { |
|
2140 switch (Op()) |
|
2141 { |
|
2142 case EOpLine: |
|
2143 if (LineInfo().iOuterRect.iBr.iY < iClipRect.iTl.iY) |
|
2144 { |
|
2145 Skip(); |
|
2146 break; |
|
2147 } |
|
2148 if (LineInfo().iOuterRect.iTl.iY > iClipRect.iBr.iY) |
|
2149 done = TRUE; |
|
2150 else |
|
2151 { |
|
2152 TRect line_rect; |
|
2153 Line(line_rect); |
|
2154 |
|
2155 // Draw background to left and right of line where it intersects the clip rectangle. |
|
2156 if (!(iFlags & EIsLabel)) |
|
2157 { |
|
2158 TRect r = iClipRect; |
|
2159 r.iTl.iY = Max(r.iTl.iY,line_rect.iTl.iY); |
|
2160 r.iBr.iY = Min(r.iBr.iY,line_rect.iBr.iY); |
|
2161 r.iBr.iX = line_rect.iTl.iX; |
|
2162 if (iDocBackground && !r.IsEmpty()) |
|
2163 { |
|
2164 DrawBackground(r,*iDocBackground); // rectangle to left of line |
|
2165 InitGraphicsContext(); |
|
2166 } |
|
2167 r.iBr.iX = iClipRect.iBr.iX; |
|
2168 r.iTl.iX = line_rect.iBr.iX; |
|
2169 if (iDocBackground && !r.IsEmpty()) |
|
2170 { |
|
2171 DrawBackground(r,*iDocBackground); // rectangle to right of line |
|
2172 InitGraphicsContext(); |
|
2173 } |
|
2174 if (drawn.IsEmpty()) |
|
2175 drawn.iTl.iY = line_rect.iTl.iY; |
|
2176 drawn.iBr.iY = line_rect.iBr.iY; |
|
2177 } |
|
2178 } |
|
2179 break; |
|
2180 case EOpText: |
|
2181 Text(); |
|
2182 break; |
|
2183 case EOpInlineText: |
|
2184 InlineText(); |
|
2185 break; |
|
2186 case EOpSpecialChar: |
|
2187 TRAP(error,SpecialCharL()); |
|
2188 break; |
|
2189 case EOpRule: |
|
2190 Rule(); |
|
2191 break; |
|
2192 case EOpLabel: |
|
2193 Label(); |
|
2194 break; |
|
2195 default: |
|
2196 Skip(); // unimplemented |
|
2197 break; |
|
2198 } |
|
2199 } |
|
2200 |
|
2201 iParFormat.Close(); |
|
2202 |
|
2203 /* |
|
2204 Draw undrawn background areas outside the text. These may themselves be partially covered by |
|
2205 a custom background, so each one has to be drawn by DrawBackground, which can then |
|
2206 fill in any parts not custom-drawn. |
|
2207 */ |
|
2208 if (iDocBackground && !(iFlags & EIsLabel)) |
|
2209 { |
|
2210 if (iLabelLeft < drawn.iTl.iX) |
|
2211 drawn.iTl.iX = iLabelLeft; |
|
2212 drawn.Intersection(iClipRect); |
|
2213 if (drawn != iClipRect) |
|
2214 { |
|
2215 TRect r[4]; |
|
2216 SubtractRect(iClipRect,drawn,r); |
|
2217 for (int i = 0; i < 4; i++) |
|
2218 if (!r[i].IsEmpty()) |
|
2219 DrawBackground(r[i],*iDocBackground); |
|
2220 } |
|
2221 } |
|
2222 |
|
2223 // if the highlight is not visible (because the custom drawer defines a |
|
2224 // highlighted background color identical to the highlighted foreground color) |
|
2225 // draw the selection inverting every pixel in the highlighted region. |
|
2226 if (! iHighlightedLineRect.IsEmpty()) |
|
2227 { |
|
2228 InvertHighlightedLineRgn(); |
|
2229 } |
|
2230 } |
|
2231 |
|
2232 void RTmDrawingInterpreter::InitGraphicsContext() |
|
2233 { |
|
2234 iGc.SetDrawMode(CGraphicsContext::EDrawModePEN); |
|
2235 iGc.SetBrushStyle(CGraphicsContext::ESolidBrush); |
|
2236 iGc.SetPenStyle(CGraphicsContext::ESolidPen); |
|
2237 iGc.SetClippingRect(iClipRect); |
|
2238 } |
|
2239 |
|
2240 void RTmDrawingInterpreter::Line(TRect& aDrawn) |
|
2241 { |
|
2242 if (! iHighlightedLineRect.IsEmpty()) |
|
2243 { |
|
2244 InvertHighlightedLineRgn(); |
|
2245 } |
|
2246 |
|
2247 if (iFirstLine || ParStart()) |
|
2248 { |
|
2249 int error; |
|
2250 TRAP(error,Source().GetParagraphFormatL(StartChar(),iParFormat)); |
|
2251 if (LineInfo().iFlags & TTmLineInfo::EParRightToLeft) |
|
2252 iParFormat.iFlags |= RTmParFormat::ERightToLeft; |
|
2253 else |
|
2254 iParFormat.iFlags &= ~RTmParFormat::ERightToLeft; |
|
2255 iLabelled = FALSE; |
|
2256 MFormLabelApi* labelApi = (MFormLabelApi*)Source().GetExtendedInterface(KFormLabelApiExtensionUid); |
|
2257 if ((labelApi != NULL) && (labelApi->LabelModeSelect(MTmSource::EParLabel, StartChar()))) |
|
2258 { |
|
2259 RTmParFormat pf; |
|
2260 TRAP(error,Source().GetParagraphFormatL(0,pf)); |
|
2261 if (!error) |
|
2262 { |
|
2263 iLabelled = TRUE; |
|
2264 iLabelBackground = pf.iBackgroundColor; |
|
2265 } |
|
2266 labelApi->LabelModeCancel(); |
|
2267 pf.Close(); |
|
2268 } |
|
2269 TSize label_size(0, 0); |
|
2270 int margin_size = 0; |
|
2271 if (labelApi != NULL) |
|
2272 labelApi->LabelMetrics(MTmSource::EParLabel, label_size, margin_size); |
|
2273 iLabelLeft = LineInfo().iOuterRect.iTl.iX - margin_size; |
|
2274 iLabelRight = iLabelLeft + label_size.iWidth; |
|
2275 } |
|
2276 |
|
2277 TRect inner_border_bounds; |
|
2278 TRect outer_border_bounds(LineInfo().iOuterRect); |
|
2279 TInt left_border_width = 0, right_border_width = 0, top_border_width = 0, bottom_border_width = 0; |
|
2280 GetBorderInfo(inner_border_bounds,outer_border_bounds, |
|
2281 left_border_width,right_border_width,top_border_width,bottom_border_width); |
|
2282 TRect r(outer_border_bounds); |
|
2283 r.BoundingRect(LineInfo().iOuterRect); |
|
2284 r.Intersection(iClipRect); |
|
2285 |
|
2286 if (!(iFlags & EIsLabel)) |
|
2287 { |
|
2288 // Draw paragraph background if specified. |
|
2289 if (iFlags & EDrawParBackground) |
|
2290 { |
|
2291 DrawBackground(r,iParFormat.iBackgroundColor); |
|
2292 InitGraphicsContext(); |
|
2293 } |
|
2294 // Otherwise use the document background if any as a paragraph background. |
|
2295 else if (iDocBackground) |
|
2296 { |
|
2297 DrawBackground(r,*iDocBackground); |
|
2298 InitGraphicsContext(); |
|
2299 } |
|
2300 |
|
2301 DrawLineGraphics(r); |
|
2302 |
|
2303 if (iLabelLeft < LineInfo().iOuterRect.iTl.iX) |
|
2304 DrawLabelBackground(); |
|
2305 |
|
2306 if (Source().PageBreakInRange(StartChar(),Min(EndChar(),Source().DocumentLength()))) |
|
2307 DrawPageBreak(); |
|
2308 } |
|
2309 |
|
2310 if (ParStart() && iParFormat.Bullet()) |
|
2311 DrawBullet(); |
|
2312 |
|
2313 if (Bordered()) |
|
2314 DrawBorders(inner_border_bounds,outer_border_bounds, |
|
2315 left_border_width,right_border_width,top_border_width,bottom_border_width); |
|
2316 |
|
2317 iFirstLine = FALSE; |
|
2318 aDrawn = r; |
|
2319 } |
|
2320 |
|
2321 void RTmDrawingInterpreter::DrawLineGraphics(const TRect& aRect) |
|
2322 { |
|
2323 Source().DrawLineGraphics(iGc, TextLayoutTopLeft(), aRect, LineInfo()); |
|
2324 InitGraphicsContext(); |
|
2325 } |
|
2326 |
|
2327 void RTmDrawingInterpreter::DrawLabelBackground() |
|
2328 { |
|
2329 TRect r = LineInfo().iOuterRect; |
|
2330 r.iTl.iX = iLabelLeft; |
|
2331 r.iBr.iX = iLabelRight; |
|
2332 |
|
2333 // Draw the label background. |
|
2334 if (iFlags & EDrawParBackground) |
|
2335 DrawBackground(r,iLabelBackground); |
|
2336 else if (iDocBackground) |
|
2337 DrawBackground(r,*iDocBackground); |
|
2338 |
|
2339 // Draw the gutter. |
|
2340 r.iTl.iX = iLabelRight; |
|
2341 r.iBr.iX = LineInfo().iOuterRect.iTl.iX; |
|
2342 if (iDocBackground && !r.IsEmpty()) |
|
2343 DrawBackground(r,*iDocBackground); |
|
2344 |
|
2345 InitGraphicsContext(); |
|
2346 } |
|
2347 |
|
2348 void RTmDrawingInterpreter::DrawPageBreak() |
|
2349 { |
|
2350 iGc.SetPenStyle(CGraphicsContext::EDashedPen); |
|
2351 TLogicalRgb color = iParFormat.iBackgroundColor; |
|
2352 TUint index = color.SystemColorIndex(); |
|
2353 if (index) |
|
2354 color = Source().SystemColor(index,color); |
|
2355 iGc.SetPenColor(~(color & 0xFFFFFF)); |
|
2356 TPoint p = LineInfo().iOuterRect.iBr; |
|
2357 p.iY--; |
|
2358 TPoint q = p; |
|
2359 q.iX = LineInfo().iOuterRect.iTl.iX; |
|
2360 TmTextDrawExt().DrawLine(iGc, p, q); |
|
2361 InitGraphicsContext(); |
|
2362 } |
|
2363 |
|
2364 void RTmDrawingInterpreter::DrawBullet() |
|
2365 { |
|
2366 int left_margin = 0; |
|
2367 int right_margin = 0; |
|
2368 int first_line_left_margin = 0; |
|
2369 int first_line_right_margin = 0; |
|
2370 int bullet_margin = 0; |
|
2371 int bullet_width = 0; |
|
2372 int bullet_ascent = 0; |
|
2373 int bullet_descent = 0; |
|
2374 CFont* font = NULL; |
|
2375 TRAPD(error,TmGetMarginsL(Device(),iParFormat,left_margin,right_margin, |
|
2376 first_line_left_margin,first_line_right_margin, |
|
2377 bullet_margin,bullet_width,bullet_ascent,bullet_descent,&font)); |
|
2378 if (!error && font) |
|
2379 { |
|
2380 TBuf<1> bullet; |
|
2381 bullet.SetLength(1); |
|
2382 bullet[0] = (TText)iParFormat.Bullet()->iCharacterCode; |
|
2383 TPoint p; |
|
2384 if (iParFormat.RightToLeft()) |
|
2385 { |
|
2386 p = EndPen(); |
|
2387 p.iX -= bullet_margin - first_line_right_margin + bullet_width; |
|
2388 } |
|
2389 else |
|
2390 { |
|
2391 p = StartPen(); |
|
2392 p.iX += bullet_margin - first_line_left_margin; |
|
2393 } |
|
2394 iGc.UseFont(font); |
|
2395 TRgb color = Source().SystemColor(iParFormat.Bullet()->iColor); |
|
2396 SetPenColor(color); |
|
2397 iGc.SetUnderlineStyle(EUnderlineOff); |
|
2398 TmTextDrawExt().DrawText(iGc, bullet, p); |
|
2399 iGc.DiscardFont(); |
|
2400 Device().ReleaseFont(font); |
|
2401 } |
|
2402 } |
|
2403 |
|
2404 void RTmDrawingInterpreter::GetBorderInfo(TRect& aInnerBounds,TRect& aOuterBounds, |
|
2405 TInt& aLeftWidth,TInt& aRightWidth,TInt& aTopWidth,TInt& aBottomWidth) |
|
2406 { |
|
2407 const MGraphicsDeviceMap& device = Device(); |
|
2408 int left = 0, right = 0, top = 0, bottom = 0; |
|
2409 int left_full = 0, right_full = 0, top_full = 0, bottom_full = 0; |
|
2410 TmGetBorderWidth(device,iParFormat,RTmParFormat::ELeadingBorder,left,left_full); |
|
2411 TmGetBorderWidth(device,iParFormat,RTmParFormat::ETrailingBorder,right,right_full); |
|
2412 if (ParStart()) |
|
2413 TmGetBorderWidth(device,iParFormat,RTmParFormat::ETopBorder,top,top_full); |
|
2414 if (ParEnd()) |
|
2415 TmGetBorderWidth(device,iParFormat,RTmParFormat::EBottomBorder,bottom,bottom_full); |
|
2416 int h_margin = device.HorizontalTwipsToPixels(iParFormat.iBorderMargin); |
|
2417 int v_margin = device.VerticalTwipsToPixels(iParFormat.iBorderMargin); |
|
2418 |
|
2419 // Establish the outer bounds of the inner border rule. |
|
2420 TRect inner_bounds = LineInfo().iInnerRect; |
|
2421 int left_margin = device.HorizontalTwipsToPixels(iParFormat.iLeadingMargin); |
|
2422 int first_line_left_margin = left_margin + device.HorizontalTwipsToPixels(iParFormat.iFirstLineIndent); |
|
2423 inner_bounds.iTl.iX = LineInfo().iOuterRect.iTl.iX + Min(left_margin,first_line_left_margin); |
|
2424 inner_bounds.iBr.iX = LineInfo().iOuterRect.iBr.iX - device.HorizontalTwipsToPixels(iParFormat.iTrailingMargin); |
|
2425 |
|
2426 // Include paragraph labels in the border rule area. |
|
2427 if (iLabelled) |
|
2428 inner_bounds.iTl.iX = Min(inner_bounds.iTl.iX,iLabelLeft); |
|
2429 |
|
2430 if (left) |
|
2431 inner_bounds.iTl.iX -= h_margin + left; |
|
2432 if (right) |
|
2433 inner_bounds.iBr.iX += h_margin + right; |
|
2434 if (top) |
|
2435 inner_bounds.iTl.iY -= v_margin + top; |
|
2436 if (bottom) |
|
2437 inner_bounds.iBr.iY += v_margin + bottom; |
|
2438 |
|
2439 // Establish the outer bounds of the outer border rule. |
|
2440 TRect outer_bounds = inner_bounds; |
|
2441 outer_bounds.iTl.iX -= left_full - left; |
|
2442 outer_bounds.iBr.iX += right_full - right; |
|
2443 outer_bounds.iTl.iY -= top_full - top; |
|
2444 outer_bounds.iBr.iY += bottom_full - bottom; |
|
2445 |
|
2446 aInnerBounds = inner_bounds; |
|
2447 aOuterBounds = outer_bounds; |
|
2448 aLeftWidth = left; |
|
2449 aRightWidth = right; |
|
2450 aTopWidth = top; |
|
2451 aBottomWidth = bottom; |
|
2452 } |
|
2453 |
|
2454 void RTmDrawingInterpreter::DrawBorders(const TRect& aInnerBounds,const TRect& aOuterBounds, |
|
2455 TInt aLeftWidth,TInt aRightWidth,TInt aTopWidth,TInt aBottomWidth) |
|
2456 { |
|
2457 iGc.SetBrushStyle(CGraphicsContext::ESolidBrush); |
|
2458 TRect r; |
|
2459 const TTmParBorder* b = iParFormat.Border(RTmParFormat::ELeadingBorder); |
|
2460 if (b && (aLeftWidth != 0)) |
|
2461 { |
|
2462 r = aInnerBounds; |
|
2463 r.iBr.iX = r.iTl.iX + aLeftWidth; |
|
2464 DrawBorderRect(*b,r); |
|
2465 r = aOuterBounds; |
|
2466 r.iBr.iX = r.iTl.iX + aLeftWidth; |
|
2467 DrawBorderRect(*b,r); |
|
2468 } |
|
2469 b = iParFormat.Border(RTmParFormat::ETrailingBorder); |
|
2470 if (b && (aRightWidth != 0)) |
|
2471 { |
|
2472 r = aInnerBounds; |
|
2473 r.iTl.iX = r.iBr.iX - aRightWidth; |
|
2474 DrawBorderRect(*b,r); |
|
2475 r = aOuterBounds; |
|
2476 r.iTl.iX = r.iBr.iX - aRightWidth; |
|
2477 DrawBorderRect(*b,r); |
|
2478 } |
|
2479 b = iParFormat.Border(RTmParFormat::ETopBorder); |
|
2480 if (b && (aTopWidth != 0)) |
|
2481 { |
|
2482 r = aInnerBounds; |
|
2483 r.iBr.iY = r.iTl.iY + aTopWidth; |
|
2484 DrawBorderRect(*b,r); |
|
2485 r = aOuterBounds; |
|
2486 r.iBr.iY = r.iTl.iY + aTopWidth; |
|
2487 DrawBorderRect(*b,r); |
|
2488 } |
|
2489 b = iParFormat.Border(RTmParFormat::EBottomBorder); |
|
2490 if (b && (aBottomWidth != 0)) |
|
2491 { |
|
2492 r = aInnerBounds; |
|
2493 r.iTl.iY = r.iBr.iY - aBottomWidth; |
|
2494 DrawBorderRect(*b,r); |
|
2495 r = aOuterBounds; |
|
2496 r.iTl.iY = r.iBr.iY - aBottomWidth; |
|
2497 DrawBorderRect(*b,r); |
|
2498 } |
|
2499 } |
|
2500 |
|
2501 void RTmDrawingInterpreter::DrawBorderRect(const TTmParBorder& aBorder,const TRect& aRect) |
|
2502 { |
|
2503 if (aBorder.iStyle == TTmParBorder::ESolidStyle || aBorder.iStyle == TTmParBorder::EDoubleStyle) |
|
2504 { |
|
2505 iGc.SetPenStyle(CGraphicsContext::ENullPen); |
|
2506 SetBrushColor(aBorder.iColor); |
|
2507 TmTextDrawExt().DrawRect(iGc, aRect); |
|
2508 return; |
|
2509 } |
|
2510 switch (aBorder.iStyle) |
|
2511 { |
|
2512 case TTmParBorder::EDotStyle: |
|
2513 iGc.SetPenStyle(CGraphicsContext::EDottedPen); |
|
2514 break; |
|
2515 case TTmParBorder::EDashStyle: |
|
2516 iGc.SetPenStyle(CGraphicsContext::EDashedPen); |
|
2517 break; |
|
2518 case TTmParBorder::EDotDashStyle: |
|
2519 iGc.SetPenStyle(CGraphicsContext::EDotDashPen); |
|
2520 break; |
|
2521 case TTmParBorder::EDotDotDashStyle: |
|
2522 iGc.SetPenStyle(CGraphicsContext::EDotDotDashPen); |
|
2523 break; |
|
2524 default: |
|
2525 return; |
|
2526 } |
|
2527 SetPenColor(aBorder.iColor); |
|
2528 TPoint p = aRect.iTl; |
|
2529 TPoint q = aRect.iBr; |
|
2530 if (aRect.Width() > aRect.Height()) |
|
2531 { |
|
2532 q.iY = p.iY; |
|
2533 TmTextDrawExt().DrawLine(iGc, p, q); |
|
2534 } |
|
2535 else |
|
2536 { |
|
2537 q.iX = p.iX; |
|
2538 // Set the top to the paragraph top and clip to the rectangle so that the dot or dash phase is consistent. |
|
2539 p.iY = LineInfo().iParTop; |
|
2540 TRect clip = aRect; |
|
2541 clip.Intersection(iClipRect); |
|
2542 iGc.SetClippingRect(clip); |
|
2543 TmTextDrawExt().DrawLine(iGc, p, q); |
|
2544 iGc.SetClippingRect(iClipRect); |
|
2545 } |
|
2546 iGc.SetPenStyle(CGraphicsContext::ESolidPen); |
|
2547 } |
|
2548 |
|
2549 /* |
|
2550 Draw the background in aRect, using the custom background where possible, and filling in with |
|
2551 the default background. |
|
2552 */ |
|
2553 void RTmDrawingInterpreter::DrawBackground(const TRect& aRect,const TLogicalRgb& aBackground) |
|
2554 { |
|
2555 if (aRect.IsEmpty()) |
|
2556 { |
|
2557 return; |
|
2558 } |
|
2559 |
|
2560 // 1 - first draw the background |
|
2561 |
|
2562 TRect drawn; |
|
2563 Source().DrawBackground(iGc,TextLayoutTopLeft(),aRect,aBackground,drawn); |
|
2564 |
|
2565 |
|
2566 // 2 - then draw the highlighted part of the background |
|
2567 |
|
2568 if (iDrawInvertedHighlight) |
|
2569 { |
|
2570 // if we are drawing an inverted selection, then we calculate the union of |
|
2571 // all the highlighted rects. Since we are clipping our drawing with the current Line() |
|
2572 // rect, we can assume that all the rects have the same height and their union is a |
|
2573 // single rectangle. |
|
2574 RTmBoundingRectInterpreter interpreter(iSource, iParam); |
|
2575 TRect rect; |
|
2576 TBool found = GetFirstHighlightClipRect(interpreter, aRect, rect); |
|
2577 while (found) |
|
2578 { |
|
2579 rect.Intersection(LineInfo().iOuterRect); |
|
2580 if (! rect.IsEmpty()) |
|
2581 { |
|
2582 // iHighlightedLineRgn identifies the highlighted area in the current line. |
|
2583 // note that with Right-to-left text the selection on a single line can be |
|
2584 // composed by several disjoined rectangles. |
|
2585 iHighlightedLineRgn.AddRect(rect); // this may fail and set the error flag |
|
2586 iHighlightedLineRgn.Tidy(); // this allows us to compact the region in the smallest |
|
2587 // number of rectangles, making it very unlikely to run out of memory. |
|
2588 |
|
2589 // iHighlightedLineRect keeps the bounding rect of the highlighted area in the current line. |
|
2590 // if highlight extensions are not used, this rect corresponds to the highlighted rect. |
|
2591 if (iHighlightedLineRect.IsEmpty()) |
|
2592 { |
|
2593 iHighlightedLineRect = rect; |
|
2594 } |
|
2595 else |
|
2596 { |
|
2597 iHighlightedLineRect.BoundingRect(rect); |
|
2598 } |
|
2599 } |
|
2600 found = GetNextHighlightClipRect(interpreter, aRect, rect); |
|
2601 } |
|
2602 interpreter.Close(); |
|
2603 } |
|
2604 else |
|
2605 { |
|
2606 // the selection should not be inverted but only drawn with different colors, using TTmHighlightSource. |
|
2607 |
|
2608 RRegion highlightRgn; |
|
2609 |
|
2610 // we are using a region that can grow to contain an arbitrary number of rectangles. |
|
2611 // so we must handle the case in which a rectangle allocation fails in a region operation. |
|
2612 TBool outOfMemory = ! GetHighlightClipRegion(aRect, highlightRgn); |
|
2613 if (outOfMemory) |
|
2614 { |
|
2615 // we ran out of memory allocating rectangles in the region. |
|
2616 // we can still draw the highlighted background area enumerating the rectangles that |
|
2617 // would compose the region and setting them as clipping rects in the graphics context. |
|
2618 RTmBoundingRectInterpreter interpreter(iSource, iParam); |
|
2619 TRect rect; |
|
2620 TBool found = GetFirstHighlightClipRect(interpreter, aRect, rect); |
|
2621 while (found) |
|
2622 { |
|
2623 iGc.SetClippingRect(rect); |
|
2624 TTmHighlightSource highlightSource(Source()); |
|
2625 highlightSource.DrawBackground(iGc, TextLayoutTopLeft(), rect, aBackground, drawn); |
|
2626 iGc.SetClippingRect(iClipRect); |
|
2627 found = GetNextHighlightClipRect(interpreter, aRect, rect); |
|
2628 } |
|
2629 interpreter.Close(); |
|
2630 } |
|
2631 else if (! highlightRgn.IsEmpty()) |
|
2632 { |
|
2633 // here highlightRgn contains the highlighted region. We can use it to clip the graphics context |
|
2634 // and draw only the highlighted background area. This is faster than drawing it rect by rect. |
|
2635 |
|
2636 highlightRgn.ClipRect(iClipRect); // ClipRect() is a safe operation, it never sets the region error flag |
|
2637 |
|
2638 if (! highlightRgn.IsEmpty()) |
|
2639 { |
|
2640 // if the selection should not be inverted but only drawn with different colors, |
|
2641 // then we clip the graphics context region and use a TTmHighlightSource to draw it. |
|
2642 TBool useClippingRgn = highlightRgn.Count() > 1; |
|
2643 if (useClippingRgn) |
|
2644 { |
|
2645 iGc.SetClippingRegion(highlightRgn); |
|
2646 } |
|
2647 else |
|
2648 { |
|
2649 iGc.SetClippingRect(highlightRgn[0]); |
|
2650 } |
|
2651 |
|
2652 TRect clipRect = highlightRgn.BoundingRect(); |
|
2653 clipRect.Intersection(aRect); |
|
2654 |
|
2655 TTmHighlightSource highlightSource(Source()); |
|
2656 highlightSource.DrawBackground(iGc, TextLayoutTopLeft(), clipRect, aBackground, drawn); |
|
2657 |
|
2658 if (useClippingRgn) |
|
2659 { |
|
2660 iGc.CancelClippingRegion(); |
|
2661 } |
|
2662 else |
|
2663 { |
|
2664 iGc.SetClippingRect(iClipRect); |
|
2665 } |
|
2666 } |
|
2667 } |
|
2668 |
|
2669 highlightRgn.Close(); |
|
2670 } |
|
2671 } |
|
2672 |
|
2673 void RTmDrawingInterpreter::Text() |
|
2674 { |
|
2675 // Copy all the text into a single buffer. |
|
2676 int buffer_length = EndChar() - StartChar(); |
|
2677 // If the buffer is overlong, we will truncate. This happens when a huge |
|
2678 // number of spaces terminates a line. |
|
2679 // This causes two bad effects: |
|
2680 // 1) the cursor cannot be seen after the truncation position. |
|
2681 // 2) finding the end of the line just finds the truncation position, not |
|
2682 // the actual end of the line. |
|
2683 // TPB 2/7/2001 - fix for DAS-4XVEJ7 |
|
2684 if (KMaxTextChunkSize < buffer_length) |
|
2685 buffer_length = KMaxTextChunkSize; |
|
2686 TText buffer[KMaxTextChunkSize + 2]; |
|
2687 TTmCharFormat format; |
|
2688 CTmTextFontCache* font = NULL; |
|
2689 TInt err = TextCache().GetDisplayedText(StartChar(), StartChar() + buffer_length, |
|
2690 RightToLeft()? |
|
2691 RTmTextCache::EVisualRightToLeft : RTmTextCache::ELeftToRight, |
|
2692 buffer,ContextCharChar(), &format, &font); |
|
2693 |
|
2694 if (err == KErrNone) |
|
2695 { |
|
2696 // Draw the text |
|
2697 TPtrC text(buffer, buffer_length + 2); |
|
2698 if (*text.Ptr() == 0xFFFF) |
|
2699 DrawText(text,0, text.Length() - 1, format,&font->Font()); |
|
2700 else |
|
2701 DrawText(text,1, text.Length() - 1, format,&font->Font()); |
|
2702 font->Close(); |
|
2703 } |
|
2704 } |
|
2705 |
|
2706 void RTmDrawingInterpreter::InlineText() |
|
2707 { |
|
2708 TPtrC text; |
|
2709 TTmCharFormat format; |
|
2710 CTmTextFontCache* font = NULL; |
|
2711 GetInlineText(text,&format,&font); |
|
2712 if (font != NULL) |
|
2713 { |
|
2714 DrawText(text,0, text.Length() - 1, format,&font->Font()); |
|
2715 font->Close(); |
|
2716 } |
|
2717 } |
|
2718 |
|
2719 void RTmDrawingInterpreter::DrawText(const TDesC& aText,const TInt aStart, const TInt aEnd, const TTmCharFormat& aFormat,CFont* aFont) |
|
2720 { |
|
2721 if (!aFont) |
|
2722 return; |
|
2723 |
|
2724 // Set the graphics context up for drawing the text. |
|
2725 iGc.UseFont(aFont); |
|
2726 iGc.SetPenStyle(CGraphicsContext::ESolidPen); |
|
2727 SetPenColor(aFormat.iTextColor); |
|
2728 if (aFormat.iEffects & TTmCharFormat::EUnderline) |
|
2729 iGc.SetUnderlineStyle(EUnderlineOn); |
|
2730 else |
|
2731 iGc.SetUnderlineStyle(EUnderlineOff); |
|
2732 if (aFormat.iEffects & TTmCharFormat::EStrikethrough) |
|
2733 iGc.SetStrikethroughStyle(EStrikethroughOn); |
|
2734 else |
|
2735 iGc.SetStrikethroughStyle(EStrikethroughOff); |
|
2736 |
|
2737 // Calculate the text bounds. |
|
2738 TRect text_bounds = LineInfo().iInnerRect; |
|
2739 text_bounds.iTl.iX = StartPen().iX; |
|
2740 text_bounds.iBr.iX = EndPen().iX; |
|
2741 |
|
2742 // Set character justification to perform copy fitting. |
|
2743 int extra_pixels = 0; |
|
2744 if (CopyFit() || (aFormat.iEffects & (TTmCharFormat::EUnderline | TTmCharFormat::EStrikethrough))) |
|
2745 { |
|
2746 CFont::TMeasureTextInput input; |
|
2747 input.iFlags = CFont::TMeasureTextInput::EFVisualOrder; |
|
2748 input.iStartInputChar = 1; |
|
2749 extra_pixels = text_bounds.Width() - aFont->MeasureText(aText, &input); |
|
2750 } |
|
2751 |
|
2752 // Draw the text. |
|
2753 |
|
2754 if (iDrawInvertedHighlight || ! IsCurrentOpCompletelyHighlighted() || |
|
2755 (NULL != iHighlightExtensions && iHighlightExtensions->Shrinks())) |
|
2756 { |
|
2757 // If a custom interface to draw the text in context exists, then use it to call the appropriate DrawText method. |
|
2758 MTmCustomExtension* extensionInterface = reinterpret_cast <MTmCustomExtension*> (Source().GetExtendedInterface(KTmCustomExtensionUid)); |
|
2759 if (extensionInterface) |
|
2760 { |
|
2761 extensionInterface->DrawText(iGc,TextLayoutTopLeft(),text_bounds,LineInfo(),aFormat,aText, aStart, aEnd, StartPen(),extra_pixels); |
|
2762 } |
|
2763 else |
|
2764 { |
|
2765 Source().DrawText(iGc,TextLayoutTopLeft(),text_bounds,LineInfo(),aFormat,aText.Mid(aStart,aEnd - aStart + 1),StartPen(),extra_pixels); |
|
2766 } |
|
2767 } |
|
2768 |
|
2769 // Draw the text again if some part of it is highlighted. |
|
2770 |
|
2771 // If we are inverting the highlighted area at the end of Line(), then we should not draw highlighted text. |
|
2772 if (! iDrawInvertedHighlight) |
|
2773 { |
|
2774 RRegion highlightRgn; |
|
2775 |
|
2776 if (! GetHighlightClipRegion(text_bounds, highlightRgn)) |
|
2777 { |
|
2778 // If the error flag is set, there was not enough memory to allocate all the rectangles. |
|
2779 // We must use a slower method: enumerate all the rectangles that compose the highlighted (and |
|
2780 // maybe extended) area of the textview and set each one of these rectangles as clipping rect |
|
2781 // of the graphics context. Then we draw the text. |
|
2782 RTmBoundingRectInterpreter interpreter(iSource, iParam); |
|
2783 TRect rect; |
|
2784 TBool found = GetFirstHighlightClipRect(interpreter, iClipRect, rect); |
|
2785 while (found) |
|
2786 { |
|
2787 iGc.SetClippingRect(rect); |
|
2788 TTmHighlightSource highlightSource(Source()); |
|
2789 highlightSource.DrawText(iGc,TextLayoutTopLeft(),text_bounds,LineInfo(),aFormat,aText,aStart,aEnd,StartPen(),extra_pixels); |
|
2790 iGc.SetClippingRect(iClipRect); |
|
2791 found = GetNextHighlightClipRect(interpreter, iClipRect, rect); |
|
2792 } |
|
2793 interpreter.Close(); |
|
2794 } |
|
2795 else |
|
2796 { |
|
2797 // If the error flag is not set, then there was enough memory to allocate the rectangles in the region. |
|
2798 // We can set a single clipping region in the GC, that should be faster |
|
2799 if (! highlightRgn.IsEmpty()) |
|
2800 { |
|
2801 highlightRgn.ClipRect(iClipRect); // ClipRect() is safe (never sets the region error flag). |
|
2802 |
|
2803 if (! highlightRgn.IsEmpty()) |
|
2804 { |
|
2805 TBool useClippingRgn = highlightRgn.Count() > 1; |
|
2806 if (useClippingRgn) |
|
2807 { |
|
2808 iGc.SetClippingRegion(highlightRgn); |
|
2809 } |
|
2810 else |
|
2811 { |
|
2812 iGc.SetClippingRect(highlightRgn[0]); // much faster |
|
2813 } |
|
2814 |
|
2815 TTmHighlightSource highlightSource(Source()); |
|
2816 highlightSource.DrawText(iGc,TextLayoutTopLeft(),text_bounds,LineInfo(),aFormat,aText,aStart,aEnd,StartPen(),extra_pixels); |
|
2817 |
|
2818 if (useClippingRgn) |
|
2819 { |
|
2820 iGc.CancelClippingRegion(); |
|
2821 } |
|
2822 else |
|
2823 { |
|
2824 iGc.SetClippingRect(iClipRect); |
|
2825 } |
|
2826 } |
|
2827 } |
|
2828 } |
|
2829 |
|
2830 highlightRgn.Close(); |
|
2831 } |
|
2832 |
|
2833 iGc.DiscardFont(); |
|
2834 } |
|
2835 |
|
2836 void RTmDrawingInterpreter::SpecialCharL() |
|
2837 { |
|
2838 TPtrC text; |
|
2839 GetText(StartChar(),EndChar(),text); |
|
2840 if (text[0] == CEditableText::EPictureCharacter) |
|
2841 { |
|
2842 ReleaseFont(); |
|
2843 CPicture* p = Source().PictureL(StartChar()); |
|
2844 if (p) |
|
2845 { |
|
2846 DrawPicture(p); |
|
2847 } |
|
2848 } |
|
2849 } |
|
2850 |
|
2851 void RTmDrawingInterpreter::DrawPicture(CPicture* aPicture) |
|
2852 { |
|
2853 TSize size; |
|
2854 aPicture->GetSizeInPixels(&Device(),size); |
|
2855 |
|
2856 TPoint top_left = StartPen(); |
|
2857 top_left.iY -= size.iHeight - Subscript(); |
|
2858 TRect clip(top_left,size); |
|
2859 clip.Intersection(iClipRect); |
|
2860 |
|
2861 TInt highlightStartPos = 0; |
|
2862 TInt highlightEndPos = 0; |
|
2863 if (! iDrawInvertedHighlight && |
|
2864 GetHighlightPos(highlightStartPos, highlightEndPos)) |
|
2865 { |
|
2866 // if the highlighted interval [iHighlightStartPos, iHighlightEndPos] overlaps |
|
2867 // the current object [StartDocPos(), EndDocPos()], then the whole picture is selected. |
|
2868 TTmHighlightSource highlightSource(Source()); |
|
2869 highlightSource.DrawPicture(iGc, top_left, clip, Device(), *aPicture); |
|
2870 } |
|
2871 else |
|
2872 { |
|
2873 Source().DrawPicture(iGc, top_left, clip, Device(), *aPicture); |
|
2874 } |
|
2875 |
|
2876 iGc.Reset(); |
|
2877 InitGraphicsContext(); |
|
2878 } |
|
2879 |
|
2880 void RTmDrawingInterpreter::Rule() |
|
2881 { |
|
2882 SetBrushColor(RuleColour()); |
|
2883 TmTextDrawExt().DrawRect(iGc, Bounds()); |
|
2884 } |
|
2885 |
|
2886 void RTmDrawingInterpreter::Label() |
|
2887 { |
|
2888 ReleaseFont(); |
|
2889 |
|
2890 /* |
|
2891 The label rectangle is a hybrid; the source interface provides x coords but the y coords come from the bytecode. |
|
2892 This is so that the gutter between label and text can be adjusted at the time of drawing. |
|
2893 */ |
|
2894 MFormLabelApi* labelApi = (MFormLabelApi*)Source().GetExtendedInterface(KFormLabelApiExtensionUid); |
|
2895 if ((labelApi != NULL) && (labelApi->LabelModeSelect(LabelType(), StartChar()))) |
|
2896 { |
|
2897 TRect label_rect = Bounds(); |
|
2898 label_rect.Move(LineInfo().iOuterRect.iTl); |
|
2899 label_rect.iTl.iX = iLabelLeft; |
|
2900 label_rect.iBr.iX = iLabelRight; |
|
2901 |
|
2902 TTmInterpreterParam param(ByteCode()); |
|
2903 param.iCodeStart = CodePos(); |
|
2904 param.iCodeEnd = EndCodePos(); |
|
2905 param.iTextStart = 0; |
|
2906 param.iWidth = Bounds().Width(); |
|
2907 TRect label_clip_rect = label_rect; |
|
2908 label_clip_rect.Intersection(iClipRect); |
|
2909 RTmDrawingInterpreter interpreter(Source(), iGc,param, label_rect.iTl, |
|
2910 label_clip_rect, iDocBackground, iFlags | EIsLabel, NULL, NULL); |
|
2911 interpreter.Draw(); |
|
2912 interpreter.Close(); |
|
2913 iGc.Reset(); |
|
2914 InitGraphicsContext(); |
|
2915 labelApi->LabelModeCancel(); |
|
2916 } |
|
2917 Skip(); |
|
2918 } |
|
2919 |
|
2920 |
|
2921 void RTmDrawingInterpreter::InvertHighlightedLineRgn() |
|
2922 { |
|
2923 if (! iHighlightedLineRect.IsEmpty()) |
|
2924 { |
|
2925 TBool useClippingRgn = (! iHighlightedLineRgn.IsEmpty() && ! iHighlightedLineRgn.CheckError()); |
|
2926 if (useClippingRgn) |
|
2927 { |
|
2928 if (1 == iHighlightedLineRgn.Count()) |
|
2929 { |
|
2930 iHighlightedLineRect = iHighlightedLineRgn[0]; |
|
2931 useClippingRgn = EFalse; |
|
2932 } |
|
2933 } |
|
2934 |
|
2935 if (useClippingRgn) |
|
2936 { |
|
2937 iGc.SetClippingRegion(iHighlightedLineRgn); |
|
2938 } |
|
2939 else |
|
2940 { |
|
2941 iGc.SetClippingRect(iHighlightedLineRect); |
|
2942 } |
|
2943 |
|
2944 iGc.SetBrushStyle(CGraphicsContext::ESolidBrush); |
|
2945 iGc.SetBrushColor(iHighlightXorColor); |
|
2946 iGc.SetPenStyle(CGraphicsContext::ENullPen); |
|
2947 iGc.SetDrawMode(CGraphicsContext::EDrawModeXOR); |
|
2948 |
|
2949 TTmTextDrawExt tmTextDrawExtDefault; //The default implementation of MTmTextDrawExt |
|
2950 const MTmTextDrawExt* tmTextDrawExt = reinterpret_cast <const MTmTextDrawExt*>( |
|
2951 (MTmSource*)(iSource.GetExtendedInterface(KTmTextDrawExtId))); |
|
2952 if (NULL == tmTextDrawExt) { |
|
2953 |
|
2954 tmTextDrawExt = &tmTextDrawExtDefault; |
|
2955 } |
|
2956 tmTextDrawExt->DrawRect(iGc, iHighlightedLineRect); |
|
2957 |
|
2958 iGc.SetDrawMode(CGraphicsContext::EDrawModePEN); |
|
2959 iGc.SetPenStyle(CGraphicsContext::ESolidPen); |
|
2960 |
|
2961 if (useClippingRgn) |
|
2962 { |
|
2963 iGc.CancelClippingRegion(); |
|
2964 } |
|
2965 else |
|
2966 { |
|
2967 iGc.SetClippingRect(iClipRect); |
|
2968 } |
|
2969 |
|
2970 iHighlightedLineRect = TRect(TRect::EUninitialized); |
|
2971 iHighlightedLineRgn.Clear(); |
|
2972 } |
|
2973 } |
|
2974 |
|
2975 |
|
2976 RTmBoundingRectInterpreter::RTmBoundingRectInterpreter(MTmSource& aSource,const TTmInterpreterParam& aParam): |
|
2977 RTmGeneralInterpreter(aSource,aParam), |
|
2978 iStartDocPos(-1,FALSE), |
|
2979 iEndDocPos(-1,FALSE), |
|
2980 iRangeState(EBeforeAllLines) |
|
2981 { |
|
2982 } |
|
2983 |
|
2984 TBool RTmBoundingRectInterpreter::FirstRect(TInt aStartDocPos,TInt aEndDocPos,TRect& aRect) |
|
2985 { |
|
2986 iStartDocPos = TTmDocPos(aStartDocPos,TRUE); |
|
2987 iEndDocPos = TTmDocPos(aEndDocPos,FALSE); |
|
2988 TInt dummy = StartDocPos().iPos; |
|
2989 if (aStartDocPos < StartDocPos().iPos && aEndDocPos > StartDocPos().iPos) |
|
2990 {//Highlight starts before formatted band but ends inside it |
|
2991 //Do nothing (do not attempt to run DocPosToLine) |
|
2992 } |
|
2993 else if (!DocPosToLine(TTmDocPosSpec(iStartDocPos))) |
|
2994 { |
|
2995 return FALSE; |
|
2996 } |
|
2997 if (iStartDocPos == iEndDocPos || PosIsInLine(iEndDocPos)) |
|
2998 { |
|
2999 iRangeState = EInLastLine; |
|
3000 } |
|
3001 else |
|
3002 iRangeState = EInFirstLine; |
|
3003 return NextRect(aRect); |
|
3004 } |
|
3005 |
|
3006 TBool RTmBoundingRectInterpreter::NextRect(TRect& aRect) |
|
3007 { |
|
3008 if (iRangeState == EAfterAllLines || !Next()) |
|
3009 { |
|
3010 aRect.SetRect(0,0,0,0); |
|
3011 return FALSE; |
|
3012 } |
|
3013 iRect.SetRect(0,0,0,0); |
|
3014 switch (Op()) |
|
3015 { |
|
3016 case EOpLine: |
|
3017 Line(); |
|
3018 break; |
|
3019 case EOpText: |
|
3020 Text(); |
|
3021 break; |
|
3022 case EOpSpecialChar: |
|
3023 SpecialCharacter(); |
|
3024 break; |
|
3025 default: |
|
3026 Skip(); |
|
3027 break; |
|
3028 } |
|
3029 aRect = iRect; |
|
3030 return TRUE; |
|
3031 } |
|
3032 |
|
3033 void RTmBoundingRectInterpreter::Line() |
|
3034 { |
|
3035 if (iRangeState == EInFirstLine) |
|
3036 { |
|
3037 if (PosIsInLine(iEndDocPos)) |
|
3038 iRangeState = EInLastLine; |
|
3039 else |
|
3040 iRangeState = EInMedialLine; |
|
3041 } |
|
3042 else if (iRangeState == EInMedialLine) |
|
3043 { |
|
3044 if (PosIsInLine(iEndDocPos)) |
|
3045 iRangeState = EInLastLine; |
|
3046 } |
|
3047 else if (iRangeState == EInLastLine) |
|
3048 iRangeState = EAfterAllLines; |
|
3049 if (iRangeState == EInMedialLine) |
|
3050 { |
|
3051 iRect = LineInfo().iOuterRect; |
|
3052 iRect.iTl.iX = LineInfo().iInnerRect.iTl.iX; |
|
3053 iRect.iBr.iX = LineInfo().iInnerRect.iBr.iX; |
|
3054 Skip(); |
|
3055 } |
|
3056 } |
|
3057 |
|
3058 void RTmBoundingRectInterpreter::Text() |
|
3059 { |
|
3060 if (DontMeasure()) |
|
3061 return; |
|
3062 |
|
3063 TTmDocPos startPos = StartDocPos(); |
|
3064 TTmDocPos endPos = EndDocPos(); |
|
3065 |
|
3066 // Return with an empty rectangle if the range doesn't overlap this section |
|
3067 // of text. |
|
3068 if (iEndDocPos <= startPos || endPos <= iStartDocPos) |
|
3069 return; |
|
3070 |
|
3071 iRect = LineInfo().iOuterRect; |
|
3072 iRect.iTl.iX = StartPen().iX; |
|
3073 iRect.iBr.iX = EndPen().iX; |
|
3074 |
|
3075 // Work out if we need to find the start and end within this text chunk |
|
3076 TBool startRequired = startPos.iPos < iStartDocPos.iPos? ETrue : EFalse; |
|
3077 TBool endRequired = iEndDocPos.iPos < endPos.iPos? ETrue : EFalse; |
|
3078 |
|
3079 // Return with a full rectangle if the range totally covers this section of |
|
3080 // text. |
|
3081 if (!startRequired && !endRequired) |
|
3082 return; |
|
3083 |
|
3084 // Sort the end points left to right. |
|
3085 TBool leftRequired = startRequired; |
|
3086 TBool rightRequired = endRequired; |
|
3087 TTmDocPos leftPos = iStartDocPos; |
|
3088 TTmDocPos rightPos = iEndDocPos; |
|
3089 if (RightToLeft()) |
|
3090 { |
|
3091 leftRequired = endRequired; |
|
3092 rightRequired = startRequired; |
|
3093 leftPos = iEndDocPos; |
|
3094 rightPos = iStartDocPos; |
|
3095 } |
|
3096 |
|
3097 // Truncate the rectangle as required. |
|
3098 RTmGraphemeInTextChunkIteratorNice edgeIterator(*this); |
|
3099 if (leftRequired) |
|
3100 { |
|
3101 edgeIterator.FindEdge(leftPos); |
|
3102 iRect.iTl.iX = edgeIterator.Get()->iPos.iEdge.iX; |
|
3103 } |
|
3104 if (rightRequired) |
|
3105 { |
|
3106 edgeIterator.FindEdge(rightPos); |
|
3107 iRect.iBr.iX = edgeIterator.Get()->iPos.iEdge.iX; |
|
3108 } |
|
3109 edgeIterator.Close(); |
|
3110 } |
|
3111 |
|
3112 void RTmBoundingRectInterpreter::SpecialCharacter() |
|
3113 { |
|
3114 // Return with an empty rectangle if the range doesn't overlap this section |
|
3115 // of text. |
|
3116 if (iEndDocPos.iPos <= StartChar() || EndChar() <= iStartDocPos.iPos) |
|
3117 return; |
|
3118 |
|
3119 // Otherwise return the full rectangle: special characters are indivisible. |
|
3120 iRect = LineInfo().iOuterRect; |
|
3121 iRect.iTl.iX = StartPen().iX; |
|
3122 iRect.iBr.iX = EndPen().iX; |
|
3123 } |
|
3124 |
|
3125 TTmByteCodeFinder::TTmByteCodeFinder(const TTmInterpreterParam& aParam,TInt aStartDocPos,TInt aEndDocPos): |
|
3126 TTmInterpreter(aParam), |
|
3127 iStartDocPos(aStartDocPos), |
|
3128 iEndDocPos(aEndDocPos) |
|
3129 { |
|
3130 } |
|
3131 |
|
3132 /* |
|
3133 Find the bytecode for the range iStartDocPos...iEndDocPos. |
|
3134 |
|
3135 If aToParStart is ETrue the bytecode is extended to the start of the paragraph, |
|
3136 otherwise to one line before the one containing iStartDocPos. |
|
3137 |
|
3138 If aToParEnd is ETrue the bytecode is extended to the end of the paragraph, |
|
3139 otherwise to one line after the one containing iEndDocPos. However, aToParEnd |
|
3140 is constrained by aMaxExtraLines, which is the maximum number of lines |
|
3141 allowed after the line containing iEndDocPos. |
|
3142 |
|
3143 The bidirectional contexts at the start and end are placed in iStartBdState and |
|
3144 iEndBdState if both pointers are non-null. |
|
3145 */ |
|
3146 TBool TTmByteCodeFinder::FindByteCode(TBool aToParStart,TBool aToParEnd,TInt aMaxExtraLines,TInfo& aInfo, |
|
3147 TBidirectionalContext* aStartBdState,TBidirectionalContext* aEndBdState) |
|
3148 { |
|
3149 __ASSERT_DEBUG((aStartBdState && aEndBdState) |
|
3150 || (!aStartBdState && !aEndBdState), TmPanic(EBadArg)); |
|
3151 if (aStartBdState) |
|
3152 { |
|
3153 aStartBdState->Reset(); |
|
3154 aEndBdState->Reset(); |
|
3155 } |
|
3156 |
|
3157 // Use aEndBdState to hold the bidirectional state temporarily, so that the following line doesn't overwrite it. |
|
3158 SetBdStatePtr(aEndBdState); |
|
3159 // We are looking for the context of the previous line in the byte code, to pass it on to the next line. |
|
3160 TUint contextChar = 0; |
|
3161 TUint prevContextChar = 0; |
|
3162 // Find iStartDocPos. |
|
3163 TBool foundStart = EFalse; |
|
3164 TBool get_info = EFalse; |
|
3165 while (Next()) |
|
3166 { |
|
3167 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
3168 contextChar = LineContextCharChar(); |
|
3169 foundStart = iStartDocPos >= StartChar() && iStartDocPos < EndChar(); |
|
3170 get_info = LineInfo().iLineNumber == 0 || ParStart(); |
|
3171 if (!aToParStart) |
|
3172 get_info = get_info || !foundStart; |
|
3173 if (get_info) |
|
3174 { |
|
3175 aInfo.iBounds.iTl = LineInfo().iOuterRect.iTl; |
|
3176 aInfo.iStartCodePos = StartCodePos(); |
|
3177 aInfo.iStartInfo = LineInfo(); |
|
3178 aInfo.iContextCharPerLine = prevContextChar; |
|
3179 if (aStartBdState && aEndBdState) |
|
3180 *aStartBdState = *aEndBdState; |
|
3181 } |
|
3182 if (foundStart) |
|
3183 break; |
|
3184 |
|
3185 Skip(); |
|
3186 prevContextChar = contextChar; |
|
3187 } |
|
3188 if (!foundStart) |
|
3189 return EFalse; |
|
3190 |
|
3191 // Find iEndDocPos. |
|
3192 SetBdStatePtr(aEndBdState); |
|
3193 if (aEndBdState) |
|
3194 aEndBdState->Reset(); |
|
3195 TBool foundEnd = EFalse; |
|
3196 TInt extra_lines = 0; |
|
3197 do |
|
3198 { |
|
3199 // Operators must all be EOpLine because we're skipping from line to line |
|
3200 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
3201 aInfo.iBounds.iBr = LineInfo().iOuterRect.iBr; |
|
3202 aInfo.iEndCodePos = EndCodePos(); |
|
3203 aInfo.iEndInfo = LineInfo(); |
|
3204 if (foundEnd) |
|
3205 { |
|
3206 extra_lines++; |
|
3207 SetBdStatePtr(NULL); |
|
3208 if (!aToParEnd || extra_lines >= aMaxExtraLines) |
|
3209 break; |
|
3210 } |
|
3211 if (!foundEnd) |
|
3212 foundEnd = iEndDocPos >= StartChar() && iEndDocPos < EndChar(); |
|
3213 if (foundEnd && ParEnd()) |
|
3214 break; |
|
3215 Skip(); |
|
3216 } while (Next()); |
|
3217 |
|
3218 return foundEnd; |
|
3219 } |
|
3220 |
|
3221 /* |
|
3222 Find the bytecode at the end of the formatted range. |
|
3223 The section returned must not be bigger than aMaxHeight: if aMaxHeight is sufficiently |
|
3224 small that we cannot retrieve any whole lines without going over, return EFalse. |
|
3225 |
|
3226 Otherwise place information about the section of bytecode in aInfo. |
|
3227 |
|
3228 The bidirectional contexts at the start and end are placed in iStartBdState and |
|
3229 iEndBdState if both pointers are non-null. |
|
3230 */ |
|
3231 TBool TTmByteCodeFinder::FindByteCodeAtEnd(TInfo& aInfo, TInt aMaxHeight, TInt aTotalHeight, |
|
3232 TBidirectionalContext* aStartBdState,TBidirectionalContext* aEndBdState) |
|
3233 { |
|
3234 TInt heightToSkip = aTotalHeight - aMaxHeight; |
|
3235 TInt cumulativeHeight = 0; |
|
3236 |
|
3237 __ASSERT_DEBUG((aStartBdState && aEndBdState) || (!aStartBdState && !aEndBdState), TmPanic(EBadArg)); |
|
3238 if (aStartBdState) |
|
3239 { |
|
3240 aStartBdState->Reset(); |
|
3241 aEndBdState->Reset(); |
|
3242 } |
|
3243 |
|
3244 // Use aEndBdState to hold the bidirectional state temporarily, so that the following line doesn't overwrite it. |
|
3245 SetBdStatePtr(aEndBdState); |
|
3246 // Find iStartDocPos. |
|
3247 TBool foundStart = EFalse; |
|
3248 while (Next()) |
|
3249 { |
|
3250 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
3251 if (cumulativeHeight > heightToSkip) |
|
3252 { |
|
3253 foundStart = ETrue; |
|
3254 aInfo.iBounds.iTl = LineInfo().iOuterRect.iTl; |
|
3255 aInfo.iStartCodePos = StartCodePos(); |
|
3256 aInfo.iStartInfo = LineInfo(); |
|
3257 if (aStartBdState && aEndBdState) |
|
3258 { |
|
3259 *aStartBdState = *aEndBdState; |
|
3260 } |
|
3261 Skip(); |
|
3262 break; |
|
3263 } |
|
3264 cumulativeHeight += LineInfo().iOuterRect.Height(); |
|
3265 Skip(); |
|
3266 } |
|
3267 |
|
3268 TBool foundEnd = EFalse; |
|
3269 while (Next()) |
|
3270 { |
|
3271 __ASSERT_ALWAYS(Op() == EOpLine, Panic(ECorrupt)); |
|
3272 foundEnd = ETrue; |
|
3273 aInfo.iBounds.iBr = LineInfo().iOuterRect.iBr; |
|
3274 aInfo.iEndCodePos = EndCodePos(); |
|
3275 aInfo.iEndInfo = LineInfo(); |
|
3276 Skip(); |
|
3277 } |
|
3278 |
|
3279 SetBdStatePtr(NULL); |
|
3280 return foundStart && foundEnd; |
|
3281 } |
|
3282 |