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] characterGlobalIndex Index within the whole text of the first character of the paragraph.
388 * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
389 * @param[in,out] relayoutData The text-view's data structures.
391 void ReorderLayout( std::size_t characterGlobalIndex,
392 TextViewProcessor::ParagraphLayoutInfo& paragraph,
393 TextView::RelayoutData& relayoutData )
395 // Clear any previous right to left layout.
396 if( NULL != paragraph.mRightToLeftLayout )
398 paragraph.mRightToLeftLayout->Clear();
399 paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
403 // Create a new right to left layout if there isn't any.
404 paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
407 // Reorder Text and Styles.
409 // Reserve space for the styles.
410 paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
412 // Traverses all the bidirectional info per line.
413 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
415 TextProcessor::BidirectionalLineInfo* info( *it );
417 const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
418 const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
420 // The text can be appended as it's already reordered.
421 paragraph.mRightToLeftLayout->mText.Append( info->mText );
423 // The visual to logical map needs to be used to reorder the styles.
424 for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
426 paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
430 // Reorder Layout Info.
432 // Reserve space for the new word layout.
433 paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
435 // Traverses all the bidirectional info per line.
436 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
438 TextProcessor::BidirectionalLineInfo* info( *it );
440 // Reserve space for all characters.
441 TextViewProcessor::CharacterLayoutInfoContainer characters;
442 characters.resize( info->mNumberOfCharacters );
444 // Uses the visual to logical map to set every character in its new position.
445 for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
447 SetCharacter( paragraph.mWordsLayoutInfo,
448 info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
449 *( characters.begin() + index ) );
452 // Sets the new 'x' position for each character.
453 // Updates the text-view's layout info table with the new position of the character.
454 float xPosition = 0.f;
455 std::size_t index = 0u;
456 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it, ++index )
458 TextViewProcessor::CharacterLayoutInfo& character( *it );
460 // Set the 'x' position.
461 character.mPosition.x = xPosition;
463 // Update layout info table.
464 relayoutData.mCharacterLayoutInfoTable[characterGlobalIndex + info->mVisualToLogicalMap[index]].mPosition = character.mPosition;
466 // Update the position for the next character.
467 xPosition += character.mSize.width;
470 // Split the reordered text in words.
471 std::size_t previousPosition = 0u;
472 Vector<std::size_t> positions;
473 TextProcessor::SplitInWords( info->mText, positions );
475 // Whether last character is a word or a paragraph separator.
476 const std::size_t lastCharacterIndex = info->mText.GetLength() - 1u;
477 const bool isLastCharacterParagraphSeparator = info->mText.IsNewLine( lastCharacterIndex );
478 const bool isLastCharacterWordSeparator = info->mText.IsWhiteSpace( lastCharacterIndex );
480 // Sets the characters into the words they belong to.
481 for( Vector<std::size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
483 const std::size_t position = *it;
485 TextViewProcessor::WordLayoutInfo word;
486 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
487 characters.begin() + previousPosition,
488 characters.begin() + position );
490 if( !word.mCharactersLayoutInfo.empty() )
492 // Updates the layout of the word.
493 TextViewProcessor::UpdateLayoutInfo( word );
495 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
498 // white space or new paragraph.
499 TextViewProcessor::WordLayoutInfo space;
501 space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
502 characters.begin() + position,
503 characters.begin() + position + 1u );
505 space.mType = TextViewProcessor::WordSeparator;
507 TextViewProcessor::UpdateLayoutInfo( space );
509 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
511 previousPosition = position + 1u;
515 if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
517 TextViewProcessor::WordLayoutInfo word;
518 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
519 characters.begin() + previousPosition,
522 if( isLastCharacterParagraphSeparator )
524 word.mType = TextViewProcessor::ParagraphSeparator;
526 else if( isLastCharacterWordSeparator )
528 word.mType = TextViewProcessor::WordSeparator;
530 TextViewProcessor::UpdateLayoutInfo( word );
532 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
538 * Creates the bidirectional info needed to reorder each line of the paragraph.
540 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
541 * @param[in,out] paragraph Layout info for the paragraph.
542 * @param[in] characterGlobalIndex Index to the character within the whole text.
543 * @param[in] lineLayoutInfoIndex Index to the table of lines.
545 void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
546 TextViewProcessor::ParagraphLayoutInfo& paragraph,
547 std::size_t& characterGlobalIndex,
548 std::size_t& lineLayoutInfoIndex )
550 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
551 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
553 // Clear previously created bidirectional info.
554 paragraph.ClearBidirectionalInfo();
556 // For each character, it sets the character's direction.
558 // Initialize the paragraph direction. Used to set the direction of weak characters.
559 const bool isParagraphRightToLeft = paragraph.mBidirectionalParagraphInfo->IsRightToLeftParagraph();
560 bool isPreviousRightToLeft = isParagraphRightToLeft;
562 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
564 // Get the character's layout information (the one is shared with text-input)
565 Toolkit::TextView::CharacterLayoutInfo& info = *( relayoutData.mCharacterLayoutInfoTable.begin() + ( characterGlobalIndex + index ) );
567 // Gets the character's direction.
568 const Character::CharacterDirection direction = paragraph.mText[index].GetCharacterDirection();
569 if( Character::RightToLeft == direction )
571 info.mIsRightToLeftCharacter = true;
573 else if( Character::Neutral == direction )
575 // For neutral characters it check's the next and previous directions.
576 // If they are equals set that direction. If they are not, sets the paragraph direction.
577 // If there is no next, sets the previous direction.
579 // Check next character's direction.
580 bool isNextRightToLeft = isPreviousRightToLeft;
581 if( index < paragraph.mNumberOfCharacters - 1u )
583 const Character::CharacterDirection nextDirection = paragraph.mText[index + 1u].GetCharacterDirection();
584 isNextRightToLeft = Character::RightToLeft == nextDirection;
587 info.mIsRightToLeftCharacter = isPreviousRightToLeft == isNextRightToLeft ? isPreviousRightToLeft : isParagraphRightToLeft;
591 info.mIsRightToLeftCharacter = false;
594 isPreviousRightToLeft = info.mIsRightToLeftCharacter;
597 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
598 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
602 TextViewProcessor::WordLayoutInfo& word( *wordIt );
604 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
605 characterIt != characterEndIt;
608 TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
610 // Check if there is a new line.
611 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
615 // Point to the next line.
616 ++lineLayoutInfoIndex;
617 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
619 // Arrived at last line.
620 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
623 // Number of characters of the line.
624 const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
626 // There is right to left characters in this line. It needs to be reordered.
627 bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
628 bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
629 bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
631 // Set all the Text's characters in the visual order and creates the mapping tables.
632 TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
633 bidirectionalLineInfo );
635 paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
637 for( std::size_t index = 0u; index < numberOfCharacters; ++index )
639 relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
640 relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
644 ++characterGlobalIndex;
645 ++characterParagraphIndex;
650 void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
652 // Reset conversion tables shared through public-api
653 relayoutData.mCharacterLogicalToVisualMap.clear();
654 relayoutData.mCharacterVisualToLogicalMap.clear();
656 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
657 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
659 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
660 paragraphIt != paragraphEndIt;
663 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
665 if( NULL != paragraph.mBidirectionalParagraphInfo )
667 // There is right to left text in this paragraph.
669 // Stores the current global character index as is needed in both functions.
670 const std::size_t currentGlobalIndex = characterGlobalIndex;
672 // Creates the bidirectional info needed to reorder each line of the paragraph.
673 CreateBidirectionalInfoForLines( relayoutData,
675 characterGlobalIndex,
676 lineLayoutInfoIndex );
678 // Reorder each line of the paragraph
679 ReorderLayout( currentGlobalIndex, paragraph, relayoutData );
683 // Identity in case the paragraph has no right to left text.
684 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
686 const std::size_t globalIndex = characterGlobalIndex + index;
687 relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
688 relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
690 characterGlobalIndex += paragraph.mNumberOfCharacters;
695 float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
697 float xOffset( 0.f );
698 switch( horizontalTextAlignment )
700 case Toolkit::Alignment::HorizontalLeft:
705 case Toolkit::Alignment::HorizontalCenter:
707 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
710 case Toolkit::Alignment::HorizontalRight:
712 xOffset = parentWidth - wholeTextWidth;
717 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
724 float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight )
726 float yOffset( 0.f );
727 switch( verticalTextAlignment )
729 case Toolkit::Alignment::VerticalTop:
734 case Toolkit::Alignment::VerticalCenter:
736 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
739 case Toolkit::Alignment::VerticalBottom:
741 yOffset = parentHeight - wholeTextHeight;
746 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
753 float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength )
756 switch( justification )
758 case Toolkit::TextView::Left:
763 case Toolkit::TextView::Center:
765 offset = 0.5f * ( wholeTextWidth - lineLength );
768 case Toolkit::TextView::Right:
770 offset = wholeTextWidth - lineLength;
773 case Toolkit::TextView::Justified:
783 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
785 bool visible = false;
791 // Whether the text-actor is fully inside the boundaries of the text-view.
792 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
793 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
796 case FULLY_VISIBLE_WIDTH:
798 // Whether the text-actor is between the left and right boundaries of the text-view.
799 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
802 case FULLY_VISIBLE_HEIGHT:
804 // Whether the text-actor is between the top and bottom boundaries of the text-view.
805 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
808 case PARTIALLY_VISIBLE:
810 // Whether the text-actor is partially inside the boundaries of the text-view.
811 visible = ( ( position.x < parentSize.width ) &&
812 ( position.x + size.width > 0.f ) &&
813 ( position.y > 0.f ) &&
814 ( position.y - size.height < parentSize.height ) );
817 case PARTIALLY_VISIBLE_WIDTH:
819 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
820 // It may not be partially inside the text-view.
821 visible = ( ( position.x < parentSize.width ) &&
822 ( position.x + size.width > 0.f ) );
825 case PARTIALLY_VISIBLE_HEIGHT:
827 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
828 // It may not be partially inside the text-view.
829 visible = ( ( position.y > 0.f ) &&
830 ( position.y - size.height < parentSize.height ) );
838 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
840 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
842 return Vector2( gradient, p0.y - gradient * p0.x );
845 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
846 TextView::RelayoutData& relayoutData )
848 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
849 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
851 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
852 // In that case, it will align the line to the left and/or top, and ellipsize the end.
853 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
854 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
855 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
856 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
857 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
859 RelayoutParameters relayoutParameters;
861 // Calculates the vertical and horizontal offsets.
862 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
863 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
865 // Index to the global character (within the whole text).
866 std::size_t characterGlobalIndex = 0u;
868 // Index to the line info.
869 std::size_t lineLayoutInfoIndex = 0u;
871 relayoutParameters.mIndices.mParagraphIndex = 0u;
873 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
874 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
875 paragraphLayoutIt != endParagraphLayoutIt;
876 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
878 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
880 float justificationOffset = 0.f;
882 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
883 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
885 relayoutParameters.mIndices.mWordIndex = 0u;
887 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
888 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
890 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
891 endWordLayoutIt = wordsLayoutInfo.end();
892 wordLayoutIt != endWordLayoutIt;
893 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
895 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
897 relayoutParameters.mIndices.mCharacterIndex = 0u;
899 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
900 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
901 characterLayoutIt != endCharacterLayoutIt;
902 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
904 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
906 // Check if there is a new line.
907 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
911 // Calculate line justification offset.
912 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
914 // Point to the next line.
915 ++lineLayoutInfoIndex;
916 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
918 // Arrived at last line.
919 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
923 // Deletes the offsets if the exceed policies are EllipsizeEnd.
924 const float horizontalOffset = textHorizontalOffset + justificationOffset;
925 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
926 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
928 // Updates the size and position table for text-input with the alignment offset.
929 Vector3 positionOffset( characterLayoutInfo.mPosition );
931 // Update layout info table.
932 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[characterGlobalIndex];
933 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
935 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
936 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
938 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
944 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
945 TextView::RelayoutData& relayoutData )
957 // ggggg gggggggggg bb ggggg
958 // gg gg gggggggggg bb gg gg
959 // gg gg gggg bb gg gg
960 // gg gg gggg bb gg gg
961 // ggggg gg gggg bbbbbbb ggggg
962 // gg gg gggg bb bb gg
963 // g gg gggggggggg bb bb g gg
964 // ggggg gggggggggg bbbbbbb ggggg
973 // ggggg gggg gggg bb ggggg
974 // gg gg gggg gggg bbbbbbb gg gg
975 // gg gg gggg gggg bb bb gg gg
976 // gg gg gggggggggg bb bb gg gg
977 // ggggg gggggggggg bbbbbbb ggggg
980 // ggggg gg gggg ggggg
985 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
986 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
988 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
991 void UpdateLayoutInfoTable( Vector4& minMaxXY,
992 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
993 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
994 RelayoutParameters& relayoutParameters,
995 TextView::RelayoutData& relayoutData )
997 // updates min and max position to calculate the text size for multiline policies.
998 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
999 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
1001 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1002 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
1004 // Adds layout info to be retrieved by external controls or applications.
1005 Vector3 positionOffset( characterLayoutInfo.mPosition );
1007 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
1009 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor,
1010 characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
1012 ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
1013 false, // whether the character is right to left. The value is set in a next step in the CreateBidirectionalInfoForLines function
1014 true, // whether the character is visible.
1017 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
1019 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1022 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
1023 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1024 const TextStyle& style,
1025 RelayoutParameters& relayoutParameters,
1026 FadeParameters& fadeParameters,
1027 TextView::RelayoutData& relayoutData )
1029 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
1030 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
1031 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
1032 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
1038 // Calculates visibility of a text-actor according the exceed policies.
1040 // position + alignment offset.
1041 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1042 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1043 characterLayoutInfo.mPosition.z );
1045 // Whether the text actor is fully, partially or non visible (according exceed policies).
1046 switch( layoutParameters.mExceedPolicy )
1048 case TextView::Fade:
1050 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
1051 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1052 if( !IsVisible( position,
1053 characterLayoutInfo.mSize,
1054 relayoutData.mTextViewSize,
1057 relayoutParameters.mIsVisible = false;
1058 if( IsVisible( position,
1059 characterLayoutInfo.mSize,
1060 relayoutData.mTextViewSize,
1061 PARTIALLY_VISIBLE ) )
1063 fadeParameters.mIsPartiallyVisible = true;
1065 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
1066 if( IsExceedingWidth( position,
1067 characterLayoutInfo.mSize,
1068 relayoutData.mTextViewSize ) &&
1069 IsExceedingHeight( position,
1070 characterLayoutInfo.mSize,
1071 relayoutData.mTextViewSize ) )
1073 // Combination not fully supported by text-view.
1074 // Need to check if text-actor really supports this combination.
1075 fadeParameters.mIsPartiallyVisible = false;
1081 case TextView::FadeOriginal:
1083 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
1084 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1085 if( !IsVisible( position,
1086 characterLayoutInfo.mSize,
1087 relayoutData.mTextViewSize,
1088 FULLY_VISIBLE_WIDTH ) )
1090 relayoutParameters.mIsVisible = false;
1091 if( IsVisible( position,
1092 characterLayoutInfo.mSize,
1093 relayoutData.mTextViewSize,
1094 PARTIALLY_VISIBLE_WIDTH ) )
1096 fadeParameters.mIsPartiallyVisible = true;
1101 case TextView::OriginalFade:
1102 case TextView::SplitFade: // Fallthrough
1104 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
1105 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1106 if( !IsVisible( position,
1107 characterLayoutInfo.mSize,
1108 relayoutData.mTextViewSize,
1109 FULLY_VISIBLE_HEIGHT ) )
1111 relayoutParameters.mIsVisible = false;
1112 if( IsVisible( position,
1113 characterLayoutInfo.mSize,
1114 relayoutData.mTextViewSize,
1115 PARTIALLY_VISIBLE_HEIGHT ) )
1117 fadeParameters.mIsPartiallyVisible = true;
1124 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
1129 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
1131 characterLayoutInfo.mIsVisible = true;
1133 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1134 const float characterPositionPlusWidth = position.x + size.width;
1135 const float characterPositionMinusHeight = position.y - size.height;
1137 // Calculates which edges need to be faded-out.
1138 bool rightFadeOut = false;
1139 bool leftFadeOut = false;
1140 bool bottomFadeOut = false;
1141 bool topFadeOut = false;
1143 switch( layoutParameters.mExceedPolicy )
1145 case TextView::Fade:
1147 // All text-actors exceeding any of the boundaries will be faded-out.
1148 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1149 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1150 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1151 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1154 case TextView::FadeOriginal:
1156 // Only text-actors exceeding the left or the right boundaries will be faded-out.
1157 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1158 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1161 case TextView::SplitFade:
1162 case TextView::OriginalFade: //Fallthrough
1164 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
1165 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1166 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1171 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
1176 // Calculates gradient parameters for a text-actor.
1177 Vector4 gradientColor = Vector4::ZERO;
1178 Vector2 startPoint = Vector2::ZERO;
1179 Vector2 endPoint = Vector2::ZERO;
1181 if( !( rightFadeOut && leftFadeOut ) )
1183 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
1186 gradientColor = style.GetTextColor();
1188 // Calculates gradient coeficients.
1189 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
1190 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
1192 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1193 endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
1195 if( NULL == characterLayoutInfo.mGradientInfo )
1197 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1200 else if( leftFadeOut )
1202 gradientColor = style.GetTextColor();
1204 // Calculates gradient coeficients.
1205 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
1206 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
1208 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1209 endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
1211 if( NULL == characterLayoutInfo.mGradientInfo )
1213 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1218 if( !( bottomFadeOut && topFadeOut ) )
1220 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
1223 gradientColor = style.GetTextColor();
1225 // Calculates gradient coeficients.
1226 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
1227 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
1229 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1230 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
1232 if( NULL == characterLayoutInfo.mGradientInfo )
1234 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1237 else if( topFadeOut )
1239 gradientColor = style.GetTextColor();
1241 // Calculates gradient coeficients.
1242 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
1243 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
1245 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1246 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
1248 if( NULL == characterLayoutInfo.mGradientInfo )
1250 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1255 if( NULL != characterLayoutInfo.mGradientInfo )
1257 characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
1258 characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
1259 characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
1264 characterLayoutInfo.mIsVisible = false;
1268 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1269 const EllipsizeParameters& ellipsizeParameters )
1271 bool isPartiallyVisible = false;
1273 if( !IsVisible( ellipsizeParameters.mPosition,
1274 characterLayoutInfo.mSize,
1275 ellipsizeParameters.mEllipsizeBoundary,
1276 FULLY_VISIBLE_WIDTH ) )
1278 // The character doesn't fit in the text-view's width.
1279 characterLayoutInfo.mIsVisible = false;
1281 // Checks if the character is partially visible (it's cut by the boundary)
1282 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
1283 characterLayoutInfo.mSize,
1284 ellipsizeParameters.mEllipsizeBoundary,
1285 PARTIALLY_VISIBLE_WIDTH );
1289 // The character fits in the text-view's width. Set it to visible.
1290 characterLayoutInfo.mIsVisible = true;
1293 return isPartiallyVisible;
1296 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1297 const EllipsizeParameters& ellipsizeParameters )
1299 bool isPartiallyVisible = false;
1301 if( !IsVisible( ellipsizeParameters.mPosition,
1302 characterLayoutInfo.mSize,
1303 ellipsizeParameters.mEllipsizeBoundary,
1306 // The character is not fully visible. Needs to check if it's partially visible.
1307 characterLayoutInfo.mIsVisible = false;
1309 // Checks if the character doesn't cut the bottom edge of the text-view.
1310 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
1311 characterLayoutInfo.mSize,
1312 ellipsizeParameters.mEllipsizeBoundary,
1313 FULLY_VISIBLE_HEIGHT );
1315 // Checks if the character cuts the right edge of the text-view.
1316 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
1317 characterLayoutInfo.mSize,
1318 ellipsizeParameters.mEllipsizeBoundary,
1319 PARTIALLY_VISIBLE_WIDTH );
1321 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
1322 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
1326 // The character fits in the boundary of the text-view. Set it to visible.
1327 characterLayoutInfo.mIsVisible = true;
1330 return isPartiallyVisible;
1333 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
1334 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1335 EllipsizeParameters& ellipsizeParameters,
1336 TextView::RelayoutData& relayoutData )
1338 // Calculates visibility for EllipsizeEnd exceed policies.
1340 // 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.
1341 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
1342 // 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.
1344 // Position of the character used to do the visibility test.
1345 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1346 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1347 characterLayoutInfo.mPosition.z );
1349 // 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).
1350 bool isPartiallyVisible = false;
1352 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
1353 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
1355 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
1358 // The line or word fits completely inside the text-view's width. Nothing else to do.
1359 characterLayoutInfo.mIsVisible = true;
1363 // The line or word doesn't fit in the text-view's width.
1365 // Calculates visibility for each type of ellipsize policies.
1366 switch( layoutParameters.mExceedPolicy )
1368 case TextView::EllipsizeEndOriginal:
1370 // 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.
1372 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1373 ellipsizeParameters );
1377 case TextView::SplitEllipsizeEnd:
1378 case TextView::EllipsizeEnd:
1380 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1382 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1383 ellipsizeParameters );
1389 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1395 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1396 // In that case, the charater needs to be replaced by the ellipsize text.
1397 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1400 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1401 TextView::RelayoutData& relayoutData )
1403 // 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.
1404 // The code bellow creates the text-actors needed for the ellipsize text.
1406 // Set ellipsize's position by the end of visible text.
1407 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1408 // Stores current ellipsize text.
1410 // Stores current ellipsize style.
1411 TextStyle ellipsizeStyle;
1412 // Stores the current size.
1414 //Whether current glyph is an emoticon.
1415 bool isColorGlyph = false;
1417 float bearingOffset = 0.f;
1419 // Create ellipsize text-actor.
1420 std::size_t characterIndex = 0u;
1421 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1422 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1423 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1424 ++ellipsizeCharacterLayoutIt, ++characterIndex )
1426 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1427 const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
1430 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1431 ( ellipsizeStyle != style ) )
1433 // The style is different, so a new text-actor is needed.
1434 if( !ellipsizeText.IsEmpty() )
1436 // It only creates a text-actor if there is any text.
1437 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1438 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1439 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1441 // Updates the position for the next text-actor.
1442 ellipsizePosition.x += ellipsizeSize.width;
1444 // Adds the text-actor to the list.
1445 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1448 // Resets the current ellipsize info.
1449 ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1450 ellipsizeStyle = style;
1451 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1452 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1454 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1458 // Updates text and size with the new character.
1459 ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1460 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1464 if( !ellipsizeText.IsEmpty() )
1466 // Creates the last glyph-actor.
1467 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1468 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1469 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1471 // Adds the glyph-actor to the list.
1472 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1476 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1477 EllipsizeParameters& ellipsizeParameters,
1478 TextView::RelayoutData& relayoutData )
1480 // Traverses the text layout info from the first character of the line
1481 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1483 // Indices to the first character of the line.
1484 TextViewProcessor::TextInfoIndices firstIndices;
1485 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1486 relayoutData.mTextLayoutInfo,
1489 // Indices to the last character of the line.
1490 TextViewProcessor::TextInfoIndices lastIndices;
1491 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1492 relayoutData.mTextLayoutInfo,
1495 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1496 // This is the boundary used to check if a character have to be ellipsized.
1497 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1498 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1500 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex,
1501 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u;
1502 paragraphLayoutIt != endParagraphLayoutIt;
1503 ++paragraphLayoutIt )
1505 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1507 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1509 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1511 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1514 bool firstWord = true;
1515 bool lastWord = false;
1517 std::size_t wordCount = 0u;
1519 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1520 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1522 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
1523 endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
1524 wordLayoutIt != endWordLayoutIt;
1525 ++wordLayoutIt, ++wordCount )
1527 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1529 if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex )
1534 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1535 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u;
1536 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1537 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u;
1538 characterLayoutIt != endCharacterLayoutIt;
1539 ++characterLayoutIt )
1541 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1543 if( ellipsizeParameters.mEllipsizeLine )
1545 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1546 CalculateVisibilityForEllipsize( layoutParameters,
1547 characterLayoutInfo,
1548 ellipsizeParameters,
1551 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1553 // Create ellipsize text-actors if the character needs to be replaced.
1554 CreateEllipsizeTextActor( ellipsizeParameters,
1560 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1561 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1563 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1565 // Make characters invisible.
1566 characterLayoutInfo.mIsVisible = false;
1576 void SetTextVisible( TextView::RelayoutData& relayoutData )
1578 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1579 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1580 paragraphLayoutIt != endParagraphLayoutIt;
1581 ++paragraphLayoutIt )
1583 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1584 std::size_t characterIndex = 0u;
1586 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1587 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1589 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1590 endWordLayoutIt = wordsLayoutInfo.end();
1591 wordLayoutIt != endWordLayoutIt;
1594 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1596 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1597 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1598 characterLayoutIt != endCharacterLayoutIt;
1599 ++characterLayoutIt, ++characterIndex )
1601 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1603 characterLayoutInfo.mIsVisible = true;
1604 delete characterLayoutInfo.mGradientInfo;
1605 characterLayoutInfo.mGradientInfo = NULL;
1606 characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
1611 // Updates the visibility for text-input..
1612 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1613 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1617 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1619 characterLayoutInfo.mIsVisible = true;
1623 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1624 const TextView::VisualParameters& visualParameters,
1625 TextView::RelayoutData& relayoutData )
1627 RelayoutParameters relayoutParameters;
1628 FadeParameters fadeParameters;
1630 // 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.
1631 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1632 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1633 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1634 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1635 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1636 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1637 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1638 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1639 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1640 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1641 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1642 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1643 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1644 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1645 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1646 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1648 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1649 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1650 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1651 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1652 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1654 // Traverses all characters and calculates the visibility.
1656 std::size_t infoTableCharacterIndex = 0u;
1658 relayoutParameters.mIndices.mParagraphIndex = 0u;
1660 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1661 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1662 paragraphLayoutIt != endParagraphLayoutIt;
1663 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
1665 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1667 std::size_t characterIndex = 0u;
1668 relayoutParameters.mIndices.mWordIndex = 0u;
1670 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1671 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1673 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1674 endWordLayoutIt = wordsLayoutInfo.end();
1675 wordLayoutIt != endWordLayoutIt;
1676 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1678 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1680 relayoutParameters.mIsFirstCharacterOfWord = true;
1681 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1682 relayoutParameters.mIndices.mCharacterIndex = 0u;
1684 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1685 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1686 characterLayoutIt != endCharacterLayoutIt;
1687 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
1689 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1691 relayoutParameters.mIsVisible = true;
1692 fadeParameters.mIsPartiallyVisible = false;
1694 // Calculates the visibility for the current character.
1695 CalculateVisibilityForFade( layoutParameters,
1696 characterLayoutInfo,
1697 *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
1702 // Updates the visibility for text-input..
1703 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[infoTableCharacterIndex];
1705 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1707 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1709 relayoutParameters.mIsFirstCharacterOfWord = false;
1715 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1716 const TextView::VisualParameters& visualParameters,
1717 TextView::RelayoutData& relayoutData )
1719 // TODO check ellipsis with rtl text.
1721 // Traverses the lines and checks which ones doesn't fit in the text-view's boundary.
1722 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1723 lineInfoIt != endLineInfoIt;
1726 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1728 // To check if a line fits in the text-view's boundary,
1729 // get the position of the first character is needed and do the test
1730 // with the line size.
1732 // An bearing offset may have been applied to the first character so it's needed to
1733 // get the start position of the line.
1735 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1736 EllipsizeParameters ellipsizeParameters;
1738 // Retrieves the first index and the last index of the line.
1739 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1740 ellipsizeParameters.mLastIndex = 0u;
1741 if( ( lineInfoIt + 1u ) != endLineInfoIt )
1743 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) );
1744 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u;
1748 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u;
1751 // Retrieves the first character of the line and build the position of the line with the bearing.
1752 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1754 // Calculates the bearing offset applied to the first character.
1755 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1757 // Build the position of the line by removing the bearing offset from the first character's position.
1758 const Vector3 position( characterInfo.mPosition.x,
1759 characterInfo.mPosition.y + bearingOffset,
1760 characterInfo.mPosition.z );
1762 // Checks if the line needs to be ellipsized,
1763 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1765 relayoutData.mTextViewSize,
1766 FULLY_VISIBLE_WIDTH );
1768 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1769 // if the line fits in the width.
1770 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1772 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1773 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1774 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1775 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1776 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1777 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1779 // Need to check if there is lines which doesn't fit in the height.
1781 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1783 relayoutData.mTextViewSize,
1784 FULLY_VISIBLE_HEIGHT );
1786 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1788 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1790 // Current line is not ellipsized.
1791 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1792 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u;
1793 if( nextLineInfoIt != endLineInfoIt )
1795 // Retrives the position of the first character of the line and remove
1796 // the bearing offset to build to build the position of the line.
1797 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1798 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1800 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1802 const Vector3 position( characterInfo.mPosition.x,
1803 characterInfo.mPosition.y + bearingOffset,
1804 characterInfo.mPosition.z );
1806 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1808 relayoutData.mTextViewSize,
1809 FULLY_VISIBLE_HEIGHT );
1811 // If the next line is not visible, current line have to be ellipsized.
1812 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1817 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1819 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1822 // Sets the line descender.
1823 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1825 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1826 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1830 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1831 const TextView::VisualParameters& visualParameters,
1832 TextView::RelayoutData& relayoutData )
1834 switch( layoutParameters.mExceedPolicy )
1836 case TextView::FadeOriginal:
1837 case TextView::OriginalFade:
1838 case TextView::Fade:
1839 case TextView::SplitFade: // Fall through
1841 UpdateVisibilityForFade( layoutParameters,
1846 case TextView::EllipsizeEndOriginal:
1847 case TextView::SplitEllipsizeEnd:
1848 case TextView::EllipsizeEnd: // Fall through
1850 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1851 SetTextVisible( relayoutData );
1853 UpdateVisibilityForEllipsize( layoutParameters,
1860 SetTextVisible( relayoutData );
1867 * Creates an image actor for the emoticon.
1869 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1870 * @param[in,out] characterLayout Layout info for the character.
1871 * @param[in] character The character.
1873 void CreateEmoticon( const TextView::VisualParameters& visualParameters,
1874 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1875 const Character& character )
1877 // The character is an emoticon.
1878 ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1881 imageActor = ImageActor::New();
1883 GlyphImage image = GlyphImage::New( character );
1887 imageActor.SetImage( image );
1891 imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
1892 characterLayout.mPosition.y + characterLayout.mOffset.y,
1893 characterLayout.mPosition.z ) );
1894 imageActor.SetSize( characterLayout.mSize );
1896 // Sets the sort modifier value.
1897 imageActor.SetSortModifier( visualParameters.mSortModifier );
1899 characterLayout.mGlyphActor = imageActor;
1903 * Creates text-actors for the given text.
1905 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1906 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1907 * @param[in,out] paragraph Layout info for the paragraph.
1908 * @param[in,out] wordLayout Layout info for the word.
1909 * @param[in,out] characterLayout Layout info for the character.
1910 * @param[in] character The character.
1911 * @param[in] style The character's style.
1912 * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set.
1913 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1914 * @param[in,out] textActorCreated Whether a text-actor
1916 void CreateTextActor( const TextView::VisualParameters& visualParameters,
1917 TextView::RelayoutData& relayoutData,
1918 const TextViewProcessor::ParagraphLayoutInfo& paragraph,
1919 TextViewProcessor::WordLayoutInfo& wordLayout,
1920 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1921 const Character& character,
1922 const TextStyle& style,
1923 CurrentTextActorInfo& currentTextActorInfo,
1924 bool createGlyphActors,
1925 bool& textActorCreated )
1927 textActorCreated = false;
1929 // Set the text-actor for the current traversed text.
1930 if( currentTextActorInfo.textActor )
1932 if( ( NULL != currentTextActorInfo.characterLayout ) &&
1933 currentTextActorInfo.characterLayout->mSetText )
1935 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1936 currentTextActorInfo.characterLayout->mSetText = false;
1938 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1939 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1941 SetVisualParameters( currentTextActorInfo,
1944 paragraph.mSize.height );
1947 float rightToLeftOffset = 0.f;
1948 if( character.IsWhiteSpace() )
1950 // In left to right text, a word never starts with a white space but
1951 // it may happen in right to left text as the text is reversed.
1952 // The text alignment and justification offset is calculated without this white space.
1953 // It causes a missalignment which can be corrected by removing the size of the white space.
1954 rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
1957 // Whether this word is not a white space or if it is, it is underlined.
1958 // Don't want to create text-actors for white spaces unless they are underlined.
1959 bool isNotWhiteSpace = ( TextViewProcessor::NoSeparator == wordLayout.mType ) || ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() );
1961 if( isNotWhiteSpace )
1963 currentTextActorInfo.text = Text( character );
1967 currentTextActorInfo.text = Text();
1969 currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
1970 characterLayout.mPosition.y + characterLayout.mOffset.y,
1971 characterLayout.mPosition.z );
1972 currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
1974 currentTextActorInfo.color = style.GetTextColor();
1975 currentTextActorInfo.color.a = characterLayout.mColorAlpha;
1977 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1979 if( createGlyphActors && isNotWhiteSpace )
1981 textActorCreated = true;
1984 // Try to reuse first the text-actor of this character.
1985 textActor.SetTextStyle( style );
1989 // If there is no text-actor, try to retrieve one from the cache.
1990 textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1992 // If still there is no text-actor, create one.
1995 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1996 textActor = TextActor::New( Text(), parameters );
2000 textActor.SetTextStyle( style );
2003 characterLayout.mSetText = true;
2004 currentTextActorInfo.characterLayout = &characterLayout;
2006 characterLayout.mGlyphActor = textActor;
2009 // Update the current text-actor.
2010 currentTextActorInfo.textActor = textActor;
2014 * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position.
2016 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
2017 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
2018 * @param[in,out] paragraph Layout info for the paragraph.
2019 * @param[in,out] characterGlobalIndex Index to the character within the whole text.
2020 * @param[in,out] lineLayoutInfoIndex Index to the table of lines.
2021 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
2023 void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
2024 TextView::RelayoutData& relayoutData,
2025 TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
2026 std::size_t& characterGlobalIndex,
2027 std::size_t& lineLayoutInfoIndex,
2028 bool createGlyphActors )
2030 CurrentTextActorInfo currentTextActorInfo;
2031 currentTextActorInfo.characterLayout = NULL;
2033 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
2034 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
2035 bool textActorCreated = false; // Whether a text actor has been created for this the current group of characters traversed.
2037 TextStyle currentStyle; // style for the current text-actor.
2039 TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor.
2040 // start point for the current text-actor.
2041 // end point for the current text-actor.
2043 bool currentIsColorGlyph = false; // Whether current glyph is an emoticon.
2045 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
2047 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2048 const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
2050 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
2051 Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
2052 Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
2054 // 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.
2055 createGlyphActors = createGlyphActors || ( ( isRightToLeftLayout ) ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false );
2057 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
2058 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2059 wordIt != wordEndIt;
2062 TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
2064 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
2065 characterIt != characterEndIt;
2068 TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt );
2070 // Check if there is a new line.
2071 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
2075 // Point to the next line.
2076 ++lineLayoutInfoIndex;
2077 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
2079 // Arrived at last line.
2080 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
2082 textActorCreated = false;
2085 // Do not create a glyph-actor if there is no text.
2086 const Character character = text[characterParagraphIndex];
2087 const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
2089 // Check if the character has the same gradient info than the current one.
2090 bool differentGradientInfo = false;
2091 if( characterLayout.mGradientInfo && currentGradientInfo )
2093 differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) ||
2094 ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) ||
2095 ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint );
2097 else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) )
2099 differentGradientInfo = true;
2102 if( ( createGlyphActors && !textActorCreated ) ||
2103 characterLayout.mIsColorGlyph ||
2104 differentGradientInfo ||
2105 ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) ||
2106 ( style != currentStyle ) )
2108 characterLayout.mSetText = false;
2109 characterLayout.mSetStyle = false;
2111 if( characterLayout.mIsColorGlyph )
2113 CreateEmoticon( visualParameters,
2117 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2118 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2122 // There is a new style or a new line.
2124 CreateTextActor( visualParameters,
2131 currentTextActorInfo,
2135 if( textActorCreated )
2137 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2138 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2142 // Update style to be checked with next characters.
2143 currentStyle = style;
2144 currentGradientInfo = characterLayout.mGradientInfo;
2145 currentIsColorGlyph = characterLayout.mIsColorGlyph;
2149 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
2151 // Same style than previous one.
2153 // Add the character to the current text-actor and update the size.
2154 if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
2156 currentTextActorInfo.text.Append( character );
2158 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) );
2159 currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor;
2160 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor );
2164 if( ( createGlyphActors ) &&
2165 !characterLayout.mIsColorGlyph &&
2168 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
2171 // There is a previously created text-actor for this character.
2172 // If this character has another one put it into the cache.
2173 textActor.SetText( "" );
2174 textActorsToRemove.push_back( textActor );
2177 if( characterLayout.mGlyphActor )
2179 characterLayout.mGlyphActor.Reset();
2182 ++characterGlobalIndex;
2183 ++characterParagraphIndex;
2187 if( !currentTextActorInfo.text.IsEmpty() )
2189 if( currentTextActorInfo.textActor )
2191 if( ( NULL != currentTextActorInfo.characterLayout ) &&
2192 currentTextActorInfo.characterLayout->mSetText )
2194 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
2195 currentTextActorInfo.characterLayout->mSetText = false;
2197 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
2198 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
2200 SetVisualParameters( currentTextActorInfo,
2203 paragraphLayout.mSize.height );
2207 // Insert the spare text-actors into the cache.
2208 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
2211 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
2212 TextView::RelayoutData& relayoutData,
2213 bool createGlyphActors )
2215 if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
2217 // nothing to do if there is no paragraphs.
2221 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
2222 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
2224 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2225 paragraphIt != paragraphEndIt;
2228 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2230 UpdateTextActorInfoForParagraph( visualParameters,
2233 characterGlobalIndex,
2234 lineLayoutInfoIndex,
2235 createGlyphActors );
2238 // Set visual parameters for ellipsis renderable actors.
2239 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2240 endIt = relayoutData.mEllipsizedGlyphActors.end();
2244 RenderableActor glyphActor = ( *it );
2246 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2247 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2249 // Sets the sort modifier value.
2250 glyphActor.SetSortModifier( visualParameters.mSortModifier );
2252 // Enables or disables the blending.
2253 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
2257 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
2259 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2261 // 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.
2262 // According with the layout option, one of this paragraphs could be laid-out in more than one line.
2264 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2265 paragraphIt != paragraphEndIt;
2268 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2270 std::size_t characterIndex = 0u;
2272 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2273 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2275 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2276 wordIt != wordEndIt;
2279 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2281 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2282 characterIt != characterEndIt;
2283 ++characterIt, ++characterIndex )
2285 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2286 const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2288 // Check if current character is the first of a new line
2289 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
2290 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
2293 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2296 if( style.IsUnderlineEnabled() )
2298 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
2299 isNewLine ) // Current character is underlined and is the first of current line.
2301 // Create a new underline info for the current underlined characters.
2302 UnderlineInfo underlineInfo;
2303 underlineInfo.mMaxHeight = character.mSize.height;
2304 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2305 underlineInfo.mPosition = character.mUnderlinePosition;
2307 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
2309 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
2313 // Retrieve last underline info and update it if current underline thickness is bigger.
2314 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) );
2316 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height );
2318 if( character.mUnderlineThickness > underlineInfo.mMaxThickness )
2320 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2321 underlineInfo.mPosition = character.mUnderlinePosition;
2327 textUnderlineStatus.mCurrentUnderlineStatus = false;
2330 ++textUnderlineStatus.mCharacterGlobalIndex;
2331 } // end characters.
2333 } // end paragraphs.
2336 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
2338 // 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.
2339 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
2341 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2342 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
2344 if( textUnderlineStatus.mUnderlineInfo.empty() )
2346 // There is no underlined text. Just exit.
2350 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
2351 // Traverse the whole text and set the previously stored underline info in the text style.
2353 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
2354 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
2356 UnderlineInfo underlineInfo;
2358 if( underlineInfoIt < underlineInfoEndIt )
2360 underlineInfo = ( *underlineInfoIt );
2363 // Whether current text is underlined.
2364 textUnderlineStatus.mCurrentUnderlineStatus = false;
2365 textUnderlineStatus.mCharacterGlobalIndex = 0u;
2366 textUnderlineStatus.mLineGlobalIndex = 0u;
2368 float currentLineHeight = 0.f;
2369 float currentLineAscender = 0.f;
2371 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2372 paragraphIt != paragraphEndIt;
2375 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2376 std::size_t characterIndex = 0u;
2378 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2379 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2381 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2382 wordIt != wordEndIt;
2385 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2387 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2388 characterIt != characterEndIt;
2389 ++characterIt, ++characterIndex )
2391 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2392 TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2394 // Check if current character is the first of a new line
2396 bool isNewLine = false;
2398 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
2400 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
2401 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
2405 currentLineHeight = lineLayoutInfo.mSize.height;
2406 currentLineAscender = lineLayoutInfo.mAscender;
2407 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2411 if( style.IsUnderlineEnabled() )
2413 if( textUnderlineStatus.mCurrentUnderlineStatus )
2417 // Retrieves the thickness and position for the next piece of underlined text.
2418 if( underlineInfoIt < underlineInfoEndIt )
2421 if( underlineInfoIt < underlineInfoEndIt )
2423 underlineInfo = *underlineInfoIt;
2429 textUnderlineStatus.mCurrentUnderlineStatus = true;
2431 // Before setting the position it needs to be adjusted to match the base line.
2432 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender );
2433 const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
2435 // Sets the underline's parameters.
2436 style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
2438 // Mark the character to be set the new style into the text-actor.
2439 character.mSetStyle = true;
2443 if( textUnderlineStatus.mCurrentUnderlineStatus )
2445 textUnderlineStatus.mCurrentUnderlineStatus = false;
2447 // Retrieves the thickness and position for the next piece of underlined text.
2448 if( underlineInfoIt < underlineInfoEndIt )
2451 if( underlineInfoIt < underlineInfoEndIt )
2453 underlineInfo = *underlineInfoIt;
2459 ++textUnderlineStatus.mCharacterGlobalIndex;
2460 } // end of characters.
2462 } // end of paragraphs.
2465 void RemoveGlyphActors( Actor textView,
2466 const std::vector<RenderableActor>& glyphActors )
2468 // Removes previously inserted renderable-actors.
2469 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
2470 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
2471 // in order to remove 'only' renderable-actors added by these functions.
2472 // Any other actor added by a programmer or application won't be removed.
2474 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
2476 textView.Remove( *it );
2480 void InsertToTextView( Actor textView,
2481 TextView::RelayoutData& relayoutData )
2483 // Add text-actors to the text-view.
2485 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
2486 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2487 paragraphLayoutIt != endParagraphLayoutIt;
2488 ++paragraphLayoutIt )
2490 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
2492 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2493 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
2494 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
2496 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
2497 endWordLayoutIt = wordsLayoutInfo.end();
2498 wordLayoutIt != endWordLayoutIt;
2501 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
2503 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
2504 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
2505 characterLayoutIt != endCharacterLayoutIt;
2506 ++characterLayoutIt )
2508 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
2510 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
2512 //Add to the text-view.
2513 textView.Add( characterLayoutInfo.mGlyphActor );
2514 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
2520 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2521 endIt = relayoutData.mEllipsizedGlyphActors.end();
2525 RenderableActor glyphActor = ( *it );
2527 //Add to the text-view.
2528 textView.Add( glyphActor );
2529 relayoutData.mGlyphActors.push_back( glyphActor );
2531 relayoutData.mEllipsizedGlyphActors.clear();
2534 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
2536 TextActor textActor = cache.RetrieveTextActor();
2540 // Update the text-actor.
2541 textActor.SetText( text );
2542 textActor.SetTextStyle( style );
2546 // The text-actor cache is empty. Create a new one.
2547 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
2548 textActor = TextActor::New( text, parameters );
2554 } // namespace TextViewRelayout
2556 } // namespace Internal
2558 } // namespace Toolkit