2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include "relayout-utilities.h"
24 #include <dali/dali.h>
25 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
26 #include "text-view-line-processor.h"
27 #include "text-view-word-processor.h"
28 #include "text-view-processor-helper-functions.h"
29 #include "text-view-processor-dbg.h"
40 namespace TextViewRelayout
43 const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same as the text-view boundary, this constant reduces it in order to avoid a zero division.
45 RelayoutParameters::RelayoutParameters()
51 mCharacterGlobalIndex( 0u ),
52 mIsFirstCharacter( false ),
53 mIsFirstCharacterOfWord( false ),
55 mIsNewLineCharacter( false ),
56 mIsWhiteSpace( false ),
61 RelayoutParameters::~RelayoutParameters()
65 FadeParameters::FadeParameters()
66 : mRightFadeBoundary( 0.f ),
67 mRightFadeThreshold( 0.f ),
68 mRightFadeBoundaryOffset( 0.f ),
69 mRightFadeThresholdOffset( 0.f ),
70 mRightAlphaCoeficients(),
71 mLeftFadeBoundary( 0.f ),
72 mLeftFadeThreshold( 0.f ),
73 mLeftFadeBoundaryOffset( 0.f ),
74 mLeftFadeThresholdOffset( 0.f ),
75 mLeftAlphaCoeficients(),
76 mTopFadeBoundary( 0.f ),
77 mTopFadeThreshold( 0.f ),
78 mTopFadeBoundaryOffset( 0.f ),
79 mTopFadeThresholdOffset( 0.f ),
80 mTopAlphaCoeficients(),
81 mBottomFadeBoundary( 0.f ),
82 mBottomFadeThreshold( 0.f ),
83 mBottomFadeBoundaryOffset( 0.f ),
84 mBottomFadeThresholdOffset( 0.f ),
85 mBottomAlphaCoeficients(),
86 mIsPartiallyVisible( false )
90 FadeParameters::~FadeParameters()
94 EllipsizeParameters::EllipsizeParameters()
96 mLineDescender( 0.f ),
101 mEllipsizeLine( false ),
102 mIsLineWidthFullyVisible( false ),
103 mIsLineHeightFullyVisible( false ),
104 mIsNextLineFullyVisibleHeight( false ),
105 mCreateEllipsizedTextActors( false ),
111 EllipsizeParameters::~EllipsizeParameters()
115 UnderlineInfo::UnderlineInfo()
117 mMaxThickness( 0.f ),
122 UnderlineInfo::~UnderlineInfo()
126 TextUnderlineStatus::TextUnderlineStatus()
128 mCharacterGlobalIndex( 0u ),
129 mLineGlobalIndex( 0u ),
130 mCurrentUnderlineStatus( false )
134 TextUnderlineStatus::~TextUnderlineStatus()
138 SubLineLayoutInfo::SubLineLayoutInfo()
139 : mLineLength( 0.f ),
140 mMaxCharHeight( 0.f ),
145 SubLineLayoutInfo::~SubLineLayoutInfo()
150 * Whether the given text-actor exceeds the left or the right boundary of the text-view.
152 * @param[in] position The position of the text-actor.
153 * @param[in] size The size of the text-actor.
154 * @param[in] parantSize The size of the text-view.
156 * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
158 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
160 return ( ( position.x < 0.f ) ||
161 ( position.x + size.width > parentSize.width ) );
165 * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
167 * @param[in] position The position of the text-actor.
168 * @param[in] size The size of the text-actor.
169 * @param[in] parantSize The size of the text-view.
171 * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
173 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
175 return ( ( position.y > parentSize.height ) ||
176 ( position.y < size.height ) );
180 * Calculates the line length adding the new word or character width.
182 * It also returns the length of white spaces if they are at the end of the line.
184 * @param[in] isWhiteSpace Whether the word is a white space.
185 * @param[in] width The width of the character or word.
186 * @param[in] parentWidth The parent width.
187 * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
188 * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
189 * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
191 void CalculateLineLength( const bool isWhiteSpace, const float width, const float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
193 if( lineLength + width > parentWidth )
196 lineLength -= endWhiteSpaceLength;
204 endWhiteSpaceLength += width;
208 endWhiteSpaceLength = 0.f;
213 struct CurrentTextActorInfo
220 Vector4 gradientColor;
225 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
226 const TextView::VisualParameters& visualParameters,
227 TextView::RelayoutData& relayoutData,
228 const float lineHeight )
230 currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
231 currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientColor );
232 currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.startPoint );
233 currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.endPoint );
235 // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
236 // due to the trick used to implement it.
237 const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
238 const float italicsOffset = lineHeight * std::tan( italicsAngle );
239 relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
241 // Sets the sort modifier value.
242 currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
244 // Enables or disables the blending.
245 currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
248 void CalculateSubLineLayout( const float parentWidth,
249 const TextViewProcessor::TextInfoIndices& indices,
250 const TextViewProcessor::LineLayoutInfo& lineLayoutInfo,
251 const HorizontalWrapType splitPolicy,
252 const float shrinkFactor,
253 SubLineLayoutInfo& subLineInfo )
255 subLineInfo.mLineLength = 0.f;
256 subLineInfo.mMaxCharHeight = 0.f;
257 subLineInfo.mMaxAscender = 0.f;
259 float endWhiteSpaceLength = 0.f;
261 std::size_t wordIndex = indices.mWordIndex;
262 std::size_t characterIndex = indices.mCharacterIndex;
263 float lineOffset = 0.f;
265 bool isFirstCharacter = true;
266 for( TextViewProcessor::WordGroupLayoutInfoContainer::const_iterator wordGroupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex,
267 wordGroupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
268 ( wordGroupIt != wordGroupEndIt ) && !found;
271 const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *wordGroupIt );
273 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex,
274 wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
275 ( wordIt != wordEndIt ) && !found;
278 const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
280 const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
281 const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
283 bool splitByCharacter = false;
285 switch( splitPolicy )
287 case WrapByCharacter:
289 splitByCharacter = true;
293 case WrapByLine: // Fall through
295 splitByCharacter = false;
298 case WrapByWordAndSplit:
300 splitByCharacter = ( shrunkWordWidth > parentWidth );
303 case WrapByLineAndSplit:
305 if( ( 0 != characterIndex ) ||
306 ( ( 0 == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
308 splitByCharacter = true;
312 lineOffset += shrunkWordWidth;
313 splitByCharacter = false;
318 if( splitByCharacter )
320 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
321 charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
322 ( charIt != charEndIt ) && !found;
325 const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
326 CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
327 if( !found || isFirstCharacter )
329 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
330 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
333 // All characters for word 'wordIndex' have been processed.
334 // Next word need to process all characters, so the characterIndex is reset to 0.
336 isFirstCharacter = false;
339 lineOffset += subLineInfo.mLineLength;
343 CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
344 if( !found || isFirstCharacter )
346 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
347 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
349 isFirstCharacter = false;
353 // All words for group 'groupIndex' have been processed.
354 // Next group need to process all words, so the wordIndex is reset to 0.
358 subLineInfo.mMaxCharHeight *= shrinkFactor;
359 subLineInfo.mMaxAscender *= shrinkFactor;
362 float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, const float parentWidth, const float wholeTextWidth )
364 float xOffset( 0.f );
365 switch( horizontalTextAlignment )
367 case Toolkit::Alignment::HorizontalLeft:
372 case Toolkit::Alignment::HorizontalCenter:
374 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
377 case Toolkit::Alignment::HorizontalRight:
379 xOffset = parentWidth - wholeTextWidth;
384 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
391 float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, const float parentHeight, const float wholeTextHeight )
393 float yOffset( 0.f );
394 switch( verticalTextAlignment )
396 case Toolkit::Alignment::VerticalTop:
401 case Toolkit::Alignment::VerticalCenter:
403 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
406 case Toolkit::Alignment::VerticalBottom:
408 yOffset = parentHeight - wholeTextHeight;
413 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
420 float CalculateJustificationOffset( const Toolkit::TextView::LineJustification justification, const float wholeTextWidth, const float lineLength )
423 switch( justification )
425 case Toolkit::TextView::Left:
430 case Toolkit::TextView::Center:
432 offset = 0.5f * ( wholeTextWidth - lineLength );
435 case Toolkit::TextView::Right:
437 offset = wholeTextWidth - lineLength;
440 case Toolkit::TextView::Justified:
450 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, const VisibilityTestType type )
452 bool visible = false;
458 // Whether the text-actor is fully inside the boundaries of the text-view.
459 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
460 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
463 case FULLY_VISIBLE_WIDTH:
465 // Whether the text-actor is between the left and right boundaries of the text-view.
466 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
469 case FULLY_VISIBLE_HEIGHT:
471 // Whether the text-actor is between the top and bottom boundaries of the text-view.
472 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
475 case PARTIALLY_VISIBLE:
477 // Whether the text-actor is partially inside the boundaries of the text-view.
478 visible = ( ( position.x < parentSize.width ) &&
479 ( position.x + size.width > 0.f ) &&
480 ( position.y > 0.f ) &&
481 ( position.y - size.height < parentSize.height ) );
484 case PARTIALLY_VISIBLE_WIDTH:
486 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
487 // It may not be partially inside the text-view.
488 visible = ( ( position.x < parentSize.width ) &&
489 ( position.x + size.width > 0.f ) );
492 case PARTIALLY_VISIBLE_HEIGHT:
494 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
495 // It may not be partially inside the text-view.
496 visible = ( ( position.y > 0.f ) &&
497 ( position.y - size.height < parentSize.height ) );
505 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
507 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
509 return Vector2( gradient, p0.y - gradient * p0.x );
512 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
513 TextView::RelayoutData& relayoutData )
515 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
516 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
518 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
519 // In that case, it will align the line to the left and/or top, and ellipsize the end.
520 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
521 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
522 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
523 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
524 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
526 RelayoutParameters relayoutParameters;
528 // Calculates the vertical and horizontal offsets.
529 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
530 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
532 std::size_t lineJustificationIndex = 0; // Index to the first position of the vector which stores all line justification info.
533 std::size_t infoTableCharacterIndex = 0;
535 relayoutParameters.mIndices.mLineIndex = 0;
537 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
538 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
539 lineLayoutIt != endLineLayoutIt;
540 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
542 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
544 relayoutParameters.mIndices.mGroupIndex = 0;
545 float justificationOffset = 0.f;
547 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
548 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
549 groupLayoutIt != endGroupLayoutIt;
550 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
552 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
554 relayoutParameters.mIndices.mWordIndex = 0;
556 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
557 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
558 wordLayoutIt != endWordLayoutIt;
559 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
561 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
563 relayoutParameters.mIndices.mCharacterIndex = 0;
565 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
566 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
567 characterLayoutIt != endCharacterLayoutIt;
568 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
570 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
572 // Calculate line justification offset.
573 if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() )
575 const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) );
577 if( relayoutParameters.mIndices == lineJustificationInfo.mIndices )
579 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength );
580 ++lineJustificationIndex; // increase the index to point the next position in the vector.
584 // Deletes the offsets if the exceed policies are EllipsizeEnd.
585 const float horizontalOffset = textHorizontalOffset + justificationOffset;
586 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
587 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
589 // Updates the size and position table for text-input with the alignment offset.
590 Vector3 positionOffset( characterLayoutInfo.mPosition );
592 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
593 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
595 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
596 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
598 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
601 } // end group of words
605 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
606 TextView::RelayoutData& relayoutData )
618 // ggggg gggggggggg bb ggggg
619 // gg gg gggggggggg bb gg gg
620 // gg gg gggg bb gg gg
621 // gg gg gggg bb gg gg
622 // ggggg gg gggg bbbbbbb ggggg
623 // gg gg gggg bb bb gg
624 // g gg gggggggggg bb bb g gg
625 // ggggg gggggggggg bbbbbbb ggggg
634 // ggggg gggg gggg bb ggggg
635 // gg gg gggg gggg bbbbbbb gg gg
636 // gg gg gggg gggg bb bb gg gg
637 // gg gg gggggggggg bb bb gg gg
638 // ggggg gggggggggg bbbbbbb ggggg
641 // ggggg gg gggg ggggg
646 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1 ) );
647 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
649 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
652 void UpdateLayoutInfoTable( Vector4& minMaxXY,
653 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo,
654 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
655 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
656 RelayoutParameters& relayoutParameters,
657 TextView::RelayoutData& relayoutData )
659 // updates min and max position to calculate the text size for multiline policies.
660 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
661 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
663 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
664 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
666 // Adds layout info to be retrieved by external controls or applications.
667 Vector3 positionOffset( characterLayoutInfo.mPosition );
669 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
671 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor,
672 characterLayoutInfo.mHeight * relayoutData.mShrinkFactor ),
674 ( TextViewProcessor::LineSeparator == wordLayoutInfo.mType ),
675 ( TextViewProcessor::RTL == wordGroupLayoutInfo.mDirection ),
679 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
681 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
684 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
685 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
686 RelayoutParameters& relayoutParameters,
687 FadeParameters& fadeParameters,
688 TextView::RelayoutData& relayoutData )
690 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
691 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
692 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
693 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
699 // Calculates visibility of a text-actor according the exceed policies.
701 // position + alignment offset.
702 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
703 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
704 characterLayoutInfo.mPosition.z );
706 // Whether the text actor is fully, partially or non visible (according exceed policies).
707 switch( layoutParameters.mExceedPolicy )
711 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
712 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
713 if( !IsVisible( position,
714 characterLayoutInfo.mSize,
715 relayoutData.mTextViewSize,
718 relayoutParameters.mIsVisible = false;
719 if( IsVisible( position,
720 characterLayoutInfo.mSize,
721 relayoutData.mTextViewSize,
722 PARTIALLY_VISIBLE ) )
724 fadeParameters.mIsPartiallyVisible = true;
726 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
727 if( IsExceedingWidth( position,
728 characterLayoutInfo.mSize,
729 relayoutData.mTextViewSize ) &&
730 IsExceedingHeight( position,
731 characterLayoutInfo.mSize,
732 relayoutData.mTextViewSize ) )
734 // Combination not fully supported by text-view.
735 // Need to check if text-actor really supports this combination.
736 fadeParameters.mIsPartiallyVisible = false;
742 case TextView::FadeOriginal:
744 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
745 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
746 if( !IsVisible( position,
747 characterLayoutInfo.mSize,
748 relayoutData.mTextViewSize,
749 FULLY_VISIBLE_WIDTH ) )
751 relayoutParameters.mIsVisible = false;
752 if( IsVisible( position,
753 characterLayoutInfo.mSize,
754 relayoutData.mTextViewSize,
755 PARTIALLY_VISIBLE_WIDTH ) )
757 fadeParameters.mIsPartiallyVisible = true;
762 case TextView::OriginalFade:
763 case TextView::SplitFade: // Fallthrough
765 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
766 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
767 if( !IsVisible( position,
768 characterLayoutInfo.mSize,
769 relayoutData.mTextViewSize,
770 FULLY_VISIBLE_HEIGHT ) )
772 relayoutParameters.mIsVisible = false;
773 if( IsVisible( position,
774 characterLayoutInfo.mSize,
775 relayoutData.mTextViewSize,
776 PARTIALLY_VISIBLE_HEIGHT ) )
778 fadeParameters.mIsPartiallyVisible = true;
785 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
790 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
792 characterLayoutInfo.mIsVisible = true;
794 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
795 const float characterPositionPlusWidth = position.x + size.width;
796 const float characterPositionMinusHeight = position.y - size.height;
798 // Calculates which edges need to be faded-out.
799 bool rightFadeOut = false;
800 bool leftFadeOut = false;
801 bool bottomFadeOut = false;
802 bool topFadeOut = false;
804 switch( layoutParameters.mExceedPolicy )
808 // All text-actors exceeding any of the boundaries will be faded-out.
809 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
810 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
811 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
812 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
815 case TextView::FadeOriginal:
817 // Only text-actors exceeding the left or the right boundaries will be faded-out.
818 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
819 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
822 case TextView::SplitFade:
823 case TextView::OriginalFade: //Fallthrough
825 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
826 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
827 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
832 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
837 // Calculates gradient parameters for a text-actor.
838 Vector4 gradientColor = Vector4::ZERO;
839 Vector2 startPoint = Vector2::ZERO;
840 Vector2 endPoint = Vector2::ZERO;
842 if( !( rightFadeOut && leftFadeOut ) )
844 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
847 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
849 // Calculates gradient coeficients.
850 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
851 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
853 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ), 0.5f );
854 endPoint = Vector2( std::min( 1.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ), 0.5f );
856 else if( leftFadeOut )
858 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
860 // Calculates gradient coeficients.
861 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
862 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
864 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ), 0.5f );
865 endPoint = Vector2( std::min( 1.f, -position.x / size.width ), 0.5f );
869 if( !( bottomFadeOut && topFadeOut ) )
871 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
874 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
876 // Calculates gradient coeficients.
877 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
878 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
880 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
881 endPoint = Vector2( 0.5f, std::min( 1.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) );
883 else if( topFadeOut )
885 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
887 // Calculates gradient coeficients.
888 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
889 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
891 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
892 endPoint = Vector2( 0.5f, std::min( 1.f, -characterPositionMinusHeight / size.height ) );
896 characterLayoutInfo.mGradientColor = gradientColor;
897 characterLayoutInfo.mStartPoint = startPoint;
898 characterLayoutInfo.mEndPoint = endPoint;
902 characterLayoutInfo.mIsVisible = false;
906 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
907 const EllipsizeParameters& ellipsizeParameters )
909 bool isPartiallyVisible = false;
911 if( !IsVisible( ellipsizeParameters.mPosition,
912 characterLayoutInfo.mSize,
913 ellipsizeParameters.mEllipsizeBoundary,
914 FULLY_VISIBLE_WIDTH ) )
916 // The character doesn't fit in the text-view's width.
917 characterLayoutInfo.mIsVisible = false;
919 // Checks if the character is partially visible (it's cut by the boundary)
920 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
921 characterLayoutInfo.mSize,
922 ellipsizeParameters.mEllipsizeBoundary,
923 PARTIALLY_VISIBLE_WIDTH );
927 // The character fits in the text-view's width. Set it to visible.
928 characterLayoutInfo.mIsVisible = true;
931 return isPartiallyVisible;
934 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
935 const EllipsizeParameters& ellipsizeParameters )
937 bool isPartiallyVisible = false;
939 if( !IsVisible( ellipsizeParameters.mPosition,
940 characterLayoutInfo.mSize,
941 ellipsizeParameters.mEllipsizeBoundary,
944 // The character is not fully visible. Needs to check if it's partially visible.
945 characterLayoutInfo.mIsVisible = false;
947 // Checks if the character doesn't cut the bottom edge of the text-view.
948 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
949 characterLayoutInfo.mSize,
950 ellipsizeParameters.mEllipsizeBoundary,
951 FULLY_VISIBLE_HEIGHT );
953 // Checks if the character cuts the right edge of the text-view.
954 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
955 characterLayoutInfo.mSize,
956 ellipsizeParameters.mEllipsizeBoundary,
957 PARTIALLY_VISIBLE_WIDTH );
959 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
960 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
964 // The character fits in the boundary of the text-view. Set it to visible.
965 characterLayoutInfo.mIsVisible = true;
968 return isPartiallyVisible;
971 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
972 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
973 EllipsizeParameters& ellipsizeParameters,
974 TextView::RelayoutData& relayoutData )
976 // Calculates visibility for EllipsizeEnd exceed policies.
978 // It defines a boundary on the right side of the text-view by substracting the ellipsize-text's size (...) to the text-view's size.
979 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
980 // or the whole word (if the multi-line policy is split-by-word) doesn't fit in the text-view's width, then it's replaced by the ellipsize-text.
982 // Position of the character used to do the visibility test.
983 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
984 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
985 characterLayoutInfo.mPosition.z );
987 // Text will be ellipsized if a character is partially visible (it's cut by the boundary defined in the right side of the text-view).
988 bool isPartiallyVisible = false;
990 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
991 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
993 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
996 // The line or word fits completely inside the text-view's width. Nothing else to do.
997 characterLayoutInfo.mIsVisible = true;
1001 // The line or word doesn't fit in the text-view's width.
1003 // Calculates visibility for each type of ellipsize policies.
1004 switch( layoutParameters.mExceedPolicy )
1006 case TextView::EllipsizeEndOriginal:
1008 // Ellipsizes the text if it doesn't fit in the width but it doesn't ellipsize if the text doesn't fit in the height.
1010 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1011 ellipsizeParameters );
1015 case TextView::SplitEllipsizeEnd:
1016 case TextView::EllipsizeEnd:
1018 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1020 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1021 ellipsizeParameters );
1027 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1033 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1034 // In that case, the charater needs to be replaced by the ellipsize text.
1035 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1038 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1039 TextView::RelayoutData& relayoutData )
1041 // The default ellipsize text is '...' and all dots have the same style. However, a differernt ellipsize text could be set and it can have characters with differernt styles.
1042 // The code bellow creates the text-actors needed for the ellipsize text.
1044 // Set ellipsize's position by the end of visible text.
1045 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1046 // Stores current ellipsize text.
1048 // Stores current ellipsize style.
1049 TextStyle ellipsizeStyle;
1050 // Stores the current size.
1052 //Whether current glyph is an emoticon.
1053 bool isColorGlyph = false;
1055 float bearingOffset = 0.f;
1057 // Create ellipsize text-actor.
1058 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1059 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1060 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1061 ++ellipsizeCharacterLayoutIt )
1063 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1066 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1067 ( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle ) )
1069 // The style is different, so a new text-actor is needed.
1070 if( !ellipsizeText.IsEmpty() )
1072 // It only creates a text-actor if there is any text.
1073 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1074 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1075 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1077 // Updates the position for the next text-actor.
1078 ellipsizePosition.x += ellipsizeSize.width;
1080 // Adds the text-actor to the list.
1081 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1084 // Resets the current ellipsize info.
1085 ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText;
1086 ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle;
1087 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1088 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1090 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1094 // Updates text and size with the new character.
1095 ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText );
1096 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1101 if( !ellipsizeText.IsEmpty() )
1103 // Creates the last glyph-actor.
1104 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1105 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1106 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1108 // Adds the glyph-actor to the list.
1109 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1113 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1114 EllipsizeParameters& ellipsizeParameters,
1115 TextView::RelayoutData& relayoutData )
1117 // Traverses the text layout info from the first character of the laid out line
1118 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1120 // Indices to the first character of the laid out line.
1121 TextViewProcessor::TextInfoIndices firstIndices;
1122 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1123 relayoutData.mTextLayoutInfo,
1126 // Indices to the last character of the laid out line.
1127 TextViewProcessor::TextInfoIndices lastIndices;
1128 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1129 relayoutData.mTextLayoutInfo,
1132 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1133 // This is the boundary used to check if a character have to be ellipsized.
1134 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1135 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1137 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + firstIndices.mLineIndex,
1138 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lastIndices.mLineIndex + 1;
1139 lineLayoutIt != endLineLayoutIt;
1142 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1144 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1146 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1148 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1151 bool firstGroup = true;
1152 bool lastGroup = false;
1153 std::size_t groupCount = 0;
1155 bool firstWord = true;
1156 bool lastWord = false;
1158 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + firstIndices.mGroupIndex,
1159 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + lastIndices.mGroupIndex + 1;
1160 groupLayoutIt != endGroupLayoutIt;
1161 ++groupLayoutIt, ++groupCount )
1163 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1165 if( groupCount == lastIndices.mGroupIndex - firstIndices.mGroupIndex )
1170 std::size_t wordCount = 0;
1171 const std::size_t firstWordIndex = firstGroup ? firstIndices.mWordIndex : 0u;
1172 const std::size_t lastWordIndex = lastGroup ? lastIndices.mWordIndex : wordGroupLayoutInfo.mWordsLayoutInfo.size() - 1;
1174 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + firstWordIndex,
1175 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + lastWordIndex + 1;
1176 wordLayoutIt != endWordLayoutIt;
1177 ++wordLayoutIt, ++wordCount )
1179 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1181 if( lastGroup && ( wordCount == lastIndices.mWordIndex - firstWordIndex ) )
1186 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1187 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1;
1188 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1189 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1;
1190 characterLayoutIt != endCharacterLayoutIt;
1191 ++characterLayoutIt )
1193 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1195 if( ellipsizeParameters.mEllipsizeLine )
1197 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1198 CalculateVisibilityForEllipsize( layoutParameters,
1199 characterLayoutInfo,
1200 ellipsizeParameters,
1203 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1205 // Create ellipsize text-actors if the character needs to be replaced.
1206 CreateEllipsizeTextActor( ellipsizeParameters,
1212 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1213 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1215 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1217 // Make characters invisible.
1218 characterLayoutInfo.mIsVisible = false;
1230 void SetTextVisible( TextView::RelayoutData& relayoutData )
1232 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1233 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1234 lineLayoutIt != endLineLayoutIt;
1237 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1239 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1240 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1241 groupLayoutIt != endGroupLayoutIt;
1244 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1246 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1247 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1248 wordLayoutIt != endWordLayoutIt;
1251 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1253 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1254 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1255 characterLayoutIt != endCharacterLayoutIt;
1256 ++characterLayoutIt )
1258 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1260 characterLayoutInfo.mIsVisible = true;
1261 characterLayoutInfo.mGradientColor = Vector4::ZERO;
1262 characterLayoutInfo.mStartPoint = Vector2::ZERO;
1263 characterLayoutInfo.mEndPoint = Vector2::ZERO;
1266 } // end group of words
1269 // Updates the visibility for text-input..
1270 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1271 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1275 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1277 characterLayoutInfo.mIsVisible = true;
1281 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1282 const TextView::VisualParameters& visualParameters,
1283 TextView::RelayoutData& relayoutData )
1285 RelayoutParameters relayoutParameters;
1286 FadeParameters fadeParameters;
1288 // Calculates the fade thresholds (from where the text starts to fade out). If any of the fade boundaries is zero, it sets a very small value just to avoid a zero division.
1289 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1290 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0 ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1291 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1292 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1293 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1294 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0 ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1295 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1296 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1297 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1298 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0 ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1299 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1300 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1301 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1302 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0 ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1303 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1304 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1306 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1307 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1308 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1309 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1310 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1312 // Traverses all groups of characters and calculates the visibility.
1314 std::size_t infoTableCharacterIndex = 0;
1316 relayoutParameters.mIndices.mLineIndex = 0;
1318 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1319 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1320 lineLayoutIt != endLineLayoutIt;
1321 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
1323 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1325 relayoutParameters.mIndices.mGroupIndex = 0;
1327 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1328 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1329 groupLayoutIt != endGroupLayoutIt;
1330 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
1332 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1334 relayoutParameters.mIndices.mWordIndex = 0;
1336 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1337 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1338 wordLayoutIt != endWordLayoutIt;
1339 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1341 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1343 relayoutParameters.mIsFirstCharacterOfWord = true;
1344 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1345 relayoutParameters.mIndices.mCharacterIndex = 0;
1347 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1348 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1349 characterLayoutIt != endCharacterLayoutIt;
1350 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
1352 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1354 relayoutParameters.mIsVisible = true;
1355 fadeParameters.mIsPartiallyVisible = false;
1357 // Calculates the visibility for the current group of characters.
1358 CalculateVisibilityForFade( layoutParameters,
1359 characterLayoutInfo,
1364 // Updates the visibility for text-input..
1365 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
1367 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1369 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1371 relayoutParameters.mIsFirstCharacterOfWord = false;
1372 } // end group of character
1374 } // end group of words
1378 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1379 const TextView::VisualParameters& visualParameters,
1380 TextView::RelayoutData& relayoutData )
1382 // Traverses the laid-out lines and checks which ones doesn't fit in the text-view's boundary.
1383 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1384 lineInfoIt != endLineInfoIt;
1387 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1389 // To check if a laid-out line fits in the text-view's boundary,
1390 // get the position of the first character is needed and do the test
1391 // with the laid-out line size.
1393 // An bearing offset may have been applied to the first character so it's needed to
1394 // get the start position of the line.
1396 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1397 EllipsizeParameters ellipsizeParameters;
1399 // Retrieves the first index and the last index of the line.
1400 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1401 ellipsizeParameters.mLastIndex = 0;
1402 if( ( lineInfoIt + 1 ) != endLineInfoIt )
1404 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1 ) );
1405 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1;
1409 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1;
1412 // Retrieves the first character of the line and build the position of the line with the bearing.
1413 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1415 // Calculates the bearing offset applied to the first character.
1416 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1418 // Build the position of the line by removing the bearing offset from the first character's position.
1419 const Vector3 position( characterInfo.mPosition.x,
1420 characterInfo.mPosition.y + bearingOffset,
1421 characterInfo.mPosition.z );
1423 // Checks if the line needs to be ellipsized,
1424 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1426 relayoutData.mTextViewSize,
1427 FULLY_VISIBLE_WIDTH );
1429 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1430 // if the line fits in the width.
1431 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1433 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1434 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1435 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1436 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1437 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1438 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1440 // Need to check if there is lines which doesn't fit in the height.
1442 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1444 relayoutData.mTextViewSize,
1445 FULLY_VISIBLE_HEIGHT );
1447 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1449 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1451 // Current line is not ellipsized.
1452 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1453 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1;
1454 if( nextLineInfoIt != endLineInfoIt )
1456 // Retrives the position of the first character of the line and remove
1457 // the bearing offset to build to build the position of the line.
1458 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1459 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1461 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1463 const Vector3 position( characterInfo.mPosition.x,
1464 characterInfo.mPosition.y + bearingOffset,
1465 characterInfo.mPosition.z );
1467 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1469 relayoutData.mTextViewSize,
1470 FULLY_VISIBLE_HEIGHT );
1472 // If the next line is not visible, current line have to be ellipsized.
1473 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1478 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1480 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1483 // Sets the line descender.
1484 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1486 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1487 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1491 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1492 const TextView::VisualParameters& visualParameters,
1493 TextView::RelayoutData& relayoutData )
1495 switch( layoutParameters.mExceedPolicy )
1497 case TextView::FadeOriginal:
1498 case TextView::OriginalFade:
1499 case TextView::Fade:
1500 case TextView::SplitFade: // Fall through
1502 UpdateVisibilityForFade( layoutParameters,
1507 case TextView::EllipsizeEndOriginal:
1508 case TextView::SplitEllipsizeEnd:
1509 case TextView::EllipsizeEnd: // Fall through
1511 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1512 SetTextVisible( relayoutData );
1514 UpdateVisibilityForEllipsize( layoutParameters,
1521 SetTextVisible( relayoutData );
1527 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
1528 TextView::RelayoutData& relayoutData )
1530 CurrentTextActorInfo currentTextActorInfo;
1532 // Traverses the text-actor and layout info data structures.
1533 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1534 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1535 lineLayoutIt != endLineLayoutIt;
1538 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1540 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1541 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1542 groupLayoutIt != endGroupLayoutIt;
1545 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1547 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1548 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1549 wordLayoutIt != endWordLayoutIt;
1552 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1554 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1555 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1556 characterLayoutIt != endCharacterLayoutIt;
1557 ++characterLayoutIt )
1559 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1561 if( characterLayoutInfo.mIsColorGlyph )
1563 ImageActor imageActor = ImageActor::DownCast( characterLayoutInfo.mGlyphActor );
1565 if( characterLayoutInfo.mSetText )
1567 GlyphImage image = GlyphImage::New( characterLayoutInfo.mStyledText.mText[0] );
1571 imageActor.SetImage( image );
1573 characterLayoutInfo.mSetText = false;
1576 imageActor.SetPosition( Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1577 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1578 characterLayoutInfo.mPosition.z ) );
1579 imageActor.SetSize( characterLayoutInfo.mSize );
1581 // Sets the sort modifier value.
1582 imageActor.SetSortModifier( visualParameters.mSortModifier );
1586 TextActor textActor = TextActor::DownCast( characterLayoutInfo.mGlyphActor );
1589 // There is a new text-actor. Set text and everything to the previous one.
1590 if( currentTextActorInfo.textActor )
1592 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1593 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1594 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1596 SetVisualParameters( currentTextActorInfo,
1599 lineLayoutInfo.mSize.height );
1602 currentTextActorInfo.text = characterLayoutInfo.mStyledText.mText;
1603 currentTextActorInfo.position = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1604 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1605 characterLayoutInfo.mPosition.z );
1606 currentTextActorInfo.size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1608 currentTextActorInfo.color = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
1609 currentTextActorInfo.color.a = characterLayoutInfo.mColorAlpha;
1611 currentTextActorInfo.gradientColor = characterLayoutInfo.mGradientColor;
1612 currentTextActorInfo.startPoint = characterLayoutInfo.mStartPoint;
1613 currentTextActorInfo.endPoint = characterLayoutInfo.mEndPoint;
1615 // Update the current text-actor.
1616 currentTextActorInfo.textActor = textActor;
1620 // If this character layout has no text-actor is because this character has the same style than previous one.
1621 // Add the character to the current text-actor and update the size.
1622 if( characterLayoutInfo.mIsVisible && ( TextViewProcessor::LineSeparator != wordLayoutInfo.mType ) )
1624 currentTextActorInfo.text.Append( characterLayoutInfo.mStyledText.mText );
1626 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y ) );
1627 currentTextActorInfo.size.width += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1628 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1635 if( !currentTextActorInfo.text.IsEmpty() )
1637 if( currentTextActorInfo.textActor )
1639 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1640 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1641 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1643 SetVisualParameters( currentTextActorInfo,
1646 lineLayoutInfo.mSize.height );
1649 } //end groups of words
1652 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1653 endIt = relayoutData.mEllipsizedGlyphActors.end();
1657 RenderableActor glyphActor = ( *it );
1659 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1660 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1662 // Sets the sort modifier value.
1663 glyphActor.SetSortModifier( visualParameters.mSortModifier );
1665 // Enables or disables the blending.
1666 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
1670 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
1672 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1674 // Note that relayoutData.mTextLayoutInfo contains layout info per line but these lines are the result of split the whole text every time a '\n' is found.
1675 // According with the layout option, one of this lines could be laid-out in more than one.
1677 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1678 lineIt != lineEndIt;
1681 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1683 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1684 groupIt != groupEndIt;
1687 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1689 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1690 wordIt != wordEndIt;
1693 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1695 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1696 characterIt != characterEndIt;
1699 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1701 // Check if current character is the first of a new laid-out line
1702 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
1703 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
1706 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1709 if( characterGroup.mStyledText.mStyle.GetUnderline() )
1711 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
1712 isNewLine ) // Current character is underlined and is the first of current laid-out line.
1714 // Create a new underline info for the current underlined characters.
1715 UnderlineInfo underlineInfo;
1716 underlineInfo.mMaxHeight = characterGroup.mSize.height;
1717 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1718 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1720 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
1722 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
1726 // Retrieve last underline info and update it if current underline thickness is bigger.
1727 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1 ) );
1729 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, characterGroup.mSize.height );
1731 if( characterGroup.mUnderlineThickness > underlineInfo.mMaxThickness )
1733 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1734 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1740 textUnderlineStatus.mCurrentUnderlineStatus = false;
1743 ++textUnderlineStatus.mCharacterGlobalIndex;
1744 } // end group of characters.
1746 } // end group of words.
1750 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
1752 // Stores for each group of consecutive underlined text in each laid-out line its maximum thicknes, its position of that thickness and the maximum character's height.
1753 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
1755 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1756 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
1758 if( textUnderlineStatus.mUnderlineInfo.empty() )
1760 // There is no underlined text. Just exit.
1764 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
1765 // Traverse the whole text and set the previously stored underline info in the text style.
1767 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
1768 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
1770 UnderlineInfo underlineInfo;
1772 if( underlineInfoIt < underlineInfoEndIt )
1774 underlineInfo = ( *underlineInfoIt );
1777 // Whether current text is underlined.
1778 textUnderlineStatus.mCurrentUnderlineStatus = false;
1779 textUnderlineStatus.mCharacterGlobalIndex = 0;
1780 textUnderlineStatus.mLineGlobalIndex = 0;
1782 float currentLineHeight = 0.f;
1783 float currentLineAscender = 0.f;
1785 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1786 lineIt != lineEndIt;
1789 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1791 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1792 groupIt != groupEndIt;
1795 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1797 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1798 wordIt != wordEndIt;
1801 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1803 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1804 characterIt != characterEndIt;
1807 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1809 // Check if current character is the first of a new laid-out line
1811 bool isNewLine = false;
1813 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
1815 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
1816 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
1820 currentLineHeight = lineLayoutInfo.mSize.height;
1821 currentLineAscender = lineLayoutInfo.mAscender;
1822 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1826 if( characterGroup.mStyledText.mStyle.GetUnderline() )
1828 if( textUnderlineStatus.mCurrentUnderlineStatus )
1832 // Retrieves the thickness and position for the next piece of underlined text.
1833 if( underlineInfoIt < underlineInfoEndIt )
1836 if( underlineInfoIt < underlineInfoEndIt )
1838 underlineInfo = *underlineInfoIt;
1844 textUnderlineStatus.mCurrentUnderlineStatus = true;
1846 // Sets the underline's thickness.
1847 characterGroup.mStyledText.mStyle.SetUnderlineThickness( underlineInfo.mMaxThickness );
1849 // Before setting the position it needs to be adjusted to match the base line.
1850 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( characterGroup.mSize.height - characterGroup.mAscender );
1851 const float positionOffset = ( underlineInfo.mMaxHeight - characterGroup.mSize.height ) - bearingOffset;
1853 // Sets the underline's position.
1854 characterGroup.mStyledText.mStyle.SetUnderlinePosition( underlineInfo.mPosition - positionOffset );
1856 // Mark the group of characters to be set the new style into the text-actor.
1857 characterGroup.mSetStyle = true;
1861 if( textUnderlineStatus.mCurrentUnderlineStatus )
1863 textUnderlineStatus.mCurrentUnderlineStatus = false;
1865 // Retrieves the thickness and position for the next piece of underlined text.
1866 if( underlineInfoIt < underlineInfoEndIt )
1869 if( underlineInfoIt < underlineInfoEndIt )
1871 underlineInfo = *underlineInfoIt;
1877 ++textUnderlineStatus.mCharacterGlobalIndex;
1878 } // end of group of characters.
1880 } // end of group of words.
1884 void RemoveGlyphActors( Actor textView,
1885 const std::vector<RenderableActor>& glyphActors )
1887 // Removes previously inserted renderable-actors.
1888 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
1889 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
1890 // in order to remove 'only' renderable-actors added by these functions.
1891 // Any other actor added by a programmer or application won't be removed.
1893 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
1895 textView.Remove( *it );
1899 void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMask,
1901 TextView::RelayoutData& relayoutData )
1903 const bool insertToTextView = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW;
1904 const bool insertToTextActorList = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST;
1906 // Add text-actors to the text-view.
1908 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1909 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1910 lineLayoutIt != endLineLayoutIt;
1913 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1915 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1916 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1917 groupLayoutIt != endGroupLayoutIt;
1920 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1922 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1923 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1924 wordLayoutIt != endWordLayoutIt;
1927 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1929 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1930 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1931 characterLayoutIt != endCharacterLayoutIt;
1932 ++characterLayoutIt )
1934 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1936 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
1938 //Add to the text-view.
1939 if( insertToTextView )
1941 textView.Add( characterLayoutInfo.mGlyphActor );
1943 if( insertToTextActorList )
1945 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
1948 } // end group of character
1950 } // end group of words
1953 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1954 endIt = relayoutData.mEllipsizedGlyphActors.end();
1958 RenderableActor glyphActor = ( *it );
1960 //Add to the text-view.
1961 if( insertToTextView )
1963 textView.Add( glyphActor );
1965 if( insertToTextActorList )
1967 relayoutData.mGlyphActors.push_back( glyphActor );
1970 relayoutData.mEllipsizedGlyphActors.clear();
1973 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
1975 TextActor textActor = cache.RetrieveTextActor();
1979 // Update the text-actor.
1980 textActor.SetText( text );
1981 textActor.SetTextStyle( style );
1985 // The text-actor cache is empty. Create a new one.
1986 textActor = TextActor::New( text, style, false, true );
1992 } // namespace TextViewRelayout
1994 } // namespace Internal
1996 } // namespace Toolkit