2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "relayout-utilities.h"
25 #include <dali/dali.h>
26 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
27 #include "text-view-line-processor.h"
28 #include "text-view-word-processor.h"
29 #include "text-view-processor-helper-functions.h"
30 #include "text-view-processor-dbg.h"
41 namespace TextViewRelayout
44 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.
46 RelayoutParameters::RelayoutParameters()
52 mCharacterGlobalIndex( 0u ),
53 mIsFirstCharacter( false ),
54 mIsFirstCharacterOfWord( false ),
56 mIsNewLineCharacter( false ),
57 mIsWhiteSpace( false ),
62 RelayoutParameters::~RelayoutParameters()
66 FadeParameters::FadeParameters()
67 : mRightFadeBoundary( 0.f ),
68 mRightFadeThreshold( 0.f ),
69 mRightFadeBoundaryOffset( 0.f ),
70 mRightFadeThresholdOffset( 0.f ),
71 mRightAlphaCoeficients(),
72 mLeftFadeBoundary( 0.f ),
73 mLeftFadeThreshold( 0.f ),
74 mLeftFadeBoundaryOffset( 0.f ),
75 mLeftFadeThresholdOffset( 0.f ),
76 mLeftAlphaCoeficients(),
77 mTopFadeBoundary( 0.f ),
78 mTopFadeThreshold( 0.f ),
79 mTopFadeBoundaryOffset( 0.f ),
80 mTopFadeThresholdOffset( 0.f ),
81 mTopAlphaCoeficients(),
82 mBottomFadeBoundary( 0.f ),
83 mBottomFadeThreshold( 0.f ),
84 mBottomFadeBoundaryOffset( 0.f ),
85 mBottomFadeThresholdOffset( 0.f ),
86 mBottomAlphaCoeficients(),
87 mIsPartiallyVisible( false )
91 FadeParameters::~FadeParameters()
95 EllipsizeParameters::EllipsizeParameters()
97 mLineDescender( 0.f ),
102 mEllipsizeLine( false ),
103 mIsLineWidthFullyVisible( false ),
104 mIsLineHeightFullyVisible( false ),
105 mIsNextLineFullyVisibleHeight( false ),
106 mCreateEllipsizedTextActors( false ),
112 EllipsizeParameters::~EllipsizeParameters()
116 UnderlineInfo::UnderlineInfo()
118 mMaxThickness( 0.f ),
123 UnderlineInfo::~UnderlineInfo()
127 TextUnderlineStatus::TextUnderlineStatus()
129 mCharacterGlobalIndex( 0u ),
130 mLineGlobalIndex( 0u ),
131 mCurrentUnderlineStatus( false )
135 TextUnderlineStatus::~TextUnderlineStatus()
139 SubLineLayoutInfo::SubLineLayoutInfo()
140 : mLineLength( 0.f ),
141 mMaxCharHeight( 0.f ),
146 SubLineLayoutInfo::~SubLineLayoutInfo()
151 * Whether the given text-actor exceeds the left or the right boundary of the text-view.
153 * @param[in] position The position of the text-actor.
154 * @param[in] size The size of the text-actor.
155 * @param[in] parantSize The size of the text-view.
157 * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
159 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
161 return ( ( position.x < 0.f ) ||
162 ( position.x + size.width > parentSize.width ) );
166 * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
168 * @param[in] position The position of the text-actor.
169 * @param[in] size The size of the text-actor.
170 * @param[in] parantSize The size of the text-view.
172 * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
174 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
176 return ( ( position.y > parentSize.height ) ||
177 ( position.y < size.height ) );
181 * Calculates the line length adding the new word or character width.
183 * It also returns the length of white spaces if they are at the end of the line.
185 * @param[in] isWhiteSpace Whether the word is a white space.
186 * @param[in] width The width of the character or word.
187 * @param[in] parentWidth The parent width.
188 * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
189 * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
190 * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
192 void CalculateLineLength( const bool isWhiteSpace, const float width, const float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
194 if( lineLength + width > parentWidth )
197 lineLength -= endWhiteSpaceLength;
205 endWhiteSpaceLength += width;
209 endWhiteSpaceLength = 0.f;
214 struct CurrentTextActorInfo
221 Vector4 gradientColor;
226 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
227 const TextView::VisualParameters& visualParameters,
228 TextView::RelayoutData& relayoutData,
229 const float lineHeight )
231 currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
232 currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientColor );
233 currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.startPoint );
234 currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.endPoint );
236 // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
237 // due to the trick used to implement it.
238 const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
239 const float italicsOffset = lineHeight * std::tan( italicsAngle );
240 relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
242 // Sets the sort modifier value.
243 currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
245 // Enables or disables the blending.
246 currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
249 void CalculateSubLineLayout( const float parentWidth,
250 const TextViewProcessor::TextInfoIndices& indices,
251 const TextViewProcessor::LineLayoutInfo& lineLayoutInfo,
252 const HorizontalWrapType splitPolicy,
253 const float shrinkFactor,
254 SubLineLayoutInfo& subLineInfo )
256 subLineInfo.mLineLength = 0.f;
257 subLineInfo.mMaxCharHeight = 0.f;
258 subLineInfo.mMaxAscender = 0.f;
260 float endWhiteSpaceLength = 0.f;
262 std::size_t wordIndex = indices.mWordIndex;
263 std::size_t characterIndex = indices.mCharacterIndex;
264 float lineOffset = 0.f;
266 bool isFirstCharacter = true;
267 for( TextViewProcessor::WordGroupLayoutInfoContainer::const_iterator wordGroupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex,
268 wordGroupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
269 ( wordGroupIt != wordGroupEndIt ) && !found;
272 const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *wordGroupIt );
274 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex,
275 wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
276 ( wordIt != wordEndIt ) && !found;
279 const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
281 const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
282 const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
284 bool splitByCharacter = false;
286 switch( splitPolicy )
288 case WrapByCharacter:
290 splitByCharacter = true;
294 case WrapByLine: // Fall through
296 splitByCharacter = false;
299 case WrapByWordAndSplit:
301 splitByCharacter = ( shrunkWordWidth > parentWidth );
304 case WrapByLineAndSplit:
306 if( ( 0 != characterIndex ) ||
307 ( ( 0 == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
309 splitByCharacter = true;
313 lineOffset += shrunkWordWidth;
314 splitByCharacter = false;
319 if( splitByCharacter )
321 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
322 charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
323 ( charIt != charEndIt ) && !found;
326 const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
327 CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
328 if( !found || isFirstCharacter )
330 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
331 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
334 // All characters for word 'wordIndex' have been processed.
335 // Next word need to process all characters, so the characterIndex is reset to 0.
337 isFirstCharacter = false;
340 lineOffset += subLineInfo.mLineLength;
344 CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
345 if( !found || isFirstCharacter )
347 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
348 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
350 isFirstCharacter = false;
354 // All words for group 'groupIndex' have been processed.
355 // Next group need to process all words, so the wordIndex is reset to 0.
359 subLineInfo.mMaxCharHeight *= shrinkFactor;
360 subLineInfo.mMaxAscender *= shrinkFactor;
363 float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, const float parentWidth, const float wholeTextWidth )
365 float xOffset( 0.f );
366 switch( horizontalTextAlignment )
368 case Toolkit::Alignment::HorizontalLeft:
373 case Toolkit::Alignment::HorizontalCenter:
375 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
378 case Toolkit::Alignment::HorizontalRight:
380 xOffset = parentWidth - wholeTextWidth;
385 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
392 float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, const float parentHeight, const float wholeTextHeight )
394 float yOffset( 0.f );
395 switch( verticalTextAlignment )
397 case Toolkit::Alignment::VerticalTop:
402 case Toolkit::Alignment::VerticalCenter:
404 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
407 case Toolkit::Alignment::VerticalBottom:
409 yOffset = parentHeight - wholeTextHeight;
414 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
421 float CalculateJustificationOffset( const Toolkit::TextView::LineJustification justification, const float wholeTextWidth, const float lineLength )
424 switch( justification )
426 case Toolkit::TextView::Left:
431 case Toolkit::TextView::Center:
433 offset = 0.5f * ( wholeTextWidth - lineLength );
436 case Toolkit::TextView::Right:
438 offset = wholeTextWidth - lineLength;
441 case Toolkit::TextView::Justified:
451 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, const VisibilityTestType type )
453 bool visible = false;
459 // Whether the text-actor is fully inside the boundaries of the text-view.
460 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
461 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
464 case FULLY_VISIBLE_WIDTH:
466 // Whether the text-actor is between the left and right boundaries of the text-view.
467 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
470 case FULLY_VISIBLE_HEIGHT:
472 // Whether the text-actor is between the top and bottom boundaries of the text-view.
473 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
476 case PARTIALLY_VISIBLE:
478 // Whether the text-actor is partially inside the boundaries of the text-view.
479 visible = ( ( position.x < parentSize.width ) &&
480 ( position.x + size.width > 0.f ) &&
481 ( position.y > 0.f ) &&
482 ( position.y - size.height < parentSize.height ) );
485 case PARTIALLY_VISIBLE_WIDTH:
487 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
488 // It may not be partially inside the text-view.
489 visible = ( ( position.x < parentSize.width ) &&
490 ( position.x + size.width > 0.f ) );
493 case PARTIALLY_VISIBLE_HEIGHT:
495 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
496 // It may not be partially inside the text-view.
497 visible = ( ( position.y > 0.f ) &&
498 ( position.y - size.height < parentSize.height ) );
506 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
508 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
510 return Vector2( gradient, p0.y - gradient * p0.x );
513 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
514 TextView::RelayoutData& relayoutData )
516 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
517 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
519 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
520 // In that case, it will align the line to the left and/or top, and ellipsize the end.
521 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
522 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
523 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
524 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
525 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
527 RelayoutParameters relayoutParameters;
529 // Calculates the vertical and horizontal offsets.
530 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
531 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
533 std::size_t lineJustificationIndex = 0; // Index to the first position of the vector which stores all line justification info.
534 std::size_t infoTableCharacterIndex = 0;
536 relayoutParameters.mIndices.mLineIndex = 0;
538 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
539 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
540 lineLayoutIt != endLineLayoutIt;
541 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
543 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
545 relayoutParameters.mIndices.mGroupIndex = 0;
546 float justificationOffset = 0.f;
548 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
549 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
550 groupLayoutIt != endGroupLayoutIt;
551 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
553 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
555 relayoutParameters.mIndices.mWordIndex = 0;
557 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
558 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
559 wordLayoutIt != endWordLayoutIt;
560 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
562 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
564 relayoutParameters.mIndices.mCharacterIndex = 0;
566 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
567 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
568 characterLayoutIt != endCharacterLayoutIt;
569 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
571 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
573 // Calculate line justification offset.
574 if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() )
576 const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) );
578 if( relayoutParameters.mIndices == lineJustificationInfo.mIndices )
580 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength );
581 ++lineJustificationIndex; // increase the index to point the next position in the vector.
585 // Deletes the offsets if the exceed policies are EllipsizeEnd.
586 const float horizontalOffset = textHorizontalOffset + justificationOffset;
587 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
588 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
590 // Updates the size and position table for text-input with the alignment offset.
591 Vector3 positionOffset( characterLayoutInfo.mPosition );
593 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
594 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
596 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
597 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
599 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
602 } // end group of words
606 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
607 TextView::RelayoutData& relayoutData )
619 // ggggg gggggggggg bb ggggg
620 // gg gg gggggggggg bb gg gg
621 // gg gg gggg bb gg gg
622 // gg gg gggg bb gg gg
623 // ggggg gg gggg bbbbbbb ggggg
624 // gg gg gggg bb bb gg
625 // g gg gggggggggg bb bb g gg
626 // ggggg gggggggggg bbbbbbb ggggg
635 // ggggg gggg gggg bb ggggg
636 // gg gg gggg gggg bbbbbbb gg gg
637 // gg gg gggg gggg bb bb gg gg
638 // gg gg gggggggggg bb bb gg gg
639 // ggggg gggggggggg bbbbbbb ggggg
642 // ggggg gg gggg ggggg
647 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1 ) );
648 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
650 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
653 void UpdateLayoutInfoTable( Vector4& minMaxXY,
654 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo,
655 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
656 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
657 RelayoutParameters& relayoutParameters,
658 TextView::RelayoutData& relayoutData )
660 // updates min and max position to calculate the text size for multiline policies.
661 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
662 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
664 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
665 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
667 // Adds layout info to be retrieved by external controls or applications.
668 Vector3 positionOffset( characterLayoutInfo.mPosition );
670 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
672 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor,
673 characterLayoutInfo.mHeight * relayoutData.mShrinkFactor ),
675 ( TextViewProcessor::LineSeparator == wordLayoutInfo.mType ),
676 ( TextViewProcessor::RTL == wordGroupLayoutInfo.mDirection ),
680 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
682 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
685 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
686 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
687 RelayoutParameters& relayoutParameters,
688 FadeParameters& fadeParameters,
689 TextView::RelayoutData& relayoutData )
691 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
692 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
693 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
694 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
700 // Calculates visibility of a text-actor according the exceed policies.
702 // position + alignment offset.
703 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
704 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
705 characterLayoutInfo.mPosition.z );
707 // Whether the text actor is fully, partially or non visible (according exceed policies).
708 switch( layoutParameters.mExceedPolicy )
712 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
713 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
714 if( !IsVisible( position,
715 characterLayoutInfo.mSize,
716 relayoutData.mTextViewSize,
719 relayoutParameters.mIsVisible = false;
720 if( IsVisible( position,
721 characterLayoutInfo.mSize,
722 relayoutData.mTextViewSize,
723 PARTIALLY_VISIBLE ) )
725 fadeParameters.mIsPartiallyVisible = true;
727 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
728 if( IsExceedingWidth( position,
729 characterLayoutInfo.mSize,
730 relayoutData.mTextViewSize ) &&
731 IsExceedingHeight( position,
732 characterLayoutInfo.mSize,
733 relayoutData.mTextViewSize ) )
735 // Combination not fully supported by text-view.
736 // Need to check if text-actor really supports this combination.
737 fadeParameters.mIsPartiallyVisible = false;
743 case TextView::FadeOriginal:
745 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
746 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
747 if( !IsVisible( position,
748 characterLayoutInfo.mSize,
749 relayoutData.mTextViewSize,
750 FULLY_VISIBLE_WIDTH ) )
752 relayoutParameters.mIsVisible = false;
753 if( IsVisible( position,
754 characterLayoutInfo.mSize,
755 relayoutData.mTextViewSize,
756 PARTIALLY_VISIBLE_WIDTH ) )
758 fadeParameters.mIsPartiallyVisible = true;
763 case TextView::OriginalFade:
764 case TextView::SplitFade: // Fallthrough
766 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
767 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
768 if( !IsVisible( position,
769 characterLayoutInfo.mSize,
770 relayoutData.mTextViewSize,
771 FULLY_VISIBLE_HEIGHT ) )
773 relayoutParameters.mIsVisible = false;
774 if( IsVisible( position,
775 characterLayoutInfo.mSize,
776 relayoutData.mTextViewSize,
777 PARTIALLY_VISIBLE_HEIGHT ) )
779 fadeParameters.mIsPartiallyVisible = true;
786 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
791 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
793 characterLayoutInfo.mIsVisible = true;
795 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
796 const float characterPositionPlusWidth = position.x + size.width;
797 const float characterPositionMinusHeight = position.y - size.height;
799 // Calculates which edges need to be faded-out.
800 bool rightFadeOut = false;
801 bool leftFadeOut = false;
802 bool bottomFadeOut = false;
803 bool topFadeOut = false;
805 switch( layoutParameters.mExceedPolicy )
809 // All text-actors exceeding any of the boundaries will be faded-out.
810 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
811 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
812 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
813 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
816 case TextView::FadeOriginal:
818 // Only text-actors exceeding the left or the right boundaries will be faded-out.
819 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
820 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
823 case TextView::SplitFade:
824 case TextView::OriginalFade: //Fallthrough
826 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
827 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
828 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
833 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
838 // Calculates gradient parameters for a text-actor.
839 Vector4 gradientColor = Vector4::ZERO;
840 Vector2 startPoint = Vector2::ZERO;
841 Vector2 endPoint = Vector2::ZERO;
843 if( !( rightFadeOut && leftFadeOut ) )
845 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
848 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
850 // Calculates gradient coeficients.
851 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
852 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
854 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ), 0.5f );
855 endPoint = Vector2( std::min( 1.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ), 0.5f );
857 else if( leftFadeOut )
859 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
861 // Calculates gradient coeficients.
862 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
863 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
865 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ), 0.5f );
866 endPoint = Vector2( std::min( 1.f, -position.x / size.width ), 0.5f );
870 if( !( bottomFadeOut && topFadeOut ) )
872 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
875 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
877 // Calculates gradient coeficients.
878 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
879 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
881 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
882 endPoint = Vector2( 0.5f, std::min( 1.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) );
884 else if( topFadeOut )
886 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
888 // Calculates gradient coeficients.
889 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
890 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
892 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
893 endPoint = Vector2( 0.5f, std::min( 1.f, -characterPositionMinusHeight / size.height ) );
897 characterLayoutInfo.mGradientColor = gradientColor;
898 characterLayoutInfo.mStartPoint = startPoint;
899 characterLayoutInfo.mEndPoint = endPoint;
903 characterLayoutInfo.mIsVisible = false;
907 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
908 const EllipsizeParameters& ellipsizeParameters )
910 bool isPartiallyVisible = false;
912 if( !IsVisible( ellipsizeParameters.mPosition,
913 characterLayoutInfo.mSize,
914 ellipsizeParameters.mEllipsizeBoundary,
915 FULLY_VISIBLE_WIDTH ) )
917 // The character doesn't fit in the text-view's width.
918 characterLayoutInfo.mIsVisible = false;
920 // Checks if the character is partially visible (it's cut by the boundary)
921 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
922 characterLayoutInfo.mSize,
923 ellipsizeParameters.mEllipsizeBoundary,
924 PARTIALLY_VISIBLE_WIDTH );
928 // The character fits in the text-view's width. Set it to visible.
929 characterLayoutInfo.mIsVisible = true;
932 return isPartiallyVisible;
935 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
936 const EllipsizeParameters& ellipsizeParameters )
938 bool isPartiallyVisible = false;
940 if( !IsVisible( ellipsizeParameters.mPosition,
941 characterLayoutInfo.mSize,
942 ellipsizeParameters.mEllipsizeBoundary,
945 // The character is not fully visible. Needs to check if it's partially visible.
946 characterLayoutInfo.mIsVisible = false;
948 // Checks if the character doesn't cut the bottom edge of the text-view.
949 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
950 characterLayoutInfo.mSize,
951 ellipsizeParameters.mEllipsizeBoundary,
952 FULLY_VISIBLE_HEIGHT );
954 // Checks if the character cuts the right edge of the text-view.
955 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
956 characterLayoutInfo.mSize,
957 ellipsizeParameters.mEllipsizeBoundary,
958 PARTIALLY_VISIBLE_WIDTH );
960 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
961 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
965 // The character fits in the boundary of the text-view. Set it to visible.
966 characterLayoutInfo.mIsVisible = true;
969 return isPartiallyVisible;
972 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
973 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
974 EllipsizeParameters& ellipsizeParameters,
975 TextView::RelayoutData& relayoutData )
977 // Calculates visibility for EllipsizeEnd exceed policies.
979 // 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.
980 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
981 // 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.
983 // Position of the character used to do the visibility test.
984 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
985 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
986 characterLayoutInfo.mPosition.z );
988 // 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).
989 bool isPartiallyVisible = false;
991 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
992 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
994 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
997 // The line or word fits completely inside the text-view's width. Nothing else to do.
998 characterLayoutInfo.mIsVisible = true;
1002 // The line or word doesn't fit in the text-view's width.
1004 // Calculates visibility for each type of ellipsize policies.
1005 switch( layoutParameters.mExceedPolicy )
1007 case TextView::EllipsizeEndOriginal:
1009 // 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.
1011 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1012 ellipsizeParameters );
1016 case TextView::SplitEllipsizeEnd:
1017 case TextView::EllipsizeEnd:
1019 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1021 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1022 ellipsizeParameters );
1028 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1034 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1035 // In that case, the charater needs to be replaced by the ellipsize text.
1036 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1039 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1040 TextView::RelayoutData& relayoutData )
1042 // 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.
1043 // The code bellow creates the text-actors needed for the ellipsize text.
1045 // Set ellipsize's position by the end of visible text.
1046 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1047 // Stores current ellipsize text.
1049 // Stores current ellipsize style.
1050 TextStyle ellipsizeStyle;
1051 // Stores the current size.
1053 //Whether current glyph is an emoticon.
1054 bool isColorGlyph = false;
1056 float bearingOffset = 0.f;
1058 // Create ellipsize text-actor.
1059 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1060 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1061 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1062 ++ellipsizeCharacterLayoutIt )
1064 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1067 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1068 ( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle ) )
1070 // The style is different, so a new text-actor is needed.
1071 if( !ellipsizeText.IsEmpty() )
1073 // It only creates a text-actor if there is any text.
1074 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1075 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1076 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1078 // Updates the position for the next text-actor.
1079 ellipsizePosition.x += ellipsizeSize.width;
1081 // Adds the text-actor to the list.
1082 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1085 // Resets the current ellipsize info.
1086 ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText;
1087 ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle;
1088 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1089 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1091 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1095 // Updates text and size with the new character.
1096 ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText );
1097 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1102 if( !ellipsizeText.IsEmpty() )
1104 // Creates the last glyph-actor.
1105 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1106 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1107 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1109 // Adds the glyph-actor to the list.
1110 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1114 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1115 EllipsizeParameters& ellipsizeParameters,
1116 TextView::RelayoutData& relayoutData )
1118 // Traverses the text layout info from the first character of the laid out line
1119 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1121 // Indices to the first character of the laid out line.
1122 TextViewProcessor::TextInfoIndices firstIndices;
1123 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1124 relayoutData.mTextLayoutInfo,
1127 // Indices to the last character of the laid out line.
1128 TextViewProcessor::TextInfoIndices lastIndices;
1129 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1130 relayoutData.mTextLayoutInfo,
1133 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1134 // This is the boundary used to check if a character have to be ellipsized.
1135 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1136 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1138 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + firstIndices.mLineIndex,
1139 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lastIndices.mLineIndex + 1;
1140 lineLayoutIt != endLineLayoutIt;
1143 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1145 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1147 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1149 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1152 bool firstGroup = true;
1153 bool lastGroup = false;
1154 std::size_t groupCount = 0;
1156 bool firstWord = true;
1157 bool lastWord = false;
1159 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + firstIndices.mGroupIndex,
1160 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + lastIndices.mGroupIndex + 1;
1161 groupLayoutIt != endGroupLayoutIt;
1162 ++groupLayoutIt, ++groupCount )
1164 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1166 if( groupCount == lastIndices.mGroupIndex - firstIndices.mGroupIndex )
1171 std::size_t wordCount = 0;
1172 const std::size_t firstWordIndex = firstGroup ? firstIndices.mWordIndex : 0u;
1173 const std::size_t lastWordIndex = lastGroup ? lastIndices.mWordIndex : wordGroupLayoutInfo.mWordsLayoutInfo.size() - 1;
1175 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + firstWordIndex,
1176 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + lastWordIndex + 1;
1177 wordLayoutIt != endWordLayoutIt;
1178 ++wordLayoutIt, ++wordCount )
1180 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1182 if( lastGroup && ( wordCount == lastIndices.mWordIndex - firstWordIndex ) )
1187 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1188 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1;
1189 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1190 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1;
1191 characterLayoutIt != endCharacterLayoutIt;
1192 ++characterLayoutIt )
1194 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1196 if( ellipsizeParameters.mEllipsizeLine )
1198 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1199 CalculateVisibilityForEllipsize( layoutParameters,
1200 characterLayoutInfo,
1201 ellipsizeParameters,
1204 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1206 // Create ellipsize text-actors if the character needs to be replaced.
1207 CreateEllipsizeTextActor( ellipsizeParameters,
1213 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1214 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1216 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1218 // Make characters invisible.
1219 characterLayoutInfo.mIsVisible = false;
1231 void SetTextVisible( TextView::RelayoutData& relayoutData )
1233 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1234 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1235 lineLayoutIt != endLineLayoutIt;
1238 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1240 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1241 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1242 groupLayoutIt != endGroupLayoutIt;
1245 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1247 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1248 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1249 wordLayoutIt != endWordLayoutIt;
1252 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1254 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1255 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1256 characterLayoutIt != endCharacterLayoutIt;
1257 ++characterLayoutIt )
1259 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1261 characterLayoutInfo.mIsVisible = true;
1262 characterLayoutInfo.mGradientColor = Vector4::ZERO;
1263 characterLayoutInfo.mStartPoint = Vector2::ZERO;
1264 characterLayoutInfo.mEndPoint = Vector2::ZERO;
1265 characterLayoutInfo.mColorAlpha = characterLayoutInfo.mStyledText.mStyle.GetTextColor().a;
1268 } // end group of words
1271 // Updates the visibility for text-input..
1272 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1273 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1277 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1279 characterLayoutInfo.mIsVisible = true;
1283 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1284 const TextView::VisualParameters& visualParameters,
1285 TextView::RelayoutData& relayoutData )
1287 RelayoutParameters relayoutParameters;
1288 FadeParameters fadeParameters;
1290 // 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.
1291 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1292 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0 ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1293 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1294 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1295 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1296 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0 ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1297 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1298 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1299 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1300 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0 ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1301 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1302 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1303 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1304 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0 ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1305 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1306 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1308 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1309 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1310 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1311 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1312 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1314 // Traverses all groups of characters and calculates the visibility.
1316 std::size_t infoTableCharacterIndex = 0;
1318 relayoutParameters.mIndices.mLineIndex = 0;
1320 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1321 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1322 lineLayoutIt != endLineLayoutIt;
1323 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
1325 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1327 relayoutParameters.mIndices.mGroupIndex = 0;
1329 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1330 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1331 groupLayoutIt != endGroupLayoutIt;
1332 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
1334 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1336 relayoutParameters.mIndices.mWordIndex = 0;
1338 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1339 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1340 wordLayoutIt != endWordLayoutIt;
1341 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1343 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1345 relayoutParameters.mIsFirstCharacterOfWord = true;
1346 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1347 relayoutParameters.mIndices.mCharacterIndex = 0;
1349 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1350 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1351 characterLayoutIt != endCharacterLayoutIt;
1352 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
1354 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1356 relayoutParameters.mIsVisible = true;
1357 fadeParameters.mIsPartiallyVisible = false;
1359 // Calculates the visibility for the current group of characters.
1360 CalculateVisibilityForFade( layoutParameters,
1361 characterLayoutInfo,
1366 // Updates the visibility for text-input..
1367 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
1369 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1371 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1373 relayoutParameters.mIsFirstCharacterOfWord = false;
1374 } // end group of character
1376 } // end group of words
1380 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1381 const TextView::VisualParameters& visualParameters,
1382 TextView::RelayoutData& relayoutData )
1384 // Traverses the laid-out lines and checks which ones doesn't fit in the text-view's boundary.
1385 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1386 lineInfoIt != endLineInfoIt;
1389 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1391 // To check if a laid-out line fits in the text-view's boundary,
1392 // get the position of the first character is needed and do the test
1393 // with the laid-out line size.
1395 // An bearing offset may have been applied to the first character so it's needed to
1396 // get the start position of the line.
1398 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1399 EllipsizeParameters ellipsizeParameters;
1401 // Retrieves the first index and the last index of the line.
1402 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1403 ellipsizeParameters.mLastIndex = 0;
1404 if( ( lineInfoIt + 1 ) != endLineInfoIt )
1406 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1 ) );
1407 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1;
1411 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1;
1414 // Retrieves the first character of the line and build the position of the line with the bearing.
1415 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1417 // Calculates the bearing offset applied to the first character.
1418 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1420 // Build the position of the line by removing the bearing offset from the first character's position.
1421 const Vector3 position( characterInfo.mPosition.x,
1422 characterInfo.mPosition.y + bearingOffset,
1423 characterInfo.mPosition.z );
1425 // Checks if the line needs to be ellipsized,
1426 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1428 relayoutData.mTextViewSize,
1429 FULLY_VISIBLE_WIDTH );
1431 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1432 // if the line fits in the width.
1433 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1435 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1436 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1437 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1438 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1439 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1440 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1442 // Need to check if there is lines which doesn't fit in the height.
1444 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1446 relayoutData.mTextViewSize,
1447 FULLY_VISIBLE_HEIGHT );
1449 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1451 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1453 // Current line is not ellipsized.
1454 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1455 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1;
1456 if( nextLineInfoIt != endLineInfoIt )
1458 // Retrives the position of the first character of the line and remove
1459 // the bearing offset to build to build the position of the line.
1460 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1461 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1463 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1465 const Vector3 position( characterInfo.mPosition.x,
1466 characterInfo.mPosition.y + bearingOffset,
1467 characterInfo.mPosition.z );
1469 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1471 relayoutData.mTextViewSize,
1472 FULLY_VISIBLE_HEIGHT );
1474 // If the next line is not visible, current line have to be ellipsized.
1475 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1480 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1482 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1485 // Sets the line descender.
1486 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1488 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1489 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1493 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1494 const TextView::VisualParameters& visualParameters,
1495 TextView::RelayoutData& relayoutData )
1497 switch( layoutParameters.mExceedPolicy )
1499 case TextView::FadeOriginal:
1500 case TextView::OriginalFade:
1501 case TextView::Fade:
1502 case TextView::SplitFade: // Fall through
1504 UpdateVisibilityForFade( layoutParameters,
1509 case TextView::EllipsizeEndOriginal:
1510 case TextView::SplitEllipsizeEnd:
1511 case TextView::EllipsizeEnd: // Fall through
1513 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1514 SetTextVisible( relayoutData );
1516 UpdateVisibilityForEllipsize( layoutParameters,
1523 SetTextVisible( relayoutData );
1529 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
1530 TextView::RelayoutData& relayoutData )
1532 CurrentTextActorInfo currentTextActorInfo;
1534 // Traverses the text-actor and layout info data structures.
1535 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1536 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1537 lineLayoutIt != endLineLayoutIt;
1540 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1542 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1543 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1544 groupLayoutIt != endGroupLayoutIt;
1547 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1549 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1550 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1551 wordLayoutIt != endWordLayoutIt;
1554 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1556 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1557 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1558 characterLayoutIt != endCharacterLayoutIt;
1559 ++characterLayoutIt )
1561 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1563 if( characterLayoutInfo.mIsColorGlyph )
1565 ImageActor imageActor = ImageActor::DownCast( characterLayoutInfo.mGlyphActor );
1567 if( characterLayoutInfo.mSetText )
1569 GlyphImage image = GlyphImage::New( characterLayoutInfo.mStyledText.mText[0] );
1573 imageActor.SetImage( image );
1575 characterLayoutInfo.mSetText = false;
1578 imageActor.SetPosition( Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1579 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1580 characterLayoutInfo.mPosition.z ) );
1581 imageActor.SetSize( characterLayoutInfo.mSize );
1583 // Sets the sort modifier value.
1584 imageActor.SetSortModifier( visualParameters.mSortModifier );
1588 TextActor textActor = TextActor::DownCast( characterLayoutInfo.mGlyphActor );
1591 // There is a new text-actor. Set text and everything to the previous one.
1592 if( currentTextActorInfo.textActor )
1594 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1595 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1596 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1598 SetVisualParameters( currentTextActorInfo,
1601 lineLayoutInfo.mSize.height );
1604 currentTextActorInfo.text = characterLayoutInfo.mStyledText.mText;
1605 currentTextActorInfo.position = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1606 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1607 characterLayoutInfo.mPosition.z );
1608 currentTextActorInfo.size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1610 currentTextActorInfo.color = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
1611 currentTextActorInfo.color.a = characterLayoutInfo.mColorAlpha;
1613 currentTextActorInfo.gradientColor = characterLayoutInfo.mGradientColor;
1614 currentTextActorInfo.startPoint = characterLayoutInfo.mStartPoint;
1615 currentTextActorInfo.endPoint = characterLayoutInfo.mEndPoint;
1617 // Update the current text-actor.
1618 currentTextActorInfo.textActor = textActor;
1622 // If this character layout has no text-actor is because this character has the same style than previous one.
1623 // Add the character to the current text-actor and update the size.
1624 if( characterLayoutInfo.mIsVisible && ( TextViewProcessor::LineSeparator != wordLayoutInfo.mType ) )
1626 currentTextActorInfo.text.Append( characterLayoutInfo.mStyledText.mText );
1628 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y ) );
1629 currentTextActorInfo.size.width += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1630 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1637 if( !currentTextActorInfo.text.IsEmpty() )
1639 if( currentTextActorInfo.textActor )
1641 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1642 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1643 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1645 SetVisualParameters( currentTextActorInfo,
1648 lineLayoutInfo.mSize.height );
1651 } //end groups of words
1654 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1655 endIt = relayoutData.mEllipsizedGlyphActors.end();
1659 RenderableActor glyphActor = ( *it );
1661 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1662 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1664 // Sets the sort modifier value.
1665 glyphActor.SetSortModifier( visualParameters.mSortModifier );
1667 // Enables or disables the blending.
1668 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
1672 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
1674 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1676 // 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.
1677 // According with the layout option, one of this lines could be laid-out in more than one.
1679 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1680 lineIt != lineEndIt;
1683 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1685 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1686 groupIt != groupEndIt;
1689 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1691 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1692 wordIt != wordEndIt;
1695 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1697 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1698 characterIt != characterEndIt;
1701 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1703 // Check if current character is the first of a new laid-out line
1704 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
1705 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
1708 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1711 if( characterGroup.mStyledText.mStyle.IsUnderlineEnabled() )
1713 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
1714 isNewLine ) // Current character is underlined and is the first of current laid-out line.
1716 // Create a new underline info for the current underlined characters.
1717 UnderlineInfo underlineInfo;
1718 underlineInfo.mMaxHeight = characterGroup.mSize.height;
1719 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1720 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1722 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
1724 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
1728 // Retrieve last underline info and update it if current underline thickness is bigger.
1729 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1 ) );
1731 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, characterGroup.mSize.height );
1733 if( characterGroup.mUnderlineThickness > underlineInfo.mMaxThickness )
1735 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1736 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1742 textUnderlineStatus.mCurrentUnderlineStatus = false;
1745 ++textUnderlineStatus.mCharacterGlobalIndex;
1746 } // end group of characters.
1748 } // end group of words.
1752 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
1754 // 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.
1755 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
1757 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1758 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
1760 if( textUnderlineStatus.mUnderlineInfo.empty() )
1762 // There is no underlined text. Just exit.
1766 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
1767 // Traverse the whole text and set the previously stored underline info in the text style.
1769 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
1770 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
1772 UnderlineInfo underlineInfo;
1774 if( underlineInfoIt < underlineInfoEndIt )
1776 underlineInfo = ( *underlineInfoIt );
1779 // Whether current text is underlined.
1780 textUnderlineStatus.mCurrentUnderlineStatus = false;
1781 textUnderlineStatus.mCharacterGlobalIndex = 0;
1782 textUnderlineStatus.mLineGlobalIndex = 0;
1784 float currentLineHeight = 0.f;
1785 float currentLineAscender = 0.f;
1787 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1788 lineIt != lineEndIt;
1791 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1793 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1794 groupIt != groupEndIt;
1797 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1799 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1800 wordIt != wordEndIt;
1803 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1805 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1806 characterIt != characterEndIt;
1809 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1811 // Check if current character is the first of a new laid-out line
1813 bool isNewLine = false;
1815 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
1817 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
1818 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
1822 currentLineHeight = lineLayoutInfo.mSize.height;
1823 currentLineAscender = lineLayoutInfo.mAscender;
1824 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1828 if( characterGroup.mStyledText.mStyle.IsUnderlineEnabled() )
1830 if( textUnderlineStatus.mCurrentUnderlineStatus )
1834 // Retrieves the thickness and position for the next piece of underlined text.
1835 if( underlineInfoIt < underlineInfoEndIt )
1838 if( underlineInfoIt < underlineInfoEndIt )
1840 underlineInfo = *underlineInfoIt;
1846 textUnderlineStatus.mCurrentUnderlineStatus = true;
1848 // Before setting the position it needs to be adjusted to match the base line.
1849 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( characterGroup.mSize.height - characterGroup.mAscender );
1850 const float positionOffset = ( underlineInfo.mMaxHeight - characterGroup.mSize.height ) - bearingOffset;
1852 // Sets the underline's parameters.
1853 characterGroup.mStyledText.mStyle.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
1855 // Mark the group of characters to be set the new style into the text-actor.
1856 characterGroup.mSetStyle = true;
1860 if( textUnderlineStatus.mCurrentUnderlineStatus )
1862 textUnderlineStatus.mCurrentUnderlineStatus = false;
1864 // Retrieves the thickness and position for the next piece of underlined text.
1865 if( underlineInfoIt < underlineInfoEndIt )
1868 if( underlineInfoIt < underlineInfoEndIt )
1870 underlineInfo = *underlineInfoIt;
1876 ++textUnderlineStatus.mCharacterGlobalIndex;
1877 } // end of group of characters.
1879 } // end of group of words.
1883 void RemoveGlyphActors( Actor textView,
1884 const std::vector<RenderableActor>& glyphActors )
1886 // Removes previously inserted renderable-actors.
1887 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
1888 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
1889 // in order to remove 'only' renderable-actors added by these functions.
1890 // Any other actor added by a programmer or application won't be removed.
1892 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
1894 textView.Remove( *it );
1898 void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMask,
1900 TextView::RelayoutData& relayoutData )
1902 const bool insertToTextView = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW;
1903 const bool insertToTextActorList = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST;
1905 // Add text-actors to the text-view.
1907 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1908 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1909 lineLayoutIt != endLineLayoutIt;
1912 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1914 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1915 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1916 groupLayoutIt != endGroupLayoutIt;
1919 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1921 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1922 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1923 wordLayoutIt != endWordLayoutIt;
1926 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1928 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1929 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1930 characterLayoutIt != endCharacterLayoutIt;
1931 ++characterLayoutIt )
1933 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1935 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
1937 //Add to the text-view.
1938 if( insertToTextView )
1940 textView.Add( characterLayoutInfo.mGlyphActor );
1942 if( insertToTextActorList )
1944 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
1947 } // end group of character
1949 } // end group of words
1952 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1953 endIt = relayoutData.mEllipsizedGlyphActors.end();
1957 RenderableActor glyphActor = ( *it );
1959 //Add to the text-view.
1960 if( insertToTextView )
1962 textView.Add( glyphActor );
1964 if( insertToTextActorList )
1966 relayoutData.mGlyphActors.push_back( glyphActor );
1969 relayoutData.mEllipsizedGlyphActors.clear();
1972 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
1974 TextActor textActor = cache.RetrieveTextActor();
1978 // Update the text-actor.
1979 textActor.SetText( text );
1980 textActor.SetTextStyle( style );
1984 // The text-actor cache is empty. Create a new one.
1985 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1986 textActor = TextActor::New( text, parameters );
1992 } // namespace TextViewRelayout
1994 } // namespace Internal
1996 } // namespace Toolkit