Update contrib.
1 // Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include "BidiTextImp.h"
19 #include "BidiCompact.h"
22 //#include <textbase.h>
24 #include <linebreak.h>
26 _LIT(KBidiPanicCategory,"Bidi");
27 static const TInt KLineSeparator = 0x2028;
28 static const TInt KParagraphSeparator = 0x2029;
29 static const TInt KCodeCR = 0x000D;
30 static const TInt KCodeLF = 0x000A;
31 static const TInt KCodeEllipsis = 0x2026;
33 void DeleteTRunInfo(void* aRunInfo)
35 delete[] reinterpret_cast<TBidirectionalState::TRunInfo*>(aRunInfo);
38 void BidiPanic(TInt aError)
40 User::Panic(KBidiPanicCategory, aError);
44 // One page-full of TRunInfos
45 const TInt KMaxRunInfoArraySize = 4*1024 / sizeof(TBidirectionalState::TRunInfo);
46 const TInt KBidiTlsHandle = 0x101F633D;
50 * Ref-counted TLS for the shared run info array used by the SetText() method.
52 NONSHARABLE_CLASS(CBidiTextTls) : public CObject
55 static CBidiTextTls* NewL();
56 static CBidiTextTls* GetTls();
58 inline TUint MaxArraySize();
59 inline TBidirectionalState::TRunInfo* RunArray();
63 void ConstructL(TUint aMaxArraySize);
66 TBidirectionalState::TRunInfo* iRunInfoArray;
72 CBidiTextTls::CBidiTextTls()
73 : iRunInfoArray(NULL),
79 CBidiTextTls::~CBidiTextTls()
81 UserSvr::DllFreeTls(KBidiTlsHandle);
85 delete [] iRunInfoArray;
90 TUint CBidiTextTls::MaxArraySize()
96 TBidirectionalState::TRunInfo* CBidiTextTls::RunArray()
103 * Helper function provided to simplify reading the TLS data and improve the
104 * readability of the code
106 CBidiTextTls* CBidiTextTls::GetTls()
108 return reinterpret_cast<CBidiTextTls*>(UserSvr::DllTls(KBidiTlsHandle));
112 CBidiTextTls* CBidiTextTls::NewL()
114 CBidiTextTls* self = new (ELeave) CBidiTextTls;
115 CleanupClosePushL(*self);
116 self->ConstructL(KMaxRunInfoArraySize);
117 CleanupStack::Pop(self);
122 void CBidiTextTls::ConstructL(TUint aMaxArraySize)
124 iMaxArraySize = aMaxArraySize;
125 iRunInfoArray = new (ELeave) TBidirectionalState::TRunInfo[aMaxArraySize];
126 User::LeaveIfError(UserSvr::DllSetTls(KBidiTlsHandle, this));
130 EXPORT_C RRunInfoArray::RRunInfoArray()
137 Creates the run array if necessary and increases the reference count on it.
138 RRunInfoArray::OpenL() must be called prior to calling TBidiText::SetText().
140 EXPORT_C void RRunInfoArray::OpenL()
144 iTls = CBidiTextTls::GetTls();
147 iTls->Open(); // Increase ref count
151 iTls = CBidiTextTls::NewL();
158 Decreases the reference count on the run array. The run array will be deleted
159 if the reference count reaches zero. The client application must ensure that
160 there is a matching call to Close() for every call to OpenL() or memory will
163 EXPORT_C void RRunInfoArray::Close()
174 @return Pointer to the run array buffer
177 TBidirectionalState::TRunInfo* RRunInfoArray::RunArray() const
179 return iTls ? iTls->RunArray() : NULL;
184 @return Number of bytes needed to hold the TBidiTextImp member variables, plus the
185 text data allocated off the end of the TBidiTextImp object.
188 TInt TBidiTextImp::RequiredBytes(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
190 // size of TBidiTextImp class
191 TInt bytes = TBidiTextImp::AlignedSizeOf();
192 // size of text for logical and visual orderings.
193 // This includes aMaxLines - 1 line breaks with surrounding
194 // zero-width joiners, and a truncation character (possibly
195 // a surrogate pair) plus a zero-width joiner.
196 bytes += sizeof(TText) * (aLength * 2 + aMaxLines * 3);
197 // size of line length array
198 bytes += sizeof(TInt16*) * aMaxLines;
200 bytes = (bytes + 3) & 0xFFFFFFFC;
201 // array of TRunInfoCompact
202 bytes += sizeof(TRunInfoCompact) * aBdRunArraySize;
209 @return A TBidiTextImp object of sufficient size to hold the amount of text data specified
210 by the the arguments.
211 @param aLength The number of characters in the text.
212 @param aMaxLines The maximum number of lines
213 @param aBdRunArraySize The size of the bidi run array.
216 TBidiTextImp* TBidiTextImp::NewL(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
218 const TInt bytes = RequiredBytes(aLength, aMaxLines, aBdRunArraySize);
219 TInt8* mem = static_cast<TInt8*>(User::AllocL(bytes));
220 TBidiTextImp* me = reinterpret_cast<TBidiTextImp*>(mem);
222 me->iTextLengthAndFlags = aLength;
223 me->iVisualOrderedTextLength = -1;
224 me->iWrappingWidth = 0xFFFF;
225 me->iBidiRunArrayLength = aBdRunArraySize;
226 me->iLines = static_cast<TUint8>(aMaxLines);
227 me->iTruncationCharPlane = 0;
228 me->iTruncationChar16 = KCodeEllipsis;
229 me->SetAllocatedTextDataBytes(bytes - TBidiTextImp::AlignedSizeOf() - (sizeof(TRunInfoCompact) * aBdRunArraySize));
234 @return Position of logically-ordered text portion of the heap cell.
237 TText* TBidiTextImp::LogicalText()
239 return reinterpret_cast<TText*>(
240 reinterpret_cast<TInt8*>(this)
241 + TBidiTextImp::AlignedSizeOf());
245 @return Position of visually-ordered text portion of the heap cell.
248 TText* TBidiTextImp::VisualText()
250 TInt bytes = TBidiTextImp::AlignedSizeOf();
251 bytes += sizeof(TText) * TextLength();
252 return reinterpret_cast<TText*>(
253 reinterpret_cast<TInt8*>(this) + bytes);
257 Returns a pointer to the array containing the width in pixels of each and every line.
258 @return Position of the array of line widths portion of the heap cell.
261 TInt16* TBidiTextImp::LineWidthArray()
263 TInt bytes = TBidiTextImp::AlignedSizeOf();
264 bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
265 return reinterpret_cast<TInt16*>(
266 reinterpret_cast<TInt8*>(this) + bytes);
270 @return Position of the array of runs portion of the heap cell.
273 TRunInfoCompact* TBidiTextImp::BidiRunArray()
275 TInt bytes = TBidiTextImp::AlignedSizeOf();
276 bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
277 bytes += sizeof(TInt16*) * iLines;
278 bytes = (bytes + 3) & 0xFFFFFFFC;
279 return reinterpret_cast<TRunInfoCompact*>(
280 reinterpret_cast<TInt8*>(this) + bytes);
284 Report if the current character is an explicit line break. Both
285 aText[0] and aText[1] must be part of the string.
286 @return Size of line break.
289 TInt SizeLineBreak(const TText* aText, const TText* aTextEnd)
291 if (aText == aTextEnd )
294 if (*aText == KLineSeparator || *aText == KParagraphSeparator
295 || *aText == KCodeLF)
297 if (aText[0] == KCodeCR)
299 // first check for space before checking for LF
300 if (aText+1 < aTextEnd )
302 return aText[1] == KCodeLF? 2 : 1;
311 Find the next line break character.
314 const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd)
316 while (aStart != aEnd && *aStart != KLineSeparator
317 && *aStart != KParagraphSeparator && *aStart != KCodeLF
318 && *aStart != KCodeCR)
324 Count number of lines in text.
327 TInt NumberOfLines(const TText* aStart, const TText* aEnd)
330 while (aStart != aEnd)
332 aStart = FindEndOfThisLine(aStart, aEnd);
333 aStart += SizeLineBreak(aStart, aEnd);
339 /** Returns the directionality of a given language.
340 @param aLanguage Language.
341 @return The directionality of the given language. */
342 EXPORT_C TBidiText::TDirectionality TBidiText::ScriptDirectionality(
345 const TUint32 DirectionalityBitmap[] =
348 // Arabic, Farsi, Hebrew
353 TUint index = aLanguage;
354 if (index < sizeof(DirectionalityBitmap) * 8)
357 TInt bit = aLanguage & 31;
358 return (DirectionalityBitmap[index] >> bit) & 1?
359 ERightToLeft : ELeftToRight;
365 /** Reports the implicit directionality of a piece of text.
367 @param aText The text to be examined.
368 @param aFound If non-null, returns ETrue if there were any strongly directional
369 characters and EFalse if there were none. If a piece of text is spread over
370 several descriptors, They need to be queried in sequence until one returns
372 @return The directionality implicit in aText. 131 */
373 EXPORT_C TBidiText::TDirectionality TBidiText::TextDirectionality(
374 const TDesC& aText, TBool* aFound)
376 return BidiCopy::ImplicitDirectionalityIsRightToLeft(
377 aText.Ptr(), aText.Length(), aFound)?
378 ERightToLeft : ELeftToRight;
381 /** Creates a bidirectional text object with directionality determined by
382 aDirectionality. Use this for text that has come from user input.
384 @param aText The text in logical order.
386 The maximum number of lines that this text will need to be split into. Must
387 be at least 1, but should not be too large, as each potential line takes an
388 extra 8 bytes of memory.
389 @param aDirectionality Direction to use.
390 @return The newly constructed object.
392 EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines,
393 TBidiText::TDirectionality aDirectionality)
395 __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
396 const TText* text = aText.Ptr();
397 const TInt length = aText.Length();
398 TInt linesInOriginalText = NumberOfLines(text, text + length);
399 if (aMaxLines < linesInOriginalText)
400 aMaxLines = linesInOriginalText;
402 const TInt arraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
403 TBidirectionalState::TRunInfo* runInfoArray = new(ELeave) TBidirectionalState::TRunInfo[arraySize];
404 TCleanupItem ci(DeleteTRunInfo, runInfoArray);
405 CleanupStack::PushL(ci);
406 TBidirectionalState::GenerateBdRunArray(text, length, runInfoArray, arraySize);
407 TBidirectionalState state;
408 state.ReorderLine(runInfoArray, arraySize, ETrue, ETrue, aDirectionality,
409 TChar::EOtherNeutral, TChar::EOtherNeutral);
410 TInt compactArraySize = TRunInfoCompact::Convert(0, aText, runInfoArray, arraySize);
412 // size of TBidiTextImp class
413 TBidiTextImp* me = TBidiTextImp::NewL(length, aMaxLines, compactArraySize);
414 me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
416 TRunInfoCompact::Convert(me->BidiRunArray(), aText, runInfoArray, arraySize);
417 CleanupStack::PopAndDestroy(runInfoArray);
419 Mem::Copy(me->LogicalText(), text, length * sizeof(TText));
423 /** Creates a bidirectional text object with directionality determined by the text
424 itself. Use this for text that has been obtained from a resource file.
426 @param aText The text in logical order.
427 @param aMaxLines The maximum number of lines that this text will need to be
428 split into. Must be at least 1, but should not be too large, as each potential
429 line takes an extra 8 bytes of memory.
430 @return The newly constructed object. */
431 EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines)
433 return NewL(aText, aMaxLines, TextDirectionality(aText));
437 /** Creates a bidirectional text object with enough room for up to aReservedMaxLength
438 number of characters. The number of characters that will actually fit (when calling
439 SetText()) might be slightly less than aReservedMaxLength, as each change between a
440 left-to-right and a right-to-left sub-string (and the other way around) needs about
441 two characters worth of memory.
443 @param aReservedMaxLength The maximum number of characters.
444 @param aMaxLines The maximum number of lines that this text will need to be
445 split into. Must be at least 1, but should not be too large, as each potential
446 line takes an extra 8 bytes of memory.
447 @return The newly constructed object. */
448 EXPORT_C TBidiText* TBidiText::NewL(TInt aReservedMaxLength, TInt aMaxLines)
450 __ASSERT_ALWAYS(0 < aReservedMaxLength, BidiPanic(EBidiPanic_InvalidReservedMaxLength));
451 __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
453 const TInt compactArraySize = 1; // Always at least one needed
455 TBidiTextImp* me = TBidiTextImp::NewL(aReservedMaxLength, aMaxLines, compactArraySize);
456 me->SetTextLength(0); // no text yet, just reserved memory
460 /** Sets the text of the bidirectional text object with directionality determined
461 by the text itself. Use this for text that has been obtained from a resource file.
463 @param aText The text in logical order.
464 @return The number of characters that didn't fit in the available buffer.
466 EXPORT_C TInt TBidiText::SetText(const TDesC& aText, RRunInfoArray& aRunInfoArray)
468 return SetText(aText, TextDirectionality(aText), aRunInfoArray);
472 /** Sets the text of the bidirectional text with directionality determined by
473 aDirectionality. Use this for text that has come from user input.
475 @param aText The text in logical order.
476 @param aDirectionality Direction to use.
477 @return The number of characters that didn't fit in the available buffer.
478 @panic Bidi EBidiPanic_RunArrayNull The call to RRunInfoArray::OpenL() has not
479 been made prior to this call to TBidiText::SetText()
481 EXPORT_C TInt TBidiText::SetText(const TDesC& aText,
482 TDirectionality aDirectionality,
483 RRunInfoArray& aRunInfoArray)
485 TBidirectionalState::TRunInfo* const runArray = aRunInfoArray.RunArray();
486 __ASSERT_ALWAYS(runArray, BidiPanic(EBidiPanic_RunArrayNull));
488 TBidiTextImp* me = TBidiTextImp::Imp(this);
489 const TInt maxLines = me->iLines;
490 const TText* text = aText.Ptr();
491 TInt length = aText.Length();
493 TInt requiredArraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
494 const TInt actualArraySize = aRunInfoArray.iTls->MaxArraySize();
496 if (requiredArraySize > actualArraySize)
498 // Handle the case where we do not have enough space in the run array
499 // to cope with the input text. The text will be truncated to ensure
500 // we don't overrun the buffer and the number of excess characters
501 // returned as a negative number.
502 requiredArraySize = actualArraySize;
503 TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
506 for (TInt index = 0; index < requiredArraySize; index++)
508 length += runArray[index].iLength;
513 TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
518 TBidirectionalState state;
519 state.ReorderLine(runArray,
524 TChar::EOtherNeutral,
525 TChar::EOtherNeutral);
526 const TInt compactArraySize = TRunInfoCompact::Convert(0,
531 // Calculate number of bytes needed to keep text data
532 TInt requiredBytes = sizeof(TText) * (length * 2 + maxLines * 3); // size of text for logical & visual orderings.
533 requiredBytes += sizeof(TInt16*) * maxLines; // size of line length array
534 requiredBytes = (requiredBytes + 3) & 0xFFFFFFFC; // alignment
536 TInt textLength = length;
537 const TInt excessData = Max(0, requiredBytes - me->AllocatedTextDataBytes());
538 TInt excessChars = 0;
541 // Calculate how much text data that can be fitted into the available bytes,
542 // given the bytes needed for run array data
543 excessChars = excessData / (sizeof(TText) * 2);
544 textLength -= excessChars;
546 else if (aText.Length() > length)
548 excessChars = aText.Length() - length;
551 me->SetTextLength(textLength);
552 me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
553 me->iVisualOrderedTextLength = -1;
554 me->iBidiRunArrayLength = static_cast<TUint16>(compactArraySize);
556 TRunInfoCompact::Convert(me->BidiRunArray(), aText, runArray, requiredArraySize);
557 Mem::Copy(me->LogicalText(), text, textLength * sizeof(TText));
562 /** Sets the character that will be added at the end of the text if the whole text
563 cannot fit into the space specified.
565 @param aTruncateWith The truncation char. */
566 EXPORT_C void TBidiText::SetTruncationChar(TChar aTruncateWith)
568 TBidiTextImp* me = TBidiTextImp::Imp(this);
569 me->iTruncationCharPlane = static_cast<TUint8>(aTruncateWith >> 16);
570 me->iTruncationChar16 = static_cast<TUint16>(aTruncateWith);
573 TInt RemoveTrailingSpaces(const MLineBreaker* aBreaker,
574 const TText* aInput, TInt aMinPos, TInt aEndPos)
576 // Ignore space characters at the end of the line.
577 // Don't bother to ignore spaces made of surrogate pairs:
578 // more processing than it's worth.
579 TUint dummy1, dummy2;
580 while (aEndPos != aMinPos && MLineBreaker::ESpLineBreakClass
581 == aBreaker->LineBreakClass(aInput[aEndPos - 1], dummy1, dummy2))
588 /** Prepares the visually-ordered text according to the wrapping width and font
589 specified. Text cannot be drawn until this has been done.
590 @param aWrappingWidth
591 The maximum width of the text in pixels. Note that this distance should be
592 slightly less than the available width to allow for characters such as "W"
593 which can have side-bearings that leak into the margins.
594 @param aFont The font that will provide the character metrics.
596 An object for breaking the lines. May be NULL for default behaviour.
598 Number of lines to restrict wrapping to. The truncation character will be
599 used if the text is too long for this number of lines. The number of lines
600 wrapped to may not be greater than the figure passed to NewL.
602 EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
603 const MLineBreaker* aBreaker, TInt aMaxLines)
605 TBidiTextImp* me = TBidiTextImp::Imp(this);
606 me->iWrappingWidth = aWrappingWidth;
608 TInt16* lineWidths = me->LineWidthArray();
609 TText* output = me->VisualText();
612 DoWrapText(aWrappingWidth, aFont, aBreaker, aMaxLines, output, numLines, lineWidths);
613 me->iVisualOrderedTextLength = output - me->VisualText();
616 /** Calculate the minimum size needed to draw the current text, given the specified
617 wrapping width, font, and line gap. Calling this method will not rewrap the object's
620 @param aWrappingWidth
621 The maximum width of the text in pixels. Note that this distance should be
622 slightly less than the available width to allow for characters such as "W"
623 which can have side-bearings that leak into the margins.
624 @param aFont The font that will provide the character metrics.
625 @param aLineGap The number of empty pixels between two lines of text.
626 Note that this is not the same as the baseline spacing, which is the font
627 height plus the line gap.
629 Number of lines to restrict wrapping to. The truncation character will be
630 used if the text is too long for this number of lines. The number of lines
631 wrapped to may be greater than the figure passed to NewL, and that figure
632 will be used if the number of lines is specified as -1. If 0 (zero) is specified
635 An object for breaking the lines. May be NULL for default behaviour.
637 EXPORT_C TSize TBidiText::MinimumSize(TInt aWrappingWidth, const CFont& aFont, TInt aLineGap,
638 TInt aMaxLines, const MLineBreaker* aBreaker) const
640 __ASSERT_ALWAYS(0 <= aWrappingWidth, BidiPanic(EBidiPanic_InvalidWrappingWidth));
641 __ASSERT_ALWAYS(0 <= aLineGap, BidiPanic(EBidiPanic_InvalidLineGap));
642 __ASSERT_ALWAYS(-1 <= aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
645 TText* output = NULL;
646 const TInt minWidth = DoWrapText(aWrappingWidth,
649 (aMaxLines = 0 ? KMaxTInt : aMaxLines),
653 const TInt minHeight = (aFont.FontMaxHeight() + aLineGap) * numLines - aLineGap;
654 return TSize(minWidth, minHeight);
658 TInt TBidiText::DoWrapText(TInt aWrappingWidth, const CFont& aFont, const MLineBreaker* aBreaker,
659 TInt aMaxLines, TText*& aOutputText, TInt& aNumLines, TInt16* aLineWidthArray) const
661 MLineBreaker defaultBreaker;
663 aBreaker = &defaultBreaker;
665 const TBidiTextImp* me = TBidiTextImp::Imp(this);
666 if (me->iLines < aMaxLines)
667 aMaxLines = me->iLines;
669 const TRunInfoCompact* runArray = me->BidiRunArray();
670 const TRunInfoCompact* runArrayEnd = runArray + me->iBidiRunArrayLength;
672 const TText* input = me->LogicalText();
673 const TInt inputLength = me->TextLength();
674 TPtrC textDes(input, inputLength);
675 const TText* output = me->VisualText();
677 TRunInfoCompact::TReorderingContext context;
678 context.iSource = input;
679 context.iTruncation = 0xFFFF;
680 context.iJoinsAtEnd = EFalse;
683 CFont::TMeasureTextInput measureInput;
684 measureInput.iMaxAdvance = aWrappingWidth;
685 measureInput.iEndInputChar = FindEndOfThisLine(input, input + inputLength) - input;
686 CFont::TMeasureTextOutput measureOutput;
689 TInt widestLineWidth = 0;
690 TBool bLastLine = EFalse;
691 for (aNumLines = 0; aNumLines != aMaxLines && start < inputLength; ++aNumLines)
694 context.iJoinsAtStart = context.iJoinsAtEnd;
695 if(aNumLines != 0 && aOutputText)
696 *(aOutputText++) = KLineSeparator;
698 measureInput.iStartInputChar = start;
699 TInt advance = aFont.MeasureText(textDes, &measureInput, &measureOutput);
700 TInt breakPos = measureOutput.iChars;
701 TInt endOfLine = breakPos;
702 // truncationCharWidth is the width of any truncation character on this
704 TInt truncationCharWidth = 0;
705 if (endOfLine == measureInput.iEndInputChar)
707 //handle the dangling lines here
708 TInt sizeLineBreak = SizeLineBreak(input + endOfLine, input + inputLength);
709 if((measureInput.iEndInputChar < inputLength - sizeLineBreak) && (aNumLines == aMaxLines - 1))
712 else if (aNumLines == aMaxLines - 1)
717 { // Not last line, so find a legal line break.
718 aBreaker->GetLineBreak(textDes,
720 measureOutput.iChars,
729 // Last line, so re-measure leaving enough room for
730 // truncation character.
731 context.iTruncation = me->TruncationChar();
732 truncationCharWidth = aFont.CharWidthInPixels(context.iTruncation);
733 measureInput.iMaxAdvance = aWrappingWidth - truncationCharWidth;
734 advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
735 breakPos = RemoveTrailingSpaces(aBreaker, input, start, measureOutput.iChars);
740 // if the break position has changed, we need to remeasure
741 if (breakPos != measureOutput.iChars)
743 const TInt oldEnd = measureInput.iEndInputChar;
744 measureInput.iEndInputChar = breakPos;
745 advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
746 measureInput.iEndInputChar = oldEnd;
750 //width may be greater than advance
751 advance = Max(advance,measureOutput.iBounds.Width());
753 if(widestLineWidth < advance)
754 widestLineWidth = advance;
757 *(aLineWidthArray++) = static_cast<TInt16>(advance);
759 context.iStart = start;
760 context.iEnd = breakPos;
763 context.iJoinsAtEnd = breakPos < inputLength?
764 TRunInfoCompact::JoinBefore(input, breakPos) : EFalse;
768 context.iJoinsAtEnd = endOfLine < inputLength?
769 TRunInfoCompact::JoinBefore(input, endOfLine) : EFalse;
773 for (const TRunInfoCompact* p = runArray; p != runArrayEnd; ++p)
774 aOutputText = p->Reorder(aOutputText, context);
776 // Set 'start' to the beginning of the next line...
779 // ...move it past any line break...
780 const TInt sizeOfLineBreak = SizeLineBreak(input + start, input + inputLength);
781 if (sizeOfLineBreak != 0)
783 start += sizeOfLineBreak;
784 // ...and find the end of this next line.
785 const TText* endLine = FindEndOfThisLine(input + start, input + inputLength);
786 measureInput.iEndInputChar = endLine - input;
790 return widestLineWidth;
794 /** Prepares the visually-ordered text according to the wrapping width and font
795 specified. Text cannot be drawn until this has been done.
797 @param aWrappingWidth The maximum width of the text in pixels. Note that this
798 distance should be slightly less than the available width to allow for characters
799 such as "W" which can have side-bearings that leak into the margins.
800 @param aFont The font that will provide the character metrics.
801 @param aBreaker An object for breaking the lines. May be NULL for default behaviour. */
802 EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
803 const MLineBreaker* aBreaker)
805 WrapText(aWrappingWidth, aFont, aBreaker, KMaxTInt);
808 /** Returns the original logically-ordered text supplied in the constructor.
809 @return The original logically-ordered text supplied in the constructor. */
810 EXPORT_C TPtrC TBidiText::Text() const
812 const TBidiTextImp* me = TBidiTextImp::Imp(this);
813 const TText* text = me->LogicalText();
814 return TPtrC(text, me->TextLength());
817 /** Returns the text as prepared for display, provided that WrapText has been called.
818 If WrapText has not been called, a panic will result.
820 @return The text as prepared for display */
821 EXPORT_C TPtrC TBidiText::DisplayText() const
823 const TBidiTextImp* me = TBidiTextImp::Imp(this);
824 __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
825 const TText* text = me->VisualText();
826 return TPtrC(text, me->iVisualOrderedTextLength);
829 /** Returns the wrapping width previously supplied to WrapText.
831 @return The wrapping. */
832 EXPORT_C TInt TBidiText::WrappingWidth() const
834 const TBidiTextImp* me = TBidiTextImp::Imp(this);
835 return me->iWrappingWidth;
838 /** Returns the directionality of the text.
840 @return The directionality. */
841 EXPORT_C TBidiText::TDirectionality TBidiText::Directionality() const
843 const TBidiTextImp* me = TBidiTextImp::Imp(this);
844 return me->HasRightToLeftDirectionality() ? ERightToLeft : ELeftToRight;
847 /** Returns the truncation character used.
849 @return The truncation character. */
850 EXPORT_C TChar TBidiText::TruncationChar() const
852 const TBidiTextImp* me = TBidiTextImp::Imp(this);
853 return me->TruncationChar();
856 /** Reports the number of lines in the text to be drawn.
858 WrapText must have been called already.
860 The number of lines in the text which would be drawn by DrawText.
862 EXPORT_C TInt TBidiText::NumberOfLinesInDisplayText() const
864 const TBidiTextImp* me = TBidiTextImp::Imp(this);
865 if (me->iVisualOrderedTextLength <0)
869 const TText* text = me->VisualText();
870 const TText* textEnd = text + me->iVisualOrderedTextLength;
871 return NumberOfLines(text, textEnd);
874 /** Returns the text as prepared for display, provided that WrapText has been called.
875 If WrapText has not been called, a panic will result.
876 @param aLine Line number to retrieve.
877 @param aWidth Returns the width in pixels of the line retrieved.
878 @return The text as prepared for display. */
879 EXPORT_C TPtrC TBidiText::LineOfDisplayText(TInt aLine, TInt& aWidthInPixels) const
881 const TBidiTextImp* me = TBidiTextImp::Imp(this);
882 __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
883 __ASSERT_ALWAYS(0 <= aLine && aLine < me->iLines, BidiPanic(EBidiPanic_InvalidLineNumber));
884 aWidthInPixels = me->LineWidthArray()[aLine];
885 const TText* text = me->VisualText();
886 const TText* textEnd = text + me->iVisualOrderedTextLength;
887 for (; aLine != 0; --aLine)
889 text = FindEndOfThisLine(text, textEnd);
890 text += SizeLineBreak(text, textEnd);
892 const TText* endOfLine = FindEndOfThisLine(text, textEnd);
893 return TPtrC(text, endOfLine - text);
896 /** Draws all of the text. WrapText must have been called already.
898 @param aGc The graphics context to draw the text to. The graphics context's
899 font is assumed to have been set to the same font that was passed to the previous
901 @param aLeft The left extreme of the baseline. Note that this should not be
902 at the very edge of the available space, or characters such as "W" with left
903 side bearings may be truncated.
904 @param aBaseLineSpacing The spacing between each line. If 0, only the first
906 @param aAlignment How to position the text horizontally. */
907 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
908 TInt aBaseLineSpacing, CGraphicsContext::TTextAlign aAlignment) const
911 origin.iY = aLeft.iY;
912 TInt lines = aBaseLineSpacing == 0? 1 : NumberOfLinesInDisplayText();
913 TInt wrappingWidth = WrappingWidth();
914 for (TInt i = 0; i != lines; ++i)
917 TPtrC textLine = LineOfDisplayText(i, width);
918 origin.iX = aLeft.iX;
919 if (aAlignment != CGraphicsContext::ELeft)
921 TInt excess = wrappingWidth - width;
922 origin.iX += aAlignment != CGraphicsContext::ECenter?
923 excess : excess >> 1;
925 aGc.DrawText(textLine, origin);
926 origin.iY += aBaseLineSpacing;
930 /** Draws all of the text. Alignment is taken from the directionality of the text.
931 WrapText must have been called already.
933 @param aGc The graphics context to draw the text to. The graphics context's
934 font is assumed to have been set to the same font that was passed to the previous
936 @param aLeft The left extreme of the baseline. Note that this should not be
937 at the very edge of the available space, or characters such as "W" with left
938 side bearings may be truncated.
939 @param aBaseLineSpacing The spacing between each line. If 0, only the first
941 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
942 TInt aBaseLineSpacing) const
944 DrawText(aGc, aLeft, aBaseLineSpacing,
945 Directionality() == ELeftToRight?
946 CGraphicsContext::ELeft : CGraphicsContext::ERight);
949 /** Draws the first line of the text. WrapText must have been called already. Alignment
950 is taken from the directionality of the text.
952 @param aGc The graphics context to draw the text to. The graphics context's
953 font is assumed to have been set to the same font that was passed to the previous
955 @param aLeft The left extreme of the baseline. Note that this should not be
956 at the very edge of the available space, or characters such as "W" with left
957 side bearings may be truncated. */
958 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft) const
960 DrawText(aGc, aLeft, 0);