--- a/graphicsdeviceinterface/gdi/sgdi/BidiText.cpp Thu Sep 02 21:50:40 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,961 +0,0 @@
-// Copyright (c) 2002-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 <e32svr.h>
-#include "BidiTextImp.h"
-#include "BidiCopy.h"
-#include "BidiCompact.h"
-#include <bidi.h>
-#include <e32base.h>
-#include <gdi.h>
-#include <linebreak.h>
-
-_LIT(KBidiPanicCategory,"Bidi");
-static const TInt KLineSeparator = 0x2028;
-static const TInt KParagraphSeparator = 0x2029;
-static const TInt KCodeCR = 0x000D;
-static const TInt KCodeLF = 0x000A;
-static const TInt KCodeEllipsis = 0x2026;
-
-void DeleteTRunInfo(void* aRunInfo)
- {
- delete[] reinterpret_cast<TBidirectionalState::TRunInfo*>(aRunInfo);
- }
-
-void BidiPanic(TInt aError)
- {
- User::Panic(KBidiPanicCategory, aError);
- }
-
-
-// One page-full of TRunInfos
-const TInt KMaxRunInfoArraySize = 4*1024 / sizeof(TBidirectionalState::TRunInfo);
-const TInt KBidiTlsHandle = 0x101F633D;
-
-
-/*
-* Ref-counted TLS for the shared run info array used by the SetText() method.
-*/
-NONSHARABLE_CLASS(CBidiTextTls) : public CObject
- {
-public:
- static CBidiTextTls* NewL();
- static CBidiTextTls* GetTls();
- ~CBidiTextTls();
- inline TUint MaxArraySize();
- inline TBidirectionalState::TRunInfo* RunArray();
-
-private:
- CBidiTextTls();
- void ConstructL(TUint aMaxArraySize);
-
-private:
- TBidirectionalState::TRunInfo* iRunInfoArray;
- TUint iMaxArraySize;
- };
-
-
-
-CBidiTextTls::CBidiTextTls()
-: iRunInfoArray(NULL),
- iMaxArraySize(0)
- {
- }
-
-
-CBidiTextTls::~CBidiTextTls()
- {
- UserSvr::DllFreeTls(KBidiTlsHandle);
-
- if (iRunInfoArray)
- {
- delete [] iRunInfoArray;
- }
- }
-
-
-TUint CBidiTextTls::MaxArraySize()
- {
- return iMaxArraySize;
- }
-
-
-TBidirectionalState::TRunInfo* CBidiTextTls::RunArray()
- {
- return iRunInfoArray;
- }
-
-
-/**
- * Helper function provided to simplify reading the TLS data and improve the
- * readability of the code
- */
-CBidiTextTls* CBidiTextTls::GetTls()
- {
- return reinterpret_cast<CBidiTextTls*>(UserSvr::DllTls(KBidiTlsHandle));
- }
-
-
-CBidiTextTls* CBidiTextTls::NewL()
- {
- CBidiTextTls* self = new (ELeave) CBidiTextTls;
- CleanupClosePushL(*self);
- self->ConstructL(KMaxRunInfoArraySize);
- CleanupStack::Pop(self);
- return self;
- }
-
-
-void CBidiTextTls::ConstructL(TUint aMaxArraySize)
- {
- iMaxArraySize = aMaxArraySize;
- iRunInfoArray = new (ELeave) TBidirectionalState::TRunInfo[aMaxArraySize];
- User::LeaveIfError(UserSvr::DllSetTls(KBidiTlsHandle, this));
- }
-
-
-EXPORT_C RRunInfoArray::RRunInfoArray()
-: iTls(NULL)
- {
- }
-
-
-/**
-Creates the run array if necessary and increases the reference count on it.
-RRunInfoArray::OpenL() must be called prior to calling TBidiText::SetText().
- */
-EXPORT_C void RRunInfoArray::OpenL()
- {
- if(!iTls)
- {
- iTls = CBidiTextTls::GetTls();
- if(iTls)
- {
- iTls->Open(); // Increase ref count
- }
- else
- {
- iTls = CBidiTextTls::NewL();
- }
- }
- }
-
-
-/**
-Decreases the reference count on the run array. The run array will be deleted
-if the reference count reaches zero. The client application must ensure that
-there is a matching call to Close() for every call to OpenL() or memory will
-be leaked.
- */
-EXPORT_C void RRunInfoArray::Close()
- {
- if(iTls)
- {
- iTls->Close();
- iTls = NULL;
- }
- }
-
-
-/**
-@return Pointer to the run array buffer
-@internalComponent
- */
-TBidirectionalState::TRunInfo* RRunInfoArray::RunArray() const
- {
- return iTls ? iTls->RunArray() : NULL;
- }
-
-
-/**
-@return Number of bytes needed to hold the TBidiTextImp member variables, plus the
- text data allocated off the end of the TBidiTextImp object.
-@internalComponent
-*/
-TInt TBidiTextImp::RequiredBytes(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
- {
- // size of TBidiTextImp class
- TInt bytes = TBidiTextImp::AlignedSizeOf();
- // size of text for logical and visual orderings.
- // This includes aMaxLines - 1 line breaks with surrounding
- // zero-width joiners, and a truncation character (possibly
- // a surrogate pair) plus a zero-width joiner.
- bytes += sizeof(TText) * (aLength * 2 + aMaxLines * 3);
- // size of line length array
- bytes += sizeof(TInt16*) * aMaxLines;
- // alignment
- bytes = (bytes + 3) & 0xFFFFFFFC;
- // array of TRunInfoCompact
- bytes += sizeof(TRunInfoCompact) * aBdRunArraySize;
-
- return bytes;
- }
-
-
-/**
-@return A TBidiTextImp object of sufficient size to hold the amount of text data specified
- by the the arguments.
-@param aLength The number of characters in the text.
-@param aMaxLines The maximum number of lines
-@param aBdRunArraySize The size of the bidi run array.
-@internalComponent
-*/
-TBidiTextImp* TBidiTextImp::NewL(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
- {
- const TInt bytes = RequiredBytes(aLength, aMaxLines, aBdRunArraySize);
- TInt8* mem = static_cast<TInt8*>(User::AllocL(bytes));
- TBidiTextImp* me = reinterpret_cast<TBidiTextImp*>(mem);
-
- me->iTextLengthAndFlags = aLength;
- me->iVisualOrderedTextLength = -1;
- me->iWrappingWidth = 0xFFFF;
- me->iBidiRunArrayLength = aBdRunArraySize;
- me->iLines = static_cast<TUint8>(aMaxLines);
- me->iTruncationCharPlane = 0;
- me->iTruncationChar16 = KCodeEllipsis;
- me->SetAllocatedTextDataBytes(bytes - TBidiTextImp::AlignedSizeOf() - (sizeof(TRunInfoCompact) * aBdRunArraySize));
- return me;
- }
-
-/**
-@return Position of logically-ordered text portion of the heap cell.
-@internalComponent
-*/
-TText* TBidiTextImp::LogicalText()
- {
- return reinterpret_cast<TText*>(
- reinterpret_cast<TInt8*>(this)
- + TBidiTextImp::AlignedSizeOf());
- }
-
-/**
-@return Position of visually-ordered text portion of the heap cell.
-@internalComponent
-*/
-TText* TBidiTextImp::VisualText()
- {
- TInt bytes = TBidiTextImp::AlignedSizeOf();
- bytes += sizeof(TText) * TextLength();
- return reinterpret_cast<TText*>(
- reinterpret_cast<TInt8*>(this) + bytes);
- }
-
-/**
-Returns a pointer to the array containing the width in pixels of each and every line.
-@return Position of the array of line widths portion of the heap cell.
-@internalComponent
-*/
-TInt16* TBidiTextImp::LineWidthArray()
- {
- TInt bytes = TBidiTextImp::AlignedSizeOf();
- bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
- return reinterpret_cast<TInt16*>(
- reinterpret_cast<TInt8*>(this) + bytes);
- }
-
-/**
-@return Position of the array of runs portion of the heap cell.
-@internalComponent
-*/
-TRunInfoCompact* TBidiTextImp::BidiRunArray()
- {
- TInt bytes = TBidiTextImp::AlignedSizeOf();
- bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
- bytes += sizeof(TInt16*) * iLines;
- bytes = (bytes + 3) & 0xFFFFFFFC;
- return reinterpret_cast<TRunInfoCompact*>(
- reinterpret_cast<TInt8*>(this) + bytes);
- }
-
-/**
-Report if the current character is an explicit line break. Both
-aText[0] and aText[1] must be part of the string.
-@return Size of line break.
-@internalComponent
-*/
-TInt SizeLineBreak(const TText* aText, const TText* aTextEnd)
- {
- if (aText == aTextEnd )
- return 0;
-
- if (*aText == KLineSeparator || *aText == KParagraphSeparator
- || *aText == KCodeLF)
- return 1;
- if (aText[0] == KCodeCR)
- {
- // first check for space before checking for LF
- if (aText+1 < aTextEnd )
- {
- return aText[1] == KCodeLF? 2 : 1;
- }
- else
- return 1;
- }
- return 0;
- }
-
-/**
-Find the next line break character.
-@internalComponent
-*/
-const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd)
- {
- while (aStart != aEnd && *aStart != KLineSeparator
- && *aStart != KParagraphSeparator && *aStart != KCodeLF
- && *aStart != KCodeCR)
- ++aStart;
- return aStart;
- }
-
-/**
-Count number of lines in text.
-@internalComponent
-*/
-TInt NumberOfLines(const TText* aStart, const TText* aEnd)
- {
- TInt num = 0;
- while (aStart != aEnd)
- {
- aStart = FindEndOfThisLine(aStart, aEnd);
- aStart += SizeLineBreak(aStart, aEnd);
- ++num;
- }
- return num;
- }
-
-/** Returns the directionality of a given language.
-@param aLanguage Language.
-@return The directionality of the given language. */
-EXPORT_C TBidiText::TDirectionality TBidiText::ScriptDirectionality(
- TLanguage aLanguage)
- {
- const TUint32 DirectionalityBitmap[] =
- {
- 0,
- // Arabic, Farsi, Hebrew
- 0x02040020,
- // Urdu
- 0x40000000
- };
- TUint index = aLanguage;
- if (index < sizeof(DirectionalityBitmap) * 8)
- {
- index >>= 5;
- TInt bit = aLanguage & 31;
- return (DirectionalityBitmap[index] >> bit) & 1?
- ERightToLeft : ELeftToRight;
- }
- return ELeftToRight;
- }
-
-
-/** Reports the implicit directionality of a piece of text.
-
-@param aText The text to be examined.
-@param aFound If non-null, returns ETrue if there were any strongly directional
-characters and EFalse if there were none. If a piece of text is spread over
-several descriptors, They need to be queried in sequence until one returns
-ETrue in aFound.
-@return The directionality implicit in aText. 131 */
-EXPORT_C TBidiText::TDirectionality TBidiText::TextDirectionality(
- const TDesC& aText, TBool* aFound)
- {
- return BidiCopy::ImplicitDirectionalityIsRightToLeft(
- aText.Ptr(), aText.Length(), aFound)?
- ERightToLeft : ELeftToRight;
- }
-
-/** Creates a bidirectional text object with directionality determined by
-aDirectionality. Use this for text that has come from user input.
-
-@param aText The text in logical order.
-@param aMaxLines
- The maximum number of lines that this text will need to be split into. Must
- be at least 1, but should not be too large, as each potential line takes an
- extra 8 bytes of memory.
-@param aDirectionality Direction to use.
-@return The newly constructed object.
- */
-EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines,
- TBidiText::TDirectionality aDirectionality)
- {
- __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
- const TText* text = aText.Ptr();
- const TInt length = aText.Length();
- TInt linesInOriginalText = NumberOfLines(text, text + length);
- if (aMaxLines < linesInOriginalText)
- aMaxLines = linesInOriginalText;
-
- const TInt arraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
- TBidirectionalState::TRunInfo* runInfoArray = new(ELeave) TBidirectionalState::TRunInfo[arraySize];
- TCleanupItem ci(DeleteTRunInfo, runInfoArray);
- CleanupStack::PushL(ci);
- TBidirectionalState::GenerateBdRunArray(text, length, runInfoArray, arraySize);
- TBidirectionalState state;
- state.ReorderLine(runInfoArray, arraySize, ETrue, ETrue, aDirectionality,
- TChar::EOtherNeutral, TChar::EOtherNeutral);
- TInt compactArraySize = TRunInfoCompact::Convert(0, aText, runInfoArray, arraySize);
-
- // size of TBidiTextImp class
- TBidiTextImp* me = TBidiTextImp::NewL(length, aMaxLines, compactArraySize);
- me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
-
- TRunInfoCompact::Convert(me->BidiRunArray(), aText, runInfoArray, arraySize);
- CleanupStack::PopAndDestroy(runInfoArray);
-
- Mem::Copy(me->LogicalText(), text, length * sizeof(TText));
- return me;
- }
-
-/** Creates a bidirectional text object with directionality determined by the text
-itself. Use this for text that has been obtained from a resource file.
-
-@param aText The text in logical order.
-@param aMaxLines The maximum number of lines that this text will need to be
-split into. Must be at least 1, but should not be too large, as each potential
-line takes an extra 8 bytes of memory.
-@return The newly constructed object. */
-EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines)
- {
- return NewL(aText, aMaxLines, TextDirectionality(aText));
- }
-
-
-/** Creates a bidirectional text object with enough room for up to aReservedMaxLength
-number of characters. The number of characters that will actually fit (when calling
-SetText()) might be slightly less than aReservedMaxLength, as each change between a
-left-to-right and a right-to-left sub-string (and the other way around) needs about
-two characters worth of memory.
-
-@param aReservedMaxLength The maximum number of characters.
-@param aMaxLines The maximum number of lines that this text will need to be
-split into. Must be at least 1, but should not be too large, as each potential
-line takes an extra 8 bytes of memory.
-@return The newly constructed object. */
-EXPORT_C TBidiText* TBidiText::NewL(TInt aReservedMaxLength, TInt aMaxLines)
- {
- __ASSERT_ALWAYS(0 < aReservedMaxLength, BidiPanic(EBidiPanic_InvalidReservedMaxLength));
- __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
-
- const TInt compactArraySize = 1; // Always at least one needed
-
- TBidiTextImp* me = TBidiTextImp::NewL(aReservedMaxLength, aMaxLines, compactArraySize);
- me->SetTextLength(0); // no text yet, just reserved memory
- return me;
- }
-
-/** Sets the text of the bidirectional text object with directionality determined
-by the text itself. Use this for text that has been obtained from a resource file.
-
-@param aText The text in logical order.
-@return The number of characters that didn't fit in the available buffer.
-*/
-EXPORT_C TInt TBidiText::SetText(const TDesC& aText, RRunInfoArray& aRunInfoArray)
- {
- return SetText(aText, TextDirectionality(aText), aRunInfoArray);
- }
-
-
-/** Sets the text of the bidirectional text with directionality determined by
-aDirectionality. Use this for text that has come from user input.
-
-@param aText The text in logical order.
-@param aDirectionality Direction to use.
-@return The number of characters that didn't fit in the available buffer.
-@panic Bidi EBidiPanic_RunArrayNull The call to RRunInfoArray::OpenL() has not
-been made prior to this call to TBidiText::SetText()
-*/
-EXPORT_C TInt TBidiText::SetText(const TDesC& aText,
- TDirectionality aDirectionality,
- RRunInfoArray& aRunInfoArray)
- {
- TBidirectionalState::TRunInfo* const runArray = aRunInfoArray.RunArray();
- __ASSERT_ALWAYS(runArray, BidiPanic(EBidiPanic_RunArrayNull));
-
- TBidiTextImp* me = TBidiTextImp::Imp(this);
- const TInt maxLines = me->iLines;
- const TText* text = aText.Ptr();
- TInt length = aText.Length();
-
- TInt requiredArraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
- const TInt actualArraySize = aRunInfoArray.iTls->MaxArraySize();
-
- if (requiredArraySize > actualArraySize)
- {
- // Handle the case where we do not have enough space in the run array
- // to cope with the input text. The text will be truncated to ensure
- // we don't overrun the buffer and the number of excess characters
- // returned as a negative number.
- requiredArraySize = actualArraySize;
- TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
-
- length = 0;
- for (TInt index = 0; index < requiredArraySize; index++)
- {
- length += runArray[index].iLength;
- }
- }
- else
- {
- TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
- }
-
-
-
- TBidirectionalState state;
- state.ReorderLine(runArray,
- requiredArraySize,
- ETrue,
- ETrue,
- aDirectionality,
- TChar::EOtherNeutral,
- TChar::EOtherNeutral);
- const TInt compactArraySize = TRunInfoCompact::Convert(0,
- aText,
- runArray,
- requiredArraySize);
-
- // Calculate number of bytes needed to keep text data
- TInt requiredBytes = sizeof(TText) * (length * 2 + maxLines * 3); // size of text for logical & visual orderings.
- requiredBytes += sizeof(TInt16*) * maxLines; // size of line length array
- requiredBytes = (requiredBytes + 3) & 0xFFFFFFFC; // alignment
-
- TInt textLength = length;
- const TInt excessData = Max(0, requiredBytes - me->AllocatedTextDataBytes());
- TInt excessChars = 0;
- if(excessData)
- {
- // Calculate how much text data that can be fitted into the available bytes,
- // given the bytes needed for run array data
- excessChars = excessData / (sizeof(TText) * 2);
- textLength -= excessChars;
- }
- else if (aText.Length() > length)
- {
- excessChars = aText.Length() - length;
- }
-
- me->SetTextLength(textLength);
- me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
- me->iVisualOrderedTextLength = -1;
- me->iBidiRunArrayLength = static_cast<TUint16>(compactArraySize);
-
- TRunInfoCompact::Convert(me->BidiRunArray(), aText, runArray, requiredArraySize);
- Mem::Copy(me->LogicalText(), text, textLength * sizeof(TText));
-
- return excessChars;
- }
-
-/** Sets the character that will be added at the end of the text if the whole text
-cannot fit into the space specified.
-
-@param aTruncateWith The truncation char. */
-EXPORT_C void TBidiText::SetTruncationChar(TChar aTruncateWith)
- {
- TBidiTextImp* me = TBidiTextImp::Imp(this);
- me->iTruncationCharPlane = static_cast<TUint8>(aTruncateWith >> 16);
- me->iTruncationChar16 = static_cast<TUint16>(aTruncateWith);
- }
-
-TInt RemoveTrailingSpaces(const MLineBreaker* aBreaker,
- const TText* aInput, TInt aMinPos, TInt aEndPos)
- {
- // Ignore space characters at the end of the line.
- // Don't bother to ignore spaces made of surrogate pairs:
- // more processing than it's worth.
- TUint dummy1, dummy2;
- while (aEndPos != aMinPos && MLineBreaker::ESpLineBreakClass
- == aBreaker->LineBreakClass(aInput[aEndPos - 1], dummy1, dummy2))
- {
- --aEndPos;
- }
- return aEndPos;
- }
-
-/** Prepares the visually-ordered text according to the wrapping width and font
-specified. Text cannot be drawn until this has been done.
-@param aWrappingWidth
- The maximum width of the text in pixels. Note that this distance should be
- slightly less than the available width to allow for characters such as "W"
- which can have side-bearings that leak into the margins.
-@param aFont The font that will provide the character metrics.
-@param aBreaker
- An object for breaking the lines. May be NULL for default behaviour.
-@param aMaxLines
- Number of lines to restrict wrapping to. The truncation character will be
- used if the text is too long for this number of lines. The number of lines
- wrapped to may not be greater than the figure passed to NewL.
-*/
-EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
- const MLineBreaker* aBreaker, TInt aMaxLines)
- {
- TBidiTextImp* me = TBidiTextImp::Imp(this);
- me->iWrappingWidth = aWrappingWidth;
-
- TInt16* lineWidths = me->LineWidthArray();
- TText* output = me->VisualText();
-
- TInt numLines = 0;
- DoWrapText(aWrappingWidth, aFont, aBreaker, aMaxLines, output, numLines, lineWidths);
- me->iVisualOrderedTextLength = output - me->VisualText();
- }
-
-/** Calculate the minimum size needed to draw the current text, given the specified
-wrapping width, font, and line gap. Calling this method will not rewrap the object's
-text.
-
-@param aWrappingWidth
- The maximum width of the text in pixels. Note that this distance should be
- slightly less than the available width to allow for characters such as "W"
- which can have side-bearings that leak into the margins.
-@param aFont The font that will provide the character metrics.
-@param aLineGap The number of empty pixels between two lines of text.
- Note that this is not the same as the baseline spacing, which is the font
- height plus the line gap.
-@param aMaxLines
- Number of lines to restrict wrapping to. The truncation character will be
- used if the text is too long for this number of lines. The number of lines
- wrapped to may be greater than the figure passed to NewL, and that figure
- will be used if the number of lines is specified as -1. If 0 (zero) is specified
- no limit is applied.
-@param aBreaker
- An object for breaking the lines. May be NULL for default behaviour.
-*/
-EXPORT_C TSize TBidiText::MinimumSize(TInt aWrappingWidth, const CFont& aFont, TInt aLineGap,
- TInt aMaxLines, const MLineBreaker* aBreaker) const
- {
- __ASSERT_ALWAYS(0 <= aWrappingWidth, BidiPanic(EBidiPanic_InvalidWrappingWidth));
- __ASSERT_ALWAYS(0 <= aLineGap, BidiPanic(EBidiPanic_InvalidLineGap));
- __ASSERT_ALWAYS(-1 <= aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
-
- TInt numLines = 0;
- TText* output = NULL;
- const TInt minWidth = DoWrapText(aWrappingWidth,
- aFont,
- aBreaker,
- (aMaxLines = 0 ? KMaxTInt : aMaxLines),
- output,
- numLines,
- NULL);
- const TInt minHeight = (aFont.FontMaxHeight() + aLineGap) * numLines - aLineGap;
- return TSize(minWidth, minHeight);
- }
-
-
-TInt TBidiText::DoWrapText(TInt aWrappingWidth, const CFont& aFont, const MLineBreaker* aBreaker,
- TInt aMaxLines, TText*& aOutputText, TInt& aNumLines, TInt16* aLineWidthArray) const
- {
- MLineBreaker defaultBreaker;
- if (!aBreaker)
- aBreaker = &defaultBreaker;
-
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- if (me->iLines < aMaxLines)
- aMaxLines = me->iLines;
-
- const TRunInfoCompact* runArray = me->BidiRunArray();
- const TRunInfoCompact* runArrayEnd = runArray + me->iBidiRunArrayLength;
-
- const TText* input = me->LogicalText();
- const TInt inputLength = me->TextLength();
- TPtrC textDes(input, inputLength);
- const TText* output = me->VisualText();
-
- TRunInfoCompact::TReorderingContext context;
- context.iSource = input;
- context.iTruncation = 0xFFFF;
- context.iJoinsAtEnd = EFalse;
-
- TInt start = 0;
- CFont::TMeasureTextInput measureInput;
- measureInput.iMaxAdvance = aWrappingWidth;
- measureInput.iEndInputChar = FindEndOfThisLine(input, input + inputLength) - input;
- CFont::TMeasureTextOutput measureOutput;
- TBool truncated;
-
- TInt widestLineWidth = 0;
- TBool bLastLine = EFalse;
- for (aNumLines = 0; aNumLines != aMaxLines && start < inputLength; ++aNumLines)
- {
- truncated=EFalse;
- context.iJoinsAtStart = context.iJoinsAtEnd;
- if(aNumLines != 0 && aOutputText)
- *(aOutputText++) = KLineSeparator;
-
- measureInput.iStartInputChar = start;
- TInt advance = aFont.MeasureText(textDes, &measureInput, &measureOutput);
- TInt breakPos = measureOutput.iChars;
- TInt endOfLine = breakPos;
- // truncationCharWidth is the width of any truncation character on this
- // line only.
- TInt truncationCharWidth = 0;
- if (endOfLine == measureInput.iEndInputChar)
- {
- //handle the dangling lines here
- TInt sizeLineBreak = SizeLineBreak(input + endOfLine, input + inputLength);
- if((measureInput.iEndInputChar < inputLength - sizeLineBreak) && (aNumLines == aMaxLines - 1))
- bLastLine = ETrue;
- }
- else if (aNumLines == aMaxLines - 1)
- {
- bLastLine = ETrue;
- }
- else
- { // Not last line, so find a legal line break.
- aBreaker->GetLineBreak(textDes,
- start + 1,
- measureOutput.iChars,
- EFalse,
- 0,
- breakPos,
- endOfLine);
- }
-
- if (bLastLine)
- {
- // Last line, so re-measure leaving enough room for
- // truncation character.
- context.iTruncation = me->TruncationChar();
- truncationCharWidth = aFont.CharWidthInPixels(context.iTruncation);
- measureInput.iMaxAdvance = aWrappingWidth - truncationCharWidth;
- advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
- breakPos = RemoveTrailingSpaces(aBreaker, input, start, measureOutput.iChars);
- truncated=ETrue;
- bLastLine = EFalse;
- }
-
- // if the break position has changed, we need to remeasure
- if (breakPos != measureOutput.iChars)
- {
- const TInt oldEnd = measureInput.iEndInputChar;
- measureInput.iEndInputChar = breakPos;
- advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
- measureInput.iEndInputChar = oldEnd;
- truncated=ETrue;
- }
-
- //width may be greater than advance
- advance = Max(advance,measureOutput.iBounds.Width());
-
- if(widestLineWidth < advance)
- widestLineWidth = advance;
-
- if(aLineWidthArray)
- *(aLineWidthArray++) = static_cast<TInt16>(advance);
-
- context.iStart = start;
- context.iEnd = breakPos;
- if (truncated)
- {
- context.iJoinsAtEnd = breakPos < inputLength?
- TRunInfoCompact::JoinBefore(input, breakPos) : EFalse;
- }
- else
- {
- context.iJoinsAtEnd = endOfLine < inputLength?
- TRunInfoCompact::JoinBefore(input, endOfLine) : EFalse;
- }
- if (aOutputText)
- {
- for (const TRunInfoCompact* p = runArray; p != runArrayEnd; ++p)
- aOutputText = p->Reorder(aOutputText, context);
- }
- // Set 'start' to the beginning of the next line...
- start = endOfLine;
-
- // ...move it past any line break...
- const TInt sizeOfLineBreak = SizeLineBreak(input + start, input + inputLength);
- if (sizeOfLineBreak != 0)
- {
- start += sizeOfLineBreak;
- // ...and find the end of this next line.
- const TText* endLine = FindEndOfThisLine(input + start, input + inputLength);
- measureInput.iEndInputChar = endLine - input;
- }
- }
-
- return widestLineWidth;
- }
-
-
-/** Prepares the visually-ordered text according to the wrapping width and font
-specified. Text cannot be drawn until this has been done.
-
-@param aWrappingWidth The maximum width of the text in pixels. Note that this
-distance should be slightly less than the available width to allow for characters
-such as "W" which can have side-bearings that leak into the margins.
-@param aFont The font that will provide the character metrics.
-@param aBreaker An object for breaking the lines. May be NULL for default behaviour. */
-EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
- const MLineBreaker* aBreaker)
- {
- WrapText(aWrappingWidth, aFont, aBreaker, KMaxTInt);
- }
-
-/** Returns the original logically-ordered text supplied in the constructor.
-@return The original logically-ordered text supplied in the constructor. */
-EXPORT_C TPtrC TBidiText::Text() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- const TText* text = me->LogicalText();
- return TPtrC(text, me->TextLength());
- }
-
-/** Returns the text as prepared for display, provided that WrapText has been called.
-If WrapText has not been called, a panic will result.
-
-@return The text as prepared for display */
-EXPORT_C TPtrC TBidiText::DisplayText() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
- const TText* text = me->VisualText();
- return TPtrC(text, me->iVisualOrderedTextLength);
- }
-
-/** Returns the wrapping width previously supplied to WrapText.
-
-@return The wrapping. */
-EXPORT_C TInt TBidiText::WrappingWidth() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- return me->iWrappingWidth;
- }
-
-/** Returns the directionality of the text.
-
-@return The directionality. */
-EXPORT_C TBidiText::TDirectionality TBidiText::Directionality() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- return me->HasRightToLeftDirectionality() ? ERightToLeft : ELeftToRight;
- }
-
-/** Returns the truncation character used.
-
-@return The truncation character. */
-EXPORT_C TChar TBidiText::TruncationChar() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- return me->TruncationChar();
- }
-
-/** Reports the number of lines in the text to be drawn.
-
-WrapText must have been called already.
-@return
- The number of lines in the text which would be drawn by DrawText.
-*/
-EXPORT_C TInt TBidiText::NumberOfLinesInDisplayText() const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- if (me->iVisualOrderedTextLength <0)
- {
- return 0;
- }
- const TText* text = me->VisualText();
- const TText* textEnd = text + me->iVisualOrderedTextLength;
- return NumberOfLines(text, textEnd);
- }
-
-/** Returns the text as prepared for display, provided that WrapText has been called.
-If WrapText has not been called, a panic will result.
-@param aLine Line number to retrieve.
-@param aWidth Returns the width in pixels of the line retrieved.
-@return The text as prepared for display. */
-EXPORT_C TPtrC TBidiText::LineOfDisplayText(TInt aLine, TInt& aWidthInPixels) const
- {
- const TBidiTextImp* me = TBidiTextImp::Imp(this);
- __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
- __ASSERT_ALWAYS(0 <= aLine && aLine < me->iLines, BidiPanic(EBidiPanic_InvalidLineNumber));
- aWidthInPixels = me->LineWidthArray()[aLine];
- const TText* text = me->VisualText();
- const TText* textEnd = text + me->iVisualOrderedTextLength;
- for (; aLine != 0; --aLine)
- {
- text = FindEndOfThisLine(text, textEnd);
- text += SizeLineBreak(text, textEnd);
- }
- const TText* endOfLine = FindEndOfThisLine(text, textEnd);
- return TPtrC(text, endOfLine - text);
- }
-
-/** Draws all of the text. WrapText must have been called already.
-
-@param aGc The graphics context to draw the text to. The graphics context's
-font is assumed to have been set to the same font that was passed to the previous
-call to WrapText.
-@param aLeft The left extreme of the baseline. Note that this should not be
-at the very edge of the available space, or characters such as "W" with left
-side bearings may be truncated.
-@param aBaseLineSpacing The spacing between each line. If 0, only the first
-line is drawn.
-@param aAlignment How to position the text horizontally. */
-EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
- TInt aBaseLineSpacing, CGraphicsContext::TTextAlign aAlignment) const
- {
- TPoint origin;
- origin.iY = aLeft.iY;
- TInt lines = aBaseLineSpacing == 0? 1 : NumberOfLinesInDisplayText();
- TInt wrappingWidth = WrappingWidth();
- for (TInt i = 0; i != lines; ++i)
- {
- TInt width;
- TPtrC textLine = LineOfDisplayText(i, width);
- origin.iX = aLeft.iX;
- if (aAlignment != CGraphicsContext::ELeft)
- {
- TInt excess = wrappingWidth - width;
- origin.iX += aAlignment != CGraphicsContext::ECenter?
- excess : excess >> 1;
- }
- aGc.DrawText(textLine, origin);
- origin.iY += aBaseLineSpacing;
- }
- }
-
-/** Draws all of the text. Alignment is taken from the directionality of the text.
-WrapText must have been called already.
-
-@param aGc The graphics context to draw the text to. The graphics context's
-font is assumed to have been set to the same font that was passed to the previous
-call to WrapText.
-@param aLeft The left extreme of the baseline. Note that this should not be
-at the very edge of the available space, or characters such as "W" with left
-side bearings may be truncated.
-@param aBaseLineSpacing The spacing between each line. If 0, only the first
-line is drawn. */
-EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
- TInt aBaseLineSpacing) const
- {
- DrawText(aGc, aLeft, aBaseLineSpacing,
- Directionality() == ELeftToRight?
- CGraphicsContext::ELeft : CGraphicsContext::ERight);
- }
-
-/** Draws the first line of the text. WrapText must have been called already. Alignment
-is taken from the directionality of the text.
-
-@param aGc The graphics context to draw the text to. The graphics context's
-font is assumed to have been set to the same font that was passed to the previous
-call to WrapText.
-@param aLeft The left extreme of the baseline. Note that this should not be
-at the very edge of the available space, or characters such as "W" with left
-side bearings may be truncated. */
-EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft) const
- {
- DrawText(aGc, aLeft, 0);
- }
-