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>
23 #include <dali/public-api/text/text-actor-parameters.h>
26 #include <dali-toolkit/internal/controls/text-view/text-processor.h>
27 #include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
28 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
29 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
30 #include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
41 namespace TextViewRelayout
44 const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same as the text-view boundary, this constant reduces it in order to avoid a zero division.
46 RelayoutParameters::RelayoutParameters()
52 mCharacterGlobalIndex( 0u ),
53 mIsFirstCharacter( false ),
54 mIsFirstCharacterOfWord( false ),
56 mIsNewParagraphCharacter( false ),
57 mIsWhiteSpace( false ),
62 RelayoutParameters::~RelayoutParameters()
66 FadeParameters::FadeParameters()
67 : mRightFadeBoundary( 0.f ),
68 mRightFadeThreshold( 0.f ),
69 mRightFadeBoundaryOffset( 0.f ),
70 mRightFadeThresholdOffset( 0.f ),
71 mRightAlphaCoeficients(),
72 mLeftFadeBoundary( 0.f ),
73 mLeftFadeThreshold( 0.f ),
74 mLeftFadeBoundaryOffset( 0.f ),
75 mLeftFadeThresholdOffset( 0.f ),
76 mLeftAlphaCoeficients(),
77 mTopFadeBoundary( 0.f ),
78 mTopFadeThreshold( 0.f ),
79 mTopFadeBoundaryOffset( 0.f ),
80 mTopFadeThresholdOffset( 0.f ),
81 mTopAlphaCoeficients(),
82 mBottomFadeBoundary( 0.f ),
83 mBottomFadeThreshold( 0.f ),
84 mBottomFadeBoundaryOffset( 0.f ),
85 mBottomFadeThresholdOffset( 0.f ),
86 mBottomAlphaCoeficients(),
87 mIsPartiallyVisible( false )
91 FadeParameters::~FadeParameters()
95 EllipsizeParameters::EllipsizeParameters()
97 mLineDescender( 0.f ),
102 mEllipsizeLine( false ),
103 mIsLineWidthFullyVisible( false ),
104 mIsLineHeightFullyVisible( false ),
105 mIsNextLineFullyVisibleHeight( false ),
106 mCreateEllipsizedTextActors( false ),
112 EllipsizeParameters::~EllipsizeParameters()
116 UnderlineInfo::UnderlineInfo()
118 mMaxThickness( 0.f ),
123 UnderlineInfo::~UnderlineInfo()
127 TextUnderlineStatus::TextUnderlineStatus()
129 mCharacterGlobalIndex( 0u ),
130 mLineGlobalIndex( 0u ),
131 mCurrentUnderlineStatus( false )
135 TextUnderlineStatus::~TextUnderlineStatus()
139 LineLayoutInfo::LineLayoutInfo()
140 : mLineLength( 0.f ),
141 mMaxCharHeight( 0.f ),
146 LineLayoutInfo::~LineLayoutInfo()
151 * Whether the given text-actor exceeds the left or the right boundary of the text-view.
153 * @param[in] position The position of the text-actor.
154 * @param[in] size The size of the text-actor.
155 * @param[in] parantSize The size of the text-view.
157 * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
159 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
161 return ( ( position.x < 0.f ) ||
162 ( position.x + size.width > parentSize.width ) );
166 * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
168 * @param[in] position The position of the text-actor.
169 * @param[in] size The size of the text-actor.
170 * @param[in] parantSize The size of the text-view.
172 * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
174 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
176 return ( ( position.y > parentSize.height ) ||
177 ( position.y < size.height ) );
181 * Calculates the line length adding the new word or character width.
183 * It also returns the length of white spaces if they are at the end of the line.
185 * @param[in] isWhiteSpace Whether the word is a white space.
186 * @param[in] width The width of the character or word.
187 * @param[in] parentWidth The parent width.
188 * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
189 * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
190 * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
192 void CalculateLineLength( bool isWhiteSpace, float width, float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
194 if( lineLength + width > parentWidth )
197 lineLength -= endWhiteSpaceLength;
205 endWhiteSpaceLength += width;
209 endWhiteSpaceLength = 0.f;
214 struct CurrentTextActorInfo
221 TextViewProcessor::CharacterLayoutInfo* characterLayout;
224 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
225 const TextView::VisualParameters& visualParameters,
226 TextView::RelayoutData& relayoutData,
227 const float lineHeight )
229 currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
230 if( ( NULL != currentTextActorInfo.characterLayout ) &&
231 ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) )
233 currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.characterLayout->mGradientInfo->mGradientColor );
234 currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.characterLayout->mGradientInfo->mStartPoint );
235 currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.characterLayout->mGradientInfo->mEndPoint );
238 // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
239 // due to the trick used to implement it.
240 const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
241 const float italicsOffset = lineHeight * std::tan( italicsAngle );
242 relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
244 // Sets the sort modifier value.
245 currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
247 // Enables or disables the blending.
248 currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
251 void CalculateLineLayout( float parentWidth,
252 const TextViewProcessor::TextInfoIndices& indices,
253 const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo,
254 HorizontalWrapType splitPolicy,
256 LineLayoutInfo& subLineInfo )
258 subLineInfo.mLineLength = 0.f;
259 subLineInfo.mMaxCharHeight = 0.f;
260 subLineInfo.mMaxAscender = 0.f;
262 float endWhiteSpaceLength = 0.f;
264 std::size_t characterIndex = indices.mCharacterIndex;
265 float lineOffset = 0.f;
267 bool isFirstCharacter = true;
268 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex,
269 wordEndIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
270 ( wordIt != wordEndIt ) && !found;
273 const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
275 const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
276 const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
278 bool splitByCharacter = false;
280 switch( splitPolicy )
282 case WrapByCharacter:
284 splitByCharacter = true;
288 case WrapByParagraphCharacter: // Fall through
290 splitByCharacter = false;
293 case WrapByWordAndSplit:
295 splitByCharacter = ( shrunkWordWidth > parentWidth );
298 case WrapByParagraphCharacterAndSplit:
300 if( ( 0u != characterIndex ) ||
301 ( ( 0u == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
303 splitByCharacter = true;
307 lineOffset += shrunkWordWidth;
308 splitByCharacter = false;
313 if( splitByCharacter )
315 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
316 charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
317 ( charIt != charEndIt ) && !found;
320 const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
321 CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
322 if( !found || isFirstCharacter )
324 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
325 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
328 // All characters for word 'wordIndex' have been processed.
329 // Next word need to process all characters, so the characterIndex is reset to 0.
331 isFirstCharacter = false;
334 lineOffset += subLineInfo.mLineLength;
338 CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
339 if( !found || isFirstCharacter )
341 subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
342 subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
344 isFirstCharacter = false;
348 subLineInfo.mMaxCharHeight *= shrinkFactor;
349 subLineInfo.mMaxAscender *= shrinkFactor;
354 * Sets a character of a line of a bidirectional paragraph in the new position.
356 * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph.
357 * @param[in] index Index within the paragraph to the character to be set in the new position.
358 * @param[in,out] character Reference to the character in the new position.
360 void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo,
362 TextViewProcessor::CharacterLayoutInfo& character )
364 // Traverse all the characters of the paragraph till the one pointed by index is found.
365 std::size_t traversedCharacters = 0u;
366 for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(),
367 wordEndIt = wordsLayoutInfo.end();
371 const TextViewProcessor::WordLayoutInfo& word( *wordIt );
373 const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size();
374 if( index < traversedCharacters + numberOfCharacters )
376 character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) );
379 traversedCharacters += numberOfCharacters;
384 * Reorders the layout info of each line of the paragraph.
386 * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics).
388 * @param[in] characterGlobalIndex Index within the whole text of the first character of the paragraph.
389 * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
390 * @param[in,out] relayoutData The text-view's data structures.
392 void ReorderLayout( std::size_t characterGlobalIndex,
393 TextViewProcessor::ParagraphLayoutInfo& paragraph,
394 TextView::RelayoutData& relayoutData )
396 // Clear any previous right to left layout.
397 if( NULL != paragraph.mRightToLeftLayout )
399 paragraph.mRightToLeftLayout->Clear();
400 paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
404 // Create a new right to left layout if there isn't any.
405 paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
408 // Reorder Text and Styles.
410 // Reserve space for the styles.
411 paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
413 // Traverses all the bidirectional info per line.
414 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
416 TextProcessor::BidirectionalLineInfo* info( *it );
418 const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
419 const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
421 // The text can be appended as it's already reordered.
422 paragraph.mRightToLeftLayout->mText.Append( info->mText );
424 // The visual to logical map needs to be used to reorder the styles.
425 for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
427 paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
431 // Reorder Layout Info.
433 // Reserve space for the new word layout.
434 paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
436 // Traverses all the bidirectional info per line.
437 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
439 TextProcessor::BidirectionalLineInfo* info( *it );
441 // Reserve space for all characters.
442 TextViewProcessor::CharacterLayoutInfoContainer characters;
443 characters.resize( info->mNumberOfCharacters );
445 // Uses the visual to logical map to set every character in its new position.
446 for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
448 SetCharacter( paragraph.mWordsLayoutInfo,
449 info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
450 *( characters.begin() + index ) );
453 // Sets the new 'x' position for each character.
454 // Updates the text-view's layout info table with the new position of the character.
455 float xPosition = 0.f;
456 std::size_t index = 0u;
457 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it, ++index )
459 TextViewProcessor::CharacterLayoutInfo& character( *it );
461 // Set the 'x' position.
462 character.mPosition.x = xPosition;
464 // Update layout info table.
465 relayoutData.mCharacterLayoutInfoTable[characterGlobalIndex + info->mVisualToLogicalMap[index]].mPosition = character.mPosition;
467 // Update the position for the next character.
468 xPosition += character.mSize.width;
471 // Split the reordered text in words.
472 std::size_t previousPosition = 0u;
473 Vector<std::size_t> positions;
474 TextProcessor::SplitInWords( info->mText, positions );
476 // Whether last character is a word or a paragraph separator.
477 const std::size_t lastCharacterIndex = info->mText.GetLength() - 1u;
478 const bool isLastCharacterParagraphSeparator = info->mText.IsNewLine( lastCharacterIndex );
479 const bool isLastCharacterWordSeparator = info->mText.IsWhiteSpace( lastCharacterIndex );
481 // Sets the characters into the words they belong to.
482 for( Vector<std::size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
484 const std::size_t position = *it;
486 TextViewProcessor::WordLayoutInfo word;
487 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
488 characters.begin() + previousPosition,
489 characters.begin() + position );
491 if( !word.mCharactersLayoutInfo.empty() )
493 // Updates the layout of the word.
494 TextViewProcessor::UpdateLayoutInfo( word );
496 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
499 // white space or new paragraph.
500 TextViewProcessor::WordLayoutInfo space;
502 space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
503 characters.begin() + position,
504 characters.begin() + position + 1u );
506 space.mType = TextViewProcessor::WordSeparator;
508 TextViewProcessor::UpdateLayoutInfo( space );
510 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
512 previousPosition = position + 1u;
516 if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
518 TextViewProcessor::WordLayoutInfo word;
519 word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
520 characters.begin() + previousPosition,
523 if( isLastCharacterParagraphSeparator )
525 word.mType = TextViewProcessor::ParagraphSeparator;
527 else if( isLastCharacterWordSeparator )
529 word.mType = TextViewProcessor::WordSeparator;
531 TextViewProcessor::UpdateLayoutInfo( word );
533 paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
539 * Creates the bidirectional info needed to reorder each line of the paragraph.
541 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
542 * @param[in,out] paragraph Layout info for the paragraph.
543 * @param[in] characterGlobalIndex Index to the character within the whole text.
544 * @param[in] lineLayoutInfoIndex Index to the table of lines.
546 void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
547 TextViewProcessor::ParagraphLayoutInfo& paragraph,
548 std::size_t& characterGlobalIndex,
549 std::size_t& lineLayoutInfoIndex )
551 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
552 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
554 // Clear previously created bidirectional info.
555 paragraph.ClearBidirectionalInfo();
557 // For each character, it sets the character's direction.
559 // Initialize the paragraph direction. Used to set the direction of weak characters.
560 const bool isParagraphRightToLeft = paragraph.mBidirectionalParagraphInfo->IsRightToLeftParagraph();
561 bool isPreviousRightToLeft = isParagraphRightToLeft;
563 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
565 // Get the character's layout information (the one is shared with text-input)
566 Toolkit::TextView::CharacterLayoutInfo& info = *( relayoutData.mCharacterLayoutInfoTable.begin() + ( characterGlobalIndex + index ) );
568 // Gets the character's direction.
569 const Character::CharacterDirection direction = paragraph.mText[index].GetCharacterDirection();
570 if( Character::RightToLeft == direction )
572 info.mIsRightToLeftCharacter = true;
574 else if( Character::Neutral == direction )
576 // For neutral characters it check's the next and previous directions.
577 // If they are equals set that direction. If they are not, sets the paragraph direction.
578 // If there is no next, sets the previous direction.
580 // Check next character's direction.
581 bool isNextRightToLeft = isPreviousRightToLeft;
582 if( index < paragraph.mNumberOfCharacters - 1u )
584 const Character::CharacterDirection nextDirection = paragraph.mText[index + 1u].GetCharacterDirection();
585 isNextRightToLeft = Character::RightToLeft == nextDirection;
588 info.mIsRightToLeftCharacter = isPreviousRightToLeft == isNextRightToLeft ? isPreviousRightToLeft : isParagraphRightToLeft;
592 info.mIsRightToLeftCharacter = false;
595 isPreviousRightToLeft = info.mIsRightToLeftCharacter;
598 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
599 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
603 TextViewProcessor::WordLayoutInfo& word( *wordIt );
605 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
606 characterIt != characterEndIt;
609 TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
611 // Check if there is a new line.
612 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
616 // Point to the next line.
617 ++lineLayoutInfoIndex;
618 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
620 // Arrived at last line.
621 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
624 // Number of characters of the line.
625 const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
627 // There is right to left characters in this line. It needs to be reordered.
628 bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
629 bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
630 bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
632 // Set all the Text's characters in the visual order and creates the mapping tables.
633 TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
634 bidirectionalLineInfo );
636 paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
638 for( std::size_t index = 0u; index < numberOfCharacters; ++index )
640 relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
641 relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
645 ++characterGlobalIndex;
646 ++characterParagraphIndex;
651 void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
653 // Reset conversion tables shared through public-api
654 relayoutData.mCharacterLogicalToVisualMap.clear();
655 relayoutData.mCharacterVisualToLogicalMap.clear();
657 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
658 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
660 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
661 paragraphIt != paragraphEndIt;
664 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
666 if( NULL != paragraph.mBidirectionalParagraphInfo )
668 // There is right to left text in this paragraph.
670 // Stores the current global character index as is needed in both functions.
671 const std::size_t currentGlobalIndex = characterGlobalIndex;
673 // Creates the bidirectional info needed to reorder each line of the paragraph.
674 CreateBidirectionalInfoForLines( relayoutData,
676 characterGlobalIndex,
677 lineLayoutInfoIndex );
679 // Reorder each line of the paragraph
680 ReorderLayout( currentGlobalIndex, paragraph, relayoutData );
684 // Identity in case the paragraph has no right to left text.
685 for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
687 const std::size_t globalIndex = characterGlobalIndex + index;
688 relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
689 relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
691 characterGlobalIndex += paragraph.mNumberOfCharacters;
696 float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
698 float xOffset( 0.f );
699 switch( horizontalTextAlignment )
701 case Toolkit::Alignment::HorizontalLeft:
706 case Toolkit::Alignment::HorizontalCenter:
708 xOffset = 0.5f * ( parentWidth - wholeTextWidth );
711 case Toolkit::Alignment::HorizontalRight:
713 xOffset = parentWidth - wholeTextWidth;
718 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
725 float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight )
727 float yOffset( 0.f );
728 switch( verticalTextAlignment )
730 case Toolkit::Alignment::VerticalTop:
735 case Toolkit::Alignment::VerticalCenter:
737 yOffset = 0.5f * ( parentHeight - wholeTextHeight );
740 case Toolkit::Alignment::VerticalBottom:
742 yOffset = parentHeight - wholeTextHeight;
747 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
754 float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength )
757 switch( justification )
759 case Toolkit::TextView::Left:
764 case Toolkit::TextView::Center:
766 offset = 0.5f * ( wholeTextWidth - lineLength );
769 case Toolkit::TextView::Right:
771 offset = wholeTextWidth - lineLength;
774 case Toolkit::TextView::Justified:
784 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
786 bool visible = false;
792 // Whether the text-actor is fully inside the boundaries of the text-view.
793 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
794 ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
797 case FULLY_VISIBLE_WIDTH:
799 // Whether the text-actor is between the left and right boundaries of the text-view.
800 visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
803 case FULLY_VISIBLE_HEIGHT:
805 // Whether the text-actor is between the top and bottom boundaries of the text-view.
806 visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
809 case PARTIALLY_VISIBLE:
811 // Whether the text-actor is partially inside the boundaries of the text-view.
812 visible = ( ( position.x < parentSize.width ) &&
813 ( position.x + size.width > 0.f ) &&
814 ( position.y > 0.f ) &&
815 ( position.y - size.height < parentSize.height ) );
818 case PARTIALLY_VISIBLE_WIDTH:
820 // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
821 // It may not be partially inside the text-view.
822 visible = ( ( position.x < parentSize.width ) &&
823 ( position.x + size.width > 0.f ) );
826 case PARTIALLY_VISIBLE_HEIGHT:
828 // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
829 // It may not be partially inside the text-view.
830 visible = ( ( position.y > 0.f ) &&
831 ( position.y - size.height < parentSize.height ) );
839 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
841 const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
843 return Vector2( gradient, p0.y - gradient * p0.x );
846 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
847 TextView::RelayoutData& relayoutData )
849 // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
850 // The offset could be negative if the whole text is bigger than the boundary of the text-view.
852 // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
853 // In that case, it will align the line to the left and/or top, and ellipsize the end.
854 const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
855 ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
856 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
857 const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
858 ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
860 RelayoutParameters relayoutParameters;
862 // Calculates the vertical and horizontal offsets.
863 const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
864 const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
866 // Index to the global character (within the whole text).
867 std::size_t characterGlobalIndex = 0u;
869 // Index to the line info.
870 std::size_t lineLayoutInfoIndex = 0u;
872 relayoutParameters.mIndices.mParagraphIndex = 0u;
874 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
875 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
876 paragraphLayoutIt != endParagraphLayoutIt;
877 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
879 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
881 float justificationOffset = 0.f;
883 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
884 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
886 relayoutParameters.mIndices.mWordIndex = 0u;
888 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
889 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
891 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
892 endWordLayoutIt = wordsLayoutInfo.end();
893 wordLayoutIt != endWordLayoutIt;
894 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
896 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
898 relayoutParameters.mIndices.mCharacterIndex = 0u;
900 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
901 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
902 characterLayoutIt != endCharacterLayoutIt;
903 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
905 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
907 // Check if there is a new line.
908 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
912 // Calculate line justification offset.
913 justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
915 // Point to the next line.
916 ++lineLayoutInfoIndex;
917 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
919 // Arrived at last line.
920 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
924 // Deletes the offsets if the exceed policies are EllipsizeEnd.
925 const float horizontalOffset = textHorizontalOffset + justificationOffset;
926 characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
927 characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
929 // Updates the size and position table for text-input with the alignment offset.
930 Vector3 positionOffset( characterLayoutInfo.mPosition );
932 // Update layout info table.
933 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[characterGlobalIndex];
934 Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
936 characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
937 characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
939 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
945 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
946 TextView::RelayoutData& relayoutData )
958 // ggggg gggggggggg bb ggggg
959 // gg gg gggggggggg bb gg gg
960 // gg gg gggg bb gg gg
961 // gg gg gggg bb gg gg
962 // ggggg gg gggg bbbbbbb ggggg
963 // gg gg gggg bb bb gg
964 // g gg gggggggggg bb bb g gg
965 // ggggg gggggggggg bbbbbbb ggggg
974 // ggggg gggg gggg bb ggggg
975 // gg gg gggg gggg bbbbbbb gg gg
976 // gg gg gggg gggg bb bb gg gg
977 // gg gg gggggggggg bb bb gg gg
978 // ggggg gggggggggg bbbbbbb ggggg
981 // ggggg gg gggg ggggg
986 const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
987 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
989 characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
992 void UpdateLayoutInfoTable( Vector4& minMaxXY,
993 TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
994 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
995 RelayoutParameters& relayoutParameters,
996 TextView::RelayoutData& relayoutData )
998 // updates min and max position to calculate the text size for multiline policies.
999 minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
1000 minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
1002 minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1003 minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y );
1005 // Adds layout info to be retrieved by external controls or applications.
1006 Vector3 positionOffset( characterLayoutInfo.mPosition );
1008 const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
1010 const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor,
1011 characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
1013 ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
1014 false, // whether the character is right to left. The value is set in a next step in the CreateBidirectionalInfoForLines function
1015 true, // whether the character is visible.
1018 relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
1020 positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1023 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
1024 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1025 const TextStyle& style,
1026 RelayoutParameters& relayoutParameters,
1027 FadeParameters& fadeParameters,
1028 TextView::RelayoutData& relayoutData )
1030 if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
1031 ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
1032 ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
1033 ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
1039 // Calculates visibility of a text-actor according the exceed policies.
1041 // position + alignment offset.
1042 const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1043 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1044 characterLayoutInfo.mPosition.z );
1046 // Whether the text actor is fully, partially or non visible (according exceed policies).
1047 switch( layoutParameters.mExceedPolicy )
1049 case TextView::Fade:
1051 // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
1052 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1053 if( !IsVisible( position,
1054 characterLayoutInfo.mSize,
1055 relayoutData.mTextViewSize,
1058 relayoutParameters.mIsVisible = false;
1059 if( IsVisible( position,
1060 characterLayoutInfo.mSize,
1061 relayoutData.mTextViewSize,
1062 PARTIALLY_VISIBLE ) )
1064 fadeParameters.mIsPartiallyVisible = true;
1066 // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
1067 if( IsExceedingWidth( position,
1068 characterLayoutInfo.mSize,
1069 relayoutData.mTextViewSize ) &&
1070 IsExceedingHeight( position,
1071 characterLayoutInfo.mSize,
1072 relayoutData.mTextViewSize ) )
1074 // Combination not fully supported by text-view.
1075 // Need to check if text-actor really supports this combination.
1076 fadeParameters.mIsPartiallyVisible = false;
1082 case TextView::FadeOriginal:
1084 // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
1085 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1086 if( !IsVisible( position,
1087 characterLayoutInfo.mSize,
1088 relayoutData.mTextViewSize,
1089 FULLY_VISIBLE_WIDTH ) )
1091 relayoutParameters.mIsVisible = false;
1092 if( IsVisible( position,
1093 characterLayoutInfo.mSize,
1094 relayoutData.mTextViewSize,
1095 PARTIALLY_VISIBLE_WIDTH ) )
1097 fadeParameters.mIsPartiallyVisible = true;
1102 case TextView::OriginalFade:
1103 case TextView::SplitFade: // Fallthrough
1105 // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
1106 // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1107 if( !IsVisible( position,
1108 characterLayoutInfo.mSize,
1109 relayoutData.mTextViewSize,
1110 FULLY_VISIBLE_HEIGHT ) )
1112 relayoutParameters.mIsVisible = false;
1113 if( IsVisible( position,
1114 characterLayoutInfo.mSize,
1115 relayoutData.mTextViewSize,
1116 PARTIALLY_VISIBLE_HEIGHT ) )
1118 fadeParameters.mIsPartiallyVisible = true;
1125 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
1130 if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
1132 characterLayoutInfo.mIsVisible = true;
1134 const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1135 const float characterPositionPlusWidth = position.x + size.width;
1136 const float characterPositionMinusHeight = position.y - size.height;
1138 // Calculates which edges need to be faded-out.
1139 bool rightFadeOut = false;
1140 bool leftFadeOut = false;
1141 bool bottomFadeOut = false;
1142 bool topFadeOut = false;
1144 switch( layoutParameters.mExceedPolicy )
1146 case TextView::Fade:
1148 // All text-actors exceeding any of the boundaries will be faded-out.
1149 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1150 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1151 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1152 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1155 case TextView::FadeOriginal:
1157 // Only text-actors exceeding the left or the right boundaries will be faded-out.
1158 rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1159 leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1162 case TextView::SplitFade:
1163 case TextView::OriginalFade: //Fallthrough
1165 // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
1166 bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1167 topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1172 DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
1177 // Calculates gradient parameters for a text-actor.
1178 Vector4 gradientColor = Vector4::ZERO;
1179 Vector2 startPoint = Vector2::ZERO;
1180 Vector2 endPoint = Vector2::ZERO;
1182 if( !( rightFadeOut && leftFadeOut ) )
1184 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
1187 gradientColor = style.GetTextColor();
1189 // Calculates gradient coeficients.
1190 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
1191 gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
1193 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1194 endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
1196 if( NULL == characterLayoutInfo.mGradientInfo )
1198 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1201 else if( leftFadeOut )
1203 gradientColor = style.GetTextColor();
1205 // Calculates gradient coeficients.
1206 characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
1207 gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
1209 startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1210 endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
1212 if( NULL == characterLayoutInfo.mGradientInfo )
1214 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1219 if( !( bottomFadeOut && topFadeOut ) )
1221 // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
1224 gradientColor = style.GetTextColor();
1226 // Calculates gradient coeficients.
1227 characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
1228 gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
1230 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1231 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
1233 if( NULL == characterLayoutInfo.mGradientInfo )
1235 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1238 else if( topFadeOut )
1240 gradientColor = style.GetTextColor();
1242 // Calculates gradient coeficients.
1243 characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
1244 gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
1246 startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1247 endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
1249 if( NULL == characterLayoutInfo.mGradientInfo )
1251 characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1256 if( NULL != characterLayoutInfo.mGradientInfo )
1258 characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
1259 characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
1260 characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
1265 characterLayoutInfo.mIsVisible = false;
1269 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1270 const EllipsizeParameters& ellipsizeParameters )
1272 bool isPartiallyVisible = false;
1274 if( !IsVisible( ellipsizeParameters.mPosition,
1275 characterLayoutInfo.mSize,
1276 ellipsizeParameters.mEllipsizeBoundary,
1277 FULLY_VISIBLE_WIDTH ) )
1279 // The character doesn't fit in the text-view's width.
1280 characterLayoutInfo.mIsVisible = false;
1282 // Checks if the character is partially visible (it's cut by the boundary)
1283 isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
1284 characterLayoutInfo.mSize,
1285 ellipsizeParameters.mEllipsizeBoundary,
1286 PARTIALLY_VISIBLE_WIDTH );
1290 // The character fits in the text-view's width. Set it to visible.
1291 characterLayoutInfo.mIsVisible = true;
1294 return isPartiallyVisible;
1297 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1298 const EllipsizeParameters& ellipsizeParameters )
1300 bool isPartiallyVisible = false;
1302 if( !IsVisible( ellipsizeParameters.mPosition,
1303 characterLayoutInfo.mSize,
1304 ellipsizeParameters.mEllipsizeBoundary,
1307 // The character is not fully visible. Needs to check if it's partially visible.
1308 characterLayoutInfo.mIsVisible = false;
1310 // Checks if the character doesn't cut the bottom edge of the text-view.
1311 const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
1312 characterLayoutInfo.mSize,
1313 ellipsizeParameters.mEllipsizeBoundary,
1314 FULLY_VISIBLE_HEIGHT );
1316 // Checks if the character cuts the right edge of the text-view.
1317 const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
1318 characterLayoutInfo.mSize,
1319 ellipsizeParameters.mEllipsizeBoundary,
1320 PARTIALLY_VISIBLE_WIDTH );
1322 // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
1323 isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
1327 // The character fits in the boundary of the text-view. Set it to visible.
1328 characterLayoutInfo.mIsVisible = true;
1331 return isPartiallyVisible;
1334 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
1335 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1336 EllipsizeParameters& ellipsizeParameters,
1337 TextView::RelayoutData& relayoutData )
1339 // Calculates visibility for EllipsizeEnd exceed policies.
1341 // 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.
1342 // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
1343 // 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.
1345 // Position of the character used to do the visibility test.
1346 ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1347 characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1348 characterLayoutInfo.mPosition.z );
1350 // 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).
1351 bool isPartiallyVisible = false;
1353 // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
1354 const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
1356 // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
1359 // The line or word fits completely inside the text-view's width. Nothing else to do.
1360 characterLayoutInfo.mIsVisible = true;
1364 // The line or word doesn't fit in the text-view's width.
1366 // Calculates visibility for each type of ellipsize policies.
1367 switch( layoutParameters.mExceedPolicy )
1369 case TextView::EllipsizeEndOriginal:
1371 // 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.
1373 isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1374 ellipsizeParameters );
1378 case TextView::SplitEllipsizeEnd:
1379 case TextView::EllipsizeEnd:
1381 // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1383 isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1384 ellipsizeParameters );
1390 DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1396 // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1397 // In that case, the charater needs to be replaced by the ellipsize text.
1398 ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1401 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1402 TextView::RelayoutData& relayoutData )
1404 // 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.
1405 // The code bellow creates the text-actors needed for the ellipsize text.
1407 // Set ellipsize's position by the end of visible text.
1408 Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1409 // Stores current ellipsize text.
1411 // Stores current ellipsize style.
1412 TextStyle ellipsizeStyle;
1413 // Stores the current size.
1415 //Whether current glyph is an emoticon.
1416 bool isColorGlyph = false;
1418 float bearingOffset = 0.f;
1420 // Create ellipsize text-actor.
1421 std::size_t characterIndex = 0u;
1422 for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1423 endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1424 ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1425 ++ellipsizeCharacterLayoutIt, ++characterIndex )
1427 const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1428 const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
1431 ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1432 ( ellipsizeStyle != style ) )
1434 // The style is different, so a new text-actor is needed.
1435 if( !ellipsizeText.IsEmpty() )
1437 // It only creates a text-actor if there is any text.
1438 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1439 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1440 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1442 // Updates the position for the next text-actor.
1443 ellipsizePosition.x += ellipsizeSize.width;
1445 // Adds the text-actor to the list.
1446 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1449 // Resets the current ellipsize info.
1450 ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1451 ellipsizeStyle = style;
1452 ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1453 isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1455 bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1459 // Updates text and size with the new character.
1460 ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1461 TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1465 if( !ellipsizeText.IsEmpty() )
1467 // Creates the last glyph-actor.
1468 RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1469 ellipsizeGlyphActor.SetSize( ellipsizeSize );
1470 ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1472 // Adds the glyph-actor to the list.
1473 relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1477 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1478 EllipsizeParameters& ellipsizeParameters,
1479 TextView::RelayoutData& relayoutData )
1481 // Traverses the text layout info from the first character of the line
1482 // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1484 // Indices to the first character of the line.
1485 TextViewProcessor::TextInfoIndices firstIndices;
1486 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1487 relayoutData.mTextLayoutInfo,
1490 // Indices to the last character of the line.
1491 TextViewProcessor::TextInfoIndices lastIndices;
1492 TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1493 relayoutData.mTextLayoutInfo,
1496 // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1497 // This is the boundary used to check if a character have to be ellipsized.
1498 ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1499 ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1501 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex,
1502 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u;
1503 paragraphLayoutIt != endParagraphLayoutIt;
1504 ++paragraphLayoutIt )
1506 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1508 ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1510 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1512 ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1515 bool firstWord = true;
1516 bool lastWord = false;
1518 std::size_t wordCount = 0u;
1520 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1521 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1523 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
1524 endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
1525 wordLayoutIt != endWordLayoutIt;
1526 ++wordLayoutIt, ++wordCount )
1528 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1530 if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex )
1535 const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1536 const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u;
1537 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1538 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u;
1539 characterLayoutIt != endCharacterLayoutIt;
1540 ++characterLayoutIt )
1542 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1544 if( ellipsizeParameters.mEllipsizeLine )
1546 // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1547 CalculateVisibilityForEllipsize( layoutParameters,
1548 characterLayoutInfo,
1549 ellipsizeParameters,
1552 if( ellipsizeParameters.mCreateEllipsizedTextActors )
1554 // Create ellipsize text-actors if the character needs to be replaced.
1555 CreateEllipsizeTextActor( ellipsizeParameters,
1561 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1562 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1564 if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1566 // Make characters invisible.
1567 characterLayoutInfo.mIsVisible = false;
1577 void SetTextVisible( TextView::RelayoutData& relayoutData )
1579 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1580 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1581 paragraphLayoutIt != endParagraphLayoutIt;
1582 ++paragraphLayoutIt )
1584 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1585 std::size_t characterIndex = 0u;
1587 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1588 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1590 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1591 endWordLayoutIt = wordsLayoutInfo.end();
1592 wordLayoutIt != endWordLayoutIt;
1595 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1597 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1598 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1599 characterLayoutIt != endCharacterLayoutIt;
1600 ++characterLayoutIt, ++characterIndex )
1602 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1604 characterLayoutInfo.mIsVisible = true;
1605 delete characterLayoutInfo.mGradientInfo;
1606 characterLayoutInfo.mGradientInfo = NULL;
1607 characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
1612 // Updates the visibility for text-input..
1613 for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1614 endIt = relayoutData.mCharacterLayoutInfoTable.end();
1618 Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1620 characterLayoutInfo.mIsVisible = true;
1624 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1625 const TextView::VisualParameters& visualParameters,
1626 TextView::RelayoutData& relayoutData )
1628 RelayoutParameters relayoutParameters;
1629 FadeParameters fadeParameters;
1631 // 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.
1632 fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1633 fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1634 fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1635 fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1636 fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1637 fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1638 fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1639 fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1640 fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1641 fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1642 fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1643 fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1644 fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1645 fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1646 fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1647 fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1649 // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1650 fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1651 fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1652 fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1653 fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1655 // Traverses all characters and calculates the visibility.
1657 std::size_t infoTableCharacterIndex = 0u;
1659 relayoutParameters.mIndices.mParagraphIndex = 0u;
1661 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1662 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1663 paragraphLayoutIt != endParagraphLayoutIt;
1664 ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
1666 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1668 std::size_t characterIndex = 0u;
1669 relayoutParameters.mIndices.mWordIndex = 0u;
1671 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1672 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1674 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1675 endWordLayoutIt = wordsLayoutInfo.end();
1676 wordLayoutIt != endWordLayoutIt;
1677 ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1679 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1681 relayoutParameters.mIsFirstCharacterOfWord = true;
1682 relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1683 relayoutParameters.mIndices.mCharacterIndex = 0u;
1685 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1686 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1687 characterLayoutIt != endCharacterLayoutIt;
1688 ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
1690 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1692 relayoutParameters.mIsVisible = true;
1693 fadeParameters.mIsPartiallyVisible = false;
1695 // Calculates the visibility for the current character.
1696 CalculateVisibilityForFade( layoutParameters,
1697 characterLayoutInfo,
1698 *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
1703 // Updates the visibility for text-input..
1704 std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[infoTableCharacterIndex];
1706 Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1708 characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1710 relayoutParameters.mIsFirstCharacterOfWord = false;
1716 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1717 const TextView::VisualParameters& visualParameters,
1718 TextView::RelayoutData& relayoutData )
1720 // TODO check ellipsis with rtl text.
1722 // Traverses the lines and checks which ones doesn't fit in the text-view's boundary.
1723 for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1724 lineInfoIt != endLineInfoIt;
1727 const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1729 // To check if a line fits in the text-view's boundary,
1730 // get the position of the first character is needed and do the test
1731 // with the line size.
1733 // An bearing offset may have been applied to the first character so it's needed to
1734 // get the start position of the line.
1736 // Some parameters used in the CalculateVisibilityForEllipsize() function.
1737 EllipsizeParameters ellipsizeParameters;
1739 // Retrieves the first index and the last index of the line.
1740 ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1741 ellipsizeParameters.mLastIndex = 0u;
1742 if( ( lineInfoIt + 1u ) != endLineInfoIt )
1744 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) );
1745 ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u;
1749 ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u;
1752 // Retrieves the first character of the line and build the position of the line with the bearing.
1753 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1755 // Calculates the bearing offset applied to the first character.
1756 const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1758 // Build the position of the line by removing the bearing offset from the first character's position.
1759 const Vector3 position( characterInfo.mPosition.x,
1760 characterInfo.mPosition.y + bearingOffset,
1761 characterInfo.mPosition.z );
1763 // Checks if the line needs to be ellipsized,
1764 ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1766 relayoutData.mTextViewSize,
1767 FULLY_VISIBLE_WIDTH );
1769 // If the exceed policy is EllipsizeEndOriginal it's enough to check
1770 // if the line fits in the width.
1771 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1773 // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1774 // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1775 ellipsizeParameters.mIsLineHeightFullyVisible = true;
1776 ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1777 if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1778 ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1780 // Need to check if there is lines which doesn't fit in the height.
1782 ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1784 relayoutData.mTextViewSize,
1785 FULLY_VISIBLE_HEIGHT );
1787 ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1789 if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1791 // Current line is not ellipsized.
1792 // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1793 Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u;
1794 if( nextLineInfoIt != endLineInfoIt )
1796 // Retrives the position of the first character of the line and remove
1797 // the bearing offset to build to build the position of the line.
1798 const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1799 const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1801 const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1803 const Vector3 position( characterInfo.mPosition.x,
1804 characterInfo.mPosition.y + bearingOffset,
1805 characterInfo.mPosition.z );
1807 ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1809 relayoutData.mTextViewSize,
1810 FULLY_VISIBLE_HEIGHT );
1812 // If the next line is not visible, current line have to be ellipsized.
1813 ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1818 if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1820 ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1823 // Sets the line descender.
1824 ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1826 // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1827 EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1831 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1832 const TextView::VisualParameters& visualParameters,
1833 TextView::RelayoutData& relayoutData )
1835 switch( layoutParameters.mExceedPolicy )
1837 case TextView::FadeOriginal:
1838 case TextView::OriginalFade:
1839 case TextView::Fade:
1840 case TextView::SplitFade: // Fall through
1842 UpdateVisibilityForFade( layoutParameters,
1847 case TextView::EllipsizeEndOriginal:
1848 case TextView::SplitEllipsizeEnd:
1849 case TextView::EllipsizeEnd: // Fall through
1851 // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1852 SetTextVisible( relayoutData );
1854 UpdateVisibilityForEllipsize( layoutParameters,
1861 SetTextVisible( relayoutData );
1868 * Creates an image actor for the emoticon.
1870 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1871 * @param[in,out] characterLayout Layout info for the character.
1872 * @param[in] character The character.
1874 void CreateEmoticon( const TextView::VisualParameters& visualParameters,
1875 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1876 const Character& character )
1878 // The character is an emoticon.
1879 ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1882 imageActor = ImageActor::New();
1884 GlyphImage image = GlyphImage::New( character );
1888 imageActor.SetImage( image );
1892 imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
1893 characterLayout.mPosition.y + characterLayout.mOffset.y,
1894 characterLayout.mPosition.z ) );
1895 imageActor.SetSize( characterLayout.mSize );
1897 // Sets the sort modifier value.
1898 imageActor.SetSortModifier( visualParameters.mSortModifier );
1900 characterLayout.mGlyphActor = imageActor;
1904 * Creates text-actors for the given text.
1906 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1907 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1908 * @param[in,out] paragraph Layout info for the paragraph.
1909 * @param[in,out] wordLayout Layout info for the word.
1910 * @param[in,out] characterLayout Layout info for the character.
1911 * @param[in] character The character.
1912 * @param[in] style The character's style.
1913 * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set.
1914 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1915 * @param[in,out] textActorCreated Whether a text-actor
1917 void CreateTextActor( const TextView::VisualParameters& visualParameters,
1918 TextView::RelayoutData& relayoutData,
1919 const TextViewProcessor::ParagraphLayoutInfo& paragraph,
1920 TextViewProcessor::WordLayoutInfo& wordLayout,
1921 TextViewProcessor::CharacterLayoutInfo& characterLayout,
1922 const Character& character,
1923 const TextStyle& style,
1924 CurrentTextActorInfo& currentTextActorInfo,
1925 bool createGlyphActors,
1926 bool& textActorCreated )
1928 textActorCreated = false;
1930 // Set the text-actor for the current traversed text.
1931 if( currentTextActorInfo.textActor )
1933 if( ( NULL != currentTextActorInfo.characterLayout ) &&
1934 currentTextActorInfo.characterLayout->mSetText )
1936 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1937 currentTextActorInfo.characterLayout->mSetText = false;
1939 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1940 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1942 SetVisualParameters( currentTextActorInfo,
1945 paragraph.mSize.height );
1948 float rightToLeftOffset = 0.f;
1949 if( character.IsWhiteSpace() )
1951 // In left to right text, a word never starts with a white space but
1952 // it may happen in right to left text as the text is reversed.
1953 // The text alignment and justification offset is calculated without this white space.
1954 // It causes a missalignment which can be corrected by removing the size of the white space.
1955 rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
1958 // Whether this word is not a white space or if it is, it is underlined.
1959 // Don't want to create text-actors for white spaces unless they are underlined.
1960 bool isNotWhiteSpace = ( TextViewProcessor::NoSeparator == wordLayout.mType ) || ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() );
1962 if( isNotWhiteSpace )
1964 currentTextActorInfo.text = Text( character );
1968 currentTextActorInfo.text = Text();
1970 currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
1971 characterLayout.mPosition.y + characterLayout.mOffset.y,
1972 characterLayout.mPosition.z );
1973 currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
1975 currentTextActorInfo.color = style.GetTextColor();
1976 currentTextActorInfo.color.a = characterLayout.mColorAlpha;
1978 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1980 if( createGlyphActors && isNotWhiteSpace )
1982 textActorCreated = true;
1985 // Try to reuse first the text-actor of this character.
1986 textActor.SetTextStyle( style );
1990 // If there is no text-actor, try to retrieve one from the cache.
1991 textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1993 // If still there is no text-actor, create one.
1996 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1997 textActor = TextActor::New( Text(), parameters );
2001 textActor.SetTextStyle( style );
2004 characterLayout.mSetText = true;
2005 currentTextActorInfo.characterLayout = &characterLayout;
2007 characterLayout.mGlyphActor = textActor;
2010 // Update the current text-actor.
2011 currentTextActorInfo.textActor = textActor;
2015 * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position.
2017 * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
2018 * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
2019 * @param[in,out] paragraph Layout info for the paragraph.
2020 * @param[in,out] characterGlobalIndex Index to the character within the whole text.
2021 * @param[in,out] lineLayoutInfoIndex Index to the table of lines.
2022 * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
2024 void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
2025 TextView::RelayoutData& relayoutData,
2026 TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
2027 std::size_t& characterGlobalIndex,
2028 std::size_t& lineLayoutInfoIndex,
2029 bool createGlyphActors )
2031 CurrentTextActorInfo currentTextActorInfo;
2032 currentTextActorInfo.characterLayout = NULL;
2034 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
2035 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line.
2036 bool textActorCreated = false; // Whether a text actor has been created for this the current group of characters traversed.
2038 TextStyle currentStyle; // style for the current text-actor.
2040 TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor.
2041 // start point for the current text-actor.
2042 // end point for the current text-actor.
2044 bool currentIsColorGlyph = false; // Whether current glyph is an emoticon.
2046 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
2048 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2049 const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
2051 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
2052 Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
2053 Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
2055 // 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.
2056 createGlyphActors = createGlyphActors || ( ( isRightToLeftLayout ) ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false );
2058 std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph).
2059 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2060 wordIt != wordEndIt;
2063 TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
2065 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
2066 characterIt != characterEndIt;
2069 TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt );
2071 // Check if there is a new line.
2072 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
2076 // Point to the next line.
2077 ++lineLayoutInfoIndex;
2078 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
2080 // Arrived at last line.
2081 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
2083 textActorCreated = false;
2086 // Do not create a glyph-actor if there is no text.
2087 const Character character = text[characterParagraphIndex];
2088 const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
2090 // Check if the character has the same gradient info than the current one.
2091 bool differentGradientInfo = false;
2092 if( characterLayout.mGradientInfo && currentGradientInfo )
2094 differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) ||
2095 ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) ||
2096 ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint );
2098 else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) )
2100 differentGradientInfo = true;
2103 if( ( createGlyphActors && !textActorCreated ) ||
2104 characterLayout.mIsColorGlyph ||
2105 differentGradientInfo ||
2106 ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) ||
2107 ( style != currentStyle ) )
2109 characterLayout.mSetText = false;
2110 characterLayout.mSetStyle = false;
2112 if( characterLayout.mIsColorGlyph )
2114 CreateEmoticon( visualParameters,
2118 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2119 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2123 // There is a new style or a new line.
2125 CreateTextActor( visualParameters,
2132 currentTextActorInfo,
2136 if( textActorCreated )
2138 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2139 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2143 // Update style to be checked with next characters.
2144 currentStyle = style;
2145 currentGradientInfo = characterLayout.mGradientInfo;
2146 currentIsColorGlyph = characterLayout.mIsColorGlyph;
2150 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
2152 // Same style than previous one.
2154 // Add the character to the current text-actor and update the size.
2155 if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
2157 currentTextActorInfo.text.Append( character );
2159 currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) );
2160 currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor;
2161 currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor );
2165 if( ( createGlyphActors ) &&
2166 !characterLayout.mIsColorGlyph &&
2169 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
2172 // There is a previously created text-actor for this character.
2173 // If this character has another one put it into the cache.
2174 textActor.SetText( "" );
2175 textActorsToRemove.push_back( textActor );
2178 if( characterLayout.mGlyphActor )
2180 characterLayout.mGlyphActor.Reset();
2183 ++characterGlobalIndex;
2184 ++characterParagraphIndex;
2188 if( !currentTextActorInfo.text.IsEmpty() )
2190 if( currentTextActorInfo.textActor )
2192 if( ( NULL != currentTextActorInfo.characterLayout ) &&
2193 currentTextActorInfo.characterLayout->mSetText )
2195 currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
2196 currentTextActorInfo.characterLayout->mSetText = false;
2198 currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
2199 currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
2201 SetVisualParameters( currentTextActorInfo,
2204 paragraphLayout.mSize.height );
2208 // Insert the spare text-actors into the cache.
2209 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
2212 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
2213 TextView::RelayoutData& relayoutData,
2214 bool createGlyphActors )
2216 if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
2218 // nothing to do if there is no paragraphs.
2222 std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
2223 std::size_t lineLayoutInfoIndex = 0u; // Index to the line info.
2225 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2226 paragraphIt != paragraphEndIt;
2229 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2231 UpdateTextActorInfoForParagraph( visualParameters,
2234 characterGlobalIndex,
2235 lineLayoutInfoIndex,
2236 createGlyphActors );
2239 // Set visual parameters for ellipsis renderable actors.
2240 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2241 endIt = relayoutData.mEllipsizedGlyphActors.end();
2245 RenderableActor glyphActor = ( *it );
2247 glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2248 glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2250 // Sets the sort modifier value.
2251 glyphActor.SetSortModifier( visualParameters.mSortModifier );
2253 // Enables or disables the blending.
2254 glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
2258 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
2260 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2262 // 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.
2263 // According with the layout option, one of this paragraphs could be laid-out in more than one line.
2265 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2266 paragraphIt != paragraphEndIt;
2269 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2271 std::size_t characterIndex = 0u;
2273 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2274 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2276 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2277 wordIt != wordEndIt;
2280 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2282 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2283 characterIt != characterEndIt;
2284 ++characterIt, ++characterIndex )
2286 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2287 const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2289 // Check if current character is the first of a new line
2290 const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
2291 ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
2294 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2297 if( style.IsUnderlineEnabled() )
2299 if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
2300 isNewLine ) // Current character is underlined and is the first of current line.
2302 // Create a new underline info for the current underlined characters.
2303 UnderlineInfo underlineInfo;
2304 underlineInfo.mMaxHeight = character.mSize.height;
2305 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2306 underlineInfo.mPosition = character.mUnderlinePosition;
2308 textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
2310 textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
2314 // Retrieve last underline info and update it if current underline thickness is bigger.
2315 UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) );
2317 underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height );
2319 if( character.mUnderlineThickness > underlineInfo.mMaxThickness )
2321 underlineInfo.mMaxThickness = character.mUnderlineThickness;
2322 underlineInfo.mPosition = character.mUnderlinePosition;
2328 textUnderlineStatus.mCurrentUnderlineStatus = false;
2331 ++textUnderlineStatus.mCharacterGlobalIndex;
2332 } // end characters.
2334 } // end paragraphs.
2337 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
2339 // 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.
2340 TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
2342 // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2343 CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
2345 if( textUnderlineStatus.mUnderlineInfo.empty() )
2347 // There is no underlined text. Just exit.
2351 // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
2352 // Traverse the whole text and set the previously stored underline info in the text style.
2354 std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
2355 std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
2357 UnderlineInfo underlineInfo;
2359 if( underlineInfoIt < underlineInfoEndIt )
2361 underlineInfo = ( *underlineInfoIt );
2364 // Whether current text is underlined.
2365 textUnderlineStatus.mCurrentUnderlineStatus = false;
2366 textUnderlineStatus.mCharacterGlobalIndex = 0u;
2367 textUnderlineStatus.mLineGlobalIndex = 0u;
2369 float currentLineHeight = 0.f;
2370 float currentLineAscender = 0.f;
2372 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2373 paragraphIt != paragraphEndIt;
2376 TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2377 std::size_t characterIndex = 0u;
2379 const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2380 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2382 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2383 wordIt != wordEndIt;
2386 TextViewProcessor::WordLayoutInfo& word( *wordIt );
2388 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2389 characterIt != characterEndIt;
2390 ++characterIt, ++characterIndex )
2392 TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2393 TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2395 // Check if current character is the first of a new line
2397 bool isNewLine = false;
2399 if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
2401 const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
2402 isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
2406 currentLineHeight = lineLayoutInfo.mSize.height;
2407 currentLineAscender = lineLayoutInfo.mAscender;
2408 ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2412 if( style.IsUnderlineEnabled() )
2414 if( textUnderlineStatus.mCurrentUnderlineStatus )
2418 // Retrieves the thickness and position for the next piece of underlined text.
2419 if( underlineInfoIt < underlineInfoEndIt )
2422 if( underlineInfoIt < underlineInfoEndIt )
2424 underlineInfo = *underlineInfoIt;
2430 textUnderlineStatus.mCurrentUnderlineStatus = true;
2432 // Before setting the position it needs to be adjusted to match the base line.
2433 const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender );
2434 const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
2436 // Sets the underline's parameters.
2437 style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
2439 // Mark the character to be set the new style into the text-actor.
2440 character.mSetStyle = true;
2444 if( textUnderlineStatus.mCurrentUnderlineStatus )
2446 textUnderlineStatus.mCurrentUnderlineStatus = false;
2448 // Retrieves the thickness and position for the next piece of underlined text.
2449 if( underlineInfoIt < underlineInfoEndIt )
2452 if( underlineInfoIt < underlineInfoEndIt )
2454 underlineInfo = *underlineInfoIt;
2460 ++textUnderlineStatus.mCharacterGlobalIndex;
2461 } // end of characters.
2463 } // end of paragraphs.
2466 void RemoveGlyphActors( Actor textView,
2467 const std::vector<RenderableActor>& glyphActors )
2469 // Removes previously inserted renderable-actors.
2470 // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
2471 // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
2472 // in order to remove 'only' renderable-actors added by these functions.
2473 // Any other actor added by a programmer or application won't be removed.
2475 for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
2477 textView.Remove( *it );
2481 void InsertToTextView( Actor textView,
2482 TextView::RelayoutData& relayoutData )
2484 // Add text-actors to the text-view.
2486 for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
2487 endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2488 paragraphLayoutIt != endParagraphLayoutIt;
2489 ++paragraphLayoutIt )
2491 TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
2493 // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2494 const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
2495 TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
2497 for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
2498 endWordLayoutIt = wordsLayoutInfo.end();
2499 wordLayoutIt != endWordLayoutIt;
2502 TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
2504 for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
2505 endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
2506 characterLayoutIt != endCharacterLayoutIt;
2507 ++characterLayoutIt )
2509 TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
2511 if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
2513 //Add to the text-view.
2514 textView.Add( characterLayoutInfo.mGlyphActor );
2515 relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
2521 for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2522 endIt = relayoutData.mEllipsizedGlyphActors.end();
2526 RenderableActor glyphActor = ( *it );
2528 //Add to the text-view.
2529 textView.Add( glyphActor );
2530 relayoutData.mGlyphActors.push_back( glyphActor );
2532 relayoutData.mEllipsizedGlyphActors.clear();
2535 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
2537 TextActor textActor = cache.RetrieveTextActor();
2541 // Update the text-actor.
2542 textActor.SetText( text );
2543 textActor.SetTextStyle( style );
2547 // The text-actor cache is empty. Create a new one.
2548 TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
2549 textActor = TextActor::New( text, parameters );
2555 } // namespace TextViewRelayout
2557 } // namespace Internal
2559 } // namespace Toolkit