First public contribution.
1 // Copyright (c) 2002-2009 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"
23 #include <linebreak.h>
25 _LIT(KBidiPanicCategory,"Bidi");
26 static const TInt KLineSeparator = 0x2028;
27 static const TInt KParagraphSeparator = 0x2029;
28 static const TInt KCodeCR = 0x000D;
29 static const TInt KCodeLF = 0x000A;
30 static const TInt KCodeEllipsis = 0x2026;
32 void DeleteTRunInfo(void* aRunInfo)
34 delete[] reinterpret_cast<TBidirectionalState::TRunInfo*>(aRunInfo);
37 void BidiPanic(TInt aError)
39 User::Panic(KBidiPanicCategory, aError);
43 // One page-full of TRunInfos
44 const TInt KMaxRunInfoArraySize = 4*1024 / sizeof(TBidirectionalState::TRunInfo);
45 const TInt KBidiTlsHandle = 0x101F633D;
49 * Ref-counted TLS for the shared run info array used by the SetText() method.
51 NONSHARABLE_CLASS(CBidiTextTls) : public CObject
54 static CBidiTextTls* NewL();
55 static CBidiTextTls* GetTls();
57 inline TUint MaxArraySize();
58 inline TBidirectionalState::TRunInfo* RunArray();
62 void ConstructL(TUint aMaxArraySize);
65 TBidirectionalState::TRunInfo* iRunInfoArray;
71 CBidiTextTls::CBidiTextTls()
72 : iRunInfoArray(NULL),
78 CBidiTextTls::~CBidiTextTls()
80 UserSvr::DllFreeTls(KBidiTlsHandle);
84 delete [] iRunInfoArray;
89 TUint CBidiTextTls::MaxArraySize()
95 TBidirectionalState::TRunInfo* CBidiTextTls::RunArray()
102 * Helper function provided to simplify reading the TLS data and improve the
103 * readability of the code
105 CBidiTextTls* CBidiTextTls::GetTls()
107 return reinterpret_cast<CBidiTextTls*>(UserSvr::DllTls(KBidiTlsHandle));
111 CBidiTextTls* CBidiTextTls::NewL()
113 CBidiTextTls* self = new (ELeave) CBidiTextTls;
114 CleanupClosePushL(*self);
115 self->ConstructL(KMaxRunInfoArraySize);
116 CleanupStack::Pop(self);
121 void CBidiTextTls::ConstructL(TUint aMaxArraySize)
123 iMaxArraySize = aMaxArraySize;
124 iRunInfoArray = new (ELeave) TBidirectionalState::TRunInfo[aMaxArraySize];
125 User::LeaveIfError(UserSvr::DllSetTls(KBidiTlsHandle, this));
129 EXPORT_C RRunInfoArray::RRunInfoArray()
136 Creates the run array if necessary and increases the reference count on it.
137 RRunInfoArray::OpenL() must be called prior to calling TBidiText::SetText().
139 EXPORT_C void RRunInfoArray::OpenL()
143 iTls = CBidiTextTls::GetTls();
146 iTls->Open(); // Increase ref count
150 iTls = CBidiTextTls::NewL();
157 Decreases the reference count on the run array. The run array will be deleted
158 if the reference count reaches zero. The client application must ensure that
159 there is a matching call to Close() for every call to OpenL() or memory will
162 EXPORT_C void RRunInfoArray::Close()
173 @return Pointer to the run array buffer
176 TBidirectionalState::TRunInfo* RRunInfoArray::RunArray() const
178 return iTls ? iTls->RunArray() : NULL;
183 @return Number of bytes needed to hold the TBidiTextImp member variables, plus the
184 text data allocated off the end of the TBidiTextImp object.
187 TInt TBidiTextImp::RequiredBytes(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
189 // size of TBidiTextImp class
190 TInt bytes = TBidiTextImp::AlignedSizeOf();
191 // size of text for logical and visual orderings.
192 // This includes aMaxLines - 1 line breaks with surrounding
193 // zero-width joiners, and a truncation character (possibly
194 // a surrogate pair) plus a zero-width joiner.
195 bytes += sizeof(TText) * (aLength * 2 + aMaxLines * 3);
196 // size of line length array
197 bytes += sizeof(TInt16*) * aMaxLines;
199 bytes = (bytes + 3) & 0xFFFFFFFC;
200 // array of TRunInfoCompact
201 bytes += sizeof(TRunInfoCompact) * aBdRunArraySize;
208 @return A TBidiTextImp object of sufficient size to hold the amount of text data specified
209 by the the arguments.
210 @param aLength The number of characters in the text.
211 @param aMaxLines The maximum number of lines
212 @param aBdRunArraySize The size of the bidi run array.
215 TBidiTextImp* TBidiTextImp::NewL(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
217 const TInt bytes = RequiredBytes(aLength, aMaxLines, aBdRunArraySize);
218 TInt8* mem = static_cast<TInt8*>(User::AllocL(bytes));
219 TBidiTextImp* me = reinterpret_cast<TBidiTextImp*>(mem);
221 me->iTextLengthAndFlags = aLength;
222 me->iVisualOrderedTextLength = -1;
223 me->iWrappingWidth = 0xFFFF;
224 me->iBidiRunArrayLength = aBdRunArraySize;
225 me->iLines = static_cast<TUint8>(aMaxLines);
226 me->iTruncationCharPlane = 0;
227 me->iTruncationChar16 = KCodeEllipsis;
228 me->SetAllocatedTextDataBytes(bytes - TBidiTextImp::AlignedSizeOf() - (sizeof(TRunInfoCompact) * aBdRunArraySize));
233 @return Position of logically-ordered text portion of the heap cell.
236 TText* TBidiTextImp::LogicalText()
238 return reinterpret_cast<TText*>(
239 reinterpret_cast<TInt8*>(this)
240 + TBidiTextImp::AlignedSizeOf());
244 @return Position of visually-ordered text portion of the heap cell.
247 TText* TBidiTextImp::VisualText()
249 TInt bytes = TBidiTextImp::AlignedSizeOf();
250 bytes += sizeof(TText) * TextLength();
251 return reinterpret_cast<TText*>(
252 reinterpret_cast<TInt8*>(this) + bytes);
256 Returns a pointer to the array containing the width in pixels of each and every line.
257 @return Position of the array of line widths portion of the heap cell.
260 TInt16* TBidiTextImp::LineWidthArray()
262 TInt bytes = TBidiTextImp::AlignedSizeOf();
263 bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
264 return reinterpret_cast<TInt16*>(
265 reinterpret_cast<TInt8*>(this) + bytes);
269 @return Position of the array of runs portion of the heap cell.
272 TRunInfoCompact* TBidiTextImp::BidiRunArray()
274 TInt bytes = TBidiTextImp::AlignedSizeOf();
275 bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
276 bytes += sizeof(TInt16*) * iLines;
277 bytes = (bytes + 3) & 0xFFFFFFFC;
278 return reinterpret_cast<TRunInfoCompact*>(
279 reinterpret_cast<TInt8*>(this) + bytes);
283 Report if the current character is an explicit line break. Both
284 aText[0] and aText[1] must be part of the string.
285 @return Size of line break.
288 TInt SizeLineBreak(const TText* aText, const TText* aTextEnd)
290 if (aText == aTextEnd )
293 if (*aText == KLineSeparator || *aText == KParagraphSeparator
294 || *aText == KCodeLF)
296 if (aText[0] == KCodeCR)
298 // first check for space before checking for LF
299 if (aText+1 < aTextEnd )
301 return aText[1] == KCodeLF? 2 : 1;
310 Find the next line break character.
313 const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd)
315 while (aStart != aEnd && *aStart != KLineSeparator
316 && *aStart != KParagraphSeparator && *aStart != KCodeLF
317 && *aStart != KCodeCR)
323 Count number of lines in text.
326 TInt NumberOfLines(const TText* aStart, const TText* aEnd)
329 while (aStart != aEnd)
331 aStart = FindEndOfThisLine(aStart, aEnd);
332 aStart += SizeLineBreak(aStart, aEnd);
338 /** Returns the directionality of a given language.
339 @param aLanguage Language.
340 @return The directionality of the given language. */
341 EXPORT_C TBidiText::TDirectionality TBidiText::ScriptDirectionality(
344 const TUint32 DirectionalityBitmap[] =
347 // Arabic, Farsi, Hebrew
352 TUint index = aLanguage;
353 if (index < sizeof(DirectionalityBitmap) * 8)
356 TInt bit = aLanguage & 31;
357 return (DirectionalityBitmap[index] >> bit) & 1?
358 ERightToLeft : ELeftToRight;
364 /** Reports the implicit directionality of a piece of text.
366 @param aText The text to be examined.
367 @param aFound If non-null, returns ETrue if there were any strongly directional
368 characters and EFalse if there were none. If a piece of text is spread over
369 several descriptors, They need to be queried in sequence until one returns
371 @return The directionality implicit in aText. 131 */
372 EXPORT_C TBidiText::TDirectionality TBidiText::TextDirectionality(
373 const TDesC& aText, TBool* aFound)
375 return BidiCopy::ImplicitDirectionalityIsRightToLeft(
376 aText.Ptr(), aText.Length(), aFound)?
377 ERightToLeft : ELeftToRight;
380 /** Creates a bidirectional text object with directionality determined by
381 aDirectionality. Use this for text that has come from user input.
383 @param aText The text in logical order.
385 The maximum number of lines that this text will need to be split into. Must
386 be at least 1, but should not be too large, as each potential line takes an
387 extra 8 bytes of memory.
388 @param aDirectionality Direction to use.
389 @return The newly constructed object.
391 EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines,
392 TBidiText::TDirectionality aDirectionality)
394 __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
395 const TText* text = aText.Ptr();
396 const TInt length = aText.Length();
397 TInt linesInOriginalText = NumberOfLines(text, text + length);
398 if (aMaxLines < linesInOriginalText)
399 aMaxLines = linesInOriginalText;
401 const TInt arraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
402 TBidirectionalState::TRunInfo* runInfoArray = new(ELeave) TBidirectionalState::TRunInfo[arraySize];
403 TCleanupItem ci(DeleteTRunInfo, runInfoArray);
404 CleanupStack::PushL(ci);
405 TBidirectionalState::GenerateBdRunArray(text, length, runInfoArray, arraySize);
406 TBidirectionalState state;
407 state.ReorderLine(runInfoArray, arraySize, ETrue, ETrue, aDirectionality,
408 TChar::EOtherNeutral, TChar::EOtherNeutral);
409 TInt compactArraySize = TRunInfoCompact::Convert(0, aText, runInfoArray, arraySize);
411 // size of TBidiTextImp class
412 TBidiTextImp* me = TBidiTextImp::NewL(length, aMaxLines, compactArraySize);
413 me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
415 TRunInfoCompact::Convert(me->BidiRunArray(), aText, runInfoArray, arraySize);
416 CleanupStack::PopAndDestroy(runInfoArray);
418 Mem::Copy(me->LogicalText(), text, length * sizeof(TText));
422 /** Creates a bidirectional text object with directionality determined by the text
423 itself. Use this for text that has been obtained from a resource file.
425 @param aText The text in logical order.
426 @param aMaxLines The maximum number of lines that this text will need to be
427 split into. Must be at least 1, but should not be too large, as each potential
428 line takes an extra 8 bytes of memory.
429 @return The newly constructed object. */
430 EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines)
432 return NewL(aText, aMaxLines, TextDirectionality(aText));
436 /** Creates a bidirectional text object with enough room for up to aReservedMaxLength
437 number of characters. The number of characters that will actually fit (when calling
438 SetText()) might be slightly less than aReservedMaxLength, as each change between a
439 left-to-right and a right-to-left sub-string (and the other way around) needs about
440 two characters worth of memory.
442 @param aReservedMaxLength The maximum number of characters.
443 @param aMaxLines The maximum number of lines that this text will need to be
444 split into. Must be at least 1, but should not be too large, as each potential
445 line takes an extra 8 bytes of memory.
446 @return The newly constructed object. */
447 EXPORT_C TBidiText* TBidiText::NewL(TInt aReservedMaxLength, TInt aMaxLines)
449 __ASSERT_ALWAYS(0 < aReservedMaxLength, BidiPanic(EBidiPanic_InvalidReservedMaxLength));
450 __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
452 const TInt compactArraySize = 1; // Always at least one needed
454 TBidiTextImp* me = TBidiTextImp::NewL(aReservedMaxLength, aMaxLines, compactArraySize);
455 me->SetTextLength(0); // no text yet, just reserved memory
459 /** Sets the text of the bidirectional text object with directionality determined
460 by the text itself. Use this for text that has been obtained from a resource file.
462 @param aText The text in logical order.
463 @return The number of characters that didn't fit in the available buffer.
465 EXPORT_C TInt TBidiText::SetText(const TDesC& aText, RRunInfoArray& aRunInfoArray)
467 return SetText(aText, TextDirectionality(aText), aRunInfoArray);
471 /** Sets the text of the bidirectional text with directionality determined by
472 aDirectionality. Use this for text that has come from user input.
474 @param aText The text in logical order.
475 @param aDirectionality Direction to use.
476 @return The number of characters that didn't fit in the available buffer.
477 @panic Bidi EBidiPanic_RunArrayNull The call to RRunInfoArray::OpenL() has not
478 been made prior to this call to TBidiText::SetText()
480 EXPORT_C TInt TBidiText::SetText(const TDesC& aText,
481 TDirectionality aDirectionality,
482 RRunInfoArray& aRunInfoArray)
484 TBidirectionalState::TRunInfo* const runArray = aRunInfoArray.RunArray();
485 __ASSERT_ALWAYS(runArray, BidiPanic(EBidiPanic_RunArrayNull));
487 TBidiTextImp* me = TBidiTextImp::Imp(this);
488 const TInt maxLines = me->iLines;
489 const TText* text = aText.Ptr();
490 TInt length = aText.Length();
492 TInt requiredArraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
493 const TInt actualArraySize = aRunInfoArray.iTls->MaxArraySize();
495 if (requiredArraySize > actualArraySize)
497 // Handle the case where we do not have enough space in the run array
498 // to cope with the input text. The text will be truncated to ensure
499 // we don't overrun the buffer and the number of excess characters
500 // returned as a negative number.
501 requiredArraySize = actualArraySize;
502 TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
505 for (TInt index = 0; index < requiredArraySize; index++)
507 length += runArray[index].iLength;
512 TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
517 TBidirectionalState state;
518 state.ReorderLine(runArray,
523 TChar::EOtherNeutral,
524 TChar::EOtherNeutral);
525 const TInt compactArraySize = TRunInfoCompact::Convert(0,
530 // Calculate number of bytes needed to keep text data
531 TInt requiredBytes = sizeof(TText) * (length * 2 + maxLines * 3); // size of text for logical & visual orderings.
532 requiredBytes += sizeof(TInt16*) * maxLines; // size of line length array
533 requiredBytes = (requiredBytes + 3) & 0xFFFFFFFC; // alignment
535 TInt textLength = length;
536 const TInt excessData = Max(0, requiredBytes - me->AllocatedTextDataBytes());
537 TInt excessChars = 0;
540 // Calculate how much text data that can be fitted into the available bytes,
541 // given the bytes needed for run array data
542 excessChars = excessData / (sizeof(TText) * 2);
543 textLength -= excessChars;
545 else if (aText.Length() > length)
547 excessChars = aText.Length() - length;
550 me->SetTextLength(textLength);
551 me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
552 me->iVisualOrderedTextLength = -1;
553 me->iBidiRunArrayLength = static_cast<TUint16>(compactArraySize);
555 TRunInfoCompact::Convert(me->BidiRunArray(), aText, runArray, requiredArraySize);
556 Mem::Copy(me->LogicalText(), text, textLength * sizeof(TText));
561 /** Sets the character that will be added at the end of the text if the whole text
562 cannot fit into the space specified.
564 @param aTruncateWith The truncation char. */
565 EXPORT_C void TBidiText::SetTruncationChar(TChar aTruncateWith)
567 TBidiTextImp* me = TBidiTextImp::Imp(this);
568 me->iTruncationCharPlane = static_cast<TUint8>(aTruncateWith >> 16);
569 me->iTruncationChar16 = static_cast<TUint16>(aTruncateWith);
572 TInt RemoveTrailingSpaces(const MLineBreaker* aBreaker,
573 const TText* aInput, TInt aMinPos, TInt aEndPos)
575 // Ignore space characters at the end of the line.
576 // Don't bother to ignore spaces made of surrogate pairs:
577 // more processing than it's worth.
578 TUint dummy1, dummy2;
579 while (aEndPos != aMinPos && MLineBreaker::ESpLineBreakClass
580 == aBreaker->LineBreakClass(aInput[aEndPos - 1], dummy1, dummy2))
587 /** Prepares the visually-ordered text according to the wrapping width and font
588 specified. Text cannot be drawn until this has been done.
589 @param aWrappingWidth
590 The maximum width of the text in pixels. Note that this distance should be
591 slightly less than the available width to allow for characters such as "W"
592 which can have side-bearings that leak into the margins.
593 @param aFont The font that will provide the character metrics.
595 An object for breaking the lines. May be NULL for default behaviour.
597 Number of lines to restrict wrapping to. The truncation character will be
598 used if the text is too long for this number of lines. The number of lines
599 wrapped to may not be greater than the figure passed to NewL.
601 EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
602 const MLineBreaker* aBreaker, TInt aMaxLines)
604 TBidiTextImp* me = TBidiTextImp::Imp(this);
605 me->iWrappingWidth = aWrappingWidth;
607 TInt16* lineWidths = me->LineWidthArray();
608 TText* output = me->VisualText();
611 DoWrapText(aWrappingWidth, aFont, aBreaker, aMaxLines, output, numLines, lineWidths);
612 me->iVisualOrderedTextLength = output - me->VisualText();
615 /** Calculate the minimum size needed to draw the current text, given the specified
616 wrapping width, font, and line gap. Calling this method will not rewrap the object's
619 @param aWrappingWidth
620 The maximum width of the text in pixels. Note that this distance should be
621 slightly less than the available width to allow for characters such as "W"
622 which can have side-bearings that leak into the margins.
623 @param aFont The font that will provide the character metrics.
624 @param aLineGap The number of empty pixels between two lines of text.
625 Note that this is not the same as the baseline spacing, which is the font
626 height plus the line gap.
628 Number of lines to restrict wrapping to. The truncation character will be
629 used if the text is too long for this number of lines. The number of lines
630 wrapped to may be greater than the figure passed to NewL, and that figure
631 will be used if the number of lines is specified as -1. If 0 (zero) is specified
634 An object for breaking the lines. May be NULL for default behaviour.
636 EXPORT_C TSize TBidiText::MinimumSize(TInt aWrappingWidth, const CFont& aFont, TInt aLineGap,
637 TInt aMaxLines, const MLineBreaker* aBreaker) const
639 __ASSERT_ALWAYS(0 <= aWrappingWidth, BidiPanic(EBidiPanic_InvalidWrappingWidth));
640 __ASSERT_ALWAYS(0 <= aLineGap, BidiPanic(EBidiPanic_InvalidLineGap));
641 __ASSERT_ALWAYS(-1 <= aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
644 TText* output = NULL;
645 const TInt minWidth = DoWrapText(aWrappingWidth,
648 (aMaxLines = 0 ? KMaxTInt : aMaxLines),
652 const TInt minHeight = (aFont.FontMaxHeight() + aLineGap) * numLines - aLineGap;
653 return TSize(minWidth, minHeight);
657 TInt TBidiText::DoWrapText(TInt aWrappingWidth, const CFont& aFont, const MLineBreaker* aBreaker,
658 TInt aMaxLines, TText*& aOutputText, TInt& aNumLines, TInt16* aLineWidthArray) const
660 MLineBreaker defaultBreaker;
662 aBreaker = &defaultBreaker;
664 const TBidiTextImp* me = TBidiTextImp::Imp(this);
665 if (me->iLines < aMaxLines)
666 aMaxLines = me->iLines;
668 const TRunInfoCompact* runArray = me->BidiRunArray();
669 const TRunInfoCompact* runArrayEnd = runArray + me->iBidiRunArrayLength;
671 const TText* input = me->LogicalText();
672 const TInt inputLength = me->TextLength();
673 TPtrC textDes(input, inputLength);
674 const TText* output = me->VisualText();
676 TRunInfoCompact::TReorderingContext context;
677 context.iSource = input;
678 context.iTruncation = 0xFFFF;
679 context.iJoinsAtEnd = EFalse;
682 CFont::TMeasureTextInput measureInput;
683 measureInput.iMaxAdvance = aWrappingWidth;
684 measureInput.iEndInputChar = FindEndOfThisLine(input, input + inputLength) - input;
685 CFont::TMeasureTextOutput measureOutput;
688 TInt widestLineWidth = 0;
689 TBool bLastLine = EFalse;
690 for (aNumLines = 0; aNumLines != aMaxLines && start < inputLength; ++aNumLines)
693 context.iJoinsAtStart = context.iJoinsAtEnd;
694 if(aNumLines != 0 && aOutputText)
695 *(aOutputText++) = KLineSeparator;
697 measureInput.iStartInputChar = start;
698 TInt advance = aFont.MeasureText(textDes, &measureInput, &measureOutput);
699 TInt breakPos = measureOutput.iChars;
700 TInt endOfLine = breakPos;
701 // truncationCharWidth is the width of any truncation character on this
703 TInt truncationCharWidth = 0;
704 if (endOfLine == measureInput.iEndInputChar)
706 //handle the dangling lines here
707 TInt sizeLineBreak = SizeLineBreak(input + endOfLine, input + inputLength);
708 if((measureInput.iEndInputChar < inputLength - sizeLineBreak) && (aNumLines == aMaxLines - 1))
711 else if (aNumLines == aMaxLines - 1)
716 { // Not last line, so find a legal line break.
717 aBreaker->GetLineBreak(textDes,
719 measureOutput.iChars,
728 // Last line, so re-measure leaving enough room for
729 // truncation character.
730 context.iTruncation = me->TruncationChar();
731 truncationCharWidth = aFont.CharWidthInPixels(context.iTruncation);
732 measureInput.iMaxAdvance = aWrappingWidth - truncationCharWidth;
733 advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
734 breakPos = RemoveTrailingSpaces(aBreaker, input, start, measureOutput.iChars);
739 // if the break position has changed, we need to remeasure
740 if (breakPos != measureOutput.iChars)
742 const TInt oldEnd = measureInput.iEndInputChar;
743 measureInput.iEndInputChar = breakPos;
744 advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
745 measureInput.iEndInputChar = oldEnd;
749 //width may be greater than advance
750 advance = Max(advance,measureOutput.iBounds.Width());
752 if(widestLineWidth < advance)
753 widestLineWidth = advance;
756 *(aLineWidthArray++) = static_cast<TInt16>(advance);
758 context.iStart = start;
759 context.iEnd = breakPos;
762 context.iJoinsAtEnd = breakPos < inputLength?
763 TRunInfoCompact::JoinBefore(input, breakPos) : EFalse;
767 context.iJoinsAtEnd = endOfLine < inputLength?
768 TRunInfoCompact::JoinBefore(input, endOfLine) : EFalse;
772 for (const TRunInfoCompact* p = runArray; p != runArrayEnd; ++p)
773 aOutputText = p->Reorder(aOutputText, context);
775 // Set 'start' to the beginning of the next line...
778 // ...move it past any line break...
779 const TInt sizeOfLineBreak = SizeLineBreak(input + start, input + inputLength);
780 if (sizeOfLineBreak != 0)
782 start += sizeOfLineBreak;
783 // ...and find the end of this next line.
784 const TText* endLine = FindEndOfThisLine(input + start, input + inputLength);
785 measureInput.iEndInputChar = endLine - input;
789 return widestLineWidth;
793 /** Prepares the visually-ordered text according to the wrapping width and font
794 specified. Text cannot be drawn until this has been done.
796 @param aWrappingWidth The maximum width of the text in pixels. Note that this
797 distance should be slightly less than the available width to allow for characters
798 such as "W" which can have side-bearings that leak into the margins.
799 @param aFont The font that will provide the character metrics.
800 @param aBreaker An object for breaking the lines. May be NULL for default behaviour. */
801 EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
802 const MLineBreaker* aBreaker)
804 WrapText(aWrappingWidth, aFont, aBreaker, KMaxTInt);
807 /** Returns the original logically-ordered text supplied in the constructor.
808 @return The original logically-ordered text supplied in the constructor. */
809 EXPORT_C TPtrC TBidiText::Text() const
811 const TBidiTextImp* me = TBidiTextImp::Imp(this);
812 const TText* text = me->LogicalText();
813 return TPtrC(text, me->TextLength());
816 /** Returns the text as prepared for display, provided that WrapText has been called.
817 If WrapText has not been called, a panic will result.
819 @return The text as prepared for display */
820 EXPORT_C TPtrC TBidiText::DisplayText() const
822 const TBidiTextImp* me = TBidiTextImp::Imp(this);
823 __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
824 const TText* text = me->VisualText();
825 return TPtrC(text, me->iVisualOrderedTextLength);
828 /** Returns the wrapping width previously supplied to WrapText.
830 @return The wrapping. */
831 EXPORT_C TInt TBidiText::WrappingWidth() const
833 const TBidiTextImp* me = TBidiTextImp::Imp(this);
834 return me->iWrappingWidth;
837 /** Returns the directionality of the text.
839 @return The directionality. */
840 EXPORT_C TBidiText::TDirectionality TBidiText::Directionality() const
842 const TBidiTextImp* me = TBidiTextImp::Imp(this);
843 return me->HasRightToLeftDirectionality() ? ERightToLeft : ELeftToRight;
846 /** Returns the truncation character used.
848 @return The truncation character. */
849 EXPORT_C TChar TBidiText::TruncationChar() const
851 const TBidiTextImp* me = TBidiTextImp::Imp(this);
852 return me->TruncationChar();
855 /** Reports the number of lines in the text to be drawn.
857 WrapText must have been called already.
859 The number of lines in the text which would be drawn by DrawText.
861 EXPORT_C TInt TBidiText::NumberOfLinesInDisplayText() const
863 const TBidiTextImp* me = TBidiTextImp::Imp(this);
864 if (me->iVisualOrderedTextLength <0)
868 const TText* text = me->VisualText();
869 const TText* textEnd = text + me->iVisualOrderedTextLength;
870 return NumberOfLines(text, textEnd);
873 /** Returns the text as prepared for display, provided that WrapText has been called.
874 If WrapText has not been called, a panic will result.
875 @param aLine Line number to retrieve.
876 @param aWidth Returns the width in pixels of the line retrieved.
877 @return The text as prepared for display. */
878 EXPORT_C TPtrC TBidiText::LineOfDisplayText(TInt aLine, TInt& aWidthInPixels) const
880 const TBidiTextImp* me = TBidiTextImp::Imp(this);
881 __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
882 __ASSERT_ALWAYS(0 <= aLine && aLine < me->iLines, BidiPanic(EBidiPanic_InvalidLineNumber));
883 aWidthInPixels = me->LineWidthArray()[aLine];
884 const TText* text = me->VisualText();
885 const TText* textEnd = text + me->iVisualOrderedTextLength;
886 for (; aLine != 0; --aLine)
888 text = FindEndOfThisLine(text, textEnd);
889 text += SizeLineBreak(text, textEnd);
891 const TText* endOfLine = FindEndOfThisLine(text, textEnd);
892 return TPtrC(text, endOfLine - text);
895 /** Draws all of the text. WrapText must have been called already.
897 @param aGc The graphics context to draw the text to. The graphics context's
898 font is assumed to have been set to the same font that was passed to the previous
900 @param aLeft The left extreme of the baseline. Note that this should not be
901 at the very edge of the available space, or characters such as "W" with left
902 side bearings may be truncated.
903 @param aBaseLineSpacing The spacing between each line. If 0, only the first
905 @param aAlignment How to position the text horizontally. */
906 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
907 TInt aBaseLineSpacing, CGraphicsContext::TTextAlign aAlignment) const
910 origin.iY = aLeft.iY;
911 TInt lines = aBaseLineSpacing == 0? 1 : NumberOfLinesInDisplayText();
912 TInt wrappingWidth = WrappingWidth();
913 for (TInt i = 0; i != lines; ++i)
916 TPtrC textLine = LineOfDisplayText(i, width);
917 origin.iX = aLeft.iX;
918 if (aAlignment != CGraphicsContext::ELeft)
920 TInt excess = wrappingWidth - width;
921 origin.iX += aAlignment != CGraphicsContext::ECenter?
922 excess : excess >> 1;
924 aGc.DrawText(textLine, origin);
925 origin.iY += aBaseLineSpacing;
929 /** Draws all of the text. Alignment is taken from the directionality of the text.
930 WrapText must have been called already.
932 @param aGc The graphics context to draw the text to. The graphics context's
933 font is assumed to have been set to the same font that was passed to the previous
935 @param aLeft The left extreme of the baseline. Note that this should not be
936 at the very edge of the available space, or characters such as "W" with left
937 side bearings may be truncated.
938 @param aBaseLineSpacing The spacing between each line. If 0, only the first
940 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
941 TInt aBaseLineSpacing) const
943 DrawText(aGc, aLeft, aBaseLineSpacing,
944 Directionality() == ELeftToRight?
945 CGraphicsContext::ELeft : CGraphicsContext::ERight);
948 /** Draws the first line of the text. WrapText must have been called already. Alignment
949 is taken from the directionality of the text.
951 @param aGc The graphics context to draw the text to. The graphics context's
952 font is assumed to have been set to the same font that was passed to the previous
954 @param aLeft The left extreme of the baseline. Note that this should not be
955 at the very edge of the available space, or characters such as "W" with left
956 side bearings may be truncated. */
957 EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft) const
959 DrawText(aGc, aLeft, 0);