textrendering/textformatting/tagma/TMINTERP.CPP
changeset 0 1fb32624e06b
child 5 e96e8a131979
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     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