--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/textformatting/tagma/TMTEXT.CPP Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,729 @@
+/*
+* 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:
+*
+*/
+
+
+#include "TmText.h"
+#include <txtfrmat.h>
+#include <txtetext.h>
+#include "TMSTD.H"
+
+/**
+ * Creates a CTmText object using the specified device map and formatting parameters.
+ */
+EXPORT_C CTmText* CTmText::NewL(MGraphicsDeviceMap& aDevice,const TTmFormatParamBase& aFormatParam)
+ {
+ CTmText* t = new(ELeave) CTmText;
+ CleanupStack::PushL(t);
+ t->iImp = new(ELeave) CTmTextImp(aDevice,aFormatParam);
+ CleanupStack::Pop();
+ return t;
+ }
+
+/**
+ * Creates a CTmText object using the specified device map and formatting
+ * parameters that have default values (as in the default constructor for
+ * TTmFormatParamBase) apart from the wrap width and flags. The values of the
+ * flags are those used in for TTmFormatParamBase::iFlags.
+ */
+EXPORT_C CTmText* CTmText::NewL(MGraphicsDeviceMap& aDevice,TInt aWrapWidth,TInt aFlags)
+ {
+ TTmFormatParamBase param;
+ param.iWrapWidth = aWrapWidth;
+ param.iFlags = aFlags;
+ return NewL(aDevice,param);
+ }
+
+CTmText::CTmText()
+ {
+ }
+/**
+ * Destroys a CTmText object.
+ */
+EXPORT_C CTmText::~CTmText()
+ {
+ delete iImp;
+ }
+
+/**
+ * Inserts the text aText at the document position aPos. The other arguments
+ * are all pointers which have default values of null. The first two,
+ * aCharFormat and aParFormat, specify the format for the inserted text. If
+ * either is null the format immediately before the insertion point is used.
+ *
+ * Put the coordinates of the area that has been reformatted and needs to be
+ * redrawn, relative to the origin of the CText object, in aRedrawRect. Put the
+ * amount by which the text after the redrawn text needs to be scrolled up or
+ * down in aScroll: this is the amount by which the reformatted text has
+ * changed in height, and thus is positive if the text after the redrawn text
+ * has increased in height, which is usually, but not always, the case.
+ */
+EXPORT_C void CTmText::InsertL(TInt aPos,const TDesC& aText,
+ const TTmCharFormat* aCharFormat,const RTmParFormat* aParFormat,
+ TRect* aRedrawRect,TInt* aScroll)
+ {
+ iImp->InsertL(aPos,aText,aCharFormat,aParFormat,aRedrawRect,aScroll);
+ }
+
+/**
+ * Retrieves the current formatting parameters.
+ */
+EXPORT_C void CTmText::GetFormat(TTmFormatParamBase& aFormatParam) const
+ {
+ iImp->GetFormat(aFormatParam);
+ }
+
+/**
+ * Sets the wrap width and reformat the text.
+ */
+EXPORT_C void CTmText::SetWrapWidthL(TInt aWrapWidth)
+ {
+ iImp->SetWrapWidthL(aWrapWidth);
+ }
+
+/**
+ * Set the formatting parameters and reformat the text.
+ */
+EXPORT_C void CTmText::ChangeFormatL(const TTmFormatParamBase& aFormatParam)
+ {
+ iImp->ChangeFormatL(aFormatParam);
+ }
+
+/**
+ * Deletes all the text.
+ */
+EXPORT_C void CTmText::Clear()
+ {
+ iImp->Clear();
+ }
+
+/**
+ * Specifies custom drawing or layout for the object, or if aCustom is NULL,
+ * removes any customization. Reformats the object according to the new
+ * customized layout. See the MTmCustom class for details. Custom drawing
+ * allows background graphics to be drawn, and custom layout allows, among
+ * other things, control over the way line height is calculated and special
+ * characters are displayed.
+ */
+EXPORT_C void CTmText::CustomizeL(const MTmCustom* aCustom)
+ {
+ iImp->CustomizeL(aCustom);
+ }
+
+/**
+ * Returns the number of bytes of memory used by a CTmText object, allowing 8
+ * bytes overhead per heap allocation.
+*/
+EXPORT_C TInt CTmText::MemoryUsed() const
+ {
+ return sizeof(*this) + iImp->MemoryUsed() + 8;
+ }
+
+/**
+ * Returns a const reference to the CTmTextLayout object owned by this object.
+ * This function implements MTmTextLayoutForwarder::TextLayout.
+ */
+const CTmTextLayout& CTmText::TextLayout() const
+ {
+ return iImp->TextLayout();
+ }
+
+template<class T> TInt RRefCountedArray<T>::Insert(const T& aEntry,TInt& aIndex)
+ {
+ //+ replace this linear search with a binary search
+ int n = iArray.Count();
+ for (int i = 0; i < n; i++)
+ if (aEntry == iArray[i].iEntry)
+ {
+ iArray[i].iRefCount++;
+ aIndex = i;
+ return KErrNone;
+ }
+ aIndex = n;
+ TCountedEntry new_entry;
+ new_entry.iRefCount = 1;
+ int error = iArray.Append(new_entry);
+ if (!error)
+ error = iArray[iArray.Count() - 1].iEntry.Copy(aEntry);
+ return error;
+ }
+
+template<class T> void RRefCountedArray<T>::Remove(TInt aIndex)
+ {
+ if (--iArray[aIndex].iRefCount == 0)
+ iArray.Remove(aIndex);
+ }
+
+template<class T> TInt RRefCountedArray<T>::MemoryUsed() const
+ {
+ TInt bytes = sizeof(*this);
+ if (iArray.Count())
+ bytes += User::AllocLen(&iArray[0]) + 8;
+ return bytes;
+ }
+
+CTmTextImp::~CTmTextImp()
+ {
+ iCharFormatRun.Close();
+ iParFormatRun.Close();
+ iCharFormat.Close();
+ for (int i = 0; i < iParFormat.Count(); i++)
+ iParFormat[i].Close();
+ iParFormat.Close();
+ }
+
+void CTmTextImp::InsertL(TInt aPos,const TDesC& aText,
+ const TTmCharFormat* aCharFormat,const RTmParFormat* aParFormat,
+ TRect* aRedrawRect,TInt* aScroll)
+ {
+ __ASSERT_DEBUG(0 <= aPos, TmPanic(EBadArg));
+
+ // Don't insert zero-length text.
+ if (aText.Length() == 0)
+ return;
+
+ // Clamp aPos to the end of the document.
+ if (iTextLayout.EndChar() <= aPos)
+ aPos = Max(0,iTextLayout.EndChar() - 1);
+
+ // If the document is empty and character or paragraph format is unspecified, use a default format.
+ TTmCharFormat default_char_format;
+ default_char_format.iFontSpec.SetHeight(12 * 20); // set height, which must be in twips, to 12pt
+ RTmParFormat default_par_format;
+ if (iText.Length() == 0)
+ {
+ if (aCharFormat == NULL)
+ aCharFormat = &default_char_format;
+ if (aParFormat == NULL)
+ aParFormat = &default_par_format;
+ }
+
+ // Insert the character format.
+ int error = 0;
+ int char_format_index = -1;
+ if (aCharFormat)
+ error = iCharFormat.Insert((TMyCharFormat&)*aCharFormat,char_format_index);
+
+ // Insert the paragraph format.
+ int par_format_index = -1;
+ if (!error && aParFormat)
+ error = iParFormat.Insert((RMyParFormat&)*aParFormat,par_format_index);
+
+ // Insert the character format run.
+ if (!error)
+ error = iCharFormatRun.Insert(aPos,aText.Length(),char_format_index);
+
+ // If the paragraph format has changed extend it to the paragraph bounds.
+ int old_par_format_index = -1;
+ if (!error && iText.Length() > 0)
+ {
+ if (par_format_index != -1)
+ old_par_format_index = iParFormatRun.Index(aPos);
+ if (par_format_index != old_par_format_index)
+ {
+ int par_start = ParagraphStart(aPos);
+ int par_end = ParagraphEnd(aPos);
+ if (iText.Length() == par_end - 1)
+ --par_end;
+ error = iParFormatRun.Set(par_start, par_end - par_start,
+ par_format_index);
+ }
+ }
+
+ // Insert the paragraph format run.
+ if (!error)
+ error = iParFormatRun.Insert(aPos,aText.Length(),par_format_index);
+
+ // Insert the text.
+ if (!error)
+ {
+ TRAP(error,iText.InsertL(aPos,aText));
+ }
+
+ default_par_format.Close();
+
+ User::LeaveIfError(error);
+
+ if (iTextLayout.EndChar() > 0)
+ {
+ TTmReformatParam reformat_param;
+ reformat_param.iStartChar = aPos;
+ reformat_param.iOldLength = 0;
+ reformat_param.iNewLength = aText.Length();
+ reformat_param.iParFormatChanged = par_format_index != old_par_format_index;
+ TTmReformatResult result;
+ iTextLayout.FormatL(iFormatParam,reformat_param,result);
+ if (aRedrawRect)
+ *aRedrawRect = result.iRedrawRect;
+ if (aScroll)
+ *aScroll = result.iHeightChange;
+ }
+ else
+ {
+ iTextLayout.SetTextL(*this,iFormatParam);
+ if (aRedrawRect)
+ *aRedrawRect = TRect(0,0,iTextLayout.LayoutWidth(),iTextLayout.LayoutHeight());
+ if (aScroll)
+ *aScroll = 0;
+ }
+ }
+
+void CTmTextImp::ChangeFormatL(const TTmFormatParamBase& aFormatParam)
+ {
+ iFormatParam = aFormatParam;
+ ReformatL();
+ }
+
+void CTmTextImp::ReformatL()
+ {
+ if (iText.Length() > 0)
+ iTextLayout.SetTextL(*this,iFormatParam);
+ }
+
+void CTmTextImp::Clear()
+ {
+ iText.Reset();
+ iCharFormatRun.Reset();
+ iParFormatRun.Reset();
+ iCharFormat.Reset();
+ for (int i = 0; i < iParFormat.Count(); i++)
+ iParFormat[i].Close();
+ iParFormat.Reset();
+ iTextLayout.Clear();
+ }
+
+void CTmTextImp::CustomizeL(const MTmCustom* aCustom)
+ {
+ iCustom = aCustom;
+ ReformatL();
+ }
+
+TInt CTmTextImp::MemoryUsed() const
+ {
+ return sizeof(*this) +
+ iText.MemoryUsed() - sizeof(iText) +
+ iCharFormatRun.MemoryUsed() - sizeof(iCharFormatRun) +
+ iParFormatRun.MemoryUsed() - sizeof(iParFormatRun) +
+ iCharFormat.MemoryUsed() - sizeof(iCharFormat) +
+ iParFormat.MemoryUsed() - sizeof(iParFormat) +
+ iTextLayout.MemoryUsed() - sizeof(iTextLayout);
+ }
+
+MGraphicsDeviceMap& CTmTextImp::FormatDevice() const
+ {
+ return iDevice;
+ }
+
+MGraphicsDeviceMap& CTmTextImp::InterpretDevice() const
+ {
+ return iDevice;
+ }
+
+TInt CTmTextImp::DocumentLength() const
+ {
+ return iText.Length();
+ }
+
+void CTmTextImp::GetText(TInt aPos,TPtrC& aText,TTmCharFormat& aFormat) const
+ {
+ static const TText end_par = CEditableText::EParagraphDelimiter;
+ TInt index = 0;
+ TInt textLength = iText.Length();
+ __ASSERT_DEBUG(aPos <= textLength + 1, TmPanic(EIndexOutOfRange));
+ if (aPos < textLength)
+ {
+ TPtrC p = iText.PtrC(aPos);
+ TInt pLength = p.Length();
+ TRun charRun;
+ TInt charRunStart = iCharFormatRun.RunAndStartPos(aPos, charRun);
+ TInt remainingLength = charRunStart + charRun.iLength - aPos;
+ aText.Set(p.Ptr(), remainingLength < pLength? remainingLength : pLength);
+ index = charRun.iIndex;
+ }
+ else if (aPos == textLength)
+ {
+ aText.Set(&end_par,1);
+ if (0 < aPos)
+ index = iCharFormatRun.Index(aPos - 1);
+ else
+ {
+ TTmCharFormat d;
+ aFormat = d;
+ return;
+ }
+ }
+ else
+ {
+ aText.Set(0, 0);
+ return;
+ }
+ aFormat = iCharFormat[index];
+ }
+
+void CTmTextImp::GetParagraphFormatL(TInt aPos,RTmParFormat& aFormat) const
+ {
+ __ASSERT_DEBUG(0 <= aPos && aPos <= iText.Length(), TmPanic(EBadArg));
+ TInt textLength = iText.Length();
+ if (0 == textLength)
+ {
+ RTmParFormat d;
+ CleanupClosePushL(d);
+ aFormat.CopyL(d);
+ CleanupStack::PopAndDestroy(&d);
+ return;
+ }
+ if (aPos != textLength)
+ ++aPos;
+ aFormat.CopyL(iParFormat[iParFormatRun.Index(aPos)]);
+ }
+
+TInt CTmTextImp::ParagraphStart(TInt aPos) const
+ {
+ while (aPos > 0)
+ {
+ TPtrC text = iText.BackPtrC(aPos);
+ const TText *p = text.Ptr();
+ const TText *q = p + text.Length();
+ while (p < q)
+ {
+ q--;
+ aPos--;
+ if (*q == CEditableText::EParagraphDelimiter)
+ return aPos + 1;
+ }
+ }
+ return 0;
+ }
+
+TRgb CTmTextImp::SystemColor(TUint aColorIndex,TRgb aDefaultColor) const
+ {
+ if (iCustom)
+ return iCustom->SystemColor(aColorIndex,aDefaultColor);
+ else
+ return MTmSource::SystemColor(aColorIndex,aDefaultColor);
+ }
+
+TInt CTmTextImp::Stretch(TUint aChar) const
+ {
+ if (iCustom)
+ return iCustom->Stretch(aChar);
+ else
+ return MTmSource::Stretch(aChar);
+ }
+
+TUint CTmTextImp::Map(TUint aChar) const
+ {
+ if (iCustom)
+ return iCustom->Map(aChar);
+ else
+ return MTmSource::Map(aChar);
+ }
+
+void CTmTextImp::SetLineHeight(const TLineHeightParam& aParam,TInt& aAscent,TInt& aDescent) const
+ {
+ if (iCustom)
+ iCustom->SetLineHeight(aParam,aAscent,aDescent);
+ else
+ MTmSource::SetLineHeight(aParam,aAscent,aDescent);
+ }
+
+void CTmTextImp::DrawBackground(CGraphicsContext& aGc,const TPoint& aTextLayoutTopLeft,const TRect& aRect,
+ const TLogicalRgb& aBackground,TRect& aRectDrawn) const
+ {
+ if (iCustom)
+ iCustom->DrawBackground(aGc,aTextLayoutTopLeft,aRect,aBackground,aRectDrawn);
+ else
+ MTmSource::DrawBackground(aGc,aTextLayoutTopLeft,aRect,aBackground,aRectDrawn);
+ }
+
+void CTmTextImp::DrawLineGraphics(CGraphicsContext& aGc,const TPoint& aTextLayoutTopLeft,const TRect& aRect,
+ const TTmLineInfo& aLineInfo) const
+ {
+ if (iCustom)
+ iCustom->DrawLineGraphics(aGc,aTextLayoutTopLeft,aRect,aLineInfo);
+ else
+ MTmSource::DrawLineGraphics(aGc,aTextLayoutTopLeft,aRect,aLineInfo);
+ }
+
+void CTmTextImp::DrawText(CGraphicsContext& aGc,const TPoint& aTextLayoutTopLeft,const TRect& aRect,
+ const TTmLineInfo& aLineInfo,const TTmCharFormat& aFormat,
+ const TDesC& aText,const TPoint& aTextOrigin,TInt aExtraPixels) const
+ {
+ if (iCustom)
+ iCustom->DrawText(aGc,aTextLayoutTopLeft,aRect,aLineInfo,aFormat,aText,aTextOrigin,aExtraPixels);
+ else
+ MTmSource::DrawText(aGc,aTextLayoutTopLeft,aRect,aLineInfo,aFormat,aText,aTextOrigin,aExtraPixels);
+ }
+
+TInt CTmTextImp::RRunArray::SplitRun(TInt aRunIndex,TInt aOffset)
+ {
+ TRun& run = iRun[aRunIndex];
+ TRun new_run;
+ new_run.iIndex = run.iIndex;
+ new_run.iLength = run.iLength - aOffset;
+ int error = iRun.Insert(new_run, aRunIndex + 1);
+ if (!error)
+ run.iLength = aOffset;
+ return error;
+ }
+
+/*
+Find the run containing aPos. The position at the end of a run is in the run.
+The position at the start of a run is NOT in the run, but in the preceding run, if any.
+*/
+void CTmTextImp::RRunArray::FindRun(TInt aPos,TInt& aRunIndex,TInt& aOffset) const
+ {
+#ifdef _DEBUG
+ TInt error =
+#endif
+ FindRunNonstrict(aPos, aRunIndex, aOffset);
+ __ASSERT_DEBUG(!error, TmPanic(ETextRunNotFound));
+ }
+
+TInt CTmTextImp::RRunArray::FindRunNonstrict(TInt aPos,TInt& aRunIndex,TInt& aOffset) const
+ {
+ int n = iRun.Count();
+ int start = 0;
+ int end = 0;
+ for (int i = 0; i < n; i++)
+ {
+ __ASSERT_DEBUG(0 <= iRun[i].iLength, TmPanic(EInvalidTextRunLength));
+ __ASSERT_DEBUG(0 <= iRun[i].iIndex, TmPanic(EInvalidTextRunIndex));
+ end += iRun[i].iLength;
+ if (end >= aPos)
+ {
+ aRunIndex = i;
+ aOffset = aPos - start;
+ return KErrNone;
+ }
+ start = end;
+ }
+
+ aRunIndex = aOffset = -1;
+ return KErrNotFound;
+ }
+
+/* Find the latest run that starts less than or equal to aPos. Return it
+ * in aRunOut, and return its start position.
+ */
+TInt CTmTextImp::RRunArray::RunAndStartPos(TInt aPos, TRun& aRunOut) const
+ {
+ TInt runs = iRun.Count();
+ __ASSERT_DEBUG(0 < runs, TmPanic(ETextRunNotFound));
+ TInt start = 0;
+ TInt end = 0;
+ for (TInt i = 0; i != runs && end <= aPos; ++i)
+ {
+ aRunOut = iRun[i];
+ start = end;
+ end = start + aRunOut.iLength;
+ }
+ return start;
+ }
+
+// Insert a run of length aLength and attribute aIndex at aPos; if aIndex is < 0, use the index at aPos.
+TInt CTmTextImp::RRunArray::Insert(TInt aPos,TInt aLength,TInt aIndex)
+ {
+ __ASSERT_DEBUG(0 < aLength, TmPanic(EInvalidTextRunLength));
+ __ASSERT_DEBUG(0 <= aIndex || 0 < iRun.Count(), TmPanic(EParagraphFormatRequired));
+
+ int error = 0;
+ TRun new_run;
+ if (iRun.Count() == 0)
+ {
+ new_run.iLength = 0;
+ new_run.iIndex = aIndex;
+ error = iRun.Append(new_run);
+ if (error)
+ return error;
+ }
+
+ // Find the run; see if the index matches; if on a join between runs, check both.
+ int run_index, offset;
+ FindRun(aPos,run_index,offset);
+ if (offset == iRun[run_index].iLength && iRun[run_index].iIndex != aIndex && run_index < iRun.Count() - 1)
+ {
+ run_index++;
+ offset = 0;
+ }
+ TRun& run = iRun[run_index];
+
+ __ASSERT_DEBUG(0 <= offset && offset <= run.iLength, TmPanic(EInvariant));
+
+ // If aIndex is negative, it means don't change the attribute.
+ if (aIndex < 0)
+ aIndex = run.iIndex;
+
+ // No need to create a new run; just extend the existing one
+ if (run.iIndex == aIndex)
+ run.iLength += aLength;
+
+ // Split the run if necessary, then add a new run.
+ else
+ {
+ if (run.iLength == offset)
+ ++run_index;
+ else if (offset != 0)
+ {
+ error = SplitRun(run_index,offset);
+ run_index++;
+ }
+ if (!error)
+ {
+ new_run.iIndex = aIndex;
+ new_run.iLength = aLength;
+ error = iRun.Insert(new_run, run_index);
+ }
+ }
+
+ return error;
+ }
+
+TInt CTmTextImp::RRunArray::Set(TInt aPos,TInt aLength,TInt aIndex)
+ {
+ __ASSERT_DEBUG(0 <= aLength, TmPanic(EInvalidTextRunLength));
+ __ASSERT_DEBUG(0 <= aIndex, TmPanic(EInvalidTextRunIndex));
+
+ if (aLength == 0)
+ return KErrNone;
+
+ // Find the run start.
+ int start_run_index, start_run_offset;
+ FindRun(aPos,start_run_index,start_run_offset);
+
+ // Adjust the run start if there is no change to the attribute; return if this eliminates the range to be set.
+ if (iRun[start_run_index].iIndex == aIndex)
+ {
+ int n = iRun[start_run_index].iLength - start_run_offset;
+ aPos += n;
+ aLength -= n;
+ if (aLength <= 0)
+ return KErrNone;
+ }
+
+ // Find the run end.
+ int end_run_index, end_run_offset;
+ FindRun(aPos + aLength,end_run_index,end_run_offset);
+
+ // Adjust the run end if there is no change to the attribute; return if this eliminates the range to be set.
+ if (iRun[end_run_index].iIndex == aIndex)
+ {
+ aLength -= end_run_offset;
+ if (aLength <= 0)
+ return KErrNone;
+ }
+
+ // Determine the change in the number of runs. The maximum increase is 2.
+ int runs_increase = start_run_index - end_run_index + 2;
+
+ // Insert extra runs if needed.
+ int error = KErrNone;
+ if (runs_increase > 0)
+ {
+ error = SplitRun(start_run_index,start_run_offset);
+ runs_increase--;
+ if (start_run_index == end_run_index)
+ end_run_offset -= start_run_offset;
+ end_run_index++;
+ }
+ if (!error && runs_increase > 0)
+ {
+ error = SplitRun(end_run_index,end_run_offset);
+ end_run_index++;
+ end_run_offset = 0;
+ runs_increase--;
+ }
+ if (!error)
+ {
+ // Delete unneeded runs.
+ while (runs_increase < 0)
+ {
+ iRun.Remove(start_run_index + 2);
+ end_run_index--;
+ ++runs_increase;
+ }
+
+ // Adjust the size of the start run.
+ iRun[start_run_index].iLength = start_run_offset;
+
+ // Set the run after the start run to the new attribute.
+ TRun& run = iRun[start_run_index + 1];
+ run.iLength = aLength;
+ run.iIndex = aIndex;
+
+ // Adjust the size of the end run.
+ iRun[end_run_index].iLength -= end_run_offset;
+ }
+
+ return error;
+ }
+
+void CTmTextImp::RRunArray::Delete(TInt aPos,TInt aLength)
+ {
+ __ASSERT_DEBUG(0 <= aLength, TmPanic(EInvalidTextRunLength));
+
+ if (aLength == 0)
+ return;
+
+ // Find the start.
+ int start_run_index, start_run_offset;
+ FindRun(aPos,start_run_index,start_run_offset);
+
+ // Find the end.
+ int end_run_index, end_run_offset;
+ FindRun(aPos + aLength,end_run_index,end_run_offset);
+
+ // If the runs are the same it's trivial.
+ if (start_run_index == end_run_index)
+ {
+ iRun[start_run_index].iLength -= (end_run_offset - start_run_offset);
+ return;
+ }
+
+ // Shorten the start and end runs and determine the range of runs to delete.
+ iRun[start_run_index].iLength = start_run_offset;
+ int first_deleted_run = start_run_index + 1;
+ if (start_run_offset == 0)
+ first_deleted_run--;
+ iRun[end_run_index].iLength -= end_run_offset;
+ int last_deleted_run = end_run_index - 1;
+ if (iRun[end_run_index].iLength == 0)
+ last_deleted_run++;
+
+ // Delete runs.
+ for (int i = first_deleted_run; i <= last_deleted_run; i++)
+ iRun.Remove(first_deleted_run);
+ }
+
+TInt CTmTextImp::RRunArray::Index(TInt aPos) const
+ {
+ int run_index, offset;
+ TInt error = FindRunNonstrict(aPos,run_index,offset);
+ return error? error : iRun[run_index].iIndex;
+ }
+
+TInt CTmTextImp::RRunArray::MemoryUsed() const
+ {
+ TInt bytes = sizeof(*this);
+ if (iRun.Count())
+ bytes += User::AllocLen(&iRun[0]) + 8;
+ return bytes;
+ }
+
+EXPORT_C void CTmText::Spare1()
+ {
+ TmPanic(EUnimplemented);
+ }