textrendering/textformatting/tagma/TMLAYOUT.CPP
changeset 32 8b9155204a54
parent 0 1fb32624e06b
child 40 91ef7621b7fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/tagma/TMLAYOUT.CPP	Fri Jun 04 10:37:54 2010 +0100
@@ -0,0 +1,1759 @@
+/*
+* Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* The CTmTextLayout class: TAGMA's simplest text class. It holds the layout of rectangular piece of text.
+*
+*/
+
+
+#include "TmLayoutImp.h"
+#include "TmHighlightSource.h"
+#include "TMINTERP.H"
+#include "TmChunkInterp.h"
+#include <txtfrmat.h>
+#include "TmTextDrawExt.h"
+#include <frmtlay.h>
+#include "tmreformat.h"
+#include "frmUtils.h"
+
+#define UNUSED_VAR(a) a = a
+
+/**
+Construct a TTmFormatParamBase object. Set iWrapWidth, iMaxHeight and iMaxLines to 'infinity' (KMaxTInt),
+iFlags to 0 (wrapping off, no truncation with ellipsis, etc.), and iEllipsis to the ordinary ellipsis character, U+2026.
+*/
+EXPORT_C TTmFormatParamBase::TTmFormatParamBase():
+	iWrapWidth(KMaxTInt),
+	iMaxHeight(KMaxTInt),
+	iMaxLines(KMaxTInt),
+	iFlags(0),
+	iEllipsis(0x2026)
+	{
+	}
+
+/**
+Construct a TTmFormatParam object, setting iStartChar to 0, iEndChar to 'infinity' (KMaxTInt) and iLineInPar to 0.
+*/
+EXPORT_C TTmFormatParam::TTmFormatParam():
+	iStartChar(0),
+	iEndChar(KMaxTInt),
+	iLineInPar(0)
+	{
+	}
+
+/**
+Construct a TTmFormatParam object with its base class part (TTmFormatParamBase) set to aBase, and setting iStartChar to 0,
+iEndChar to 'infinity' (KMaxTInt) and iLineInPar to 0.
+*/
+EXPORT_C TTmFormatParam::TTmFormatParam(const TTmFormatParamBase& aBase):
+	TTmFormatParamBase(aBase),
+	iStartChar(0),
+	iEndChar(KMaxTInt),
+	iLineInPar(0)
+	{
+	}
+
+/**
+Construct a TTmReformatParam object, setting everything to 0 or FALSE apart from iMaxExtraLines, which is
+set to 'infinity' (KMaxTInt).
+*/
+EXPORT_C TTmReformatParam::TTmReformatParam():
+	iStartChar(0), 
+	iOldLength(0),
+	iNewLength(0),
+	iMaxExtraLines(KMaxTInt),
+	iParFormatChanged(FALSE),
+	iParInvalid(FALSE)
+	{
+	}
+
+/**
+Construct a TTmReformatResult object, setting iHeightChange to 0 and iUnchangedTop and iUnformattedStart to
+'infinity' (KMaxTInt).
+*/
+EXPORT_C TTmReformatResult::TTmReformatResult():
+	iHeightChange(0),
+	iUnchangedTop(KMaxTInt),
+	iUnformattedStart(KMaxTInt)
+	{
+	}
+
+/**
+Construct an empty object with no text and zero width and height.
+It is legal to call all CTmTextLayout functions on an empty object,
+with the exception of AddParL and FormatL, which panic with ENoSource.
+*/
+EXPORT_C CTmTextLayout::CTmTextLayout() :
+	iCurrentContextChar(NULL)
+	{
+	// do nothing
+	}
+
+/**
+The destructor.
+*/
+EXPORT_C CTmTextLayout::~CTmTextLayout()
+	{
+	delete iBdStateAtEnd;
+	}
+
+/**
+Set the text, discarding any existing layout information. The text from aParam.iStartChar to aParam.iEndChar is
+extracted from aSource and formatted.
+*/
+EXPORT_C void CTmTextLayout::SetTextL(MTmSource& aSource,const TTmFormatParam& aParam)
+	{
+	if (aParam.iMaxHeight <= 0 ||
+		aParam.iStartChar < 0 || aParam.iEndChar < aParam.iStartChar ||
+		aParam.iLineInPar < 0)
+		TmPanic(EBadArg);
+		
+	if (iBdStateAtEnd)
+		{
+		iBdStateAtEnd->Reset();
+		}
+	else
+		{
+		iBdStateAtEnd = new(ELeave) TBidirectionalContext;
+		}
+
+		
+	iSource = &aSource;
+	iCode.Reset();
+	iStartChar = aParam.iStartChar;
+	CTmFormatContext::TInfo info;
+	if (aParam.iFlags & TTmFormatParamBase::EWrap
+		&& (aParam.iWrapWidth < 1 || aParam.iMaxHeight < 1))
+		{
+		// Illegal parameters, so we should not waste time formatting.
+		// We will assume that good parameters will be along later.
+		iHeight = 0;
+		iEndChar = iStartChar;
+		iWidth = 0;
+		}
+	else
+		{
+		//Get line context character from previous line if there is
+		TTmDocPosSpec startDocPos(aParam.iStartChar - 1, static_cast<TTmDocPosSpec::TType>(1));
+		TTmInterpreter interpreter(TTmInterpreterParam(*this));
+		TBool lineFound = interpreter.DocPosToLine(startDocPos);
+		if (lineFound)
+			info.iContextCharPerLine = interpreter.LineContextCharChar();
+		else
+			info.iContextCharPerLine = NULL;
+		
+		CTmFormatContext::FormatL(aSource,aParam,iCode,info,this,NULL,iBdStateAtEnd, NULL);
+		iHeight = info.iHeight;
+		iEndChar = info.iEndChar;
+		iWidth = 0;
+		AdjustWidth(aParam,info.iWidth);
+		}
+	}
+
+/**
+Format part of the text that has changed and indicate whether further formatting needs to be done.
+
+The backing text must remain constant during background formatting. What this means is that
+if background formatting is enabled (TTmReformatParam::iMaxExtraLines is some small number, causing
+formatting to end mid-way with TTmReformatResult::iUnformattedStart less than KMaxTInt), so that text
+can be formatted bit by bit by a higher-level object, as is done by CTextView, the backing text must not
+change between the series of calls to this function that make up a single reformatting act.
+*/
+EXPORT_C void CTmTextLayout::FormatL(const TTmFormatParamBase& aParam,const TTmReformatParam& aReformatParam,
+									 TTmReformatResult& aResult)
+	{
+	if (!iSource)
+		TmPanic(ENoSource);
+
+	CTmReformat* reformat = CTmReformat::NewLC(*this, aParam, aReformatParam);
+	reformat->ReformatL();
+	CTmCode* new_code = &(reformat->NewCode());
+	TTmByteCodeFinder::TInfo oldCodeInfo = reformat->ReformatRange();
+	CTmFormatContext::TInfo newCodeInfo = reformat->FormatInfo();
+	TBool bd_changed = reformat->BidirectionalStateChanged();
+	/*
+	Find the lines that have changed and need to be redisplayed.
+	If aParagraphFormatChanged is true at least one paragraph format has changed,
+	so the redraw rectangle includes the whole of the paragraphs affected.
+
+	Also redraw the whole paragraph if background formatting is needed, or if the bidirectional state has changed.
+	*/
+	if (aReformatParam.iParFormatChanged || aResult.iUnformattedStart < KMaxTInt || bd_changed)
+		{
+		aResult.iRedrawRect = oldCodeInfo.iBounds;
+		aResult.iRedrawRect.iBr.iY = aResult.iRedrawRect.iTl.iY + newCodeInfo.iHeight;
+		}
+	else
+		{
+		TTmInterpreterParam p(*this);
+		p.iCodeStart = oldCodeInfo.iStartCodePos;
+		p.iCodeEnd = oldCodeInfo.iEndCodePos;
+		p.iTextStart = oldCodeInfo.iStartInfo.iStart;
+		TTmInterpreter old_code_interpreter(p);
+		p.iByteCode = new_code;
+		p.iCodeStart = 0;
+		p.iCodeEnd = new_code->Size();
+		TTmInterpreter new_code_interpreter(p);
+		old_code_interpreter.CalculateRedrawRect(new_code_interpreter,aReformatParam.iStartChar,
+												 aReformatParam.iOldLength,aReformatParam.iNewLength,aResult.iRedrawRect);
+		aResult.iRedrawRect.Move(0,oldCodeInfo.iBounds.iTl.iY);
+		}
+
+	// Delete the old bytecode and insert the new.
+	iCode.ChangeL(oldCodeInfo.iStartCodePos,oldCodeInfo.iEndCodePos,*new_code);
+
+	// Adjust the band's bounds.
+	iHeight += newCodeInfo.iHeight - oldCodeInfo.iBounds.Height();
+	
+	//if the range we are replacing includes the end of the current formatted range,
+	//then the end BD state pointer may be invalidated, so we need to update it
+	if(oldCodeInfo.iEndInfo.iEnd == iEndChar)
+		{
+		*iBdStateAtEnd = reformat->BidirectionalStateAtEnd();
+		}
+	// Adjust the band's width if necessary.
+	AdjustWidth(aParam,newCodeInfo.iWidth);
+
+	// Adjust the band's length.
+	TInt lengthOfOldRange = oldCodeInfo.iEndInfo.iEnd - oldCodeInfo.iStartInfo.iStart;
+	TInt lengthOfNewRange = newCodeInfo.iEndChar - oldCodeInfo.iStartInfo.iStart;
+	iEndChar += lengthOfNewRange - lengthOfOldRange;
+	// Determine the change in height of the reformatted text.
+	aResult.iHeightChange = newCodeInfo.iHeight - oldCodeInfo.iBounds.Height();
+
+	/*
+	Set the top of the unchanged text, and if not all text has been formatted
+	remove the first unformatted line from the redraw rect.
+	*/
+	if (aResult.iUnformattedStart < KMaxTInt)
+		{
+		TTmLineInfo info;
+		TTmDocPosSpec pos(aResult.iUnformattedStart,TTmDocPosSpec::ETrailing);
+		DocPosToLine(pos,info);
+		aResult.iRedrawRect.iBr.iY = info.iOuterRect.iTl.iY;
+		ParNumberToLine(info.iParNumber,KMaxTInt,info);
+		aResult.iUnchangedTop = info.iOuterRect.iBr.iY - aResult.iHeightChange;
+		}
+	else
+		aResult.iUnchangedTop = aResult.iRedrawRect.iBr.iY - aResult.iHeightChange;
+
+	CleanupStack::PopAndDestroy(reformat);
+	
+	Invariant();
+	}
+
+/**
+Format a new paragraph immediately before or after the band and add it to the formatted text.
+If the text starts or ends in the middle of the paragraph, complete the paragraph.
+Return TRUE if text was successfully added, or FALSE if there is no more text to add, or
+the new text would have exceeded the maximum height allowed. Place the height of the new text in aHeightIncrease.
+Place the increase in the number of complete paragraphs (0 or 1) in aParagraphsIncrease.
+
+Note that this function will not necessarily add a whole paragraph to the band: if the client has restricted
+the amount of formatting to add by setting the relevant values in aParam, then these restrictions will
+be respected with the result that less than a paragraph of formatting may be generated.
+
+This is the case, for example, when CTextLayout adds text below the band. 
+*/
+EXPORT_C TBool CTmTextLayout::AddParL(const TTmFormatParamBase& aParam,TBool aAtStart,TInt& aHeightIncrease,
+									  TInt& aParagraphsIncrease)
+	{	
+	if (!iSource)
+		TmPanic(ENoSource);
+
+	aHeightIncrease = 0;
+	aParagraphsIncrease = 0;
+	int start_char = 0;
+	int end_char = 0;
+	int deleted_height = 0;
+	TTmFormatParam format_param(aParam);
+
+	TBidirectionalContext* pStartBd = NULL;
+	TBidirectionalContext* pEndBd = NULL;
+	TBidirectionalEndOfLineContext* pEOLContext = NULL;		
+	
+	if (aAtStart)
+		{
+		if (iStartChar == 0)
+			return FALSE;
+		start_char = iSource->ParagraphStart(iStartChar - 1);
+		end_char = iSource->ParagraphEnd(iStartChar - 1);
+		if (end_char > iStartChar)
+			{
+			if (end_char > iEndChar)
+				end_char = iEndChar;
+			DeletePar(aParam,TRUE,KMaxTInt,deleted_height);
+			}
+		else
+			aParagraphsIncrease = 1;
+		}
+	else
+		{
+		if (iEndChar > iSource->DocumentLength())
+			return FALSE;
+		start_char = iEndChar;
+		end_char = iSource->ParagraphEnd(iEndChar);
+		
+		pStartBd = iBdStateAtEnd;
+		pEndBd = iBdStateAtEnd;
+			
+		TInt lastLineNumber = Lines()-1;
+		if(lastLineNumber >= 0)
+			{
+			TTmLineInfo lastLine;
+			TBool found = LineNumberToLine(lastLineNumber, lastLine);
+			ASSERT(found);
+			if(!(lastLine.iFlags & TTmLineInfo::EParEnd))
+				{
+				format_param.iLineInPar = lastLine.iLineInPar+1;
+				}
+			}				
+						
+		aParagraphsIncrease = 1; 
+		}
+
+	CTmCode* new_code = new(ELeave) CTmCode;
+	CleanupStack::PushL(new_code);
+	format_param.iStartChar = start_char;
+	format_param.iEndChar = end_char;
+	int code_pos = aAtStart ? 0 : iCode.Size();
+	CTmFormatContext::TInfo info;
+	
+	//Get line context character from previous line if there is
+	TTmDocPosSpec startDocPos(format_param.iStartChar - 1, static_cast<TTmDocPosSpec::TType>(1));
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool lineFound = interpreter.DocPosToLine(startDocPos);
+	if (lineFound)
+		info.iContextCharPerLine = interpreter.LineContextCharChar();
+	else
+		info.iContextCharPerLine = NULL;
+	
+	CTmFormatContext::FormatL(*iSource,format_param,*new_code,info,this,
+		pStartBd, pEndBd, pEOLContext);
+
+	// Insert the new code if any.
+	aHeightIncrease = info.iHeight;
+	if (aHeightIncrease > 0)
+		{
+		iCode.ChangeL(code_pos,code_pos,*new_code);
+
+		iHeight += aHeightIncrease;
+		if (aAtStart)
+			iStartChar = start_char;
+		else
+			iEndChar = info.iEndChar;
+
+		// Adjust the band's width if necessary.
+		AdjustWidth(aParam,info.iWidth);
+		}
+	//if we did actually format to the paragraph end, reset the bd state
+	if(!aAtStart)
+		{
+		if(iEndChar == format_param.iEndChar)
+			{
+			iBdStateAtEnd->Reset();
+			}
+		}
+	CleanupStack::PopAndDestroy();	// new code
+	aHeightIncrease -= deleted_height;
+	
+	Invariant();
+	
+	return aHeightIncrease > 0;
+	}
+	
+TBool CTmTextLayout::LastLine(TTmLineInfo& aLine)
+	{
+	TInt lastLineNumber = Lines()-1;
+	if(lastLineNumber >= 0)
+		{
+		TTmLineInfo lastLine;
+		TBool found = LineNumberToLine(lastLineNumber, aLine);
+		ASSERT(found);
+		return ETrue;
+		}
+	return EFalse;	
+	}
+
+void CTmTextLayout::SetCurrentContextChar(TUint aContextChar)
+	{
+	iCurrentContextChar = aContextChar;
+	}
+	
+TUint CTmTextLayout::GetCurrentContextChar() const
+	{
+	return iCurrentContextChar;
+	}
+/**
+Extend the formatted range downwards. That is, starting at the end of the current 
+formatted range, generate some new formatting and append it to the end of the range.
+@param aParam 
+This controls how much new formatting to generate. We will generate formatting up whichever comes first of:
+- the character position specified in TTmFormatParam::iEndChar
+- the height specified (in pixels) in TTmFormatParamBase::iMaxHeight
+- the number of lines specified in TTmFormatParamBase::iMaxLines
+We replace the values specified in TTmFormatParam::iStartChar and TmFormatParam::iLineInPar
+@pre The object must have been initialised with an MTmSource, or it will panic.
+*/
+EXPORT_C void CTmTextLayout::ExtendFormattingDownwardsL(TTmFormatParam& aParam)
+	{
+	if (!iSource)
+		TmPanic(ENoSource);
+
+	aParam.iStartChar = iEndChar;
+
+	if (iEndChar > iSource->DocumentLength())
+		return;
+	if (aParam.iStartChar > aParam.iEndChar)
+		return;
+		
+	TBidirectionalContext* pStartBd = iBdStateAtEnd;
+	TBidirectionalContext* pEndBd = iBdStateAtEnd;
+	TBidirectionalEndOfLineContext* pEOLContext = NULL;		
+
+	//if there is a last line (i.e. if there is any formatting at all)
+	//and the last line is not a paragraph boundary, 
+	//then initialise the line number				
+	TTmLineInfo lastLine;
+	TBool found = LastLine(lastLine);
+	if(found && !(lastLine.iFlags & TTmLineInfo::EParEnd))
+		{
+		aParam.iLineInPar = lastLine.iLineInPar+1;
+		}				
+	
+	//Generate the additional formatting
+	CTmCode* newCode = new(ELeave) CTmCode;
+	CleanupStack::PushL(newCode);
+
+	TInt newCodePos = iCode.Size();
+	CTmFormatContext::TInfo info;
+	
+	//Get line context character from previous line if there is
+	TTmDocPosSpec startDocPos(aParam.iStartChar - 1, static_cast<TTmDocPosSpec::TType>(1));
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool lineFound = interpreter.DocPosToLine(startDocPos);
+	if (lineFound)
+		info.iContextCharPerLine = interpreter.LineContextCharChar();
+	else
+		info.iContextCharPerLine = NULL;
+	
+	CTmFormatContext::FormatL(*iSource,aParam,*newCode,info,this,pStartBd, pEndBd, pEOLContext);
+
+	// Insert the new code if any.
+	if (info.iHeight > 0)
+		{
+		iCode.ChangeL(newCodePos,newCodePos,*newCode);
+		iHeight += info.iHeight;
+		iEndChar = info.iEndChar;
+		AdjustWidth(aParam,info.iWidth);
+		}
+	//if we did actually format to the paragraph end, reset the bd state
+	found = LastLine(lastLine);
+	if(found && (lastLine.iFlags & TTmLineInfo::EParEnd))
+		{
+		iBdStateAtEnd->Reset();
+		}
+
+	CleanupStack::PopAndDestroy();	// new code
+	Invariant();	
+	}
+
+/**
+Delete the format for the first or last paragraph if its height does not exceed aMaxDeletedHeight.
+Return TRUE if a paragraph was successfully deleted. Place the height of the deleted paragraph in aHeightDecrease.
+*/
+EXPORT_C TBool CTmTextLayout::DeletePar(const TTmFormatParamBase& aParam,TBool aAtStart,TInt aMaxDeletedHeight,
+										TInt& aHeightDecrease)
+	{
+	aHeightDecrease = 0;
+	if (!iSource || iStartChar >= iEndChar)
+		return FALSE;
+
+	int pos = aAtStart ? iStartChar : iEndChar - 1;
+	TTmByteCodeFinder finder(TTmInterpreterParam(*this), pos, pos);
+	TTmByteCodeFinder::TInfo info;
+	if (!finder.FindByteCode(TRUE,TRUE,KMaxTInt,info))
+		TmPanic(EFormatNotFound);
+	if (info.iBounds.Height() > aMaxDeletedHeight)
+		return FALSE;
+
+	iCode.Delete(info.iStartCodePos,info.iEndCodePos - info.iStartCodePos);
+	if (aAtStart)
+		iStartChar = info.iEndInfo.iEnd;
+	else
+		iEndChar = info.iStartInfo.iStart;
+	aHeightDecrease = info.iBounds.Height();
+	iHeight -= aHeightDecrease;
+
+	// Adjust the band's width if necessary.
+	AdjustWidth(aParam,0);
+	
+	Invariant();
+	
+	return TRUE;
+	}
+	
+/** 
+Delete as many lines of formatting as possible from the end of the formatted range, up to 
+the maximum height specified in aMaxDeletedHeight. The height decrease is placed in aHeightDecrease. 
+*/
+EXPORT_C void CTmTextLayout::DeleteFormattingFromEndL(const TTmFormatParamBase& aParam, TInt aMaxDeletedHeight, TInt& aHeightDecrease)
+	{
+	aHeightDecrease = 0;
+	if (!iSource || iStartChar >= iEndChar)
+		return;
+	TBidirectionalContext* bdStart = new(ELeave) TBidirectionalContext;
+	CleanupStack::PushL(bdStart);
+	TBidirectionalContext* bdEnd = new(ELeave) TBidirectionalContext;
+	CleanupStack::PushL(bdEnd);
+	TTmByteCodeFinder::TInfo info;
+	TTmByteCodeFinder sectionFinder(TTmInterpreterParam(*this), iStartChar, iStartChar);
+	TBool found = sectionFinder.FindByteCodeAtEnd(info, aMaxDeletedHeight, iHeight, bdStart, bdEnd);
+	if (!found)
+		{
+		CleanupStack::PopAndDestroy(2);
+		}
+	else
+		{
+		//should use an assignment operator here instead
+		delete iBdStateAtEnd;
+		iBdStateAtEnd = bdStart;
+		CleanupStack::PopAndDestroy(bdEnd);
+		CleanupStack::Pop(bdStart);
+		iCode.Delete(info.iStartCodePos, info.iEndCodePos - info.iStartCodePos);
+		iEndChar = info.iStartInfo.iStart;
+		aHeightDecrease = info.iBounds.Height();
+		iHeight -= aHeightDecrease;
+		// Adjust the band's width if necessary.
+		AdjustWidth(aParam,0);
+		Invariant();
+		}	
+	}
+
+/**
+Reset the object to its empty state; no source or formatting, height and width of 0, start and end char both 0.
+*/
+EXPORT_C void CTmTextLayout::Clear()
+	{
+	if(iBdStateAtEnd)
+		iBdStateAtEnd->Reset();
+	iSource = NULL;
+	iCode.Reset();
+	iWidth = 0;
+	iHeight = 0;
+	iStartChar = 0;
+	iEndChar = 0;
+
+	Invariant();
+	}
+
+/**
+Draw the text.
+
+@param aGc
+	Graphics context to draw to.
+@param aTopLeft
+	The origin of the formatted text in the coordinates of aGc.
+@param aClipRect
+	The clipping rectangle in the coordinates of aGc. Nowhere outside this
+	rectangle will be drawn.
+@param aDocBackground
+	The default document background colour, which is used for regions not drawn
+	by any custom background drawing routine and not covered by any text. If
+	null, no background is drawn in these places.
+@param aDrawParBackground
+	If false no default background is drawn on those areas covered by text.
+	Custom background drawers are invoked regardless of this argument.
+*/
+
+EXPORT_C void CTmTextLayout::DrawLayout(CGraphicsContext& aGc,
+	const TPoint& aTopLeft,const TRect& aClipRect,
+	const TLogicalRgb* aDocBackground,TBool aDrawParBackground) const
+	{
+	DrawLayout(aGc, aTopLeft, aClipRect, aDocBackground, aDrawParBackground, NULL, NULL);
+	}
+
+/**
+Draw the text.
+
+@param aGc
+	Graphics context to draw to.
+@param aTopLeft
+	The origin of the formatted text in the coordinates of aGc.
+@param aClipRect
+	The clipping rectangle in the coordinates of aGc. Nowhere outside this
+	rectangle will be drawn.
+@param aDocBackground
+	The default document background colour, which is used for regions not drawn
+	by any custom background drawing routine and not covered by any text. If
+	null, no background is drawn in these places.
+@param aDrawParBackground
+	If false no default background is drawn on those areas covered by text.
+	Custom background drawers are invoked regardless of this argument.
+@param aHighlight
+	The current selection. If null, no selection is drawn.
+@param aHighlightExtensions
+	If not null, the selection highlight has its edges moved by the specified
+	number of pixels
+*/
+
+EXPORT_C void CTmTextLayout::DrawLayout(CGraphicsContext& aGc,
+	const TPoint& aTopLeft,const TRect& aClipRect,
+	const TLogicalRgb* aDocBackground,TBool aDrawParBackground,
+	const TCursorSelection* aHighlight,
+	const TTmHighlightExtensions* aHighlightExtensions) const
+	{
+	if (iSource)
+		{
+		RTmDrawingInterpreter interpreter(*iSource, aGc,
+			TTmInterpreterParam(*this), aTopLeft, aClipRect, aDocBackground,
+			aDrawParBackground ? RTmDrawingInterpreter::EDrawParBackground : 0,
+			aHighlight, aHighlightExtensions);
+		interpreter.Draw();
+		interpreter.Close();
+		}
+	}
+
+/**
+Draw the background, using the custom background graphics implemented by overriding MTmSource::DrawBackground if any:
+aTopLeft is the top-left corner of the text, aRect is the portion of the background to be drawn, and aBackground is
+the default background colour. This function is used by higher-level classes for drawing backgrounds outside the ordinary
+text area consistently with the ordinary background.
+*/
+EXPORT_C void CTmTextLayout::DrawBackground(CGraphicsContext& aGc,const TPoint& aTopLeft,const TRect& aClipRect,
+											const TLogicalRgb& aBackground) const
+	{
+	if (iSource)
+		{
+		RTmDrawingInterpreter interpreter(*iSource, aGc, TTmInterpreterParam(*this),
+			aTopLeft, aClipRect, &aBackground, 0, NULL, NULL);
+		interpreter.DrawBackground(aClipRect, aBackground);
+		interpreter.Close();
+		}
+	}
+
+EXPORT_C void CTmTextLayout::InvertLayout(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos,TInt aEndDocPos) const
+	{
+	TTmHighlightExtensions highlightProperties;
+	highlightProperties.SetAll(0);
+	InvertLayout(aGc,aTopLeft,aStartDocPos,aEndDocPos,highlightProperties,0,0);
+	}
+
+/**
+Analogous to InvertLayout(CGraphicsContext, const TPoint&, TInt, TInt) but with
+highlight extensions applied.
+@see InvertLayout(CGraphicsContext, const TPoint&, TInt, TInt)
+@publishedPartner
+@released
+*/
+EXPORT_C void CTmTextLayout::InvertLayout(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos, TInt aEndDocPos,
+	const TTmHighlightExtensions& aHighlightExtensions,
+	TInt aHighlightStartDocPos, TInt aHighlightEndDocPos) const
+	{
+	// note: Assumes that RWindow::BeginRedraw() has been called by the caller.
+
+	if (NULL == iSource)
+		{
+		return;
+		}
+
+	TRect clipRect;
+	GetUpdateBoundingRect(aStartDocPos, aEndDocPos, aTopLeft, clipRect);
+
+	if (aStartDocPos < aHighlightStartDocPos)
+		{
+		aHighlightStartDocPos = aStartDocPos;
+		}
+	
+	if (aEndDocPos > aHighlightEndDocPos)
+		{
+		aHighlightEndDocPos = aEndDocPos;
+		}
+
+	TCursorSelection selection;
+	selection.SetSelection(aHighlightStartDocPos, aHighlightEndDocPos);
+
+	TRect boundingRect;
+	GetUpdateBoundingRect(aStartDocPos, aEndDocPos, aTopLeft, boundingRect);
+	aHighlightExtensions.AbsExtendRect(boundingRect);
+	boundingRect.Intersection(clipRect);
+	if (! boundingRect.IsEmpty())
+		{
+		RTmDrawingInterpreter interpreter(*iSource, aGc, TTmInterpreterParam(*this),
+			aTopLeft, boundingRect, NULL, ETrue, &selection, &aHighlightExtensions, ETrue);
+		interpreter.Draw();
+		interpreter.Close();
+		}
+	}
+
+/**
+Calculate the bounding rectangle of the region that must be redrawn to redraw the given document section.
+@param aStartDocPos
+	The section starting position
+@param aEndDocPos
+	The section ending position
+@param aTopLeft
+	Textview position in graphics context coordinates. The resulting region can be used
+	to clip the drawing in that graphics context.
+@param aBoundingRect
+	The resulting bounding rectangle, that is the smallest rectangle that should be redrawn
+	to redraw the specified document section.
+*/
+EXPORT_C void CTmTextLayout::GetUpdateBoundingRect(TInt aStartDocPos, TInt aEndDocPos,
+		const TPoint& aTopLeft, TRect& aBoundingRect) const
+	{
+	aBoundingRect = TRect(TRect::EUninitialized);
+
+	if (! iSource || aEndDocPos <= aStartDocPos)
+		{
+		return;
+		}
+
+	RTmBoundingRectInterpreter interpreter(*iSource, *this);
+	TRect rect(TRect::EUninitialized); // set by call to RTmBoundingRectInterpreter::FirstRect
+	TTmDocPos start(aStartDocPos, TRUE);
+	TTmDocPos end(aEndDocPos,FALSE);
+	TBool found = interpreter.FirstRect(start.iPos, end.iPos, rect);
+	while (found)
+		{
+		if (! rect.IsEmpty())
+			{
+			rect.Move(aTopLeft);
+			if(aBoundingRect.IsEmpty())
+				{
+				aBoundingRect = rect;
+				}
+			else
+				{
+				aBoundingRect.BoundingRect(rect);
+				}
+			}
+
+		found = interpreter.NextRect(rect);
+		}
+	interpreter.Close();
+	}
+
+EXPORT_C void CTmTextLayout::HighlightSection(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos, TInt aEndDocPos, const TRect& aClipRect) const
+	{
+	TTmHighlightExtensions highlightProperties;
+	highlightProperties.SetAll(0);
+	HighlightSection(aGc,aTopLeft,aStartDocPos,aEndDocPos,aClipRect,highlightProperties,0,0);
+	}
+
+/**
+Analogous to HighlightSection(CGraphicsContext&, const TPoint&, TInt, TInt,
+const TRect&) but with highlight extensions applied.
+@see HighlightSecion(CGraphicsContext&, const TPoint&, TInt, TInt, const
+TRect&)
+@publishedPartner
+@released
+*/
+EXPORT_C void CTmTextLayout::HighlightSection(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos, TInt aEndDocPos,
+	const TRect& aClipRect, const TTmHighlightExtensions& aHighlightExtensions,
+	TInt aHighlightStartDocPos, TInt aHighlightEndDocPos) const
+	{
+	if (0 == aHighlightStartDocPos && 0 == aHighlightEndDocPos)
+		{
+		aHighlightStartDocPos = aStartDocPos;
+		aHighlightEndDocPos = aEndDocPos;
+		}
+	else
+		{
+		if (aStartDocPos < aHighlightStartDocPos)
+			{
+			aHighlightStartDocPos = aStartDocPos;
+			}
+		
+		if (aEndDocPos > aHighlightEndDocPos)
+			{
+			aHighlightEndDocPos = aEndDocPos;
+			}
+		}
+
+	DrawSection(aGc, aTopLeft, aStartDocPos, aEndDocPos, aClipRect, aHighlightExtensions,
+		aHighlightStartDocPos, aHighlightEndDocPos);
+	}
+
+
+EXPORT_C void CTmTextLayout::DrawSection(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos, TInt aEndDocPos, const TRect& aClipRect) const
+	{
+	TTmHighlightExtensions highlightProperties;
+	highlightProperties.SetAll(0);
+	DrawSection(aGc,aTopLeft,aStartDocPos,aEndDocPos,aClipRect,highlightProperties,0,0);
+	}
+	
+/**
+Analogous to DrawSection(CGraphicsContext&, const TPoint&, TInt, TInt, const
+TRect&) but with highlight extensions applied.
+@see DrawSection(CGraphicsContext&, const TPoint&, TInt, TInt, const TRect&)
+@publishedPartner
+@released
+*/
+EXPORT_C void CTmTextLayout::DrawSection(CGraphicsContext& aGc,
+	const TPoint& aTopLeft, TInt aStartDocPos, TInt aEndDocPos,
+	const TRect& aClipRect, const TTmHighlightExtensions& aHighlightExtensions,
+	TInt aHighlightStartDocPos, TInt aHighlightEndDocPos) const
+	{
+	// note: Assumes that RWindow::BeginRedraw() has been called by the caller.
+
+	TCursorSelection selection;
+	selection.SetSelection(aHighlightStartDocPos, aHighlightEndDocPos);
+
+	TRect boundingRect;
+	GetUpdateBoundingRect(aStartDocPos, aEndDocPos, aTopLeft, boundingRect);
+	if (! boundingRect.IsEmpty())
+		{
+		aHighlightExtensions.AbsExtendRect(boundingRect);
+		boundingRect.Intersection(aClipRect);
+		if (! boundingRect.IsEmpty())
+			{
+			DrawLayout(aGc, aTopLeft, boundingRect, NULL, ETrue, &selection, &aHighlightExtensions);
+			}
+		}
+	}
+
+/**
+Finds a document position and returns information about it and the line it is
+in.
+@param aDocPos The position to find.
+@param aPosInfo Returns information on the found position.
+@param aLineInfo Returns information on the line containing the position found.
+@return
+	True if the position was found within the formatted text. False if the
+	position was not in the formatted text.
+*/
+EXPORT_C TBool CTmTextLayout::FindDocPos(const TTmDocPosSpec& aDocPos,
+	TTmPosInfo2& aPosInfo, TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	TBool found = interpreter.FindDocPos(aDocPos,aPosInfo);
+	aLineInfo = interpreter.LineInfo();
+	interpreter.Close();
+	return found;
+	}
+
+/**
+Find a document position and return information about it and the line it is in. Return FALSE if the document
+position is outside the formatted text. The document position to be found is passed in aDocPos and the information
+about the position found is returned in aPosInfo. The line information is returned in aLineInfo.
+@deprecated 7.0s
+*/
+EXPORT_C TBool CTmTextLayout::FindDocPos(const TTmDocPos& aDocPos,TTmPosInfo& aPosInfo,TTmLineInfo& aLineInfo) const
+	{
+	TTmDocPosSpec dp = aDocPos;
+	TTmPosInfo2 pi;
+	TBool r = FindDocPos(dp, pi, aLineInfo);
+	aPosInfo = pi;
+	return r;
+	}
+
+/**
+Finds a document position and returns information about it and the line it is
+in.
+@param aDocPos The position to find.
+@param aPosInfo Returns information on the found position.
+@param aLineInfo Returns information on the line containing the position found.
+@param aSubscript Returns the subscript height value.
+@return
+	True if the position was found within the formatted text. False if the
+	position was not in the formatted text.
+*/
+EXPORT_C TBool CTmTextLayout::FindDocPos(const TTmDocPosSpec& aDocPos,
+	TTmPosInfo2& aPosInfo, TTmLineInfo& aLineInfo, TInt& aSubscript) const
+	{
+	if (!iSource)
+		return FALSE;
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	TBool found = interpreter.FindDocPos(aDocPos,aPosInfo);
+	aLineInfo = interpreter.LineInfo();
+	aSubscript = interpreter.Subscript();
+	interpreter.Close();
+	return found;
+	}
+
+/**
+Finds a document position (i.e. the edge between two adjacent characters) by
+x-y position relative to the top-left corner of the formatted text.
+@param aXyPos Position to find.
+@param aPosInfo Returns information on the position closest to aXyPos.
+@param aLineInfo Returns information on the line containing aXyPos.
+@return
+	True if the Y-position is within the formatted text, or false otherwise.
+*/
+EXPORT_C TBool CTmTextLayout::FindXyPos(const TPoint& aXyPos,
+	TTmPosInfo2& aPosInfo, TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	TBool found = interpreter.FindXyPos(aXyPos,aPosInfo);
+	aLineInfo = interpreter.LineInfo();
+	interpreter.Close();
+	return found;
+	}
+
+/**
+Find an x-y position, relative to the top-left corner of the text, and return information about it and the line it is in.
+Return FALSE if the position is outside the formatted text. The document position to be found is passed in aDocPos and
+the information about the position found is returned in aPosInfo. The line information is returned in aLineInfo.
+@deprecated 7.0s
+*/
+EXPORT_C TBool CTmTextLayout::FindXyPos(const TPoint& aXyPos,TTmPosInfo& aPosInfo,TTmLineInfo& aLineInfo) const
+	{
+	TTmPosInfo2 pi;
+	TBool r = FindXyPos(aXyPos, pi, aLineInfo);
+	aPosInfo = pi;
+	return r;
+	}
+
+/**
+Return the number of formatted lines.
+*/
+EXPORT_C TInt CTmTextLayout::Lines() const
+	{
+	if (!iSource)
+		return 0;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	return interpreter.Lines();
+	}
+
+/**
+Return the number of formatted paragraphs.
+*/
+EXPORT_C TInt CTmTextLayout::Paragraphs() const
+	{
+	if (!iSource)
+		return 0;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	return interpreter.Paragraphs();
+	}
+
+/**
+Returns information (including line number and formatting information) of the
+line containing a given document position.
+@param aDocPos Position to find.
+@param aLineInfo
+	Returns information about the line containing aDocPos if aDocPos is within
+	the formatted text, or an undefined value if not.
+@return True if the aDocPos was within the formatted text.
+*/
+EXPORT_C TBool CTmTextLayout::DocPosToLine(const TTmDocPosSpec& aDocPos,
+	TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool found = interpreter.DocPosToLine(aDocPos);
+	aLineInfo = interpreter.LineInfo();
+	return found;
+	}
+
+/**
+Retrieve information about the line containing a certain document position.
+Put information about the line containing aDocPos in aLineInfo. Return FALSE if aDocPos is not in the formatted text.
+@deprecated 7.0s
+*/
+EXPORT_C TBool CTmTextLayout::DocPosToLine(const TTmDocPos& aDocPos,TTmLineInfo& aLineInfo) const
+	{
+	TTmDocPosSpec dp = aDocPos;
+	return DocPosToLine(dp, aLineInfo);
+	}
+
+/**
+Retrieve information about a line, referring to the line by its line number.
+
+Put information about the line numbered aLineNumber, counting the first formatted line as 0, in aLineInfo.
+Return FALSE if aLineNumber is not formatted.
+*/
+EXPORT_C TBool CTmTextLayout::LineNumberToLine(TInt aLineNumber,TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool found = interpreter.LineNumberToLine(aLineNumber);
+	aLineInfo = interpreter.LineInfo();
+	return found;
+	}
+
+/**
+Retrieve information about a line, referring to the line by its paragraph number and line number within the paragraph.
+
+Put information about line aLineNumber in paragraph aParNumber, counting the first formatted paragraph as 0,
+in aLineInfo. Return FALSE if aParNumber is not formatted. If aLineInPar is greater than the number of lines in
+the paragraph the last line in the paragraph is returned.
+*/
+EXPORT_C TBool CTmTextLayout::ParNumberToLine(TInt aParNumber,TInt aLineInPar,TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool found = interpreter.ParNumberToLine(aParNumber,aLineInPar);
+	aLineInfo = interpreter.LineInfo();
+	return found;
+	}
+
+/**
+Retrieve information about a line containing a certain y coordinate.
+
+Put information about the line containing the y coordinate aYPos, relative to 0 as the top of the formatted text, in
+aLineInfo. Return FALSE if aYPos is outside all formatted lines.
+*/
+EXPORT_C TBool CTmTextLayout::YPosToLine(TInt aYPos,TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return FALSE;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool found = interpreter.YPosToLine(aYPos);
+	aLineInfo = interpreter.LineInfo();
+	return found;
+	}
+
+
+/**
+Retrieve the text as displayed on a particular line.
+
+The text will be returned in display order, after all transformations have been
+applied to the backing text. These transformations include bidirectional
+reordering (making Arabic and Hebrew go right to left, etc.), ligation
+(combining adjacent characters into a single glyph), suppressing control
+characters, and converting characters to visible forms like visible spaces if
+necessary.
+
+Precondition: SetTextL must have been called on this object before
+GetDisplayedText can be called.
+
+Please note that any text that has passed through a shaper (for example
+Devanagari text) will be replaced in the returned text with the Unicode
+Replacement Character 0xFFFD. This is because the shaper produces glyph codes,
+not Unicode characters, and this is because Unicode does not contain all the
+ligatures and glyph variants required to display such scripts correctly.
+
+@param aLineNumber The line to fetch the display text of.
+@param aText A buffer into which the display text is placed.
+@param aNeeded
+	Returns the number of characters in the displayed line. The text is
+	truncated if aText is not big enough, aNeeded returns how large the buffer
+	would need to be to return the whole line.
+@return
+	EFalse if the operation is impossible, perhaps because aLineNumber
+is too large to be within the text.
+@since 7.0
+*/
+EXPORT_C TBool CTmTextLayout::GetDisplayedTextL(TInt aLineNumber, TDes& aText,
+	TInt& aNeeded) const
+	{
+	__ASSERT_ALWAYS(iSource, TmPanic(ENoSource));
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	CleanupClosePushL(interpreter);
+	TBool result = interpreter.GetDisplayedTextL(aLineNumber, aText,0, aNeeded);
+	CleanupStack::PopAndDestroy();
+	return result;
+	}
+
+/**
+Retrieve the text as displayed on a particular line. Return FALSE if the operation is impossible (e.g., because no
+MTmSource has yet been assigned). The text is returned in aText. The number of characters needed, which may be greater
+than the size of aText, is placed in aNeeded.
+
+The text will be returned in display order, after all transformations have been applied to the backing text. These
+transformations include bidirectional reordering (making Arabic and Hebrew go right to left, etc.), ligation (combining
+adjacent characters into a single glyph), suppressing control characters, and converting characters to visible forms like
+visible spaces if necessary.
+@deprecated 7.0 It can fail due to environmental conditions, and should therefore be leavable. Use GetDisplayedTextL instead.
+*/
+EXPORT_C TBool CTmTextLayout::GetDisplayedText(TInt aLineNumber,TDes& aText,TInt& aNeeded) const
+	{
+	if (!iSource)
+		return FALSE;
+	TBool result = EFalse;
+	TRAPD(err, result = GetDisplayedTextL(aLineNumber, aText, aNeeded));
+    UNUSED_VAR(err);
+	return result;
+	}
+
+/**
+Get the size of the minimal bounding box of the text when formatted to the specified wrap width.
+The width may be greater than aWrapWidth. To find the minimum width for the text,
+pass 0 for aWrapWidth. To find the minimum height, pass KMaxTInt for aWrapWidth.
+*/
+EXPORT_C void CTmTextLayout::GetMinimumLayoutSizeL(TInt aWrapWidth,TSize& aSize) const
+	{
+		GetMinimumLayoutSizeL(aWrapWidth,ETrue,aSize);
+	}
+
+/**
+Get the size of the minimal bounding box of the text when formatted to the specified wrap width.
+The width may be greater than aWrapWidth. To find the minimum width for the text,
+pass 0 for aWrapWidth. To find the minimum height, pass KMaxTInt for aWrapWidth.
+Use aAllowLegalLineBreaksOnly to set whether or not illegal line breaks should be considered
+when determining aSize.
+*/
+EXPORT_C void CTmTextLayout::GetMinimumLayoutSizeL(TInt aWrapWidth,TBool aAllowLegalLineBreaksOnly,TSize& aSize) const
+	{
+	if (!iSource)
+		{
+		aSize.iWidth = aSize.iHeight = 0;
+		return;
+		}
+	TTmFormatParam param;
+	param.iWrapWidth = aWrapWidth;
+	param.iFlags = TTmFormatParam::EWrap;
+	if(aAllowLegalLineBreaksOnly)
+		param.iFlags |= TTmFormatParam::ELegalLineBreaksOnly;
+	param.iStartChar = iStartChar;
+	param.iEndChar = iEndChar;
+	CTmCode* code = new(ELeave) CTmCode;
+	CleanupStack::PushL(code);
+	CTmFormatContext::TInfo info;
+	
+	//Get line context character from previous line if there is
+	TTmDocPosSpec startDocPos(param.iStartChar - 1, static_cast<TTmDocPosSpec::TType>(1));
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	TBool lineFound = interpreter.DocPosToLine(startDocPos);
+	if (lineFound)
+		info.iContextCharPerLine = interpreter.LineContextCharChar();
+	else
+		info.iContextCharPerLine = NULL;
+	
+	CTmFormatContext::FormatL(*iSource,param,*code,info,const_cast<CTmTextLayout*>(this));
+	CleanupStack::PopAndDestroy(); // code
+	aSize.iWidth = info.iWidth;
+	aSize.iHeight = info.iHeight;
+	}
+
+/**
+Find the width of the widest line in the specified vertical range. The width is the 'inner width'; that of the text
+itself not including indents or margins.
+*/
+EXPORT_C TInt CTmTextLayout::WidthOfWidestLine(TInt aTop,TInt aBottom) const
+	{
+	if (!iSource)
+		return 0;
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	return interpreter.WidthOfWidestLine(aTop, aBottom);
+	}
+
+EXPORT_C void CTmTextLayout::HorizontalExtremes(
+	TInt &aLeft, TInt &aRight, TInt aTopY, TInt aBottomY) const
+	{
+	if (!iSource)
+		{
+		aLeft = KMaxTInt;
+		aRight = KMinTInt;
+		return;
+		}
+	TTmInterpreter interpreter(TTmInterpreterParam(*this));
+	interpreter.HorizontalExtremes(aLeft, aRight, aTopY, aBottomY);
+	}
+
+/**
+Finds information about the visual position closest to the point specified. If
+there are two positions at this place that represent the ends of blocks that
+are not logically contiguous, different positions representing the ends of
+these blocks are returned. there is an ambiguity at this position, the document
+positions that represent the ends of the different blocks that meet here are
+returned.
+@param aXyPos
+	The position to find.
+@param aPosLeft
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the left.
+@param aPosRight
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the right. If it is not ambiguous, aPosLeft ==
+	aPosRight.
+@param aLineInfo
+	Information about the line containing aPosLeft and aPosRight.
+@return
+	ETrue if the position was found. EFalse otherwise. If EFalse, aPosLeft,
+	aPosRight and aLineInfo are undefined.
+*/
+EXPORT_C TBool CTmTextLayout::FindXyPosWithDisambiguation(
+	const TPoint& aXyPos,
+	TTmPosInfo2& aPosLeft, TTmPosInfo2& aPosRight,
+	TTmLineInfo& aLineInfo) const
+	{
+	if (!iSource)
+		return EFalse;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	if (!interpreter.YPosToLine(aXyPos.iY))
+		return EFalse;
+	aLineInfo = interpreter.LineInfo();
+
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+	TTmVisualDocPos pos;
+
+	edgeIterator.FindXPos(aXyPos.iX, pos);
+	aPosLeft = pos.LeftEdge();
+	aPosRight = pos.RightEdge();
+
+	edgeIterator.Close();
+	interpreter.Close();
+	return pos.Ambiguity() != TTmVisualDocPos::ENotFound;
+	}
+
+/**
+Finds the position after the horizontally spacing element after aStart. A
+horizontally spacing element is a spacing glyph (such as a letter or number)
+plus all its combining accent, or other spacing character such as a tab or
+carriage return. This function will also skip any zero-width characters that
+precede the next horizontally spacing element.
+@param aStart
+	Starting position. The returned position will be greater than this.
+@return
+	The position of the first trailing edge beyond aStart not visually
+	coincident with the leading edge of aStart, or KErrNotFound if there is
+	none, or it is not within formatted text.
+*/
+EXPORT_C TInt CTmTextLayout::FindNextPos(TInt aStart) const
+	{
+	if (!iSource)
+		return KErrNotFound;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+
+	if (!interpreter.DocPosToLine(TTmDocPos(aStart + 1, EFalse)))
+		return KErrNotFound;
+
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+
+	TInt pos = edgeIterator.NextPosition(aStart);
+
+	edgeIterator.Close();
+	interpreter.Close();
+	return pos;
+	}
+
+/**
+Finds the position before the horizontally spacing element before aStart.
+Zero-width characters immediately before aStart are also skipped.
+@param aStart
+	Starting position. The returned position will be greater than this.
+@return
+	The position of the first trailing edge beyond aStart not visually
+	coincident with the leading edge of aStart, or KErrNotFound if there is
+	none, or it is not within formatted text.
+@see FindNextPos
+*/
+EXPORT_C TInt CTmTextLayout::FindPreviousPos(TInt aStart) const
+	{
+	if (!iSource)
+		return KErrNotFound;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+
+	if (!interpreter.DocPosToLine(TTmDocPos(aStart - 1, ETrue)))
+		return KErrNotFound;
+
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+
+	TInt pos = edgeIterator.PreviousPosition(aStart);
+
+	edgeIterator.Close();
+	interpreter.Close();
+	return pos;
+	}
+
+/**
+Finds information about the position visually to the left of the position
+specified, as long as it is on the same line. If there are two positions at
+this place that represent the ends of blocks that are not logically contiguous,
+different positions representing the ends of these blocks are returned.
+@param aDocPos
+	The position to find.
+@param aPosLeft
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the left.
+@param aPosRight
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the right. If it is not ambiguous, aPosLeft ==
+	aPosRight.
+@return
+	ETrue if the position was found on the same line as aDocPos. EFalse
+	otherwise. If EFalse, aPosLeft and aPosRight are undefined.
+*/
+EXPORT_C TBool CTmTextLayout::GetNextPosLeftWithDisambiguation(
+	const TTmDocPosSpec& aDocPos,
+	TTmPosInfo2& aPosLeft, TTmPosInfo2& aPosRight) const
+	{
+	if (!iSource)
+		return EFalse;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	if (!interpreter.DocPosToLine(aDocPos))
+		return EFalse;
+
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+	TTmPosInfo2 closest;
+	TTmVisualDocPos next;
+
+	edgeIterator.FindEdgeLeftwards(aDocPos, closest, next);
+	aPosLeft = next.LeftEdge();
+	aPosRight = next.RightEdge();
+
+	edgeIterator.Close();
+	interpreter.Close();
+	return next.Ambiguity() != TTmVisualDocPos::ENotFound;
+	}
+
+/**
+Finds information about the position visually to the right of the position
+specified, as long as it is on the same line. If there are two positions at
+this place that represent the ends of blocks that are not logically contiguous,
+different positions representing the ends of these blocks are returned.
+@param aDocPos
+	The position to find.
+@param aPosLeft
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the left.
+@param aPosRight
+	The position returned. If this position is ambiguous, this is the position
+	attached to the block on the right. If it is not ambiguous, aPosLeft ==
+	aPosRight.
+@return
+	ETrue if the position was found on the same line as aDocPos. EFalse
+	otherwise. If EFalse, aPosLeft and aPosRight are undefined.
+*/
+EXPORT_C TBool CTmTextLayout::GetNextPosRightWithDisambiguation(
+	const TTmDocPosSpec& aDocPos,
+	TTmPosInfo2& aPosLeft, TTmPosInfo2& aPosRight) const
+	{
+	if (!iSource)
+		return EFalse;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	if (!interpreter.DocPosToLine(aDocPos))
+		return EFalse;
+
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+	TTmPosInfo2 closest;
+	TTmVisualDocPos next;
+
+	edgeIterator.FindEdgeRightwards(aDocPos, closest, next);
+	aPosLeft = next.LeftEdge();
+	aPosRight = next.RightEdge();
+
+	edgeIterator.Close();
+	interpreter.Close();
+	return next.Ambiguity() != TTmVisualDocPos::ENotFound;
+	}
+
+/**
+Find the nearest document position to the current one in the visual direction
+specified. This only works if the document position is within formatted text.
+False is returned if this condition is not met.
+@param aDocPos Start position.
+@param aInfo
+	Returns the position found, or an undefined value if aDocPos is not in
+	formatted text or is already at the end of the line in the direction being
+	searched.
+@param aToLeft True if the direction to search in is leftwards.
+@return True if the next position was found (see the description of aInfo).
+*/
+EXPORT_C TBool CTmTextLayout::GetNextVisualCursorPos(
+	const TTmDocPosSpec& aDocPos, TTmPosInfo2& aInfo, TBool aToLeft) const
+	{
+	TTmPosInfo2 dummy;
+	return aToLeft?
+		GetNextPosLeftWithDisambiguation(aDocPos, dummy, aInfo)
+		: GetNextPosRightWithDisambiguation(aDocPos, aInfo, dummy);
+	}
+
+/**
+Get the next cursor position in visual order. This function is useful for text that contains Arabic, Hebrew, or
+other right-to-left languages because it allows the cursor to be moved right or left on the display whatever the
+order of the backing text.
+
+The cursor position to the left or right of aDocPos is found, depending on the value of aToLeft. Information about
+the resulting position is returned in aInfo. The function returns TRUE if successful, FALSE if not. A FALSE return value
+means that there is no text, or aDocPos is outside the formatted text, or aDocPos cannot move in the required direction
+because it is at the end of the line.
+@deprecated 7.0s
+*/
+EXPORT_C TBool CTmTextLayout::GetNextVisualCursorPos(const TTmDocPos& aDocPos,TTmPosInfo& aInfo,TBool aToLeft) const
+	{
+	TTmDocPosSpec dp = aDocPos;
+	TTmPosInfo2 pi;
+	TBool r = GetNextVisualCursorPos(dp, pi, aToLeft);
+	aInfo = pi;
+	return r;
+	}
+
+/**
+Returns the position at the left or right extreme of the line containing aPos.
+@param aToRight EFalse for finding the left hand end, ETrue for the right.
+@param aExtreme Returns the document position at the end requested.
+@return
+	EFalse if the call failed either because the position was unformatted or
+	because the line contained no text.
+*/
+EXPORT_C TBool CTmTextLayout::LineExtreme(const TTmDocPosSpec& aPos,
+	TBool aToRight, TTmDocPos& aExtreme) const
+	{
+	TTmPosInfo2 posInfo;
+	TTmLineInfo lineInfo;
+	if (!FindDocPos(aPos, posInfo, lineInfo))
+		return EFalse;
+	TPoint extreme(
+		aToRight? lineInfo.iInnerRect.iBr.iX : lineInfo.iInnerRect.iTl.iX,
+		lineInfo.iInnerRect.iTl.iY);
+	if (!FindXyPos(extreme, posInfo, lineInfo))
+		return EFalse;
+	aExtreme = posInfo.iDocPos;
+	return ETrue;
+	}
+
+/**
+Returns the chunks of text adjacent to aPos.
+@param aLeft Returns a description of the chunk on the left of the cursor.
+@param aRight Returns a description of the chunk on the right.
+@return
+	EFalse if the call failed because the line is not formatted or contains
+	no text.
+*/
+EXPORT_C TBool CTmTextLayout::FindAdjacentChunks(const TTmDocPosSpec& aPos,
+	CTmTextLayout::TTmChunkDescription& aLeft,
+	CTmTextLayout::TTmChunkDescription& aRight) const
+	{
+	// Following block of code is used to check whether a doc position is shared by two text chunks. 
+	TBool overlapped = EFalse;
+	TTmChunkInterpreter tempCi(*this);
+	if (!tempCi.ChunkSetToLeftOfLine(aPos))
+		return EFalse;
+	TTmChunkInterpreter::TContainment contain1 = tempCi.ChunkContainsPos(aPos);
+	TTmChunkInterpreter::TContainment contain2;
+	while(tempCi.ChunkNext())
+		{
+		contain2 = tempCi.ChunkContainsPos(aPos);
+		if ( (contain1 == TTmChunkInterpreter::EMiddleOfChunk && contain2 != TTmChunkInterpreter::ENotInChunk)
+				|| (contain1 != TTmChunkInterpreter::ENotInChunk && contain2 == TTmChunkInterpreter::EMiddleOfChunk) )
+			{
+			overlapped = ETrue;
+			break;
+			}
+		if ( contain1 != TTmChunkInterpreter::ENotInChunk )
+			break;
+		contain1 = contain2;
+		}
+	// end of checking...
+
+	TTmChunkInterpreter ci(*this);
+	if (!ci.ChunkSetToLeftOfLine(aPos))
+		return EFalse;
+	aLeft.iStart = -1;
+	if (aPos.iPos == ci.LineInfo().iStart
+		&& aPos.iType == TTmDocPosSpec::ETrailing
+		&& !(ci.LineInfo().iFlags & TTmLineInfo::EParRightToLeft))
+		{
+		aRight.iStart = ci.ChunkStart();
+		aRight.iEnd = ci.ChunkEnd();
+		aRight.iRightToLeft = ci.ChunkRightToLeft();
+		return ETrue;
+		}
+	TTmChunkInterpreter::TContainment containment = ci.ChunkContainsPos(aPos);
+	// When a doc postion is overlapped, it would be in middle of one chunk and on edge of another
+	// chunk, so (MiddleOfChunk && overlapped) is also included.
+	while (containment == TTmChunkInterpreter::ENotInChunk
+		|| containment == TTmChunkInterpreter::ERightEdgeOfChunk
+		||(containment == TTmChunkInterpreter::EMiddleOfChunk && overlapped))
+		{
+		aLeft.iStart = ci.ChunkStart();
+		aLeft.iEnd = ci.ChunkEnd();
+		aLeft.iRightToLeft = ci.ChunkRightToLeft();
+		if (!ci.ChunkNext())
+			{
+			aRight.iStart = -1;
+			return ETrue;
+			}
+
+		if ( containment == TTmChunkInterpreter::ENotInChunk )
+			{
+			containment = ci.ChunkContainsPos(aPos);
+			}
+		else if (containment == TTmChunkInterpreter::EMiddleOfChunk && overlapped)
+			{
+			containment = ci.ChunkContainsPos(aPos);
+			// just in case the doc position is in middle of both of the two overlapped chunks,
+			// however this should not happen.
+			if (containment == TTmChunkInterpreter::EMiddleOfChunk)
+				break;
+			}
+		else if (containment == TTmChunkInterpreter::ERightEdgeOfChunk)
+			{
+			containment = TTmChunkInterpreter::ELeftEdgeOfChunk;
+			}
+		}
+	if (containment == TTmChunkInterpreter::ELeftEdgeOfChunk)
+		{
+		aRight.iStart = ci.ChunkStart();
+		aRight.iEnd = ci.ChunkEnd();
+		aRight.iRightToLeft = ci.ChunkRightToLeft();
+		return ETrue;
+		}
+	// position is in the middle of a chunk, so we will split it.
+	if (ci.ChunkRightToLeft())
+		{
+		aLeft.iRightToLeft = ETrue;
+		aRight.iRightToLeft = ETrue;
+		aRight.iStart = ci.ChunkStart();
+		aRight.iEnd = aPos.iPos;
+		aLeft.iStart = aPos.iPos;
+		aLeft.iEnd = ci.ChunkEnd();
+		}
+	else
+		{
+		aLeft.iRightToLeft = EFalse;
+		aRight.iRightToLeft = EFalse;
+		aLeft.iStart = ci.ChunkStart();
+		aLeft.iEnd = aPos.iPos;
+		aRight.iStart = aPos.iPos;
+		aRight.iEnd = ci.ChunkEnd();
+		}
+	return ETrue;
+	}
+
+/**
+Returns metrics for the cursor suitable for the document position and placement
+specified, as well as information about the line containing the position
+specified.
+@param aDocPos The document position to return information about.
+@param aPlacement The shape of the cursor.
+@param aLineInfo
+	Returns information about the line containing aDocPos if this position is
+	within the formatted text, or an undefined value otherwise.
+@param aOrigin
+	Returns a position to which aWidth, aAscent and aDescent is relative if the
+	position is within formatted text. Returns an undefined value otherwise.
+	This position will be on the baseline of the character found.
+@param aWidth
+	When aPlacement is ECursorVertical aWidth represents which side of the
+	origin to paint the cursor, -1 paint left, +1 paint right. When aPlacement
+	is ECursorUnderlineXXXX aWidth represents the X offset from the origin X to
+	draw the cursor between, -ve for previous & +ve for next when text L2R
+	(e.g. Latin), +ve for previous & -ve for next when text is R2L (e.g. Arabic)
+@param aAscent
+	Returns how far above aOrigin the cursor extends if aDocPos is within
+	formatted text, or an undefined value otherwise.
+@param aDescent
+	Returns how far below aOrigin the cursor extends if aDocPos is within
+	formatted text, or an undefined value otherwise.
+*/
+EXPORT_C TBool CTmTextLayout::GetCursor(const TTmDocPosSpec& aDocPos,TTmCursorPlacement aPlacement,
+		TTmLineInfo& aLineInfo,TPoint& aOrigin,TInt& aWidth,TInt& aAscent,TInt& aDescent) const
+	{
+	aOrigin.SetXY(0,0);
+	aWidth = aAscent = aDescent = 0;
+	if (!iSource)
+		return EFalse;
+
+	RTmGeneralInterpreter interpreter(*iSource, TTmInterpreterParam(*this));
+	if (!interpreter.DocPosToLine(aDocPos))
+		return EFalse;
+	RTmGraphemeEdgeIterator edgeIterator;
+	edgeIterator.Begin(interpreter);
+
+	TTmPosInfo2 this_info;
+	TTmVisualDocPos next;
+	TBool go_left = (aPlacement == ECursorUnderlinePrev);
+	RTmGraphemeEdgeIterator::TEdgesFound found = go_left?
+		edgeIterator.FindEdgeLeftwards(aDocPos, this_info, next)
+		: edgeIterator.FindEdgeRightwards(aDocPos, this_info, next);
+	if (found == RTmGraphemeEdgeIterator::ENone)
+		{
+		edgeIterator.Close();
+		interpreter.Close();
+		return EFalse;
+		}
+	TPoint nextPoint = this_info.iEdge;
+	if (found == RTmGraphemeEdgeIterator::ENearestAndNext)
+		nextPoint = next.NearestToX(nextPoint.iX)->iEdge;
+
+	aOrigin = go_left ? nextPoint : this_info.iEdge;
+	aLineInfo = interpreter.LineInfo();
+
+	int pos = this_info.iDocPos.iPos;
+	if (pos > interpreter.LineInfo().iStart || !interpreter.ParStart())
+		pos--;
+	TPtrC text;
+	CTmTextFontCache* font = NULL;
+	interpreter.GetText(pos,KMaxTInt,text,NULL,&font);
+
+	if (font)
+		{
+		if (aPlacement == ECursorVertical)
+			{
+			aAscent = font->Font().AscentInPixels();
+			aDescent = font->Font().DescentInPixels();
+			// In case the cursor is positioned on some super/sub or normal 
+			// font we need to adjust the Y position of the cursor with the 
+			// font's baseline offset so the cursor sits on the same horizon 
+			// as the text.
+			aOrigin.iY += font->Font().BaselineOffsetInPixels();
+			// -1 indicates that the cursor should hang to the left: this is
+			// for right-to-left paragraphs.
+			aWidth = aLineInfo.iFlags & TTmLineInfo::EParRightToLeft? -1 : 1;
+			}
+		else
+			{
+			aAscent = 0;
+			aDescent = 1;
+			aWidth = nextPoint.iX - this_info.iEdge.iX;
+			// The next if doesn't work to well with ECursorUnderlinePrev 
+			// placement as it is an approximation.
+			if (aWidth == 0) // Triggered when at start or end of text line
+				aWidth = font->Font().HeightInPixels() / 2;
+			if (aWidth < 0)
+				aWidth = -aWidth;
+			}
+		font->Close();
+		}
+	else
+		found = RTmGraphemeEdgeIterator::ENone;
+	edgeIterator.Close();
+	interpreter.Close();
+	return found != RTmGraphemeEdgeIterator::ENone;
+	}
+
+/**
+Return cursor metrics suitable for the supplied document position and placement.
+The cursor is defined like a character, with an origin, width, height and depth.
+This allows the caller to preserve the origin while overriding the other metrics.
+@deprecated 7.0s
+*/
+EXPORT_C TBool CTmTextLayout::GetCursor(const TTmDocPos& aDocPos,TTmCursorPlacement aPlacement,
+		TTmLineInfo& aLineInfo,TPoint& aOrigin,TInt& aWidth,TInt& aAscent,TInt& aDescent) const
+	{
+	TTmDocPosSpec dp = aDocPos;
+	return GetCursor(dp, aPlacement, aLineInfo, aOrigin, aWidth, aAscent, aDescent);
+	}
+
+/**
+Return the amount of memory used by a CTmTextLayout object,
+The amount returned is in bytes.
+The amount returned does not include memory used by non-owned objects.
+*/
+EXPORT_C TInt CTmTextLayout::MemoryUsed() const
+	{
+	return sizeof(*this) + iCode.MemoryUsed() - sizeof(iCode);
+	}
+
+/** 
+Stops or allows text to be drawn.  Included to allow users to control visibility
+if text is part of an invisible control.
+*/
+EXPORT_C void CTmTextLayout::MakeVisible(TBool aVisible)
+	{
+	if(aVisible)
+		{
+		iDrawingInterpFlags &= ~RTmDrawingInterpreter::EInvisible;
+		}
+	else
+		{
+		iDrawingInterpFlags |= RTmDrawingInterpreter::EInvisible;
+		}
+	}
+
+TInt CTmTextLayout::GetDrawingInterpFlags() const
+	{
+	return iDrawingInterpFlags;
+	}
+
+#ifdef _DEBUG
+void CTmTextLayout::Invariant() const
+	{
+	int lines = Lines();
+	if (lines > 0)
+		{
+		TTmLineInfo info;
+		if (!LineNumberToLine(lines - 1,info))
+			TmPanic(EInvariant);
+		int end = info.iEnd;
+		if (end != iEndChar)
+			TmPanic(EInvariant);
+		}
+	}
+#endif
+
+/*
+Adjust the width of the text, taking overwidth paragraphs like non-wrapped ones into account.
+aParam is the formatting parameters.
+aWidthOfNewText is the width of the widest line of any new text that has been inserted and has caused the adjustment.
+*/
+void CTmTextLayout::AdjustWidth(const TTmFormatParamBase& aParam,TInt aWidthOfNewText)
+	{
+	if (aParam.IsWrapping())
+		{
+		int wrap_width = aParam.iWrapWidth;
+		int x_scale = 1000;
+		int y_scale = 1000;
+		CalculateScale(*iSource,x_scale,y_scale);
+		if (x_scale != 1000)
+			wrap_width = wrap_width * x_scale / 1000;
+		if (iWidth > wrap_width || aWidthOfNewText > wrap_width)
+			{
+			iWidth = WidthOfWidestLine();
+			if (iWidth < wrap_width)
+				iWidth = wrap_width;
+			}
+		else
+			iWidth = wrap_width;
+		}
+	else
+		iWidth = WidthOfWidestLine();
+	}
+
+/**
+The equality operator.
+@return True if both sides are identical.
+*/
+EXPORT_C TBool TTmDocPos::operator==(const TTmDocPos& aPos) const
+	{
+	return iPos == aPos.iPos && !iLeadingEdge == !aPos.iLeadingEdge;
+	}
+
+/**
+Greater than operator.
+@return
+	True if the left side of the operator is further on in the document than
+	the right hand side.
+*/
+EXPORT_C TBool TTmDocPos::operator>(const TTmDocPos& aPos) const
+	{
+	return iPos > aPos.iPos || (iPos == aPos.iPos && iLeadingEdge && !aPos.iLeadingEdge);
+	}
+
+/**
+Greater than or equal to operator.
+@return
+	True if the left side of the operator is further on in the document than
+	the right hand side or if both sides are identical.
+*/
+EXPORT_C TBool TTmDocPos::operator>=(const TTmDocPos& aPos) const
+	{
+	return iPos > aPos.iPos || (iPos == aPos.iPos && (iLeadingEdge || !aPos.iLeadingEdge));
+	}