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 <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
22 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
36 namespace TextViewRelayout
39 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.
41 RelayoutParameters::RelayoutParameters()
47 mCharacterGlobalIndex( 0u ),
48 mIsFirstCharacter( false ),
49 mIsFirstCharacterOfWord( false ),
51 mIsNewLineCharacter( false ),
52 mIsWhiteSpace( false ),
57 RelayoutParameters::~RelayoutParameters()
61 FadeParameters::FadeParameters()
62 : mRightFadeBoundary( 0.f ),
63 mRightFadeThreshold( 0.f ),
64 mRightFadeBoundaryOffset( 0.f ),
65 mRightFadeThresholdOffset( 0.f ),
66 mRightAlphaCoeficients(),
67 mLeftFadeBoundary( 0.f ),
68 mLeftFadeThreshold( 0.f ),
69 mLeftFadeBoundaryOffset( 0.f ),
70 mLeftFadeThresholdOffset( 0.f ),
71 mLeftAlphaCoeficients(),
72 mTopFadeBoundary( 0.f ),
73 mTopFadeThreshold( 0.f ),
74 mTopFadeBoundaryOffset( 0.f ),
75 mTopFadeThresholdOffset( 0.f ),
76 mTopAlphaCoeficients(),
77 mBottomFadeBoundary( 0.f ),
78 mBottomFadeThreshold( 0.f ),
79 mBottomFadeBoundaryOffset( 0.f ),
80 mBottomFadeThresholdOffset( 0.f ),
81 mBottomAlphaCoeficients(),
82 mIsPartiallyVisible( false )
86 FadeParameters::~FadeParameters()
90 EllipsizeParameters::EllipsizeParameters()
92 mLineDescender( 0.f ),
97 mEllipsizeLine( false ),
98 mIsLineWidthFullyVisible( false ),
99 mIsLineHeightFullyVisible( false ),
100 mIsNextLineFullyVisibleHeight( false ),
101 mCreateEllipsizedTextActors( false ),
107 EllipsizeParameters::~EllipsizeParameters()
111 UnderlineInfo::UnderlineInfo()
113 mMaxThickness( 0.f ),
118 UnderlineInfo::~UnderlineInfo()
122 TextUnderlineStatus::TextUnderlineStatus()
124 mCharacterGlobalIndex( 0u ),
125 mLineGlobalIndex( 0u ),
126 mCurrentUnderlineStatus( false )
130 TextUnderlineStatus::~TextUnderlineStatus()
134 SubLineLayoutInfo::SubLineLayoutInfo()
135 : mLineLength( 0.f ),
136 mMaxCharHeight( 0.f ),
141 SubLineLayoutInfo::~SubLineLayoutInfo()
146 * Whether the given text-actor exceeds the left or the right boundary of the text-view.
148 * @param[in] position The position of the text-actor.
149 * @param[in] size The size of the text-actor.
150 * @param[in] parantSize The size of the text-view.
152 * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
154 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
156 return ( ( position.x < 0.f ) ||
157 ( position.x + size.width > parentSize.width ) );
161 * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
163 * @param[in] position The position of the text-actor.
164 * @param[in] size The size of the text-actor.
165 * @param[in] parantSize The size of the text-view.
167 * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
169 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
171 return ( ( position.y > parentSize.height ) ||
172 ( position.y < size.height ) );
176 * Calculates the line length adding the new word or character width.
178 * It also returns the length of white spaces if they are at the end of the line.
180 * @param[in] isWhiteSpace Whether the word is a white space.
181 * @param[in] width The width of the character or word.
182 * @param[in] parentWidth The parent width.
183 * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
184 * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
185 * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
187 void CalculateLineLength( const bool isWhiteSpace, const float width, const float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
189 if( lineLength + width > parentWidth )
192 lineLength -= endWhiteSpaceLength;
200 endWhiteSpaceLength += width;
204 endWhiteSpaceLength = 0.f;
209 struct CurrentTextActorInfo
216 Vector4 gradientColor;
221 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
222 const TextView::VisualParameters& visualParameters,
223 TextView::RelayoutData& relayoutData,
224 const float lineHeight )
226 currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
227 currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientColor );
228 currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.startPoint );
229 currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.endPoint );
231 // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
232 // due to the trick used to implement it.
233 const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
234 const float italicsOffset = lineHeight * std::tan( italicsAngle );
235 relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
237 // Sets the sort modifier value.
238 currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
240 // Enables or disables the blending.
241 currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
244 void CalculateSubLineLayout( const float parentWidth,
245 const TextViewProcessor::TextInfoIndices& indices,
246 const TextViewProcessor::LineLayoutInfo& lineLayoutInfo,
247 const HorizontalWrapType splitPolicy,
248 const float shrinkFactor,
249 SubLineLayoutInfo& subLineInfo )
251 subLineInfo.mLineLength = 0.f;
252 subLineInfo.mMaxCharHeight = 0.f;
253 subLineInfo.mMaxAscender = 0.f;
255 float endWhiteSpaceLength = 0.f;
257 std::size_t wordIndex = indices.mWordIndex;
258 std::size_t characterIndex = indices.mCharacterIndex;
259 float lineOffset = 0.f;
261 bool isFirstCharacter = true;
262 for( TextViewProcessor::WordGroupLayoutInfoContainer::const_iterator wordGroupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex,
263 wordGroupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
264 ( wordGroupIt != wordGroupEndIt ) && !found;
267 const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *wordGroupIt );
269 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex,
270 wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
271 ( wordIt != wordEndIt ) && !found;
274 const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
276 const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
277 const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
279 bool splitByCharacter = false;
281 switch( splitPolicy )
283 case WrapByCharacter:
285 splitByCharacter = true;
289 case WrapByLine: // Fall through
291 splitByCharacter = false;
294 case WrapByWordAndSplit:
296 splitByCharacter = ( shrunkWordWidth > parentWidth );
299 case WrapByLineAndSplit:
301 if( ( 0 != characterIndex ) ||
302 ( ( 0 == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
304 splitByCharacter = true;
308 lineOffset += shrunkWordWidth;
309 splitByCharacter = false;
314 if( splitByCharacter )
316 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
317 charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
318 ( charIt != charEndIt ) && !found;
321 const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
322 CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
323 if( !found || isFirstCharacter )
325 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
326 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
329 // All characters for word 'wordIndex' have been processed.
330 // Next word need to process all characters, so the characterIndex is reset to 0.
332 isFirstCharacter = false;
335 lineOffset += subLineInfo.mLineLength;
339 CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
340 if( !found || isFirstCharacter )
342 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
343 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
345 isFirstCharacter = false;
349 // All words for group 'groupIndex' have been processed.
350 // Next group need to process all words, so the wordIndex is reset to 0.
354 subLineInfo.mMaxCharHeight *= shrinkFactor;
355 subLineInfo.mMaxAscender *= shrinkFactor;
358 float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, const float parentWidth, const float wholeTextWidth )
360 float xOffset( 0.f );
361 switch( horizontalTextAlignment )
363 case Toolkit::Alignment::HorizontalLeft:
368 case Toolkit::Alignment::HorizontalCenter:
370 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
373 case Toolkit::Alignment::HorizontalRight:
375 xOffset = parentWidth - wholeTextWidth;
380 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
387 float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, const float parentHeight, const float wholeTextHeight )
389 float yOffset( 0.f );
390 switch( verticalTextAlignment )
392 case Toolkit::Alignment::VerticalTop:
397 case Toolkit::Alignment::VerticalCenter:
399 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
402 case Toolkit::Alignment::VerticalBottom:
404 yOffset = parentHeight - wholeTextHeight;
409 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
416 float CalculateJustificationOffset( const Toolkit::TextView::LineJustification justification, const float wholeTextWidth, const float lineLength )
419 switch( justification )
421 case Toolkit::TextView::Left:
426 case Toolkit::TextView::Center:
428 offset = 0.5f * ( wholeTextWidth - lineLength );
431 case Toolkit::TextView::Right:
433 offset = wholeTextWidth - lineLength;
436 case Toolkit::TextView::Justified:
446 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, const VisibilityTestType type )
448 bool visible = false;
454 // Whether the text-actor is fully inside the boundaries of the text-view.
455 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
456 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
459 case FULLY_VISIBLE_WIDTH:
461 // Whether the text-actor is between the left and right boundaries of the text-view.
462 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
465 case FULLY_VISIBLE_HEIGHT:
467 // Whether the text-actor is between the top and bottom boundaries of the text-view.
468 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
471 case PARTIALLY_VISIBLE:
473 // Whether the text-actor is partially inside the boundaries of the text-view.
474 visible = ( ( position.x < parentSize.width ) &&
475 ( position.x + size.width > 0.f ) &&
476 ( position.y > 0.f ) &&
477 ( position.y - size.height < parentSize.height ) );
480 case PARTIALLY_VISIBLE_WIDTH:
482 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
483 // It may not be partially inside the text-view.
484 visible = ( ( position.x < parentSize.width ) &&
485 ( position.x + size.width > 0.f ) );
488 case PARTIALLY_VISIBLE_HEIGHT:
490 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
491 // It may not be partially inside the text-view.
492 visible = ( ( position.y > 0.f ) &&
493 ( position.y - size.height < parentSize.height ) );
501 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
503 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
505 return Vector2( gradient, p0.y - gradient * p0.x );
508 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
509 TextView::RelayoutData& relayoutData )
511 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
512 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
514 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
515 // In that case, it will align the line to the left and/or top, and ellipsize the end.
516 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
517 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
518 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
519 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
520 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
522 RelayoutParameters relayoutParameters;
524 // Calculates the vertical and horizontal offsets.
525 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
526 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
528 std::size_t lineJustificationIndex = 0; // Index to the first position of the vector which stores all line justification info.
529 std::size_t infoTableCharacterIndex = 0;
531 relayoutParameters.mIndices.mLineIndex = 0;
533 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
534 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
535 lineLayoutIt != endLineLayoutIt;
536 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
538 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
540 relayoutParameters.mIndices.mGroupIndex = 0;
541 float justificationOffset = 0.f;
543 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
544 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
545 groupLayoutIt != endGroupLayoutIt;
546 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
548 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
550 relayoutParameters.mIndices.mWordIndex = 0;
552 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
553 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
554 wordLayoutIt != endWordLayoutIt;
555 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
557 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
559 relayoutParameters.mIndices.mCharacterIndex = 0;
561 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
562 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
563 characterLayoutIt != endCharacterLayoutIt;
564 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
566 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
568 // Calculate line justification offset.
569 if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() )
571 const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) );
573 if( relayoutParameters.mIndices == lineJustificationInfo.mIndices )
575 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength );
576 ++lineJustificationIndex; // increase the index to point the next position in the vector.
580 // Deletes the offsets if the exceed policies are EllipsizeEnd.
581 const float horizontalOffset = textHorizontalOffset + justificationOffset;
582 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
583 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
585 // Updates the size and position table for text-input with the alignment offset.
586 Vector3 positionOffset( characterLayoutInfo.mPosition );
588 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
589 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
591 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
592 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
594 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
597 } // end group of words
601 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
602 TextView::RelayoutData& relayoutData )
614 // ggggg gggggggggg bb ggggg
615 // gg gg gggggggggg bb gg gg
616 // gg gg gggg bb gg gg
617 // gg gg gggg bb gg gg
618 // ggggg gg gggg bbbbbbb ggggg
619 // gg gg gggg bb bb gg
620 // g gg gggggggggg bb bb g gg
621 // ggggg gggggggggg bbbbbbb ggggg
630 // ggggg gggg gggg bb ggggg
631 // gg gg gggg gggg bbbbbbb gg gg
632 // gg gg gggg gggg bb bb gg gg
633 // gg gg gggggggggg bb bb gg gg
634 // ggggg gggggggggg bbbbbbb ggggg
637 // ggggg gg gggg ggggg
642 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1 ) );
643 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
645 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
648 void UpdateLayoutInfoTable( Vector4& minMaxXY,
649 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo,
650 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
651 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
652 RelayoutParameters& relayoutParameters,
653 TextView::RelayoutData& relayoutData )
655 // updates min and max position to calculate the text size for multiline policies.
656 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
657 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
659 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
660 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
662 // Adds layout info to be retrieved by external controls or applications.
663 Vector3 positionOffset( characterLayoutInfo.mPosition );
665 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
667 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor,
668 characterLayoutInfo.mHeight * relayoutData.mShrinkFactor ),
670 ( TextViewProcessor::LineSeparator == wordLayoutInfo.mType ),
671 ( TextViewProcessor::RTL == wordGroupLayoutInfo.mDirection ),
675 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
677 positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor;
680 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
681 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
682 RelayoutParameters& relayoutParameters,
683 FadeParameters& fadeParameters,
684 TextView::RelayoutData& relayoutData )
686 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
687 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
688 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
689 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
695 // Calculates visibility of a text-actor according the exceed policies.
697 // position + alignment offset.
698 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
699 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
700 characterLayoutInfo.mPosition.z );
702 // Whether the text actor is fully, partially or non visible (according exceed policies).
703 switch( layoutParameters.mExceedPolicy )
707 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
708 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
709 if( !IsVisible( position,
710 characterLayoutInfo.mSize,
711 relayoutData.mTextViewSize,
714 relayoutParameters.mIsVisible = false;
715 if( IsVisible( position,
716 characterLayoutInfo.mSize,
717 relayoutData.mTextViewSize,
718 PARTIALLY_VISIBLE ) )
720 fadeParameters.mIsPartiallyVisible = true;
722 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
723 if( IsExceedingWidth( position,
724 characterLayoutInfo.mSize,
725 relayoutData.mTextViewSize ) &&
726 IsExceedingHeight( position,
727 characterLayoutInfo.mSize,
728 relayoutData.mTextViewSize ) )
730 // Combination not fully supported by text-view.
731 // Need to check if text-actor really supports this combination.
732 fadeParameters.mIsPartiallyVisible = false;
738 case TextView::FadeOriginal:
740 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
741 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
742 if( !IsVisible( position,
743 characterLayoutInfo.mSize,
744 relayoutData.mTextViewSize,
745 FULLY_VISIBLE_WIDTH ) )
747 relayoutParameters.mIsVisible = false;
748 if( IsVisible( position,
749 characterLayoutInfo.mSize,
750 relayoutData.mTextViewSize,
751 PARTIALLY_VISIBLE_WIDTH ) )
753 fadeParameters.mIsPartiallyVisible = true;
758 case TextView::OriginalFade:
759 case TextView::SplitFade: // Fallthrough
761 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
762 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
763 if( !IsVisible( position,
764 characterLayoutInfo.mSize,
765 relayoutData.mTextViewSize,
766 FULLY_VISIBLE_HEIGHT ) )
768 relayoutParameters.mIsVisible = false;
769 if( IsVisible( position,
770 characterLayoutInfo.mSize,
771 relayoutData.mTextViewSize,
772 PARTIALLY_VISIBLE_HEIGHT ) )
774 fadeParameters.mIsPartiallyVisible = true;
781 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
786 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
788 characterLayoutInfo.mIsVisible = true;
790 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
791 const float characterPositionPlusWidth = position.x + size.width;
792 const float characterPositionMinusHeight = position.y - size.height;
794 // Calculates which edges need to be faded-out.
795 bool rightFadeOut = false;
796 bool leftFadeOut = false;
797 bool bottomFadeOut = false;
798 bool topFadeOut = false;
800 switch( layoutParameters.mExceedPolicy )
804 // All text-actors exceeding any of the boundaries will be faded-out.
805 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
806 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
807 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
808 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
811 case TextView::FadeOriginal:
813 // Only text-actors exceeding the left or the right boundaries will be faded-out.
814 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
815 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
818 case TextView::SplitFade:
819 case TextView::OriginalFade: //Fallthrough
821 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
822 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
823 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
828 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
833 // Calculates gradient parameters for a text-actor.
834 Vector4 gradientColor = Vector4::ZERO;
835 Vector2 startPoint = Vector2::ZERO;
836 Vector2 endPoint = Vector2::ZERO;
838 if( !( rightFadeOut && leftFadeOut ) )
840 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
843 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
845 // Calculates gradient coeficients.
846 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
847 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
849 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ), 0.5f );
850 endPoint = Vector2( std::min( 1.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ), 0.5f );
852 else if( leftFadeOut )
854 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
856 // Calculates gradient coeficients.
857 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
858 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
860 startPoint = Vector2( std::max( 0.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ), 0.5f );
861 endPoint = Vector2( std::min( 1.f, -position.x / size.width ), 0.5f );
865 if( !( bottomFadeOut && topFadeOut ) )
867 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
870 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
872 // Calculates gradient coeficients.
873 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
874 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
876 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
877 endPoint = Vector2( 0.5f, std::min( 1.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) );
879 else if( topFadeOut )
881 gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
883 // Calculates gradient coeficients.
884 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
885 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
887 startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) );
888 endPoint = Vector2( 0.5f, std::min( 1.f, -characterPositionMinusHeight / size.height ) );
892 characterLayoutInfo.mGradientColor = gradientColor;
893 characterLayoutInfo.mStartPoint = startPoint;
894 characterLayoutInfo.mEndPoint = endPoint;
898 characterLayoutInfo.mIsVisible = false;
902 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
903 const EllipsizeParameters& ellipsizeParameters )
905 bool isPartiallyVisible = false;
907 if( !IsVisible( ellipsizeParameters.mPosition,
908 characterLayoutInfo.mSize,
909 ellipsizeParameters.mEllipsizeBoundary,
910 FULLY_VISIBLE_WIDTH ) )
912 // The character doesn't fit in the text-view's width.
913 characterLayoutInfo.mIsVisible = false;
915 // Checks if the character is partially visible (it's cut by the boundary)
916 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
917 characterLayoutInfo.mSize,
918 ellipsizeParameters.mEllipsizeBoundary,
919 PARTIALLY_VISIBLE_WIDTH );
923 // The character fits in the text-view's width. Set it to visible.
924 characterLayoutInfo.mIsVisible = true;
927 return isPartiallyVisible;
930 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
931 const EllipsizeParameters& ellipsizeParameters )
933 bool isPartiallyVisible = false;
935 if( !IsVisible( ellipsizeParameters.mPosition,
936 characterLayoutInfo.mSize,
937 ellipsizeParameters.mEllipsizeBoundary,
940 // The character is not fully visible. Needs to check if it's partially visible.
941 characterLayoutInfo.mIsVisible = false;
943 // Checks if the character doesn't cut the bottom edge of the text-view.
944 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
945 characterLayoutInfo.mSize,
946 ellipsizeParameters.mEllipsizeBoundary,
947 FULLY_VISIBLE_HEIGHT );
949 // Checks if the character cuts the right edge of the text-view.
950 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
951 characterLayoutInfo.mSize,
952 ellipsizeParameters.mEllipsizeBoundary,
953 PARTIALLY_VISIBLE_WIDTH );
955 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
956 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
960 // The character fits in the boundary of the text-view. Set it to visible.
961 characterLayoutInfo.mIsVisible = true;
964 return isPartiallyVisible;
967 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
968 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
969 EllipsizeParameters& ellipsizeParameters,
970 TextView::RelayoutData& relayoutData )
972 // Calculates visibility for EllipsizeEnd exceed policies.
974 // 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.
975 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
976 // 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.
978 // Position of the character used to do the visibility test.
979 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
980 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
981 characterLayoutInfo.mPosition.z );
983 // 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).
984 bool isPartiallyVisible = false;
986 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
987 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
989 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
992 // The line or word fits completely inside the text-view's width. Nothing else to do.
993 characterLayoutInfo.mIsVisible = true;
997 // The line or word doesn't fit in the text-view's width.
999 // Calculates visibility for each type of ellipsize policies.
1000 switch( layoutParameters.mExceedPolicy )
1002 case TextView::EllipsizeEndOriginal:
1004 // 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.
1006 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1007 ellipsizeParameters );
1011 case TextView::SplitEllipsizeEnd:
1012 case TextView::EllipsizeEnd:
1014 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1016 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1017 ellipsizeParameters );
1023 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1029 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1030 // In that case, the charater needs to be replaced by the ellipsize text.
1031 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1034 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1035 TextView::RelayoutData& relayoutData )
1037 // 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.
1038 // The code bellow creates the text-actors needed for the ellipsize text.
1040 // Set ellipsize's position by the end of visible text.
1041 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1042 // Stores current ellipsize text.
1044 // Stores current ellipsize style.
1045 TextStyle ellipsizeStyle;
1046 // Stores the current size.
1048 //Whether current glyph is an emoticon.
1049 bool isColorGlyph = false;
1051 float bearingOffset = 0.f;
1053 // Create ellipsize text-actor.
1054 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1055 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1056 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1057 ++ellipsizeCharacterLayoutIt )
1059 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1062 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1063 ( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle ) )
1065 // The style is different, so a new text-actor is needed.
1066 if( !ellipsizeText.IsEmpty() )
1068 // It only creates a text-actor if there is any text.
1069 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1070 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1071 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1073 // Updates the position for the next text-actor.
1074 ellipsizePosition.x += ellipsizeSize.width;
1076 // Adds the text-actor to the list.
1077 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1080 // Resets the current ellipsize info.
1081 ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText;
1082 ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle;
1083 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1084 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1086 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1090 // Updates text and size with the new character.
1091 ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText );
1092 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1097 if( !ellipsizeText.IsEmpty() )
1099 // Creates the last glyph-actor.
1100 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1101 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1102 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1104 // Adds the glyph-actor to the list.
1105 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1109 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1110 EllipsizeParameters& ellipsizeParameters,
1111 TextView::RelayoutData& relayoutData )
1113 // Traverses the text layout info from the first character of the laid out line
1114 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1116 // Indices to the first character of the laid out line.
1117 TextViewProcessor::TextInfoIndices firstIndices;
1118 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1119 relayoutData.mTextLayoutInfo,
1122 // Indices to the last character of the laid out line.
1123 TextViewProcessor::TextInfoIndices lastIndices;
1124 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1125 relayoutData.mTextLayoutInfo,
1128 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1129 // This is the boundary used to check if a character have to be ellipsized.
1130 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1131 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1133 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + firstIndices.mLineIndex,
1134 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lastIndices.mLineIndex + 1;
1135 lineLayoutIt != endLineLayoutIt;
1138 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1140 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1142 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1144 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1147 bool firstGroup = true;
1148 bool lastGroup = false;
1149 std::size_t groupCount = 0;
1151 bool firstWord = true;
1152 bool lastWord = false;
1154 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + firstIndices.mGroupIndex,
1155 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + lastIndices.mGroupIndex + 1;
1156 groupLayoutIt != endGroupLayoutIt;
1157 ++groupLayoutIt, ++groupCount )
1159 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1161 if( groupCount == lastIndices.mGroupIndex - firstIndices.mGroupIndex )
1166 std::size_t wordCount = 0;
1167 const std::size_t firstWordIndex = firstGroup ? firstIndices.mWordIndex : 0u;
1168 const std::size_t lastWordIndex = lastGroup ? lastIndices.mWordIndex : wordGroupLayoutInfo.mWordsLayoutInfo.size() - 1;
1170 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + firstWordIndex,
1171 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + lastWordIndex + 1;
1172 wordLayoutIt != endWordLayoutIt;
1173 ++wordLayoutIt, ++wordCount )
1175 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1177 if( lastGroup && ( wordCount == lastIndices.mWordIndex - firstWordIndex ) )
1182 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1183 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1;
1184 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1185 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1;
1186 characterLayoutIt != endCharacterLayoutIt;
1187 ++characterLayoutIt )
1189 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1191 if( ellipsizeParameters.mEllipsizeLine )
1193 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1194 CalculateVisibilityForEllipsize( layoutParameters,
1195 characterLayoutInfo,
1196 ellipsizeParameters,
1199 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1201 // Create ellipsize text-actors if the character needs to be replaced.
1202 CreateEllipsizeTextActor( ellipsizeParameters,
1208 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1209 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1211 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1213 // Make characters invisible.
1214 characterLayoutInfo.mIsVisible = false;
1226 void SetTextVisible( TextView::RelayoutData& relayoutData )
1228 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1229 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1230 lineLayoutIt != endLineLayoutIt;
1233 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1235 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1236 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1237 groupLayoutIt != endGroupLayoutIt;
1240 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1242 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1243 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1244 wordLayoutIt != endWordLayoutIt;
1247 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1249 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1250 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1251 characterLayoutIt != endCharacterLayoutIt;
1252 ++characterLayoutIt )
1254 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1256 characterLayoutInfo.mIsVisible = true;
1257 characterLayoutInfo.mGradientColor = Vector4::ZERO;
1258 characterLayoutInfo.mStartPoint = Vector2::ZERO;
1259 characterLayoutInfo.mEndPoint = Vector2::ZERO;
1260 characterLayoutInfo.mColorAlpha = characterLayoutInfo.mStyledText.mStyle.GetTextColor().a;
1263 } // end group of words
1266 // Updates the visibility for text-input..
1267 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1268 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1272 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1274 characterLayoutInfo.mIsVisible = true;
1278 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1279 const TextView::VisualParameters& visualParameters,
1280 TextView::RelayoutData& relayoutData )
1282 RelayoutParameters relayoutParameters;
1283 FadeParameters fadeParameters;
1285 // 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.
1286 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1287 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0 ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1288 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1289 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1290 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1291 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0 ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1292 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1293 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1294 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1295 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0 ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1296 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1297 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1298 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1299 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0 ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1300 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1301 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1303 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1304 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1305 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1306 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1307 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1309 // Traverses all groups of characters and calculates the visibility.
1311 std::size_t infoTableCharacterIndex = 0;
1313 relayoutParameters.mIndices.mLineIndex = 0;
1315 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1316 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1317 lineLayoutIt != endLineLayoutIt;
1318 ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
1320 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1322 relayoutParameters.mIndices.mGroupIndex = 0;
1324 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1325 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1326 groupLayoutIt != endGroupLayoutIt;
1327 ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
1329 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1331 relayoutParameters.mIndices.mWordIndex = 0;
1333 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1334 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1335 wordLayoutIt != endWordLayoutIt;
1336 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1338 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1340 relayoutParameters.mIsFirstCharacterOfWord = true;
1341 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1342 relayoutParameters.mIndices.mCharacterIndex = 0;
1344 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1345 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1346 characterLayoutIt != endCharacterLayoutIt;
1347 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
1349 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1351 relayoutParameters.mIsVisible = true;
1352 fadeParameters.mIsPartiallyVisible = false;
1354 // Calculates the visibility for the current group of characters.
1355 CalculateVisibilityForFade( layoutParameters,
1356 characterLayoutInfo,
1361 // Updates the visibility for text-input..
1362 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
1364 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1366 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1368 relayoutParameters.mIsFirstCharacterOfWord = false;
1369 } // end group of character
1371 } // end group of words
1375 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1376 const TextView::VisualParameters& visualParameters,
1377 TextView::RelayoutData& relayoutData )
1379 // Traverses the laid-out lines and checks which ones doesn't fit in the text-view's boundary.
1380 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1381 lineInfoIt != endLineInfoIt;
1384 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1386 // To check if a laid-out line fits in the text-view's boundary,
1387 // get the position of the first character is needed and do the test
1388 // with the laid-out line size.
1390 // An bearing offset may have been applied to the first character so it's needed to
1391 // get the start position of the line.
1393 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1394 EllipsizeParameters ellipsizeParameters;
1396 // Retrieves the first index and the last index of the line.
1397 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1398 ellipsizeParameters.mLastIndex = 0;
1399 if( ( lineInfoIt + 1 ) != endLineInfoIt )
1401 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1 ) );
1402 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1;
1406 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1;
1409 // Retrieves the first character of the line and build the position of the line with the bearing.
1410 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1412 // Calculates the bearing offset applied to the first character.
1413 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1415 // Build the position of the line by removing the bearing offset from the first character's position.
1416 const Vector3 position( characterInfo.mPosition.x,
1417 characterInfo.mPosition.y + bearingOffset,
1418 characterInfo.mPosition.z );
1420 // Checks if the line needs to be ellipsized,
1421 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1423 relayoutData.mTextViewSize,
1424 FULLY_VISIBLE_WIDTH );
1426 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1427 // if the line fits in the width.
1428 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1430 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1431 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1432 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1433 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1434 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1435 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1437 // Need to check if there is lines which doesn't fit in the height.
1439 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1441 relayoutData.mTextViewSize,
1442 FULLY_VISIBLE_HEIGHT );
1444 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1446 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1448 // Current line is not ellipsized.
1449 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1450 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1;
1451 if( nextLineInfoIt != endLineInfoIt )
1453 // Retrives the position of the first character of the line and remove
1454 // the bearing offset to build to build the position of the line.
1455 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1456 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1458 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1460 const Vector3 position( characterInfo.mPosition.x,
1461 characterInfo.mPosition.y + bearingOffset,
1462 characterInfo.mPosition.z );
1464 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1466 relayoutData.mTextViewSize,
1467 FULLY_VISIBLE_HEIGHT );
1469 // If the next line is not visible, current line have to be ellipsized.
1470 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1475 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1477 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1480 // Sets the line descender.
1481 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1483 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1484 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1488 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1489 const TextView::VisualParameters& visualParameters,
1490 TextView::RelayoutData& relayoutData )
1492 switch( layoutParameters.mExceedPolicy )
1494 case TextView::FadeOriginal:
1495 case TextView::OriginalFade:
1496 case TextView::Fade:
1497 case TextView::SplitFade: // Fall through
1499 UpdateVisibilityForFade( layoutParameters,
1504 case TextView::EllipsizeEndOriginal:
1505 case TextView::SplitEllipsizeEnd:
1506 case TextView::EllipsizeEnd: // Fall through
1508 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1509 SetTextVisible( relayoutData );
1511 UpdateVisibilityForEllipsize( layoutParameters,
1518 SetTextVisible( relayoutData );
1524 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
1525 TextView::RelayoutData& relayoutData )
1527 CurrentTextActorInfo currentTextActorInfo;
1529 // Traverses the text-actor and layout info data structures.
1530 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1531 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1532 lineLayoutIt != endLineLayoutIt;
1535 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1537 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1538 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1539 groupLayoutIt != endGroupLayoutIt;
1542 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1544 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1545 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1546 wordLayoutIt != endWordLayoutIt;
1549 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1551 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1552 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1553 characterLayoutIt != endCharacterLayoutIt;
1554 ++characterLayoutIt )
1556 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1558 if( characterLayoutInfo.mIsColorGlyph )
1560 ImageActor imageActor = ImageActor::DownCast( characterLayoutInfo.mGlyphActor );
1562 if( characterLayoutInfo.mSetText )
1564 GlyphImage image = GlyphImage::New( characterLayoutInfo.mStyledText.mText[0] );
1568 imageActor.SetImage( image );
1570 characterLayoutInfo.mSetText = false;
1573 imageActor.SetPosition( Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1574 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1575 characterLayoutInfo.mPosition.z ) );
1576 imageActor.SetSize( characterLayoutInfo.mSize );
1578 // Sets the sort modifier value.
1579 imageActor.SetSortModifier( visualParameters.mSortModifier );
1583 TextActor textActor = TextActor::DownCast( characterLayoutInfo.mGlyphActor );
1586 // There is a new text-actor. Set text and everything to the previous one.
1587 if( currentTextActorInfo.textActor )
1589 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1590 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1591 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1593 SetVisualParameters( currentTextActorInfo,
1596 lineLayoutInfo.mSize.height );
1599 currentTextActorInfo.text = characterLayoutInfo.mStyledText.mText;
1600 currentTextActorInfo.position = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1601 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1602 characterLayoutInfo.mPosition.z );
1603 currentTextActorInfo.size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1605 currentTextActorInfo.color = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
1606 currentTextActorInfo.color.a = characterLayoutInfo.mColorAlpha;
1608 currentTextActorInfo.gradientColor = characterLayoutInfo.mGradientColor;
1609 currentTextActorInfo.startPoint = characterLayoutInfo.mStartPoint;
1610 currentTextActorInfo.endPoint = characterLayoutInfo.mEndPoint;
1612 // Update the current text-actor.
1613 currentTextActorInfo.textActor = textActor;
1617 // If this character layout has no text-actor is because this character has the same style than previous one.
1618 // Add the character to the current text-actor and update the size.
1619 if( characterLayoutInfo.mIsVisible && ( TextViewProcessor::LineSeparator != wordLayoutInfo.mType ) )
1621 currentTextActorInfo.text.Append( characterLayoutInfo.mStyledText.mText );
1623 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y ) );
1624 currentTextActorInfo.size.width += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1625 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1632 if( !currentTextActorInfo.text.IsEmpty() )
1634 if( currentTextActorInfo.textActor )
1636 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1637 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1638 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1640 SetVisualParameters( currentTextActorInfo,
1643 lineLayoutInfo.mSize.height );
1646 } //end groups of words
1649 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1650 endIt = relayoutData.mEllipsizedGlyphActors.end();
1654 RenderableActor glyphActor = ( *it );
1656 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1657 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1659 // Sets the sort modifier value.
1660 glyphActor.SetSortModifier( visualParameters.mSortModifier );
1662 // Enables or disables the blending.
1663 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
1667 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
1669 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1671 // 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.
1672 // According with the layout option, one of this lines could be laid-out in more than one.
1674 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1675 lineIt != lineEndIt;
1678 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1680 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1681 groupIt != groupEndIt;
1684 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1686 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1687 wordIt != wordEndIt;
1690 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1692 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1693 characterIt != characterEndIt;
1696 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1698 // Check if current character is the first of a new laid-out line
1699 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
1700 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
1703 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1706 if( characterGroup.mStyledText.mStyle.IsUnderlineEnabled() )
1708 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
1709 isNewLine ) // Current character is underlined and is the first of current laid-out line.
1711 // Create a new underline info for the current underlined characters.
1712 UnderlineInfo underlineInfo;
1713 underlineInfo.mMaxHeight = characterGroup.mSize.height;
1714 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1715 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1717 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
1719 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
1723 // Retrieve last underline info and update it if current underline thickness is bigger.
1724 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1 ) );
1726 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, characterGroup.mSize.height );
1728 if( characterGroup.mUnderlineThickness > underlineInfo.mMaxThickness )
1730 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1731 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1737 textUnderlineStatus.mCurrentUnderlineStatus = false;
1740 ++textUnderlineStatus.mCharacterGlobalIndex;
1741 } // end group of characters.
1743 } // end group of words.
1747 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
1749 // 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.
1750 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
1752 // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1753 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
1755 if( textUnderlineStatus.mUnderlineInfo.empty() )
1757 // There is no underlined text. Just exit.
1761 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
1762 // Traverse the whole text and set the previously stored underline info in the text style.
1764 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
1765 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
1767 UnderlineInfo underlineInfo;
1769 if( underlineInfoIt < underlineInfoEndIt )
1771 underlineInfo = ( *underlineInfoIt );
1774 // Whether current text is underlined.
1775 textUnderlineStatus.mCurrentUnderlineStatus = false;
1776 textUnderlineStatus.mCharacterGlobalIndex = 0;
1777 textUnderlineStatus.mLineGlobalIndex = 0;
1779 float currentLineHeight = 0.f;
1780 float currentLineAscender = 0.f;
1782 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1783 lineIt != lineEndIt;
1786 TextViewProcessor::LineLayoutInfo& line( *lineIt );
1788 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1789 groupIt != groupEndIt;
1792 TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1794 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1795 wordIt != wordEndIt;
1798 TextViewProcessor::WordLayoutInfo& word( *wordIt );
1800 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1801 characterIt != characterEndIt;
1804 TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1806 // Check if current character is the first of a new laid-out line
1808 bool isNewLine = false;
1810 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
1812 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
1813 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
1817 currentLineHeight = lineLayoutInfo.mSize.height;
1818 currentLineAscender = lineLayoutInfo.mAscender;
1819 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1823 if( characterGroup.mStyledText.mStyle.IsUnderlineEnabled() )
1825 if( textUnderlineStatus.mCurrentUnderlineStatus )
1829 // Retrieves the thickness and position for the next piece of underlined text.
1830 if( underlineInfoIt < underlineInfoEndIt )
1833 if( underlineInfoIt < underlineInfoEndIt )
1835 underlineInfo = *underlineInfoIt;
1841 textUnderlineStatus.mCurrentUnderlineStatus = true;
1843 // Before setting the position it needs to be adjusted to match the base line.
1844 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( characterGroup.mSize.height - characterGroup.mAscender );
1845 const float positionOffset = ( underlineInfo.mMaxHeight - characterGroup.mSize.height ) - bearingOffset;
1847 // Sets the underline's parameters.
1848 characterGroup.mStyledText.mStyle.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
1850 // Mark the group of characters to be set the new style into the text-actor.
1851 characterGroup.mSetStyle = true;
1855 if( textUnderlineStatus.mCurrentUnderlineStatus )
1857 textUnderlineStatus.mCurrentUnderlineStatus = false;
1859 // Retrieves the thickness and position for the next piece of underlined text.
1860 if( underlineInfoIt < underlineInfoEndIt )
1863 if( underlineInfoIt < underlineInfoEndIt )
1865 underlineInfo = *underlineInfoIt;
1871 ++textUnderlineStatus.mCharacterGlobalIndex;
1872 } // end of group of characters.
1874 } // end of group of words.
1878 void RemoveGlyphActors( Actor textView,
1879 const std::vector<RenderableActor>& glyphActors )
1881 // Removes previously inserted renderable-actors.
1882 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
1883 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
1884 // in order to remove 'only' renderable-actors added by these functions.
1885 // Any other actor added by a programmer or application won't be removed.
1887 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
1889 textView.Remove( *it );
1893 void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMask,
1895 TextView::RelayoutData& relayoutData )
1897 const bool insertToTextView = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW;
1898 const bool insertToTextActorList = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST;
1900 // Add text-actors to the text-view.
1902 for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1903 endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1904 lineLayoutIt != endLineLayoutIt;
1907 TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1909 for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1910 endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1911 groupLayoutIt != endGroupLayoutIt;
1914 TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1916 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1917 endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1918 wordLayoutIt != endWordLayoutIt;
1921 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1923 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1924 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1925 characterLayoutIt != endCharacterLayoutIt;
1926 ++characterLayoutIt )
1928 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1930 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
1932 //Add to the text-view.
1933 if( insertToTextView )
1935 textView.Add( characterLayoutInfo.mGlyphActor );
1937 if( insertToTextActorList )
1939 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
1942 } // end group of character
1944 } // end group of words
1947 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
1948 endIt = relayoutData.mEllipsizedGlyphActors.end();
1952 RenderableActor glyphActor = ( *it );
1954 //Add to the text-view.
1955 if( insertToTextView )
1957 textView.Add( glyphActor );
1959 if( insertToTextActorList )
1961 relayoutData.mGlyphActors.push_back( glyphActor );
1964 relayoutData.mEllipsizedGlyphActors.clear();
1967 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
1969 TextActor textActor = cache.RetrieveTextActor();
1973 // Update the text-actor.
1974 textActor.SetText( text );
1975 textActor.SetTextStyle( style );
1979 // The text-actor cache is empty. Create a new one.
1980 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1981 textActor = TextActor::New( text, parameters );
1987 } // namespace TextViewRelayout
1989 } // namespace Internal
1991 } // namespace Toolkit