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/license/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-processor.h>
23 #include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
24 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
25 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
26 #include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
40 namespace TextViewRelayout
43 const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same as the text-view boundary, this constant reduces it in order to avoid a zero division.
45 RelayoutParameters::RelayoutParameters()
51 mCharacterGlobalIndex( 0u ),
52 mIsFirstCharacter( false ),
53 mIsFirstCharacterOfWord( false ),
55 mIsNewParagraphCharacter( false ),
56 mIsWhiteSpace( false ),
61 RelayoutParameters::~RelayoutParameters()
65 FadeParameters::FadeParameters()
66 : mRightFadeBoundary( 0.f ),
67 mRightFadeThreshold( 0.f ),
68 mRightFadeBoundaryOffset( 0.f ),
69 mRightFadeThresholdOffset( 0.f ),
70 mRightAlphaCoeficients(),
71 mLeftFadeBoundary( 0.f ),
72 mLeftFadeThreshold( 0.f ),
73 mLeftFadeBoundaryOffset( 0.f ),
74 mLeftFadeThresholdOffset( 0.f ),
75 mLeftAlphaCoeficients(),
76 mTopFadeBoundary( 0.f ),
77 mTopFadeThreshold( 0.f ),
78 mTopFadeBoundaryOffset( 0.f ),
79 mTopFadeThresholdOffset( 0.f ),
80 mTopAlphaCoeficients(),
81 mBottomFadeBoundary( 0.f ),
82 mBottomFadeThreshold( 0.f ),
83 mBottomFadeBoundaryOffset( 0.f ),
84 mBottomFadeThresholdOffset( 0.f ),
85 mBottomAlphaCoeficients(),
86 mIsPartiallyVisible( false )
90 FadeParameters::~FadeParameters()
94 EllipsizeParameters::EllipsizeParameters()
96 mLineDescender( 0.f ),
101 mEllipsizeLine( false ),
102 mIsLineWidthFullyVisible( false ),
103 mIsLineHeightFullyVisible( false ),
104 mIsNextLineFullyVisibleHeight( false ),
105 mCreateEllipsizedTextActors( false ),
111 EllipsizeParameters::~EllipsizeParameters()
115 UnderlineInfo::UnderlineInfo()
117 mMaxThickness( 0.f ),
122 UnderlineInfo::~UnderlineInfo()
126 TextUnderlineStatus::TextUnderlineStatus()
128 mCharacterGlobalIndex( 0u ),
129 mLineGlobalIndex( 0u ),
130 mCurrentUnderlineStatus( false )
134 TextUnderlineStatus::~TextUnderlineStatus()
138 LineLayoutInfo::LineLayoutInfo()
139 : mLineLength( 0.f ),
140 mMaxCharHeight( 0.f ),
145 LineLayoutInfo::~LineLayoutInfo()
150 * Whether the given text-actor exceeds the left or the right boundary of the text-view.
152 * @param[in] position The position of the text-actor.
153 * @param[in] size The size of the text-actor.
154 * @param[in] parantSize The size of the text-view.
156 * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
158 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
160 return ( ( position.x < 0.f ) ||
161 ( position.x + size.width > parentSize.width ) );
165 * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
167 * @param[in] position The position of the text-actor.
168 * @param[in] size The size of the text-actor.
169 * @param[in] parantSize The size of the text-view.
171 * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
173 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
175 return ( ( position.y > parentSize.height ) ||
176 ( position.y < size.height ) );
180 * Calculates the line length adding the new word or character width.
182 * It also returns the length of white spaces if they are at the end of the line.
184 * @param[in] isWhiteSpace Whether the word is a white space.
185 * @param[in] width The width of the character or word.
186 * @param[in] parentWidth The parent width.
187 * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
188 * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
189 * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
191 void CalculateLineLength( bool isWhiteSpace, float width, float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
193 if( lineLength + width > parentWidth )
196 lineLength -= endWhiteSpaceLength;
204 endWhiteSpaceLength += width;
208 endWhiteSpaceLength = 0.f;
213 struct CurrentTextActorInfo
220 TextViewProcessor::CharacterLayoutInfo* characterLayout;
223 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
224 const TextView::VisualParameters& visualParameters,
225 TextView::RelayoutData& relayoutData,
226 const float lineHeight )
228 currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
229 if( ( NULL != currentTextActorInfo.characterLayout ) &&
230 ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) )
232 currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.characterLayout->mGradientInfo->mGradientColor );
233 currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.characterLayout->mGradientInfo->mStartPoint );
234 currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.characterLayout->mGradientInfo->mEndPoint );
237 // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
238 // due to the trick used to implement it.
239 const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
240 const float italicsOffset = lineHeight * std::tan( italicsAngle );
241 relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
243 // Sets the sort modifier value.
244 currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
246 // Enables or disables the blending.
247 currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
250 void CalculateLineLayout( float parentWidth,
251 const TextViewProcessor::TextInfoIndices& indices,
252 const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo,
253 HorizontalWrapType splitPolicy,
255 LineLayoutInfo& subLineInfo )
257 subLineInfo.mLineLength = 0.f;
258 subLineInfo.mMaxCharHeight = 0.f;
259 subLineInfo.mMaxAscender = 0.f;
261 float endWhiteSpaceLength = 0.f;
263 std::size_t characterIndex = indices.mCharacterIndex;
264 float lineOffset = 0.f;
266 bool isFirstCharacter = true;
267 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex,
268 wordEndIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
269 ( wordIt != wordEndIt ) && !found;
272 const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
274 const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
275 const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
277 bool splitByCharacter = false;
279 switch( splitPolicy )
281 case WrapByCharacter:
283 splitByCharacter = true;
287 case WrapByParagraphCharacter: // Fall through
289 splitByCharacter = false;
292 case WrapByWordAndSplit:
294 splitByCharacter = ( shrunkWordWidth > parentWidth );
297 case WrapByParagraphCharacterAndSplit:
299 if( ( 0u != characterIndex ) ||
300 ( ( 0u == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
302 splitByCharacter = true;
306 lineOffset += shrunkWordWidth;
307 splitByCharacter = false;
312 if( splitByCharacter )
314 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
315 charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
316 ( charIt != charEndIt ) && !found;
319 const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
320 CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
321 if( !found || isFirstCharacter )
323 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
324 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
327 // All characters for word 'wordIndex' have been processed.
328 // Next word need to process all characters, so the characterIndex is reset to 0.
330 isFirstCharacter = false;
333 lineOffset += subLineInfo.mLineLength;
337 CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
338 if( !found || isFirstCharacter )
340 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
341 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
343 isFirstCharacter = false;
347 subLineInfo.mMaxCharHeight *= shrinkFactor;
348 subLineInfo.mMaxAscender *= shrinkFactor;
353 * Sets a character of a line of a bidirectional paragraph in the new position.
355 * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph.
356 * @param[in] index Index within the paragraph to the character to be set in the new position.
357 * @param[in,out] character Reference to the character in the new position.
359 void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo,
361 TextViewProcessor::CharacterLayoutInfo& character )
363 // Traverse all the characters of the paragraph till the one pointed by index is found.
364 std::size_t traversedCharacters = 0u;
365 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(),
366 wordEndIt = wordsLayoutInfo.end();
370 const TextViewProcessor::WordLayoutInfo& word( *wordIt );
372 const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size();
373 if( index < traversedCharacters + numberOfCharacters )
375 character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) );
378 traversedCharacters += numberOfCharacters;
383 * Reorders the layout info of each line of the paragraph.
385 * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics).
387 * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
389 void ReorderLayout( TextViewProcessor::ParagraphLayoutInfo& paragraph )
391 // Clear any previous right to left layout.
392 if( NULL != paragraph.mRightToLeftLayout )
394 paragraph.mRightToLeftLayout->Clear();
395 paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
399 // Create a new right to left layout if there isn't any.
400 paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
403 // Reorder Text and Styles.
405 // Reserve space for the styles.
406 paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
408 // Traverses all the bidirectional info per line.
409 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
411 TextProcessor::BidirectionalLineInfo* info( *it );
413 const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
414 const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
416 // The text can be appended as it's already reordered.
417 paragraph.mRightToLeftLayout->mText.Append( info->mText );
419 // The visual to logical map needs to be used to reorder the styles.
420 for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
422 paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
426 // Reorder Layout Info.
428 // Reserve space for the new word layout.
429 paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
431 // Traverses all the bidirectional info per line.
432 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
434 TextProcessor::BidirectionalLineInfo* info( *it );
436 // Reserve space for all characters.
437 TextViewProcessor::CharacterLayoutInfoContainer characters;
438 characters.resize( info->mNumberOfCharacters );
440 // Uses the visual to logical map to set every character in its new position.
441 for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
443 SetCharacter( paragraph.mWordsLayoutInfo,
444 info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
445 *( characters.begin() + index ) );
448 // Sets the new 'x' position for each character.
449 float xPosition = 0.f;
450 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it )
452 TextViewProcessor::CharacterLayoutInfo& character( *it );
454 character.mPosition.x = xPosition;
455 xPosition += character.mSize.width;
458 // Split the reordered text in words.
459 std::size_t previousPosition = 0u;
460 Vector<std::size_t> positions;
461 TextProcessor::SplitInWords( info->mText, positions );
463 // Sets the characters into the words they belong to.
464 for( Vector<size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
466 const std::size_t position = *it;
468 TextViewProcessor::WordLayoutInfo word;
469 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
470 characters.begin() + previousPosition,
471 characters.begin() + position );
473 if( !word.mCharactersLayoutInfo.empty() )
475 // Updates the layout of the word.
476 TextViewProcessor::UpdateLayoutInfo( word );
478 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
481 // white space or new paragraph.
482 TextViewProcessor::WordLayoutInfo space;
483 space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
484 characters.begin() + position,
485 characters.begin() + position + 1u );
487 TextViewProcessor::UpdateLayoutInfo( space );
489 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
491 previousPosition = position + 1u;
495 if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
497 TextViewProcessor::WordLayoutInfo word;
498 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
499 characters.begin() + previousPosition,
502 TextViewProcessor::UpdateLayoutInfo( word );
504 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
510 * Creates the bidirectional info needed to reorder each line of the paragraph.
512 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
513 * @param[in,out] paragraph Layout info for the paragraph.
514 * @param[in] characterGlobalIndex Index to the character within the whole text.
515 * @param[in] lineLayoutInfoIndex Index to the table of lines.
517 void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
518 TextViewProcessor::ParagraphLayoutInfo& paragraph,
519 std::size_t& characterGlobalIndex,
520 std::size_t& lineLayoutInfoIndex )
522 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
523 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
525 // Clear previously created bidirectional info.
526 paragraph.ClearBidirectionalInfo();
528 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
529 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
533 TextViewProcessor::WordLayoutInfo& word( *wordIt );
535 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
536 characterIt != characterEndIt;
539 TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
541 // Check if there is a new line.
542 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
546 // Point to the next line.
547 ++lineLayoutInfoIndex;
548 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
550 // Arrived at last line.
551 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
554 // Number of characters of the line.
555 const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
557 // There is right to left characters in this line. It needs to be reordered.
558 bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
559 bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
560 bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
562 // Set all the Text's characters in the visual order and creates the mapping tables.
563 TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
564 bidirectionalLineInfo );
566 paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
568 for( std::size_t index = 0u; index < numberOfCharacters; ++index )
570 relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
571 relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
575 ++characterGlobalIndex;
576 ++characterParagraphIndex;
581 void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
583 // Reset conversion tables shared through public-api
584 relayoutData.mCharacterLogicalToVisualMap.clear();
585 relayoutData.mCharacterVisualToLogicalMap.clear();
587 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
588 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
590 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
591 paragraphIt != paragraphEndIt;
594 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
596 if( NULL != paragraph.mBidirectionalParagraphInfo )
598 // There is right to left text in this paragraph.
600 // Creates the bidirectional info needed to reorder each line of the paragraph.
601 CreateBidirectionalInfoForLines( relayoutData,
603 characterGlobalIndex,
604 lineLayoutInfoIndex );
606 // Reorder each line of the paragraph
607 ReorderLayout( paragraph );
611 // Identity in case the paragraph has no right to left text.
612 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
614 const std::size_t globalIndex = characterGlobalIndex + index;
615 relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
616 relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
618 characterGlobalIndex += paragraph.mNumberOfCharacters;
623 float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
625 float xOffset( 0.f );
626 switch( horizontalTextAlignment )
628 case Toolkit::Alignment::HorizontalLeft:
633 case Toolkit::Alignment::HorizontalCenter:
635 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
638 case Toolkit::Alignment::HorizontalRight:
640 xOffset = parentWidth - wholeTextWidth;
645 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
652 float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight )
654 float yOffset( 0.f );
655 switch( verticalTextAlignment )
657 case Toolkit::Alignment::VerticalTop:
662 case Toolkit::Alignment::VerticalCenter:
664 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
667 case Toolkit::Alignment::VerticalBottom:
669 yOffset = parentHeight - wholeTextHeight;
674 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
681 float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength )
684 switch( justification )
686 case Toolkit::TextView::Left:
691 case Toolkit::TextView::Center:
693 offset = 0.5f * ( wholeTextWidth - lineLength );
696 case Toolkit::TextView::Right:
698 offset = wholeTextWidth - lineLength;
701 case Toolkit::TextView::Justified:
711 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
713 bool visible = false;
719 // Whether the text-actor is fully inside the boundaries of the text-view.
720 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
721 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
724 case FULLY_VISIBLE_WIDTH:
726 // Whether the text-actor is between the left and right boundaries of the text-view.
727 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
730 case FULLY_VISIBLE_HEIGHT:
732 // Whether the text-actor is between the top and bottom boundaries of the text-view.
733 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
736 case PARTIALLY_VISIBLE:
738 // Whether the text-actor is partially inside the boundaries of the text-view.
739 visible = ( ( position.x < parentSize.width ) &&
740 ( position.x + size.width > 0.f ) &&
741 ( position.y > 0.f ) &&
742 ( position.y - size.height < parentSize.height ) );
745 case PARTIALLY_VISIBLE_WIDTH:
747 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
748 // It may not be partially inside the text-view.
749 visible = ( ( position.x < parentSize.width ) &&
750 ( position.x + size.width > 0.f ) );
753 case PARTIALLY_VISIBLE_HEIGHT:
755 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
756 // It may not be partially inside the text-view.
757 visible = ( ( position.y > 0.f ) &&
758 ( position.y - size.height < parentSize.height ) );
766 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
768 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
770 return Vector2( gradient, p0.y - gradient * p0.x );
773 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
774 TextView::RelayoutData& relayoutData )
776 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
777 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
779 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
780 // In that case, it will align the line to the left and/or top, and ellipsize the end.
781 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
782 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
783 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
784 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
785 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
787 RelayoutParameters relayoutParameters;
789 // Calculates the vertical and horizontal offsets.
790 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
791 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
793 // Index to the global character (within the whole text).
794 std::size_t characterGlobalIndex = 0u;
796 // Index to the line info.
797 std::size_t lineLayoutInfoIndex = 0u;
799 relayoutParameters.mIndices.mParagraphIndex = 0u;
801 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
802 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
803 paragraphLayoutIt != endParagraphLayoutIt;
804 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
806 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
808 float justificationOffset = 0.f;
810 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
811 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
813 relayoutParameters.mIndices.mWordIndex = 0u;
815 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
816 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
818 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
819 endWordLayoutIt = wordsLayoutInfo.end();
820 wordLayoutIt != endWordLayoutIt;
821 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
823 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
825 relayoutParameters.mIndices.mCharacterIndex = 0u;
827 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
828 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
829 characterLayoutIt != endCharacterLayoutIt;
830 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
832 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
834 // Check if there is a new line.
835 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
839 // Calculate line justification offset.
840 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
842 // Point to the next line.
843 ++lineLayoutInfoIndex;
844 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
846 // Arrived at last line.
847 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
851 // Deletes the offsets if the exceed policies are EllipsizeEnd.
852 const float horizontalOffset = textHorizontalOffset + justificationOffset;
853 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
854 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
856 // Updates the size and position table for text-input with the alignment offset.
857 Vector3 positionOffset( characterLayoutInfo.mPosition );
859 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + characterGlobalIndex;
860 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
862 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
863 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
865 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
871 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
872 TextView::RelayoutData& relayoutData )
884 // ggggg gggggggggg bb ggggg
885 // gg gg gggggggggg bb gg gg
886 // gg gg gggg bb gg gg
887 // gg gg gggg bb gg gg
888 // ggggg gg gggg bbbbbbb ggggg
889 // gg gg gggg bb bb gg
890 // g gg gggggggggg bb bb g gg
891 // ggggg gggggggggg bbbbbbb ggggg
900 // ggggg gggg gggg bb ggggg
901 // gg gg gggg gggg bbbbbbb gg gg
902 // gg gg gggg gggg bb bb gg gg
903 // gg gg gggggggggg bb bb gg gg
904 // ggggg gggggggggg bbbbbbb ggggg
907 // ggggg gg gggg ggggg
912 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
913 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
915 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
918 void UpdateLayoutInfoTable( Vector4& minMaxXY,
919 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
920 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
921 RelayoutParameters& relayoutParameters,
922 TextView::RelayoutData& relayoutData )
924 // updates min and max position to calculate the text size for multiline policies.
925 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
926 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
928 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
929 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
931 // Adds layout info to be retrieved by external controls or applications.
932 Vector3 positionOffset( characterLayoutInfo.mPosition );
934 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
936 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor,
937 characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
939 ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
944 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
946 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
949 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
950 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
951 const TextStyle& style,
952 RelayoutParameters& relayoutParameters,
953 FadeParameters& fadeParameters,
954 TextView::RelayoutData& relayoutData )
956 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
957 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
958 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
959 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
965 // Calculates visibility of a text-actor according the exceed policies.
967 // position + alignment offset.
968 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
969 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
970 characterLayoutInfo.mPosition.z );
972 // Whether the text actor is fully, partially or non visible (according exceed policies).
973 switch( layoutParameters.mExceedPolicy )
977 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
978 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
979 if( !IsVisible( position,
980 characterLayoutInfo.mSize,
981 relayoutData.mTextViewSize,
984 relayoutParameters.mIsVisible = false;
985 if( IsVisible( position,
986 characterLayoutInfo.mSize,
987 relayoutData.mTextViewSize,
988 PARTIALLY_VISIBLE ) )
990 fadeParameters.mIsPartiallyVisible = true;
992 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
993 if( IsExceedingWidth( position,
994 characterLayoutInfo.mSize,
995 relayoutData.mTextViewSize ) &&
996 IsExceedingHeight( position,
997 characterLayoutInfo.mSize,
998 relayoutData.mTextViewSize ) )
1000 // Combination not fully supported by text-view.
1001 // Need to check if text-actor really supports this combination.
1002 fadeParameters.mIsPartiallyVisible = false;
1008 case TextView::FadeOriginal:
1010 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
1011 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1012 if( !IsVisible( position,
1013 characterLayoutInfo.mSize,
1014 relayoutData.mTextViewSize,
1015 FULLY_VISIBLE_WIDTH ) )
1017 relayoutParameters.mIsVisible = false;
1018 if( IsVisible( position,
1019 characterLayoutInfo.mSize,
1020 relayoutData.mTextViewSize,
1021 PARTIALLY_VISIBLE_WIDTH ) )
1023 fadeParameters.mIsPartiallyVisible = true;
1028 case TextView::OriginalFade:
1029 case TextView::SplitFade: // Fallthrough
1031 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
1032 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1033 if( !IsVisible( position,
1034 characterLayoutInfo.mSize,
1035 relayoutData.mTextViewSize,
1036 FULLY_VISIBLE_HEIGHT ) )
1038 relayoutParameters.mIsVisible = false;
1039 if( IsVisible( position,
1040 characterLayoutInfo.mSize,
1041 relayoutData.mTextViewSize,
1042 PARTIALLY_VISIBLE_HEIGHT ) )
1044 fadeParameters.mIsPartiallyVisible = true;
1051 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
1056 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
1058 characterLayoutInfo.mIsVisible = true;
1060 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1061 const float characterPositionPlusWidth = position.x + size.width;
1062 const float characterPositionMinusHeight = position.y - size.height;
1064 // Calculates which edges need to be faded-out.
1065 bool rightFadeOut = false;
1066 bool leftFadeOut = false;
1067 bool bottomFadeOut = false;
1068 bool topFadeOut = false;
1070 switch( layoutParameters.mExceedPolicy )
1072 case TextView::Fade:
1074 // All text-actors exceeding any of the boundaries will be faded-out.
1075 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1076 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1077 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1078 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1081 case TextView::FadeOriginal:
1083 // Only text-actors exceeding the left or the right boundaries will be faded-out.
1084 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1085 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1088 case TextView::SplitFade:
1089 case TextView::OriginalFade: //Fallthrough
1091 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
1092 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1093 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1098 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
1103 // Calculates gradient parameters for a text-actor.
1104 Vector4 gradientColor = Vector4::ZERO;
1105 Vector2 startPoint = Vector2::ZERO;
1106 Vector2 endPoint = Vector2::ZERO;
1108 if( !( rightFadeOut && leftFadeOut ) )
1110 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
1113 gradientColor = style.GetTextColor();
1115 // Calculates gradient coeficients.
1116 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
1117 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
1119 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1120 endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
1122 if( NULL == characterLayoutInfo.mGradientInfo )
1124 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1127 else if( leftFadeOut )
1129 gradientColor = style.GetTextColor();
1131 // Calculates gradient coeficients.
1132 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
1133 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
1135 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1136 endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
1138 if( NULL == characterLayoutInfo.mGradientInfo )
1140 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1145 if( !( bottomFadeOut && topFadeOut ) )
1147 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
1150 gradientColor = style.GetTextColor();
1152 // Calculates gradient coeficients.
1153 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
1154 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
1156 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1157 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
1159 if( NULL == characterLayoutInfo.mGradientInfo )
1161 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1164 else if( topFadeOut )
1166 gradientColor = style.GetTextColor();
1168 // Calculates gradient coeficients.
1169 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
1170 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
1172 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1173 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
1175 if( NULL == characterLayoutInfo.mGradientInfo )
1177 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1182 if( NULL != characterLayoutInfo.mGradientInfo )
1184 characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
1185 characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
1186 characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
1191 characterLayoutInfo.mIsVisible = false;
1195 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1196 const EllipsizeParameters& ellipsizeParameters )
1198 bool isPartiallyVisible = false;
1200 if( !IsVisible( ellipsizeParameters.mPosition,
1201 characterLayoutInfo.mSize,
1202 ellipsizeParameters.mEllipsizeBoundary,
1203 FULLY_VISIBLE_WIDTH ) )
1205 // The character doesn't fit in the text-view's width.
1206 characterLayoutInfo.mIsVisible = false;
1208 // Checks if the character is partially visible (it's cut by the boundary)
1209 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
1210 characterLayoutInfo.mSize,
1211 ellipsizeParameters.mEllipsizeBoundary,
1212 PARTIALLY_VISIBLE_WIDTH );
1216 // The character fits in the text-view's width. Set it to visible.
1217 characterLayoutInfo.mIsVisible = true;
1220 return isPartiallyVisible;
1223 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1224 const EllipsizeParameters& ellipsizeParameters )
1226 bool isPartiallyVisible = false;
1228 if( !IsVisible( ellipsizeParameters.mPosition,
1229 characterLayoutInfo.mSize,
1230 ellipsizeParameters.mEllipsizeBoundary,
1233 // The character is not fully visible. Needs to check if it's partially visible.
1234 characterLayoutInfo.mIsVisible = false;
1236 // Checks if the character doesn't cut the bottom edge of the text-view.
1237 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
1238 characterLayoutInfo.mSize,
1239 ellipsizeParameters.mEllipsizeBoundary,
1240 FULLY_VISIBLE_HEIGHT );
1242 // Checks if the character cuts the right edge of the text-view.
1243 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
1244 characterLayoutInfo.mSize,
1245 ellipsizeParameters.mEllipsizeBoundary,
1246 PARTIALLY_VISIBLE_WIDTH );
1248 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
1249 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
1253 // The character fits in the boundary of the text-view. Set it to visible.
1254 characterLayoutInfo.mIsVisible = true;
1257 return isPartiallyVisible;
1260 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
1261 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1262 EllipsizeParameters& ellipsizeParameters,
1263 TextView::RelayoutData& relayoutData )
1265 // Calculates visibility for EllipsizeEnd exceed policies.
1267 // 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.
1268 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
1269 // 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.
1271 // Position of the character used to do the visibility test.
1272 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1273 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1274 characterLayoutInfo.mPosition.z );
1276 // 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).
1277 bool isPartiallyVisible = false;
1279 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
1280 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
1282 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
1285 // The line or word fits completely inside the text-view's width. Nothing else to do.
1286 characterLayoutInfo.mIsVisible = true;
1290 // The line or word doesn't fit in the text-view's width.
1292 // Calculates visibility for each type of ellipsize policies.
1293 switch( layoutParameters.mExceedPolicy )
1295 case TextView::EllipsizeEndOriginal:
1297 // 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.
1299 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1300 ellipsizeParameters );
1304 case TextView::SplitEllipsizeEnd:
1305 case TextView::EllipsizeEnd:
1307 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1309 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1310 ellipsizeParameters );
1316 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1322 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1323 // In that case, the charater needs to be replaced by the ellipsize text.
1324 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1327 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1328 TextView::RelayoutData& relayoutData )
1330 // 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.
1331 // The code bellow creates the text-actors needed for the ellipsize text.
1333 // Set ellipsize's position by the end of visible text.
1334 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1335 // Stores current ellipsize text.
1337 // Stores current ellipsize style.
1338 TextStyle ellipsizeStyle;
1339 // Stores the current size.
1341 //Whether current glyph is an emoticon.
1342 bool isColorGlyph = false;
1344 float bearingOffset = 0.f;
1346 // Create ellipsize text-actor.
1347 std::size_t characterIndex = 0u;
1348 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1349 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1350 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1351 ++ellipsizeCharacterLayoutIt, ++characterIndex )
1353 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1354 const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
1357 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1358 ( ellipsizeStyle != style ) )
1360 // The style is different, so a new text-actor is needed.
1361 if( !ellipsizeText.IsEmpty() )
1363 // It only creates a text-actor if there is any text.
1364 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1365 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1366 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1368 // Updates the position for the next text-actor.
1369 ellipsizePosition.x += ellipsizeSize.width;
1371 // Adds the text-actor to the list.
1372 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1375 // Resets the current ellipsize info.
1376 ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1377 ellipsizeStyle = style;
1378 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1379 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1381 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1385 // Updates text and size with the new character.
1386 ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1387 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1391 if( !ellipsizeText.IsEmpty() )
1393 // Creates the last glyph-actor.
1394 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1395 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1396 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1398 // Adds the glyph-actor to the list.
1399 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1403 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1404 EllipsizeParameters& ellipsizeParameters,
1405 TextView::RelayoutData& relayoutData )
1407 // Traverses the text layout info from the first character of the line
1408 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1410 // Indices to the first character of the line.
1411 TextViewProcessor::TextInfoIndices firstIndices;
1412 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1413 relayoutData.mTextLayoutInfo,
1416 // Indices to the last character of the line.
1417 TextViewProcessor::TextInfoIndices lastIndices;
1418 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1419 relayoutData.mTextLayoutInfo,
1422 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1423 // This is the boundary used to check if a character have to be ellipsized.
1424 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1425 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1427 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex,
1428 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u;
1429 paragraphLayoutIt != endParagraphLayoutIt;
1430 ++paragraphLayoutIt )
1432 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1434 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1436 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1438 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1441 bool firstWord = true;
1442 bool lastWord = false;
1444 std::size_t wordCount = 0u;
1446 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1447 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1449 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
1450 endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
1451 wordLayoutIt != endWordLayoutIt;
1452 ++wordLayoutIt, ++wordCount )
1454 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1456 if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex )
1461 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1462 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u;
1463 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1464 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u;
1465 characterLayoutIt != endCharacterLayoutIt;
1466 ++characterLayoutIt )
1468 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1470 if( ellipsizeParameters.mEllipsizeLine )
1472 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1473 CalculateVisibilityForEllipsize( layoutParameters,
1474 characterLayoutInfo,
1475 ellipsizeParameters,
1478 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1480 // Create ellipsize text-actors if the character needs to be replaced.
1481 CreateEllipsizeTextActor( ellipsizeParameters,
1487 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1488 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1490 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1492 // Make characters invisible.
1493 characterLayoutInfo.mIsVisible = false;
1503 void SetTextVisible( TextView::RelayoutData& relayoutData )
1505 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1506 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1507 paragraphLayoutIt != endParagraphLayoutIt;
1508 ++paragraphLayoutIt )
1510 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1511 std::size_t characterIndex = 0u;
1513 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1514 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1516 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1517 endWordLayoutIt = wordsLayoutInfo.end();
1518 wordLayoutIt != endWordLayoutIt;
1521 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1523 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1524 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1525 characterLayoutIt != endCharacterLayoutIt;
1526 ++characterLayoutIt, ++characterIndex )
1528 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1530 characterLayoutInfo.mIsVisible = true;
1531 delete characterLayoutInfo.mGradientInfo;
1532 characterLayoutInfo.mGradientInfo = NULL;
1533 characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
1538 // Updates the visibility for text-input..
1539 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1540 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1544 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1546 characterLayoutInfo.mIsVisible = true;
1550 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1551 const TextView::VisualParameters& visualParameters,
1552 TextView::RelayoutData& relayoutData )
1554 RelayoutParameters relayoutParameters;
1555 FadeParameters fadeParameters;
1557 // 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.
1558 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1559 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1560 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1561 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1562 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1563 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1564 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1565 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1566 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1567 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1568 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1569 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1570 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1571 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1572 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1573 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1575 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1576 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1577 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1578 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1579 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1581 // Traverses all characters and calculates the visibility.
1583 std::size_t infoTableCharacterIndex = 0u;
1585 relayoutParameters.mIndices.mParagraphIndex = 0u;
1587 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1588 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1589 paragraphLayoutIt != endParagraphLayoutIt;
1590 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
1592 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1594 std::size_t characterIndex = 0u;
1595 relayoutParameters.mIndices.mWordIndex = 0u;
1597 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1598 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1600 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1601 endWordLayoutIt = wordsLayoutInfo.end();
1602 wordLayoutIt != endWordLayoutIt;
1603 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1605 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1607 relayoutParameters.mIsFirstCharacterOfWord = true;
1608 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1609 relayoutParameters.mIndices.mCharacterIndex = 0u;
1611 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1612 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1613 characterLayoutIt != endCharacterLayoutIt;
1614 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
1616 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1618 relayoutParameters.mIsVisible = true;
1619 fadeParameters.mIsPartiallyVisible = false;
1621 // Calculates the visibility for the current character.
1622 CalculateVisibilityForFade( layoutParameters,
1623 characterLayoutInfo,
1624 *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
1629 // Updates the visibility for text-input..
1630 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
1632 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1634 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1636 relayoutParameters.mIsFirstCharacterOfWord = false;
1642 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1643 const TextView::VisualParameters& visualParameters,
1644 TextView::RelayoutData& relayoutData )
1646 // Traverses the lines and checks which ones doesn't fit in the text-view's boundary.
1647 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1648 lineInfoIt != endLineInfoIt;
1651 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1653 // To check if a line fits in the text-view's boundary,
1654 // get the position of the first character is needed and do the test
1655 // with the line size.
1657 // An bearing offset may have been applied to the first character so it's needed to
1658 // get the start position of the line.
1660 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1661 EllipsizeParameters ellipsizeParameters;
1663 // Retrieves the first index and the last index of the line.
1664 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1665 ellipsizeParameters.mLastIndex = 0u;
1666 if( ( lineInfoIt + 1u ) != endLineInfoIt )
1668 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) );
1669 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u;
1673 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u;
1676 // Retrieves the first character of the line and build the position of the line with the bearing.
1677 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1679 // Calculates the bearing offset applied to the first character.
1680 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1682 // Build the position of the line by removing the bearing offset from the first character's position.
1683 const Vector3 position( characterInfo.mPosition.x,
1684 characterInfo.mPosition.y + bearingOffset,
1685 characterInfo.mPosition.z );
1687 // Checks if the line needs to be ellipsized,
1688 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1690 relayoutData.mTextViewSize,
1691 FULLY_VISIBLE_WIDTH );
1693 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1694 // if the line fits in the width.
1695 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1697 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1698 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1699 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1700 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1701 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1702 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1704 // Need to check if there is lines which doesn't fit in the height.
1706 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1708 relayoutData.mTextViewSize,
1709 FULLY_VISIBLE_HEIGHT );
1711 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1713 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1715 // Current line is not ellipsized.
1716 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1717 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u;
1718 if( nextLineInfoIt != endLineInfoIt )
1720 // Retrives the position of the first character of the line and remove
1721 // the bearing offset to build to build the position of the line.
1722 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1723 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1725 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1727 const Vector3 position( characterInfo.mPosition.x,
1728 characterInfo.mPosition.y + bearingOffset,
1729 characterInfo.mPosition.z );
1731 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1733 relayoutData.mTextViewSize,
1734 FULLY_VISIBLE_HEIGHT );
1736 // If the next line is not visible, current line have to be ellipsized.
1737 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1742 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1744 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1747 // Sets the line descender.
1748 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1750 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1751 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1755 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1756 const TextView::VisualParameters& visualParameters,
1757 TextView::RelayoutData& relayoutData )
1759 switch( layoutParameters.mExceedPolicy )
1761 case TextView::FadeOriginal:
1762 case TextView::OriginalFade:
1763 case TextView::Fade:
1764 case TextView::SplitFade: // Fall through
1766 UpdateVisibilityForFade( layoutParameters,
1771 case TextView::EllipsizeEndOriginal:
1772 case TextView::SplitEllipsizeEnd:
1773 case TextView::EllipsizeEnd: // Fall through
1775 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1776 SetTextVisible( relayoutData );
1778 UpdateVisibilityForEllipsize( layoutParameters,
1785 SetTextVisible( relayoutData );
1792 * Creates an image actor for the emoticon.
1794 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1795 * @param[in,out] characterLayout Layout info for the character.
1796 * @param[in] character The character.
1798 void CreateEmoticon( const TextView::VisualParameters& visualParameters,
1799 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1800 const Character& character )
1802 // The character is an emoticon.
1803 ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1806 imageActor = ImageActor::New();
1808 GlyphImage image = GlyphImage::New( character );
1812 imageActor.SetImage( image );
1816 imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
1817 characterLayout.mPosition.y + characterLayout.mOffset.y,
1818 characterLayout.mPosition.z ) );
1819 imageActor.SetSize( characterLayout.mSize );
1821 // Sets the sort modifier value.
1822 imageActor.SetSortModifier( visualParameters.mSortModifier );
1824 characterLayout.mGlyphActor = imageActor;
1828 * Creates text-actors for the given text.
1830 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1831 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1832 * @param[in,out] paragraph Layout info for the paragraph.
1833 * @param[in,out] characterLayout Layout info for the character.
1834 * @param[in] character The character.
1835 * @param[in] style The character's style.
1836 * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set.
1837 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1839 void CreateTextActor( const TextView::VisualParameters& visualParameters,
1840 TextView::RelayoutData& relayoutData,
1841 const TextViewProcessor::ParagraphLayoutInfo& paragraph,
1842 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1843 const Character& character,
1844 const TextStyle& style,
1845 CurrentTextActorInfo& currentTextActorInfo,
1846 bool createGlyphActors )
1848 // Set the text-actor for the current traversed text.
1849 if( currentTextActorInfo.textActor )
1851 if( ( NULL != currentTextActorInfo.characterLayout ) &&
1852 currentTextActorInfo.characterLayout->mSetText )
1854 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1855 currentTextActorInfo.characterLayout->mSetText = false;
1857 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1858 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1860 SetVisualParameters( currentTextActorInfo,
1863 paragraph.mSize.height );
1866 float rightToLeftOffset = 0.f;
1867 if( character.IsWhiteSpace() )
1869 // In left to right text, a word never starts with a white space but
1870 // it may happen in right to left text as the text is reversed.
1871 // The text alignment and justification offset is calculated without this white space.
1872 // It causes a missalignment which can be corrected by removing the size of the white space.
1873 rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
1876 currentTextActorInfo.text = Text( character );
1877 currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
1878 characterLayout.mPosition.y + characterLayout.mOffset.y,
1879 characterLayout.mPosition.z );
1880 currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
1882 currentTextActorInfo.color = style.GetTextColor();
1883 currentTextActorInfo.color.a = characterLayout.mColorAlpha;
1885 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1887 if( createGlyphActors )
1891 // Try to reuse first the text-actor of this character.
1892 textActor.SetTextStyle( style );
1896 // If there is no text-actor, try to retrieve one from the cache.
1897 textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1899 // If still there is no text-actor, create one.
1902 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1903 textActor = TextActor::New( Text(), parameters );
1907 textActor.SetTextStyle( style );
1910 characterLayout.mSetText = true;
1911 currentTextActorInfo.characterLayout = &characterLayout;
1913 characterLayout.mGlyphActor = textActor;
1916 // Update the current text-actor.
1917 currentTextActorInfo.textActor = textActor;
1921 * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position.
1923 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1924 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1925 * @param[in,out] paragraph Layout info for the paragraph.
1926 * @param[in,out] characterGlobalIndex Index to the character within the whole text.
1927 * @param[in,out] lineLayoutInfoIndex Index to the table of lines.
1928 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1930 void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
1931 TextView::RelayoutData& relayoutData,
1932 TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
1933 std::size_t& characterGlobalIndex,
1934 std::size_t& lineLayoutInfoIndex,
1935 bool createGlyphActors )
1937 CurrentTextActorInfo currentTextActorInfo;
1938 currentTextActorInfo.characterLayout = NULL;
1940 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
1941 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
1942 bool glyphActorCreatedForLine = false; // Whether a renderable actor has been created for this line.
1944 TextStyle currentStyle; // style for the current text-actor.
1946 TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor.
1947 // start point for the current text-actor.
1948 // end point for the current text-actor.
1950 bool currentIsColorGlyph = false; // Whether current glyph is an emoticon.
1952 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
1954 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
1955 const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
1957 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
1958 Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
1959 Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
1961 // In case the previous right to left layout has been cleared, all text-actors have been removed as well. If this bool is set to true, text-actors will be created again.
1962 const bool previousRightToLeftLayoutCleared = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false;
1964 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
1965 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
1966 wordIt != wordEndIt;
1969 TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
1971 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
1972 characterIt != characterEndIt;
1975 TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt );
1977 // Check if there is a new line.
1978 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
1982 // Point to the next line.
1983 ++lineLayoutInfoIndex;
1984 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
1986 // Arrived at last line.
1987 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
1989 glyphActorCreatedForLine = false;
1992 // Do not create a glyph-actor if there is no text.
1993 const Character character = text[characterParagraphIndex];
1994 const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
1996 bool appendCharacter = false;
1998 if( characterLayout.mIsColorGlyph ||
1999 ( TextViewProcessor::NoSeparator == wordLayout.mType ) ||
2000 ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() ) )
2002 // Do not create a glyph-actor if it's a white space (without underline) or a new paragraph character.
2004 // Check if the character has the same gradient info than the current one.
2005 bool differentGradientInfo = false;
2006 if( characterLayout.mGradientInfo && currentGradientInfo )
2008 differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) ||
2009 ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) ||
2010 ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint );
2012 else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) )
2014 differentGradientInfo = true;
2017 // Creates one glyph-actor for each counsecutive group of characters, with the same style, per line, or if it's an emoticon.
2018 if( !glyphActorCreatedForLine ||
2019 characterLayout.mIsColorGlyph ||
2020 differentGradientInfo ||
2021 ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) ||
2022 ( style != currentStyle ) )
2024 characterLayout.mSetText = false;
2025 characterLayout.mSetStyle = false;
2027 if( characterLayout.mIsColorGlyph )
2029 CreateEmoticon( visualParameters,
2035 CreateTextActor( visualParameters,
2041 currentTextActorInfo,
2042 createGlyphActors || previousRightToLeftLayoutCleared );
2045 // There is a new style or a new line.
2046 glyphActorCreatedForLine = true;
2048 // Update style to be checked with next characters.
2049 currentStyle = style;
2050 currentGradientInfo = characterLayout.mGradientInfo;
2051 currentIsColorGlyph = characterLayout.mIsColorGlyph;
2053 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2054 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2058 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
2060 // Same style than previous one.
2062 // Add the character to the current text-actor and update the size.
2063 appendCharacter = true;
2065 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
2068 // There is a previously created text-actor for this character.
2069 // If this character has another one put it into the cache.
2070 textActor.SetText( "" );
2071 textActorsToRemove.push_back( textActor );
2074 if( characterLayout.mGlyphActor )
2076 characterLayout.mGlyphActor.Reset();
2079 } // no white space / new paragraph char
2082 appendCharacter = true;
2085 if( appendCharacter )
2087 // Add the character to the current text-actor and update the size.
2088 if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
2090 currentTextActorInfo.text.Append( character );
2092 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) );
2093 currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor;
2094 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor );
2098 ++characterGlobalIndex;
2099 ++characterParagraphIndex;
2103 if( !currentTextActorInfo.text.IsEmpty() )
2105 if( currentTextActorInfo.textActor )
2107 if( ( NULL != currentTextActorInfo.characterLayout ) &&
2108 currentTextActorInfo.characterLayout->mSetText )
2110 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
2111 currentTextActorInfo.characterLayout->mSetText = false;
2113 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
2114 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
2116 SetVisualParameters( currentTextActorInfo,
2119 paragraphLayout.mSize.height );
2123 // Insert the spare text-actors into the cache.
2124 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
2127 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
2128 TextView::RelayoutData& relayoutData,
2129 bool createGlyphActors )
2131 if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
2133 // nothing to do if there is no paragraphs.
2137 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
2138 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
2140 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2141 paragraphIt != paragraphEndIt;
2144 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2146 UpdateTextActorInfoForParagraph( visualParameters,
2149 characterGlobalIndex,
2150 lineLayoutInfoIndex,
2151 createGlyphActors );
2154 // Set visual parameters for ellipsis renderable actors.
2155 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2156 endIt = relayoutData.mEllipsizedGlyphActors.end();
2160 RenderableActor glyphActor = ( *it );
2162 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2163 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2165 // Sets the sort modifier value.
2166 glyphActor.SetSortModifier( visualParameters.mSortModifier );
2168 // Enables or disables the blending.
2169 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
2173 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
2175 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2177 // Note that relayoutData.mTextLayoutInfo contains layout info per paragraph but these paragraphs are the result of split the whole text every time a '\n' is found.
2178 // According with the layout option, one of this paragraphs could be laid-out in more than one line.
2180 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2181 paragraphIt != paragraphEndIt;
2184 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2186 std::size_t characterIndex = 0u;
2188 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2189 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2191 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2192 wordIt != wordEndIt;
2195 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2197 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2198 characterIt != characterEndIt;
2199 ++characterIt, ++characterIndex )
2201 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2202 const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2204 // Check if current character is the first of a new line
2205 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
2206 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
2209 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2212 if( style.IsUnderlineEnabled() )
2214 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
2215 isNewLine ) // Current character is underlined and is the first of current line.
2217 // Create a new underline info for the current underlined characters.
2218 UnderlineInfo underlineInfo;
2219 underlineInfo.mMaxHeight = character.mSize.height;
2220 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2221 underlineInfo.mPosition = character.mUnderlinePosition;
2223 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
2225 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
2229 // Retrieve last underline info and update it if current underline thickness is bigger.
2230 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) );
2232 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height );
2234 if( character.mUnderlineThickness > underlineInfo.mMaxThickness )
2236 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2237 underlineInfo.mPosition = character.mUnderlinePosition;
2243 textUnderlineStatus.mCurrentUnderlineStatus = false;
2246 ++textUnderlineStatus.mCharacterGlobalIndex;
2247 } // end characters.
2249 } // end paragraphs.
2252 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
2254 // Stores for each group of consecutive underlined characters in each line its maximum thicknes, its position of that thickness and the maximum character's height.
2255 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
2257 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2258 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
2260 if( textUnderlineStatus.mUnderlineInfo.empty() )
2262 // There is no underlined text. Just exit.
2266 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
2267 // Traverse the whole text and set the previously stored underline info in the text style.
2269 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
2270 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
2272 UnderlineInfo underlineInfo;
2274 if( underlineInfoIt < underlineInfoEndIt )
2276 underlineInfo = ( *underlineInfoIt );
2279 // Whether current text is underlined.
2280 textUnderlineStatus.mCurrentUnderlineStatus = false;
2281 textUnderlineStatus.mCharacterGlobalIndex = 0u;
2282 textUnderlineStatus.mLineGlobalIndex = 0u;
2284 float currentLineHeight = 0.f;
2285 float currentLineAscender = 0.f;
2287 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2288 paragraphIt != paragraphEndIt;
2291 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2292 std::size_t characterIndex = 0u;
2294 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2295 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2297 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2298 wordIt != wordEndIt;
2301 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2303 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2304 characterIt != characterEndIt;
2305 ++characterIt, ++characterIndex )
2307 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2308 TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2310 // Check if current character is the first of a new line
2312 bool isNewLine = false;
2314 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
2316 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
2317 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
2321 currentLineHeight = lineLayoutInfo.mSize.height;
2322 currentLineAscender = lineLayoutInfo.mAscender;
2323 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2327 if( style.IsUnderlineEnabled() )
2329 if( textUnderlineStatus.mCurrentUnderlineStatus )
2333 // Retrieves the thickness and position for the next piece of underlined text.
2334 if( underlineInfoIt < underlineInfoEndIt )
2337 if( underlineInfoIt < underlineInfoEndIt )
2339 underlineInfo = *underlineInfoIt;
2345 textUnderlineStatus.mCurrentUnderlineStatus = true;
2347 // Before setting the position it needs to be adjusted to match the base line.
2348 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender );
2349 const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
2351 // Sets the underline's parameters.
2352 style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
2354 // Mark the character to be set the new style into the text-actor.
2355 character.mSetStyle = true;
2359 if( textUnderlineStatus.mCurrentUnderlineStatus )
2361 textUnderlineStatus.mCurrentUnderlineStatus = false;
2363 // Retrieves the thickness and position for the next piece of underlined text.
2364 if( underlineInfoIt < underlineInfoEndIt )
2367 if( underlineInfoIt < underlineInfoEndIt )
2369 underlineInfo = *underlineInfoIt;
2375 ++textUnderlineStatus.mCharacterGlobalIndex;
2376 } // end of characters.
2378 } // end of paragraphs.
2381 void RemoveGlyphActors( Actor textView,
2382 const std::vector<RenderableActor>& glyphActors )
2384 // Removes previously inserted renderable-actors.
2385 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
2386 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
2387 // in order to remove 'only' renderable-actors added by these functions.
2388 // Any other actor added by a programmer or application won't be removed.
2390 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
2392 textView.Remove( *it );
2396 void InsertToTextView( Actor textView,
2397 TextView::RelayoutData& relayoutData )
2399 // Add text-actors to the text-view.
2401 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
2402 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2403 paragraphLayoutIt != endParagraphLayoutIt;
2404 ++paragraphLayoutIt )
2406 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
2408 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2409 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
2410 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
2412 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
2413 endWordLayoutIt = wordsLayoutInfo.end();
2414 wordLayoutIt != endWordLayoutIt;
2417 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
2419 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
2420 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
2421 characterLayoutIt != endCharacterLayoutIt;
2422 ++characterLayoutIt )
2424 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
2426 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
2428 //Add to the text-view.
2429 textView.Add( characterLayoutInfo.mGlyphActor );
2430 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
2436 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2437 endIt = relayoutData.mEllipsizedGlyphActors.end();
2441 RenderableActor glyphActor = ( *it );
2443 //Add to the text-view.
2444 textView.Add( glyphActor );
2445 relayoutData.mGlyphActors.push_back( glyphActor );
2447 relayoutData.mEllipsizedGlyphActors.clear();
2450 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
2452 TextActor textActor = cache.RetrieveTextActor();
2456 // Update the text-actor.
2457 textActor.SetText( text );
2458 textActor.SetTextStyle( style );
2462 // The text-actor cache is empty. Create a new one.
2463 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
2464 textActor = TextActor::New( text, parameters );
2470 } // namespace TextViewRelayout
2472 } // namespace Internal
2474 } // namespace Toolkit