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 // Sets the characters into the words they belong to.
476 for( Vector<std::size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
478 const std::size_t position = *it;
480 TextViewProcessor::WordLayoutInfo word;
481 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
482 characters.begin() + previousPosition,
483 characters.begin() + position );
485 if( !word.mCharactersLayoutInfo.empty() )
487 // Updates the layout of the word.
488 TextViewProcessor::UpdateLayoutInfo( word );
490 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
493 // white space or new paragraph.
494 TextViewProcessor::WordLayoutInfo space;
495 space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
496 characters.begin() + position,
497 characters.begin() + position + 1u );
499 TextViewProcessor::UpdateLayoutInfo( space );
501 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
503 previousPosition = position + 1u;
507 if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
509 TextViewProcessor::WordLayoutInfo word;
510 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
511 characters.begin() + previousPosition,
514 TextViewProcessor::UpdateLayoutInfo( word );
516 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
522 * Creates the bidirectional info needed to reorder each line of the paragraph.
524 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
525 * @param[in,out] paragraph Layout info for the paragraph.
526 * @param[in] characterGlobalIndex Index to the character within the whole text.
527 * @param[in] lineLayoutInfoIndex Index to the table of lines.
529 void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
530 TextViewProcessor::ParagraphLayoutInfo& paragraph,
531 std::size_t& characterGlobalIndex,
532 std::size_t& lineLayoutInfoIndex )
534 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
535 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
537 // Clear previously created bidirectional info.
538 paragraph.ClearBidirectionalInfo();
540 // For each character, it sets the character's direction.
542 // Initialize the paragraph direction. Used to set the direction of weak characters.
543 const bool isParagraphRightToLeft = paragraph.mBidirectionalParagraphInfo->IsRightToLeftParagraph();
544 bool isPreviousRightToLeft = isParagraphRightToLeft;
546 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
548 // Get the character's layout information (the one is shared with text-input)
549 Toolkit::TextView::CharacterLayoutInfo& info = *( relayoutData.mCharacterLayoutInfoTable.begin() + ( characterGlobalIndex + index ) );
551 // Gets the character's direction.
552 const Character::CharacterDirection direction = paragraph.mText[index].GetCharacterDirection();
553 if( Character::RightToLeft == direction )
555 info.mIsRightToLeftCharacter = true;
557 else if( Character::Neutral == direction )
559 // For neutral characters it check's the next and previous directions.
560 // If they are equals set that direction. If they are not, sets the paragraph direction.
561 // If there is no next, sets the previous direction.
563 // Check next character's direction.
564 bool isNextRightToLeft = isPreviousRightToLeft;
565 if( index < paragraph.mNumberOfCharacters - 1u )
567 const Character::CharacterDirection nextDirection = paragraph.mText[index + 1u].GetCharacterDirection();
568 isNextRightToLeft = Character::RightToLeft == nextDirection;
571 info.mIsRightToLeftCharacter = isPreviousRightToLeft == isNextRightToLeft ? isPreviousRightToLeft : isParagraphRightToLeft;
575 info.mIsRightToLeftCharacter = false;
578 isPreviousRightToLeft = info.mIsRightToLeftCharacter;
581 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
582 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
586 TextViewProcessor::WordLayoutInfo& word( *wordIt );
588 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
589 characterIt != characterEndIt;
592 TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
594 // Check if there is a new line.
595 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
599 // Point to the next line.
600 ++lineLayoutInfoIndex;
601 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
603 // Arrived at last line.
604 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
607 // Number of characters of the line.
608 const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
610 // There is right to left characters in this line. It needs to be reordered.
611 bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
612 bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
613 bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
615 // Set all the Text's characters in the visual order and creates the mapping tables.
616 TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
617 bidirectionalLineInfo );
619 paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
621 for( std::size_t index = 0u; index < numberOfCharacters; ++index )
623 relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
624 relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
628 ++characterGlobalIndex;
629 ++characterParagraphIndex;
634 void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
636 // Reset conversion tables shared through public-api
637 relayoutData.mCharacterLogicalToVisualMap.clear();
638 relayoutData.mCharacterVisualToLogicalMap.clear();
640 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
641 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
643 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
644 paragraphIt != paragraphEndIt;
647 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
649 if( NULL != paragraph.mBidirectionalParagraphInfo )
651 // There is right to left text in this paragraph.
653 // Stores the current global character index as is needed in both functions.
654 const std::size_t currentGlobalIndex = characterGlobalIndex;
656 // Creates the bidirectional info needed to reorder each line of the paragraph.
657 CreateBidirectionalInfoForLines( relayoutData,
659 characterGlobalIndex,
660 lineLayoutInfoIndex );
662 // Reorder each line of the paragraph
663 ReorderLayout( currentGlobalIndex, paragraph, relayoutData );
667 // Identity in case the paragraph has no right to left text.
668 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
670 const std::size_t globalIndex = characterGlobalIndex + index;
671 relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
672 relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
674 characterGlobalIndex += paragraph.mNumberOfCharacters;
679 float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
681 float xOffset( 0.f );
682 switch( horizontalTextAlignment )
684 case Toolkit::Alignment::HorizontalLeft:
689 case Toolkit::Alignment::HorizontalCenter:
691 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
694 case Toolkit::Alignment::HorizontalRight:
696 xOffset = parentWidth - wholeTextWidth;
701 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
708 float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight )
710 float yOffset( 0.f );
711 switch( verticalTextAlignment )
713 case Toolkit::Alignment::VerticalTop:
718 case Toolkit::Alignment::VerticalCenter:
720 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
723 case Toolkit::Alignment::VerticalBottom:
725 yOffset = parentHeight - wholeTextHeight;
730 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
737 float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength )
740 switch( justification )
742 case Toolkit::TextView::Left:
747 case Toolkit::TextView::Center:
749 offset = 0.5f * ( wholeTextWidth - lineLength );
752 case Toolkit::TextView::Right:
754 offset = wholeTextWidth - lineLength;
757 case Toolkit::TextView::Justified:
767 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
769 bool visible = false;
775 // Whether the text-actor is fully inside the boundaries of the text-view.
776 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
777 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
780 case FULLY_VISIBLE_WIDTH:
782 // Whether the text-actor is between the left and right boundaries of the text-view.
783 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
786 case FULLY_VISIBLE_HEIGHT:
788 // Whether the text-actor is between the top and bottom boundaries of the text-view.
789 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
792 case PARTIALLY_VISIBLE:
794 // Whether the text-actor is partially inside the boundaries of the text-view.
795 visible = ( ( position.x < parentSize.width ) &&
796 ( position.x + size.width > 0.f ) &&
797 ( position.y > 0.f ) &&
798 ( position.y - size.height < parentSize.height ) );
801 case PARTIALLY_VISIBLE_WIDTH:
803 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
804 // It may not be partially inside the text-view.
805 visible = ( ( position.x < parentSize.width ) &&
806 ( position.x + size.width > 0.f ) );
809 case PARTIALLY_VISIBLE_HEIGHT:
811 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
812 // It may not be partially inside the text-view.
813 visible = ( ( position.y > 0.f ) &&
814 ( position.y - size.height < parentSize.height ) );
822 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
824 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
826 return Vector2( gradient, p0.y - gradient * p0.x );
829 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
830 TextView::RelayoutData& relayoutData )
832 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
833 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
835 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
836 // In that case, it will align the line to the left and/or top, and ellipsize the end.
837 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
838 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
839 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
840 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
841 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
843 RelayoutParameters relayoutParameters;
845 // Calculates the vertical and horizontal offsets.
846 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
847 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
849 // Index to the global character (within the whole text).
850 std::size_t characterGlobalIndex = 0u;
852 // Index to the line info.
853 std::size_t lineLayoutInfoIndex = 0u;
855 relayoutParameters.mIndices.mParagraphIndex = 0u;
857 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
858 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
859 paragraphLayoutIt != endParagraphLayoutIt;
860 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
862 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
864 float justificationOffset = 0.f;
866 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
867 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
869 relayoutParameters.mIndices.mWordIndex = 0u;
871 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
872 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
874 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
875 endWordLayoutIt = wordsLayoutInfo.end();
876 wordLayoutIt != endWordLayoutIt;
877 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
879 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
881 relayoutParameters.mIndices.mCharacterIndex = 0u;
883 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
884 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
885 characterLayoutIt != endCharacterLayoutIt;
886 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
888 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
890 // Check if there is a new line.
891 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
895 // Calculate line justification offset.
896 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
898 // Point to the next line.
899 ++lineLayoutInfoIndex;
900 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
902 // Arrived at last line.
903 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
907 // Deletes the offsets if the exceed policies are EllipsizeEnd.
908 const float horizontalOffset = textHorizontalOffset + justificationOffset;
909 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
910 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
912 // Updates the size and position table for text-input with the alignment offset.
913 Vector3 positionOffset( characterLayoutInfo.mPosition );
915 // Update layout info table.
916 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[characterGlobalIndex];
917 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
919 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
920 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
922 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
928 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
929 TextView::RelayoutData& relayoutData )
941 // ggggg gggggggggg bb ggggg
942 // gg gg gggggggggg bb gg gg
943 // gg gg gggg bb gg gg
944 // gg gg gggg bb gg gg
945 // ggggg gg gggg bbbbbbb ggggg
946 // gg gg gggg bb bb gg
947 // g gg gggggggggg bb bb g gg
948 // ggggg gggggggggg bbbbbbb ggggg
957 // ggggg gggg gggg bb ggggg
958 // gg gg gggg gggg bbbbbbb gg gg
959 // gg gg gggg gggg bb bb gg gg
960 // gg gg gggggggggg bb bb gg gg
961 // ggggg gggggggggg bbbbbbb ggggg
964 // ggggg gg gggg ggggg
969 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
970 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
972 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
975 void UpdateLayoutInfoTable( Vector4& minMaxXY,
976 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
977 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
978 RelayoutParameters& relayoutParameters,
979 TextView::RelayoutData& relayoutData )
981 // updates min and max position to calculate the text size for multiline policies.
982 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
983 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
985 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
986 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
988 // Adds layout info to be retrieved by external controls or applications.
989 Vector3 positionOffset( characterLayoutInfo.mPosition );
991 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
993 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor,
994 characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
996 ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
997 false, // whether the character is right to left. The value is set in a next step in the CreateBidirectionalInfoForLines function
998 true, // whether the character is visible.
1001 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
1003 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1006 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
1007 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1008 const TextStyle& style,
1009 RelayoutParameters& relayoutParameters,
1010 FadeParameters& fadeParameters,
1011 TextView::RelayoutData& relayoutData )
1013 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
1014 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
1015 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
1016 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
1022 // Calculates visibility of a text-actor according the exceed policies.
1024 // position + alignment offset.
1025 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1026 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1027 characterLayoutInfo.mPosition.z );
1029 // Whether the text actor is fully, partially or non visible (according exceed policies).
1030 switch( layoutParameters.mExceedPolicy )
1032 case TextView::Fade:
1034 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
1035 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1036 if( !IsVisible( position,
1037 characterLayoutInfo.mSize,
1038 relayoutData.mTextViewSize,
1041 relayoutParameters.mIsVisible = false;
1042 if( IsVisible( position,
1043 characterLayoutInfo.mSize,
1044 relayoutData.mTextViewSize,
1045 PARTIALLY_VISIBLE ) )
1047 fadeParameters.mIsPartiallyVisible = true;
1049 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
1050 if( IsExceedingWidth( position,
1051 characterLayoutInfo.mSize,
1052 relayoutData.mTextViewSize ) &&
1053 IsExceedingHeight( position,
1054 characterLayoutInfo.mSize,
1055 relayoutData.mTextViewSize ) )
1057 // Combination not fully supported by text-view.
1058 // Need to check if text-actor really supports this combination.
1059 fadeParameters.mIsPartiallyVisible = false;
1065 case TextView::FadeOriginal:
1067 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
1068 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1069 if( !IsVisible( position,
1070 characterLayoutInfo.mSize,
1071 relayoutData.mTextViewSize,
1072 FULLY_VISIBLE_WIDTH ) )
1074 relayoutParameters.mIsVisible = false;
1075 if( IsVisible( position,
1076 characterLayoutInfo.mSize,
1077 relayoutData.mTextViewSize,
1078 PARTIALLY_VISIBLE_WIDTH ) )
1080 fadeParameters.mIsPartiallyVisible = true;
1085 case TextView::OriginalFade:
1086 case TextView::SplitFade: // Fallthrough
1088 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
1089 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1090 if( !IsVisible( position,
1091 characterLayoutInfo.mSize,
1092 relayoutData.mTextViewSize,
1093 FULLY_VISIBLE_HEIGHT ) )
1095 relayoutParameters.mIsVisible = false;
1096 if( IsVisible( position,
1097 characterLayoutInfo.mSize,
1098 relayoutData.mTextViewSize,
1099 PARTIALLY_VISIBLE_HEIGHT ) )
1101 fadeParameters.mIsPartiallyVisible = true;
1108 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
1113 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
1115 characterLayoutInfo.mIsVisible = true;
1117 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1118 const float characterPositionPlusWidth = position.x + size.width;
1119 const float characterPositionMinusHeight = position.y - size.height;
1121 // Calculates which edges need to be faded-out.
1122 bool rightFadeOut = false;
1123 bool leftFadeOut = false;
1124 bool bottomFadeOut = false;
1125 bool topFadeOut = false;
1127 switch( layoutParameters.mExceedPolicy )
1129 case TextView::Fade:
1131 // All text-actors exceeding any of the boundaries will be faded-out.
1132 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1133 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1134 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1135 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1138 case TextView::FadeOriginal:
1140 // Only text-actors exceeding the left or the right boundaries will be faded-out.
1141 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1142 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1145 case TextView::SplitFade:
1146 case TextView::OriginalFade: //Fallthrough
1148 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
1149 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1150 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1155 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
1160 // Calculates gradient parameters for a text-actor.
1161 Vector4 gradientColor = Vector4::ZERO;
1162 Vector2 startPoint = Vector2::ZERO;
1163 Vector2 endPoint = Vector2::ZERO;
1165 if( !( rightFadeOut && leftFadeOut ) )
1167 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
1170 gradientColor = style.GetTextColor();
1172 // Calculates gradient coeficients.
1173 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
1174 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
1176 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1177 endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
1179 if( NULL == characterLayoutInfo.mGradientInfo )
1181 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1184 else if( leftFadeOut )
1186 gradientColor = style.GetTextColor();
1188 // Calculates gradient coeficients.
1189 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
1190 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
1192 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1193 endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
1195 if( NULL == characterLayoutInfo.mGradientInfo )
1197 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1202 if( !( bottomFadeOut && topFadeOut ) )
1204 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
1207 gradientColor = style.GetTextColor();
1209 // Calculates gradient coeficients.
1210 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
1211 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
1213 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1214 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
1216 if( NULL == characterLayoutInfo.mGradientInfo )
1218 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1221 else if( topFadeOut )
1223 gradientColor = style.GetTextColor();
1225 // Calculates gradient coeficients.
1226 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
1227 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
1229 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1230 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
1232 if( NULL == characterLayoutInfo.mGradientInfo )
1234 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1239 if( NULL != characterLayoutInfo.mGradientInfo )
1241 characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
1242 characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
1243 characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
1248 characterLayoutInfo.mIsVisible = false;
1252 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1253 const EllipsizeParameters& ellipsizeParameters )
1255 bool isPartiallyVisible = false;
1257 if( !IsVisible( ellipsizeParameters.mPosition,
1258 characterLayoutInfo.mSize,
1259 ellipsizeParameters.mEllipsizeBoundary,
1260 FULLY_VISIBLE_WIDTH ) )
1262 // The character doesn't fit in the text-view's width.
1263 characterLayoutInfo.mIsVisible = false;
1265 // Checks if the character is partially visible (it's cut by the boundary)
1266 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
1267 characterLayoutInfo.mSize,
1268 ellipsizeParameters.mEllipsizeBoundary,
1269 PARTIALLY_VISIBLE_WIDTH );
1273 // The character fits in the text-view's width. Set it to visible.
1274 characterLayoutInfo.mIsVisible = true;
1277 return isPartiallyVisible;
1280 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1281 const EllipsizeParameters& ellipsizeParameters )
1283 bool isPartiallyVisible = false;
1285 if( !IsVisible( ellipsizeParameters.mPosition,
1286 characterLayoutInfo.mSize,
1287 ellipsizeParameters.mEllipsizeBoundary,
1290 // The character is not fully visible. Needs to check if it's partially visible.
1291 characterLayoutInfo.mIsVisible = false;
1293 // Checks if the character doesn't cut the bottom edge of the text-view.
1294 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
1295 characterLayoutInfo.mSize,
1296 ellipsizeParameters.mEllipsizeBoundary,
1297 FULLY_VISIBLE_HEIGHT );
1299 // Checks if the character cuts the right edge of the text-view.
1300 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
1301 characterLayoutInfo.mSize,
1302 ellipsizeParameters.mEllipsizeBoundary,
1303 PARTIALLY_VISIBLE_WIDTH );
1305 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
1306 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
1310 // The character fits in the boundary of the text-view. Set it to visible.
1311 characterLayoutInfo.mIsVisible = true;
1314 return isPartiallyVisible;
1317 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
1318 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1319 EllipsizeParameters& ellipsizeParameters,
1320 TextView::RelayoutData& relayoutData )
1322 // Calculates visibility for EllipsizeEnd exceed policies.
1324 // 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.
1325 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
1326 // 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.
1328 // Position of the character used to do the visibility test.
1329 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1330 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1331 characterLayoutInfo.mPosition.z );
1333 // 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).
1334 bool isPartiallyVisible = false;
1336 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
1337 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
1339 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
1342 // The line or word fits completely inside the text-view's width. Nothing else to do.
1343 characterLayoutInfo.mIsVisible = true;
1347 // The line or word doesn't fit in the text-view's width.
1349 // Calculates visibility for each type of ellipsize policies.
1350 switch( layoutParameters.mExceedPolicy )
1352 case TextView::EllipsizeEndOriginal:
1354 // 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.
1356 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1357 ellipsizeParameters );
1361 case TextView::SplitEllipsizeEnd:
1362 case TextView::EllipsizeEnd:
1364 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1366 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1367 ellipsizeParameters );
1373 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1379 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1380 // In that case, the charater needs to be replaced by the ellipsize text.
1381 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1384 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1385 TextView::RelayoutData& relayoutData )
1387 // 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.
1388 // The code bellow creates the text-actors needed for the ellipsize text.
1390 // Set ellipsize's position by the end of visible text.
1391 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1392 // Stores current ellipsize text.
1394 // Stores current ellipsize style.
1395 TextStyle ellipsizeStyle;
1396 // Stores the current size.
1398 //Whether current glyph is an emoticon.
1399 bool isColorGlyph = false;
1401 float bearingOffset = 0.f;
1403 // Create ellipsize text-actor.
1404 std::size_t characterIndex = 0u;
1405 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1406 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1407 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1408 ++ellipsizeCharacterLayoutIt, ++characterIndex )
1410 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1411 const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
1414 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1415 ( ellipsizeStyle != style ) )
1417 // The style is different, so a new text-actor is needed.
1418 if( !ellipsizeText.IsEmpty() )
1420 // It only creates a text-actor if there is any text.
1421 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1422 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1423 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1425 // Updates the position for the next text-actor.
1426 ellipsizePosition.x += ellipsizeSize.width;
1428 // Adds the text-actor to the list.
1429 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1432 // Resets the current ellipsize info.
1433 ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1434 ellipsizeStyle = style;
1435 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1436 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1438 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1442 // Updates text and size with the new character.
1443 ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1444 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1448 if( !ellipsizeText.IsEmpty() )
1450 // Creates the last glyph-actor.
1451 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1452 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1453 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1455 // Adds the glyph-actor to the list.
1456 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1460 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1461 EllipsizeParameters& ellipsizeParameters,
1462 TextView::RelayoutData& relayoutData )
1464 // Traverses the text layout info from the first character of the line
1465 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1467 // Indices to the first character of the line.
1468 TextViewProcessor::TextInfoIndices firstIndices;
1469 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1470 relayoutData.mTextLayoutInfo,
1473 // Indices to the last character of the line.
1474 TextViewProcessor::TextInfoIndices lastIndices;
1475 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1476 relayoutData.mTextLayoutInfo,
1479 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1480 // This is the boundary used to check if a character have to be ellipsized.
1481 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1482 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1484 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex,
1485 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u;
1486 paragraphLayoutIt != endParagraphLayoutIt;
1487 ++paragraphLayoutIt )
1489 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1491 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1493 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1495 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1498 bool firstWord = true;
1499 bool lastWord = false;
1501 std::size_t wordCount = 0u;
1503 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1504 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1506 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
1507 endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
1508 wordLayoutIt != endWordLayoutIt;
1509 ++wordLayoutIt, ++wordCount )
1511 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1513 if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex )
1518 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1519 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u;
1520 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1521 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u;
1522 characterLayoutIt != endCharacterLayoutIt;
1523 ++characterLayoutIt )
1525 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1527 if( ellipsizeParameters.mEllipsizeLine )
1529 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1530 CalculateVisibilityForEllipsize( layoutParameters,
1531 characterLayoutInfo,
1532 ellipsizeParameters,
1535 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1537 // Create ellipsize text-actors if the character needs to be replaced.
1538 CreateEllipsizeTextActor( ellipsizeParameters,
1544 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1545 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1547 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1549 // Make characters invisible.
1550 characterLayoutInfo.mIsVisible = false;
1560 void SetTextVisible( TextView::RelayoutData& relayoutData )
1562 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1563 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1564 paragraphLayoutIt != endParagraphLayoutIt;
1565 ++paragraphLayoutIt )
1567 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1568 std::size_t characterIndex = 0u;
1570 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1571 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1573 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1574 endWordLayoutIt = wordsLayoutInfo.end();
1575 wordLayoutIt != endWordLayoutIt;
1578 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1580 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1581 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1582 characterLayoutIt != endCharacterLayoutIt;
1583 ++characterLayoutIt, ++characterIndex )
1585 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1587 characterLayoutInfo.mIsVisible = true;
1588 delete characterLayoutInfo.mGradientInfo;
1589 characterLayoutInfo.mGradientInfo = NULL;
1590 characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
1595 // Updates the visibility for text-input..
1596 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1597 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1601 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1603 characterLayoutInfo.mIsVisible = true;
1607 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1608 const TextView::VisualParameters& visualParameters,
1609 TextView::RelayoutData& relayoutData )
1611 RelayoutParameters relayoutParameters;
1612 FadeParameters fadeParameters;
1614 // 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.
1615 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1616 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1617 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1618 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1619 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1620 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1621 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1622 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1623 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1624 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1625 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1626 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1627 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1628 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1629 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1630 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1632 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1633 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1634 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1635 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1636 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1638 // Traverses all characters and calculates the visibility.
1640 std::size_t infoTableCharacterIndex = 0u;
1642 relayoutParameters.mIndices.mParagraphIndex = 0u;
1644 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1645 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1646 paragraphLayoutIt != endParagraphLayoutIt;
1647 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
1649 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1651 std::size_t characterIndex = 0u;
1652 relayoutParameters.mIndices.mWordIndex = 0u;
1654 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1655 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1657 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1658 endWordLayoutIt = wordsLayoutInfo.end();
1659 wordLayoutIt != endWordLayoutIt;
1660 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1662 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1664 relayoutParameters.mIsFirstCharacterOfWord = true;
1665 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1666 relayoutParameters.mIndices.mCharacterIndex = 0u;
1668 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1669 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1670 characterLayoutIt != endCharacterLayoutIt;
1671 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
1673 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1675 relayoutParameters.mIsVisible = true;
1676 fadeParameters.mIsPartiallyVisible = false;
1678 // Calculates the visibility for the current character.
1679 CalculateVisibilityForFade( layoutParameters,
1680 characterLayoutInfo,
1681 *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
1686 // Updates the visibility for text-input..
1687 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[infoTableCharacterIndex];
1689 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1691 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1693 relayoutParameters.mIsFirstCharacterOfWord = false;
1699 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1700 const TextView::VisualParameters& visualParameters,
1701 TextView::RelayoutData& relayoutData )
1703 // TODO check ellipsis with rtl text.
1705 // Traverses the lines and checks which ones doesn't fit in the text-view's boundary.
1706 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1707 lineInfoIt != endLineInfoIt;
1710 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1712 // To check if a line fits in the text-view's boundary,
1713 // get the position of the first character is needed and do the test
1714 // with the line size.
1716 // An bearing offset may have been applied to the first character so it's needed to
1717 // get the start position of the line.
1719 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1720 EllipsizeParameters ellipsizeParameters;
1722 // Retrieves the first index and the last index of the line.
1723 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1724 ellipsizeParameters.mLastIndex = 0u;
1725 if( ( lineInfoIt + 1u ) != endLineInfoIt )
1727 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) );
1728 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u;
1732 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u;
1735 // Retrieves the first character of the line and build the position of the line with the bearing.
1736 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1738 // Calculates the bearing offset applied to the first character.
1739 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1741 // Build the position of the line by removing the bearing offset from the first character's position.
1742 const Vector3 position( characterInfo.mPosition.x,
1743 characterInfo.mPosition.y + bearingOffset,
1744 characterInfo.mPosition.z );
1746 // Checks if the line needs to be ellipsized,
1747 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1749 relayoutData.mTextViewSize,
1750 FULLY_VISIBLE_WIDTH );
1752 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1753 // if the line fits in the width.
1754 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1756 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1757 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1758 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1759 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1760 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1761 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1763 // Need to check if there is lines which doesn't fit in the height.
1765 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1767 relayoutData.mTextViewSize,
1768 FULLY_VISIBLE_HEIGHT );
1770 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1772 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1774 // Current line is not ellipsized.
1775 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1776 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u;
1777 if( nextLineInfoIt != endLineInfoIt )
1779 // Retrives the position of the first character of the line and remove
1780 // the bearing offset to build to build the position of the line.
1781 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1782 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1784 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1786 const Vector3 position( characterInfo.mPosition.x,
1787 characterInfo.mPosition.y + bearingOffset,
1788 characterInfo.mPosition.z );
1790 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1792 relayoutData.mTextViewSize,
1793 FULLY_VISIBLE_HEIGHT );
1795 // If the next line is not visible, current line have to be ellipsized.
1796 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1801 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1803 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1806 // Sets the line descender.
1807 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1809 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1810 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1814 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1815 const TextView::VisualParameters& visualParameters,
1816 TextView::RelayoutData& relayoutData )
1818 switch( layoutParameters.mExceedPolicy )
1820 case TextView::FadeOriginal:
1821 case TextView::OriginalFade:
1822 case TextView::Fade:
1823 case TextView::SplitFade: // Fall through
1825 UpdateVisibilityForFade( layoutParameters,
1830 case TextView::EllipsizeEndOriginal:
1831 case TextView::SplitEllipsizeEnd:
1832 case TextView::EllipsizeEnd: // Fall through
1834 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1835 SetTextVisible( relayoutData );
1837 UpdateVisibilityForEllipsize( layoutParameters,
1844 SetTextVisible( relayoutData );
1851 * Creates an image actor for the emoticon.
1853 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1854 * @param[in,out] characterLayout Layout info for the character.
1855 * @param[in] character The character.
1857 void CreateEmoticon( const TextView::VisualParameters& visualParameters,
1858 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1859 const Character& character )
1861 // The character is an emoticon.
1862 ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1865 imageActor = ImageActor::New();
1867 GlyphImage image = GlyphImage::New( character );
1871 imageActor.SetImage( image );
1875 imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
1876 characterLayout.mPosition.y + characterLayout.mOffset.y,
1877 characterLayout.mPosition.z ) );
1878 imageActor.SetSize( characterLayout.mSize );
1880 // Sets the sort modifier value.
1881 imageActor.SetSortModifier( visualParameters.mSortModifier );
1883 characterLayout.mGlyphActor = imageActor;
1887 * Creates text-actors for the given text.
1889 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1890 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1891 * @param[in,out] paragraph Layout info for the paragraph.
1892 * @param[in,out] characterLayout Layout info for the character.
1893 * @param[in] character The character.
1894 * @param[in] style The character's style.
1895 * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set.
1896 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1898 void CreateTextActor( const TextView::VisualParameters& visualParameters,
1899 TextView::RelayoutData& relayoutData,
1900 const TextViewProcessor::ParagraphLayoutInfo& paragraph,
1901 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1902 const Character& character,
1903 const TextStyle& style,
1904 CurrentTextActorInfo& currentTextActorInfo,
1905 bool createGlyphActors )
1907 // Set the text-actor for the current traversed text.
1908 if( currentTextActorInfo.textActor )
1910 if( ( NULL != currentTextActorInfo.characterLayout ) &&
1911 currentTextActorInfo.characterLayout->mSetText )
1913 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1914 currentTextActorInfo.characterLayout->mSetText = false;
1916 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1917 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1919 SetVisualParameters( currentTextActorInfo,
1922 paragraph.mSize.height );
1925 float rightToLeftOffset = 0.f;
1926 if( character.IsWhiteSpace() )
1928 // In left to right text, a word never starts with a white space but
1929 // it may happen in right to left text as the text is reversed.
1930 // The text alignment and justification offset is calculated without this white space.
1931 // It causes a missalignment which can be corrected by removing the size of the white space.
1932 rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
1935 currentTextActorInfo.text = Text( character );
1936 currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
1937 characterLayout.mPosition.y + characterLayout.mOffset.y,
1938 characterLayout.mPosition.z );
1939 currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
1941 currentTextActorInfo.color = style.GetTextColor();
1942 currentTextActorInfo.color.a = characterLayout.mColorAlpha;
1944 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1946 if( createGlyphActors )
1950 // Try to reuse first the text-actor of this character.
1951 textActor.SetTextStyle( style );
1955 // If there is no text-actor, try to retrieve one from the cache.
1956 textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1958 // If still there is no text-actor, create one.
1961 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1962 textActor = TextActor::New( Text(), parameters );
1966 textActor.SetTextStyle( style );
1969 characterLayout.mSetText = true;
1970 currentTextActorInfo.characterLayout = &characterLayout;
1972 characterLayout.mGlyphActor = textActor;
1975 // Update the current text-actor.
1976 currentTextActorInfo.textActor = textActor;
1980 * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position.
1982 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1983 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1984 * @param[in,out] paragraph Layout info for the paragraph.
1985 * @param[in,out] characterGlobalIndex Index to the character within the whole text.
1986 * @param[in,out] lineLayoutInfoIndex Index to the table of lines.
1987 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1989 void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
1990 TextView::RelayoutData& relayoutData,
1991 TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
1992 std::size_t& characterGlobalIndex,
1993 std::size_t& lineLayoutInfoIndex,
1994 bool createGlyphActors )
1996 // TODO: Check if there is text-actor created only with white spaces. Check first in RTL text.
1998 CurrentTextActorInfo currentTextActorInfo;
1999 currentTextActorInfo.characterLayout = NULL;
2001 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
2002 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
2003 bool glyphActorCreatedForLine = false; // Whether a renderable actor has been created for this line.
2005 TextStyle currentStyle; // style for the current text-actor.
2007 TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor.
2008 // start point for the current text-actor.
2009 // end point for the current text-actor.
2011 bool currentIsColorGlyph = false; // Whether current glyph is an emoticon.
2013 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
2015 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2016 const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
2018 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
2019 Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
2020 Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
2022 // 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.
2023 const bool previousRightToLeftLayoutCleared = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false;
2025 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
2026 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2027 wordIt != wordEndIt;
2030 TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
2032 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
2033 characterIt != characterEndIt;
2036 TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt );
2038 // Check if there is a new line.
2039 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
2043 // Point to the next line.
2044 ++lineLayoutInfoIndex;
2045 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
2047 // Arrived at last line.
2048 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
2050 glyphActorCreatedForLine = false;
2053 // Do not create a glyph-actor if there is no text.
2054 const Character character = text[characterParagraphIndex];
2055 const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
2057 bool appendCharacter = false;
2059 if( characterLayout.mIsColorGlyph ||
2060 ( TextViewProcessor::NoSeparator == wordLayout.mType ) ||
2061 ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() ) )
2063 // Do not create a glyph-actor if it's a white space (without underline) or a new paragraph character.
2065 // Check if the character has the same gradient info than the current one.
2066 bool differentGradientInfo = false;
2067 if( characterLayout.mGradientInfo && currentGradientInfo )
2069 differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) ||
2070 ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) ||
2071 ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint );
2073 else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) )
2075 differentGradientInfo = true;
2078 // Creates one glyph-actor for each counsecutive group of characters, with the same style, per line, or if it's an emoticon.
2079 if( !glyphActorCreatedForLine ||
2080 characterLayout.mIsColorGlyph ||
2081 differentGradientInfo ||
2082 ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) ||
2083 ( style != currentStyle ) )
2085 characterLayout.mSetText = false;
2086 characterLayout.mSetStyle = false;
2088 if( characterLayout.mIsColorGlyph )
2090 CreateEmoticon( visualParameters,
2096 CreateTextActor( visualParameters,
2102 currentTextActorInfo,
2103 createGlyphActors || previousRightToLeftLayoutCleared );
2106 // There is a new style or a new line.
2107 glyphActorCreatedForLine = true;
2109 // Update style to be checked with next characters.
2110 currentStyle = style;
2111 currentGradientInfo = characterLayout.mGradientInfo;
2112 currentIsColorGlyph = characterLayout.mIsColorGlyph;
2114 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2115 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2119 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
2121 // Same style than previous one.
2123 // Add the character to the current text-actor and update the size.
2124 appendCharacter = true;
2126 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
2129 // There is a previously created text-actor for this character.
2130 // If this character has another one put it into the cache.
2131 textActor.SetText( "" );
2132 textActorsToRemove.push_back( textActor );
2135 if( characterLayout.mGlyphActor )
2137 characterLayout.mGlyphActor.Reset();
2140 } // no white space / new paragraph char
2143 appendCharacter = true;
2146 if( appendCharacter )
2148 // Add the character to the current text-actor and update the size.
2149 if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
2151 currentTextActorInfo.text.Append( character );
2153 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) );
2154 currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor;
2155 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor );
2159 ++characterGlobalIndex;
2160 ++characterParagraphIndex;
2164 if( !currentTextActorInfo.text.IsEmpty() )
2166 if( currentTextActorInfo.textActor )
2168 if( ( NULL != currentTextActorInfo.characterLayout ) &&
2169 currentTextActorInfo.characterLayout->mSetText )
2171 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
2172 currentTextActorInfo.characterLayout->mSetText = false;
2174 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
2175 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
2177 SetVisualParameters( currentTextActorInfo,
2180 paragraphLayout.mSize.height );
2184 // Insert the spare text-actors into the cache.
2185 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
2188 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
2189 TextView::RelayoutData& relayoutData,
2190 bool createGlyphActors )
2192 if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
2194 // nothing to do if there is no paragraphs.
2198 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
2199 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
2201 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2202 paragraphIt != paragraphEndIt;
2205 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2207 UpdateTextActorInfoForParagraph( visualParameters,
2210 characterGlobalIndex,
2211 lineLayoutInfoIndex,
2212 createGlyphActors );
2215 // Set visual parameters for ellipsis renderable actors.
2216 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2217 endIt = relayoutData.mEllipsizedGlyphActors.end();
2221 RenderableActor glyphActor = ( *it );
2223 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2224 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2226 // Sets the sort modifier value.
2227 glyphActor.SetSortModifier( visualParameters.mSortModifier );
2229 // Enables or disables the blending.
2230 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
2234 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
2236 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2238 // 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.
2239 // According with the layout option, one of this paragraphs could be laid-out in more than one line.
2241 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2242 paragraphIt != paragraphEndIt;
2245 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2247 std::size_t characterIndex = 0u;
2249 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2250 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2252 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2253 wordIt != wordEndIt;
2256 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2258 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2259 characterIt != characterEndIt;
2260 ++characterIt, ++characterIndex )
2262 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2263 const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2265 // Check if current character is the first of a new line
2266 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
2267 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
2270 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2273 if( style.IsUnderlineEnabled() )
2275 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
2276 isNewLine ) // Current character is underlined and is the first of current line.
2278 // Create a new underline info for the current underlined characters.
2279 UnderlineInfo underlineInfo;
2280 underlineInfo.mMaxHeight = character.mSize.height;
2281 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2282 underlineInfo.mPosition = character.mUnderlinePosition;
2284 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
2286 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
2290 // Retrieve last underline info and update it if current underline thickness is bigger.
2291 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) );
2293 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height );
2295 if( character.mUnderlineThickness > underlineInfo.mMaxThickness )
2297 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2298 underlineInfo.mPosition = character.mUnderlinePosition;
2304 textUnderlineStatus.mCurrentUnderlineStatus = false;
2307 ++textUnderlineStatus.mCharacterGlobalIndex;
2308 } // end characters.
2310 } // end paragraphs.
2313 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
2315 // 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.
2316 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
2318 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2319 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
2321 if( textUnderlineStatus.mUnderlineInfo.empty() )
2323 // There is no underlined text. Just exit.
2327 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
2328 // Traverse the whole text and set the previously stored underline info in the text style.
2330 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
2331 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
2333 UnderlineInfo underlineInfo;
2335 if( underlineInfoIt < underlineInfoEndIt )
2337 underlineInfo = ( *underlineInfoIt );
2340 // Whether current text is underlined.
2341 textUnderlineStatus.mCurrentUnderlineStatus = false;
2342 textUnderlineStatus.mCharacterGlobalIndex = 0u;
2343 textUnderlineStatus.mLineGlobalIndex = 0u;
2345 float currentLineHeight = 0.f;
2346 float currentLineAscender = 0.f;
2348 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2349 paragraphIt != paragraphEndIt;
2352 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2353 std::size_t characterIndex = 0u;
2355 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2356 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2358 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2359 wordIt != wordEndIt;
2362 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2364 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2365 characterIt != characterEndIt;
2366 ++characterIt, ++characterIndex )
2368 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2369 TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2371 // Check if current character is the first of a new line
2373 bool isNewLine = false;
2375 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
2377 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
2378 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
2382 currentLineHeight = lineLayoutInfo.mSize.height;
2383 currentLineAscender = lineLayoutInfo.mAscender;
2384 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2388 if( style.IsUnderlineEnabled() )
2390 if( textUnderlineStatus.mCurrentUnderlineStatus )
2394 // Retrieves the thickness and position for the next piece of underlined text.
2395 if( underlineInfoIt < underlineInfoEndIt )
2398 if( underlineInfoIt < underlineInfoEndIt )
2400 underlineInfo = *underlineInfoIt;
2406 textUnderlineStatus.mCurrentUnderlineStatus = true;
2408 // Before setting the position it needs to be adjusted to match the base line.
2409 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender );
2410 const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
2412 // Sets the underline's parameters.
2413 style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
2415 // Mark the character to be set the new style into the text-actor.
2416 character.mSetStyle = true;
2420 if( textUnderlineStatus.mCurrentUnderlineStatus )
2422 textUnderlineStatus.mCurrentUnderlineStatus = false;
2424 // Retrieves the thickness and position for the next piece of underlined text.
2425 if( underlineInfoIt < underlineInfoEndIt )
2428 if( underlineInfoIt < underlineInfoEndIt )
2430 underlineInfo = *underlineInfoIt;
2436 ++textUnderlineStatus.mCharacterGlobalIndex;
2437 } // end of characters.
2439 } // end of paragraphs.
2442 void RemoveGlyphActors( Actor textView,
2443 const std::vector<RenderableActor>& glyphActors )
2445 // Removes previously inserted renderable-actors.
2446 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
2447 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
2448 // in order to remove 'only' renderable-actors added by these functions.
2449 // Any other actor added by a programmer or application won't be removed.
2451 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
2453 textView.Remove( *it );
2457 void InsertToTextView( Actor textView,
2458 TextView::RelayoutData& relayoutData )
2460 // Add text-actors to the text-view.
2462 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
2463 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2464 paragraphLayoutIt != endParagraphLayoutIt;
2465 ++paragraphLayoutIt )
2467 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
2469 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2470 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
2471 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
2473 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
2474 endWordLayoutIt = wordsLayoutInfo.end();
2475 wordLayoutIt != endWordLayoutIt;
2478 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
2480 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
2481 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
2482 characterLayoutIt != endCharacterLayoutIt;
2483 ++characterLayoutIt )
2485 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
2487 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
2489 //Add to the text-view.
2490 textView.Add( characterLayoutInfo.mGlyphActor );
2491 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
2497 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2498 endIt = relayoutData.mEllipsizedGlyphActors.end();
2502 RenderableActor glyphActor = ( *it );
2504 //Add to the text-view.
2505 textView.Add( glyphActor );
2506 relayoutData.mGlyphActors.push_back( glyphActor );
2508 relayoutData.mEllipsizedGlyphActors.clear();
2511 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
2513 TextActor textActor = cache.RetrieveTextActor();
2517 // Update the text-actor.
2518 textActor.SetText( text );
2519 textActor.SetTextStyle( style );
2523 // The text-actor cache is empty. Create a new one.
2524 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
2525 textActor = TextActor::New( text, parameters );
2531 } // namespace TextViewRelayout
2533 } // namespace Internal
2535 } // namespace Toolkit