[dali_1.0.11] Merge branch 'tizen'
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / relayout-utilities.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/license/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // FILE HEADER
19 #include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/controls/text-view/text-processor.h>
23 #include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
24 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
25 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
26 #include <dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h>
27
28 // EXTERNAL INCLUDES
29 #include <cmath>
30
31 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Internal
38 {
39
40 namespace TextViewRelayout
41 {
42
43 const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same as the text-view boundary, this constant reduces it in order to avoid a zero division.
44
45 RelayoutParameters::RelayoutParameters()
46 : mPositionOffset(),
47   mParagraphSize(),
48   mWordSize(),
49   mCharacterSize(),
50   mIndices(),
51   mCharacterGlobalIndex( 0u ),
52   mIsFirstCharacter( false ),
53   mIsFirstCharacterOfWord( false ),
54   mIsNewLine( false ),
55   mIsNewParagraphCharacter( false ),
56   mIsWhiteSpace( false ),
57   mIsVisible( false )
58 {
59 }
60
61 RelayoutParameters::~RelayoutParameters()
62 {
63 }
64
65 FadeParameters::FadeParameters()
66 : mRightFadeBoundary( 0.f ),
67   mRightFadeThreshold( 0.f ),
68   mRightFadeBoundaryOffset( 0.f ),
69   mRightFadeThresholdOffset( 0.f ),
70   mRightAlphaCoeficients(),
71   mLeftFadeBoundary( 0.f ),
72   mLeftFadeThreshold( 0.f ),
73   mLeftFadeBoundaryOffset( 0.f ),
74   mLeftFadeThresholdOffset( 0.f ),
75   mLeftAlphaCoeficients(),
76   mTopFadeBoundary( 0.f ),
77   mTopFadeThreshold( 0.f ),
78   mTopFadeBoundaryOffset( 0.f ),
79   mTopFadeThresholdOffset( 0.f ),
80   mTopAlphaCoeficients(),
81   mBottomFadeBoundary( 0.f ),
82   mBottomFadeThreshold( 0.f ),
83   mBottomFadeBoundaryOffset( 0.f ),
84   mBottomFadeThresholdOffset( 0.f ),
85   mBottomAlphaCoeficients(),
86   mIsPartiallyVisible( false )
87 {
88 }
89
90 FadeParameters::~FadeParameters()
91 {
92 }
93
94 EllipsizeParameters::EllipsizeParameters()
95 : mPosition(),
96   mLineDescender( 0.f ),
97   mLineWidth( 0.f ),
98   mEllipsizeBoundary(),
99   mFirstIndex( 0u ),
100   mLastIndex( 0u ),
101   mEllipsizeLine( false ),
102   mIsLineWidthFullyVisible( false ),
103   mIsLineHeightFullyVisible( false ),
104   mIsNextLineFullyVisibleHeight( false ),
105   mCreateEllipsizedTextActors( false ),
106   mLineFits( false ),
107   mWordFits( false )
108 {
109 }
110
111 EllipsizeParameters::~EllipsizeParameters()
112 {
113 }
114
115 UnderlineInfo::UnderlineInfo()
116 : mMaxHeight( 0.f ),
117   mMaxThickness( 0.f ),
118   mPosition( 0.f )
119 {
120 }
121
122 UnderlineInfo::~UnderlineInfo()
123 {
124 }
125
126 TextUnderlineStatus::TextUnderlineStatus()
127 : mUnderlineInfo(),
128   mCharacterGlobalIndex( 0u ),
129   mLineGlobalIndex( 0u ),
130   mCurrentUnderlineStatus( false )
131 {
132 }
133
134 TextUnderlineStatus::~TextUnderlineStatus()
135 {
136 }
137
138 LineLayoutInfo::LineLayoutInfo()
139 : mLineLength( 0.f ),
140   mMaxCharHeight( 0.f ),
141   mMaxAscender( 0.f )
142 {
143 }
144
145 LineLayoutInfo::~LineLayoutInfo()
146 {
147 }
148
149 /**
150  * Whether the given text-actor exceeds the left or the right boundary of the text-view.
151  *
152  * @param[in] position The position of the text-actor.
153  * @param[in] size The size of the text-actor.
154  * @param[in] parantSize The size of the text-view.
155  *
156  * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
157  */
158 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
159 {
160   return ( ( position.x < 0.f ) ||
161            ( position.x + size.width > parentSize.width ) );
162 }
163
164 /**
165  * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
166  *
167  * @param[in] position The position of the text-actor.
168  * @param[in] size The size of the text-actor.
169  * @param[in] parantSize The size of the text-view.
170  *
171  * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
172  */
173 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
174 {
175   return ( ( position.y > parentSize.height ) ||
176            ( position.y < size.height ) );
177 }
178
179 /**
180  * Calculates the line length adding the new word or character width.
181  *
182  * It also returns the length of white spaces if they are at the end of the line.
183  *
184  * @param[in] isWhiteSpace Whether the word is a white space.
185  * @param[in] width The width of the character or word.
186  * @param[in] parentWidth The parent width.
187  * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
188  * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
189  * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
190  */
191 void CalculateLineLength( bool isWhiteSpace, float width, float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
192 {
193   if( lineLength + width > parentWidth )
194   {
195     found = true;
196     lineLength -= endWhiteSpaceLength;
197   }
198   else
199   {
200     lineLength += width;
201
202     if( isWhiteSpace )
203     {
204       endWhiteSpaceLength += width;
205     }
206     else
207     {
208       endWhiteSpaceLength = 0.f;
209     }
210   }
211 }
212
213 struct CurrentTextActorInfo
214 {
215   TextActor textActor;
216   Text text;
217   Vector3 position;
218   Size size;
219   Vector4 color;
220   TextViewProcessor::CharacterLayoutInfo* characterLayout;
221 };
222
223 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
224                           const TextView::VisualParameters& visualParameters,
225                           TextView::RelayoutData& relayoutData,
226                           const float lineHeight )
227 {
228   currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
229   if( ( NULL != currentTextActorInfo.characterLayout ) &&
230       ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) )
231   {
232     currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.characterLayout->mGradientInfo->mGradientColor );
233     currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.characterLayout->mGradientInfo->mStartPoint );
234     currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.characterLayout->mGradientInfo->mEndPoint );
235   }
236
237   // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
238   // due to the trick used to implement it.
239   const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
240   const float italicsOffset = lineHeight * std::tan( italicsAngle );
241   relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
242
243   // Sets the sort modifier value.
244   currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
245
246   // Enables or disables the blending.
247   currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
248 }
249
250 void CalculateLineLayout( float parentWidth,
251                           const TextViewProcessor::TextInfoIndices& indices,
252                           const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo,
253                           HorizontalWrapType splitPolicy,
254                           float shrinkFactor,
255                           LineLayoutInfo& subLineInfo )
256 {
257   subLineInfo.mLineLength = 0.f;
258   subLineInfo.mMaxCharHeight = 0.f;
259   subLineInfo.mMaxAscender = 0.f;
260
261   float endWhiteSpaceLength = 0.f;
262
263   std::size_t characterIndex = indices.mCharacterIndex;
264   float lineOffset = 0.f;
265   bool found = false;
266   bool isFirstCharacter = true;
267   for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex,
268          wordEndIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
269        ( wordIt != wordEndIt ) && !found;
270        ++wordIt )
271   {
272     const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
273
274     const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor;
275     const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
276
277     bool splitByCharacter = false;
278
279     switch( splitPolicy )
280     {
281       case WrapByCharacter:
282       {
283         splitByCharacter = true;
284         break;
285       }
286       case WrapByWord:
287       case WrapByParagraphCharacter: // Fall through
288       {
289         splitByCharacter = false;
290         break;
291       }
292       case WrapByWordAndSplit:
293       {
294         splitByCharacter = ( shrunkWordWidth > parentWidth );
295         break;
296       }
297       case WrapByParagraphCharacterAndSplit:
298       {
299         if( ( 0u != characterIndex ) ||
300             ( ( 0u == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) )
301         {
302           splitByCharacter = true;
303         }
304         else
305         {
306           lineOffset += shrunkWordWidth;
307           splitByCharacter = false;
308         }
309       }
310     }
311
312     if( splitByCharacter )
313     {
314       for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
315              charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
316            ( charIt != charEndIt ) && !found;
317            ++charIt )
318       {
319         const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
320         CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
321         if( !found || isFirstCharacter )
322         {
323           subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
324           subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
325         }
326
327         // All characters for word 'wordIndex' have been processed.
328         // Next word need to process all characters, so the characterIndex is reset to 0.
329         characterIndex = 0u;
330         isFirstCharacter = false;
331       }
332
333       lineOffset += subLineInfo.mLineLength;
334     }
335     else
336     {
337       CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
338       if( !found || isFirstCharacter )
339       {
340         subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
341         subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
342       }
343       isFirstCharacter = false;
344     }
345   }
346
347   subLineInfo.mMaxCharHeight *= shrinkFactor;
348   subLineInfo.mMaxAscender *= shrinkFactor;
349 }
350
351
352 /**
353  * Sets a character of a line of a bidirectional paragraph in the new position.
354  *
355  * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph.
356  * @param[in] index Index within the paragraph to the character to be set in the new position.
357  * @param[in,out] character Reference to the character in the new position.
358  */
359 void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo,
360                    std::size_t index,
361                    TextViewProcessor::CharacterLayoutInfo& character )
362 {
363   // Traverse all the characters of the paragraph till the one pointed by index is found.
364   std::size_t traversedCharacters = 0u;
365   for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(),
366          wordEndIt = wordsLayoutInfo.end();
367        wordIt != wordEndIt;
368        ++wordIt )
369   {
370     const TextViewProcessor::WordLayoutInfo& word( *wordIt );
371
372     const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size();
373     if( index < traversedCharacters + numberOfCharacters  )
374     {
375       character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) );
376       return;
377     }
378     traversedCharacters += numberOfCharacters;
379   }
380 }
381
382 /**
383  * Reorders the layout info of each line of the paragraph.
384  *
385  * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics).
386  *
387  * @param[in] characterGlobalIndex Index within the whole text of the first character of the paragraph.
388  * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text.
389  * @param[in,out] relayoutData The text-view's data structures.
390  */
391 void ReorderLayout( std::size_t characterGlobalIndex,
392                     TextViewProcessor::ParagraphLayoutInfo& paragraph,
393                     TextView::RelayoutData& relayoutData )
394 {
395   // Clear any previous right to left layout.
396   if( NULL != paragraph.mRightToLeftLayout )
397   {
398     paragraph.mRightToLeftLayout->Clear();
399     paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true;
400   }
401   else
402   {
403     // Create a new right to left layout if there isn't any.
404     paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout();
405   }
406
407   // Reorder Text and Styles.
408
409   // Reserve space for the styles.
410   paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() );
411
412   // Traverses all the bidirectional info per line.
413   for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
414   {
415     TextProcessor::BidirectionalLineInfo* info( *it );
416
417     const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex;
418     const Vector<int>& visualToLogicalMap = info->mVisualToLogicalMap;
419
420     // The text can be appended as it's already reordered.
421     paragraph.mRightToLeftLayout->mText.Append( info->mText );
422
423     // The visual to logical map needs to be used to reorder the styles.
424     for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index )
425     {
426       paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) );
427     }
428   }
429
430   // Reorder Layout Info.
431
432   // Reserve space for the new word layout.
433   paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() );
434
435   // Traverses all the bidirectional info per line.
436   for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it )
437   {
438     TextProcessor::BidirectionalLineInfo* info( *it );
439
440     // Reserve space for all characters.
441     TextViewProcessor::CharacterLayoutInfoContainer characters;
442     characters.resize( info->mNumberOfCharacters );
443
444     // Uses the visual to logical map to set every character in its new position.
445     for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index )
446     {
447       SetCharacter( paragraph.mWordsLayoutInfo,
448                     info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index],
449                     *( characters.begin() + index ) );
450     }
451
452     // Sets the new 'x' position for each character.
453     // Updates the text-view's layout info table with the new position of the character.
454     float xPosition = 0.f;
455     std::size_t index = 0u;
456     for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it, ++index )
457     {
458       TextViewProcessor::CharacterLayoutInfo& character( *it );
459
460       // Set the 'x' position.
461       character.mPosition.x = xPosition;
462
463       // Update layout info table.
464       relayoutData.mCharacterLayoutInfoTable[characterGlobalIndex + info->mVisualToLogicalMap[index]].mPosition = character.mPosition;
465
466       // Update the position for the next character.
467       xPosition += character.mSize.width;
468     }
469
470     // Split the reordered text in words.
471     std::size_t previousPosition = 0u;
472     Vector<std::size_t> positions;
473     TextProcessor::SplitInWords( info->mText, positions );
474
475     // Whether last character is a word or a paragraph separator.
476     const std::size_t lastCharacterIndex = info->mText.GetLength() - 1u;
477     const bool isLastCharacterParagraphSeparator = info->mText.IsNewLine( lastCharacterIndex );
478     const bool isLastCharacterWordSeparator = info->mText.IsWhiteSpace( lastCharacterIndex );
479
480     // Sets the characters into the words they belong to.
481     for( Vector<std::size_t>::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it )
482     {
483       const std::size_t position = *it;
484
485       TextViewProcessor::WordLayoutInfo word;
486       word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
487                                          characters.begin() + previousPosition,
488                                          characters.begin() + position );
489
490       if( !word.mCharactersLayoutInfo.empty() )
491       {
492         // Updates the layout of the word.
493         TextViewProcessor::UpdateLayoutInfo( word );
494
495         paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
496       }
497
498       // white space or new paragraph.
499       TextViewProcessor::WordLayoutInfo space;
500
501       space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(),
502                                           characters.begin() + position,
503                                           characters.begin() + position + 1u );
504
505       space.mType = TextViewProcessor::WordSeparator;
506
507       TextViewProcessor::UpdateLayoutInfo( space );
508
509       paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space );
510
511       previousPosition = position + 1u;
512     }
513
514     // The last word.
515     if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() )
516     {
517       TextViewProcessor::WordLayoutInfo word;
518       word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(),
519                                          characters.begin() + previousPosition,
520                                          characters.end() );
521
522       if( isLastCharacterParagraphSeparator )
523       {
524         word.mType = TextViewProcessor::ParagraphSeparator;
525       }
526       else if( isLastCharacterWordSeparator )
527       {
528         word.mType = TextViewProcessor::WordSeparator;
529       }
530       TextViewProcessor::UpdateLayoutInfo( word );
531
532       paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word );
533     }
534   }
535 }
536
537 /**
538  * Creates the bidirectional info needed to reorder each line of the paragraph.
539  *
540  * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
541  * @param[in,out] paragraph Layout info for the paragraph.
542  * @param[in] characterGlobalIndex Index to the character within the whole text.
543  * @param[in] lineLayoutInfoIndex Index to the table of lines.
544  */
545 void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData,
546                                       TextViewProcessor::ParagraphLayoutInfo& paragraph,
547                                       std::size_t& characterGlobalIndex,
548                                       std::size_t& lineLayoutInfoIndex )
549 {
550   const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
551   bool lineLayoutEnd = false;            // Whether lineLayoutInfoIndex points at the last laid out line.
552
553   // Clear previously created bidirectional info.
554   paragraph.ClearBidirectionalInfo();
555
556   // For each character, it sets the character's direction.
557
558   // Initialize the paragraph direction. Used to set the direction of weak characters.
559   const bool isParagraphRightToLeft = paragraph.mBidirectionalParagraphInfo->IsRightToLeftParagraph();
560   bool isPreviousRightToLeft = isParagraphRightToLeft;
561
562   for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
563   {
564     // Get the character's layout information (the one is shared with text-input)
565     Toolkit::TextView::CharacterLayoutInfo& info = *( relayoutData.mCharacterLayoutInfoTable.begin() + ( characterGlobalIndex + index ) );
566
567     // Gets the character's direction.
568     const Character::CharacterDirection direction = paragraph.mText[index].GetCharacterDirection();
569     if( Character::RightToLeft == direction )
570     {
571       info.mIsRightToLeftCharacter = true;
572     }
573     else if( Character::Neutral == direction )
574     {
575       // For neutral characters it check's the next and previous directions.
576       // If they are equals set that direction. If they are not, sets the paragraph direction.
577       // If there is no next, sets the previous direction.
578
579       // Check next character's direction.
580       bool isNextRightToLeft = isPreviousRightToLeft;
581       if( index < paragraph.mNumberOfCharacters - 1u )
582       {
583         const Character::CharacterDirection nextDirection = paragraph.mText[index + 1u].GetCharacterDirection();
584         isNextRightToLeft = Character::RightToLeft == nextDirection;
585       }
586
587       info.mIsRightToLeftCharacter = isPreviousRightToLeft == isNextRightToLeft ? isPreviousRightToLeft : isParagraphRightToLeft;
588     }
589     else
590     {
591       info.mIsRightToLeftCharacter = false;
592     }
593
594     isPreviousRightToLeft = info.mIsRightToLeftCharacter;
595   }
596
597   std::size_t characterParagraphIndex = 0u;   // Index to the character (within the paragraph).
598   for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
599        wordIt != wordEndIt;
600        ++wordIt )
601   {
602     TextViewProcessor::WordLayoutInfo& word( *wordIt );
603
604     for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
605          characterIt != characterEndIt;
606          ++characterIt )
607     {
608       TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL;
609
610       // Check if there is a new line.
611       const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
612
613       if( newLine )
614       {
615         // Point to the next line.
616         ++lineLayoutInfoIndex;
617         if( lineLayoutInfoIndex >= lineLayoutInfoSize )
618         {
619           // Arrived at last line.
620           lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
621         }
622
623         // Number of characters of the line.
624         const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex;
625
626         // There is right to left characters in this line. It needs to be reordered.
627         bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo();
628         bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex;
629         bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters;
630
631         // Set all the Text's characters in the visual order and creates the mapping tables.
632         TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo,
633                                     bidirectionalLineInfo );
634
635         paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo );
636
637         for( std::size_t index = 0u; index < numberOfCharacters; ++index )
638         {
639           relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] );
640           relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] );
641         }
642       }
643
644       ++characterGlobalIndex;
645       ++characterParagraphIndex;
646     } // characters
647   } // words
648 }
649
650 void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData )
651 {
652   // Reset conversion tables shared through public-api
653   relayoutData.mCharacterLogicalToVisualMap.clear();
654   relayoutData.mCharacterVisualToLogicalMap.clear();
655
656   std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
657   std::size_t lineLayoutInfoIndex = 0u;  // Index to the line info.
658
659   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
660        paragraphIt != paragraphEndIt;
661        ++paragraphIt )
662   {
663     TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
664
665     if( NULL != paragraph.mBidirectionalParagraphInfo )
666     {
667       // There is right to left text in this paragraph.
668
669       // Stores the current global character index as is needed in both functions.
670       const std::size_t currentGlobalIndex = characterGlobalIndex;
671
672       // Creates the bidirectional info needed to reorder each line of the paragraph.
673       CreateBidirectionalInfoForLines( relayoutData,
674                                        paragraph,
675                                        characterGlobalIndex,
676                                        lineLayoutInfoIndex );
677
678       // Reorder each line of the paragraph
679       ReorderLayout( currentGlobalIndex, paragraph, relayoutData );
680     }
681     else
682     {
683       // Identity in case the paragraph has no right to left text.
684       for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index )
685       {
686         const std::size_t globalIndex = characterGlobalIndex + index;
687         relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex );
688         relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex );
689       }
690       characterGlobalIndex += paragraph.mNumberOfCharacters;
691     }
692   } // paragraphs
693 }
694
695 float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth )
696 {
697   float xOffset( 0.f );
698   switch( horizontalTextAlignment )
699   {
700     case Toolkit::Alignment::HorizontalLeft:
701     {
702       // nothing to do.
703       break;
704     }
705     case Toolkit::Alignment::HorizontalCenter:
706     {
707       xOffset = 0.5f * ( parentWidth - wholeTextWidth );
708       break;
709     }
710     case Toolkit::Alignment::HorizontalRight:
711     {
712       xOffset = parentWidth - wholeTextWidth;
713       break;
714     }
715     default:
716     {
717       DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
718     }
719   }
720
721   return xOffset;
722 }
723
724 float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight )
725 {
726   float yOffset( 0.f );
727   switch( verticalTextAlignment )
728   {
729     case Toolkit::Alignment::VerticalTop:
730     {
731       // nothing to do.
732       break;
733     }
734     case Toolkit::Alignment::VerticalCenter:
735     {
736       yOffset = 0.5f * ( parentHeight - wholeTextHeight );
737       break;
738     }
739     case Toolkit::Alignment::VerticalBottom:
740     {
741       yOffset = parentHeight - wholeTextHeight;
742       break;
743     }
744     default:
745     {
746       DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
747     }
748   }
749
750   return yOffset;
751 }
752
753 float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength )
754 {
755   float offset = 0.f;
756   switch( justification )
757   {
758     case Toolkit::TextView::Left:
759     {
760       offset = 0.f;
761       break;
762     }
763     case Toolkit::TextView::Center:
764     {
765       offset = 0.5f * ( wholeTextWidth - lineLength );
766       break;
767     }
768     case Toolkit::TextView::Right:
769     {
770       offset = wholeTextWidth - lineLength;
771       break;
772     }
773     case Toolkit::TextView::Justified:
774     {
775       offset = 0.f;
776       break;
777     }
778   }
779
780   return offset;
781 }
782
783 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
784 {
785   bool visible = false;
786
787   switch( type )
788   {
789     case FULLY_VISIBLE:
790     {
791       // Whether the text-actor is fully inside the boundaries of the text-view.
792       visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
793                   ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
794       break;
795     }
796     case FULLY_VISIBLE_WIDTH:
797     {
798       // Whether the text-actor is between the left and right boundaries of the text-view.
799       visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
800       break;
801     }
802     case FULLY_VISIBLE_HEIGHT:
803     {
804       // Whether the text-actor is between the top and bottom boundaries of the text-view.
805       visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
806       break;
807     }
808     case PARTIALLY_VISIBLE:
809     {
810       // Whether the text-actor is partially inside the boundaries of the text-view.
811       visible = ( ( position.x < parentSize.width ) &&
812                   ( position.x + size.width > 0.f ) &&
813                   ( position.y > 0.f ) &&
814                   ( position.y - size.height < parentSize.height ) );
815       break;
816     }
817     case PARTIALLY_VISIBLE_WIDTH:
818     {
819       // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
820       // It may not be partially inside the text-view.
821       visible = ( ( position.x < parentSize.width ) &&
822                   ( position.x + size.width > 0.f ) );
823       break;
824     }
825     case PARTIALLY_VISIBLE_HEIGHT:
826     {
827       // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
828       // It may not be partially inside the text-view.
829       visible = ( ( position.y > 0.f ) &&
830                   ( position.y - size.height < parentSize.height ) );
831       break;
832     }
833   }
834
835   return visible;
836 }
837
838 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
839 {
840   const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
841
842   return Vector2( gradient, p0.y - gradient * p0.x );
843 }
844
845 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
846                       TextView::RelayoutData& relayoutData )
847 {
848   // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
849   // The offset could be negative if the whole text is bigger than the boundary of the text-view.
850
851   // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
852   // In that case, it will align the line to the left and/or top, and ellipsize the end.
853   const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) ||
854                                     ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
855                                     ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
856   const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd ) ||
857                                    ( layoutParameters.mExceedPolicy == TextView::SplitEllipsizeEnd );
858
859   RelayoutParameters relayoutParameters;
860
861   // Calculates the vertical and horizontal offsets.
862   const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width );
863   const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height );
864
865   // Index to the global character (within the whole text).
866   std::size_t characterGlobalIndex = 0u;
867
868   // Index to the line info.
869   std::size_t lineLayoutInfoIndex = 0u;
870
871   relayoutParameters.mIndices.mParagraphIndex = 0u;
872
873   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
874          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
875        paragraphLayoutIt != endParagraphLayoutIt;
876        ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
877   {
878     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
879
880     float justificationOffset = 0.f;
881
882     const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
883     bool lineLayoutEnd = false;            // Whether lineLayoutInfoIndex points at the last line.
884
885     relayoutParameters.mIndices.mWordIndex = 0u;
886
887     const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
888     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
889
890     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
891            endWordLayoutIt = wordsLayoutInfo.end();
892          wordLayoutIt != endWordLayoutIt;
893          ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
894     {
895       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
896
897       relayoutParameters.mIndices.mCharacterIndex = 0u;
898
899       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
900              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
901            characterLayoutIt != endCharacterLayoutIt;
902            ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex )
903       {
904         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
905
906         // Check if there is a new line.
907         const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
908
909         if( newLine )
910         {
911           // Calculate line justification offset.
912           justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width );
913
914           // Point to the next line.
915           ++lineLayoutInfoIndex;
916           if( lineLayoutInfoIndex >= lineLayoutInfoSize )
917           {
918             // Arrived at last line.
919             lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
920           }
921         }
922
923         // Deletes the offsets if the exceed policies are EllipsizeEnd.
924         const float horizontalOffset = textHorizontalOffset + justificationOffset;
925         characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset;
926         characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset;
927
928         // Updates the size and position table for text-input with the alignment offset.
929         Vector3 positionOffset( characterLayoutInfo.mPosition );
930
931         // Update layout info table.
932         std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[characterGlobalIndex];
933         Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt );
934
935         characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x;
936         characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y;
937
938         positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
939       } // end characters
940     } // end words
941   } // end paragraphs
942 }
943
944 void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
945                        TextView::RelayoutData& relayoutData )
946 {
947   // No bearing used.
948   //
949   //            gggggggggg
950   //            gggggggggg
951   //          gggg      gggg
952   //          gggg      gggg
953   //          gggg      gggg
954   //          gggg      gggg
955   //          gggg      gggg
956   //          gggg      gggg
957   //  ggggg     gggggggggg        bb         ggggg
958   // gg   gg    gggggggggg        bb        gg   gg
959   // gg   gg            gggg      bb        gg   gg
960   // gg   gg            gggg      bb        gg   gg
961   //  ggggg   gg        gggg      bbbbbbb    ggggg
962   //      gg  gg        gggg      bb    bb       gg
963   // g    gg    gggggggggg        bb    bb  g    gg
964   //  ggggg     gggggggggg        bbbbbbb    ggggg
965   //
966   // Bearing used.
967   //
968   //            gggggggggg
969   //            gggggggggg
970   //          gggg      gggg      bb
971   //          gggg      gggg      bb
972   //          gggg      gggg      bb
973   //  ggggg   gggg      gggg      bb         ggggg
974   // gg   gg  gggg      gggg      bbbbbbb   gg   gg
975   // gg   gg  gggg      gggg      bb    bb  gg   gg
976   // gg   gg    gggggggggg        bb    bb  gg   gg
977   //  ggggg     gggggggggg        bbbbbbb    ggggg
978   //      gg            gggg                     gg
979   // g    gg            gggg                g    gg
980   //  ggggg   gg        gggg                 ggggg
981   //          gg        gggg
982   //            gggggggggg
983   //            gggggggggg
984
985   const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
986   const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender );
987
988   characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor;
989 }
990
991 void UpdateLayoutInfoTable( Vector4& minMaxXY,
992                             TextViewProcessor::WordLayoutInfo& wordLayoutInfo,
993                             TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
994                             RelayoutParameters& relayoutParameters,
995                             TextView::RelayoutData& relayoutData )
996 {
997   // updates min and max position to calculate the text size for multiline policies.
998   minMaxXY.x = std::min( minMaxXY.x, characterLayoutInfo.mPosition.x );
999   minMaxXY.z = std::max( minMaxXY.z, characterLayoutInfo.mPosition.x + characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor );
1000
1001   minMaxXY.y = std::min( minMaxXY.y, characterLayoutInfo.mPosition.y - characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1002   minMaxXY.w = std::max( minMaxXY.w, characterLayoutInfo.mPosition.y   );
1003
1004   // Adds layout info to be retrieved by external controls or applications.
1005   Vector3 positionOffset( characterLayoutInfo.mPosition );
1006
1007   const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender;
1008
1009   const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor,
1010                                                                                characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ),
1011                                                                          positionOffset,
1012                                                                          ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ),
1013                                                                          false, // whether the character is right to left. The value is set in a next step in the CreateBidirectionalInfoForLines function
1014                                                                          true,  // whether the character is visible.
1015                                                                          descender );
1016
1017   relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo );
1018
1019   positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1020 }
1021
1022 void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters,
1023                                  TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1024                                  const TextStyle& style,
1025                                  RelayoutParameters& relayoutParameters,
1026                                  FadeParameters& fadeParameters,
1027                                  TextView::RelayoutData& relayoutData )
1028 {
1029   if( ( TextView::Fade != layoutParameters.mExceedPolicy ) &&
1030       ( TextView::SplitFade != layoutParameters.mExceedPolicy ) &&
1031       ( TextView::FadeOriginal != layoutParameters.mExceedPolicy ) &&
1032       ( TextView::OriginalFade != layoutParameters.mExceedPolicy ) )
1033   {
1034     // nothing to fade
1035     return;
1036   }
1037
1038   // Calculates visibility of a text-actor according the exceed policies.
1039
1040   // position + alignment offset.
1041   const Vector3 position( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1042                           characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1043                           characterLayoutInfo.mPosition.z );
1044
1045   // Whether the text actor is fully, partially or non visible (according exceed policies).
1046   switch( layoutParameters.mExceedPolicy )
1047   {
1048     case TextView::Fade:
1049     {
1050       // All text-actors which are not completely inside the text-view's boundaries are set as non visible.
1051       // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1052       if( !IsVisible( position,
1053                       characterLayoutInfo.mSize,
1054                       relayoutData.mTextViewSize,
1055                       FULLY_VISIBLE ) )
1056       {
1057         relayoutParameters.mIsVisible = false;
1058         if( IsVisible( position,
1059                        characterLayoutInfo.mSize,
1060                        relayoutData.mTextViewSize,
1061                        PARTIALLY_VISIBLE ) )
1062         {
1063           fadeParameters.mIsPartiallyVisible = true;
1064
1065           // Checks if a text-actor is exceeding more than one boundary as this case is not supported.
1066           if( IsExceedingWidth( position,
1067                                 characterLayoutInfo.mSize,
1068                                 relayoutData.mTextViewSize ) &&
1069               IsExceedingHeight( position,
1070                                  characterLayoutInfo.mSize,
1071                                  relayoutData.mTextViewSize ) )
1072           {
1073             // Combination not fully supported by text-view.
1074             // Need to check if text-actor really supports this combination.
1075             fadeParameters.mIsPartiallyVisible = false;
1076           }
1077         }
1078       }
1079       break;
1080     }
1081     case TextView::FadeOriginal:
1082     {
1083       // All text-actors which are not completely between the left and right text-view's boundaries are set as non visible.
1084       // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1085       if( !IsVisible( position,
1086                       characterLayoutInfo.mSize,
1087                       relayoutData.mTextViewSize,
1088                       FULLY_VISIBLE_WIDTH ) )
1089       {
1090         relayoutParameters.mIsVisible = false;
1091         if( IsVisible( position,
1092                        characterLayoutInfo.mSize,
1093                        relayoutData.mTextViewSize,
1094                        PARTIALLY_VISIBLE_WIDTH ) )
1095         {
1096           fadeParameters.mIsPartiallyVisible = true;
1097         }
1098       }
1099       break;
1100     }
1101     case TextView::OriginalFade:
1102     case TextView::SplitFade: // Fallthrough
1103     {
1104       // All text-actors which are not completely between the top and bottom text-view's boundaries are set as non visible.
1105       // All text-actors which are partially inside the text-view's boundaries are set as partially visible.
1106       if( !IsVisible( position,
1107                       characterLayoutInfo.mSize,
1108                       relayoutData.mTextViewSize,
1109                       FULLY_VISIBLE_HEIGHT ) )
1110       {
1111         relayoutParameters.mIsVisible = false;
1112         if( IsVisible( position,
1113                        characterLayoutInfo.mSize,
1114                        relayoutData.mTextViewSize,
1115                        PARTIALLY_VISIBLE_HEIGHT ) )
1116         {
1117           fadeParameters.mIsPartiallyVisible = true;
1118         }
1119       }
1120       break;
1121     }
1122     default:
1123     {
1124       DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." )
1125       break;
1126     }
1127   }
1128
1129   if( relayoutParameters.mIsVisible || fadeParameters.mIsPartiallyVisible )
1130   {
1131     characterLayoutInfo.mIsVisible = true;
1132
1133     const Size size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1134     const float characterPositionPlusWidth = position.x + size.width;
1135     const float characterPositionMinusHeight = position.y - size.height;
1136
1137     // Calculates which edges need to be faded-out.
1138     bool rightFadeOut = false;
1139     bool leftFadeOut = false;
1140     bool bottomFadeOut = false;
1141     bool topFadeOut = false;
1142
1143     switch( layoutParameters.mExceedPolicy )
1144     {
1145       case TextView::Fade:
1146       {
1147         // All text-actors exceeding any of the boundaries will be faded-out.
1148         rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1149         leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1150         bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1151         topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1152         break;
1153       }
1154       case TextView::FadeOriginal:
1155       {
1156         // Only text-actors exceeding the left or the right boundaries will be faded-out.
1157         rightFadeOut = ( characterPositionPlusWidth > fadeParameters.mRightFadeThreshold );
1158         leftFadeOut = ( position.x < fadeParameters.mLeftFadeThreshold );
1159         break;
1160       }
1161       case TextView::SplitFade:
1162       case TextView::OriginalFade: //Fallthrough
1163       {
1164         // Only text-actors exceeding the top or the bottom boundaries will be faded-out.
1165         bottomFadeOut = ( position.y > fadeParameters.mBottomFadeThreshold );
1166         topFadeOut = ( characterPositionMinusHeight < fadeParameters.mTopFadeThreshold );
1167         break;
1168       }
1169       default:
1170       {
1171         DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateVisibilityForFade. Wrong exceed policies." );
1172         break;
1173       }
1174     }
1175
1176     // Calculates gradient parameters for a text-actor.
1177     Vector4 gradientColor = Vector4::ZERO;
1178     Vector2 startPoint = Vector2::ZERO;
1179     Vector2 endPoint = Vector2::ZERO;
1180
1181     if( !( rightFadeOut && leftFadeOut ) )
1182     {
1183       // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries.
1184       if( rightFadeOut )
1185       {
1186         gradientColor = style.GetTextColor();
1187
1188         // Calculates gradient coeficients.
1189         characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y );
1190         gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y );
1191
1192         startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1193         endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f );
1194
1195         if( NULL == characterLayoutInfo.mGradientInfo )
1196         {
1197           characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1198         }
1199       }
1200       else if( leftFadeOut )
1201       {
1202         gradientColor = style.GetTextColor();
1203
1204         // Calculates gradient coeficients.
1205         characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y );
1206         gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y );
1207
1208         startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f );
1209         endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f );
1210
1211         if( NULL == characterLayoutInfo.mGradientInfo )
1212         {
1213           characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1214         }
1215       }
1216     }
1217
1218     if( !( bottomFadeOut && topFadeOut ) )
1219     {
1220       // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries.
1221       if( bottomFadeOut )
1222       {
1223         gradientColor = style.GetTextColor();
1224
1225         // Calculates gradient coeficients.
1226         characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y );
1227         gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y );
1228
1229         startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1230         endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) );
1231
1232         if( NULL == characterLayoutInfo.mGradientInfo )
1233         {
1234           characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1235         }
1236       }
1237       else if( topFadeOut )
1238       {
1239         gradientColor = style.GetTextColor();
1240
1241         // Calculates gradient coeficients.
1242         characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y );
1243         gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y );
1244
1245         startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) );
1246         endPoint = Vector2( 0.5f, std::min( 1.f,  std::max( 0.f, -characterPositionMinusHeight / size.height ) ) );
1247
1248         if( NULL == characterLayoutInfo.mGradientInfo )
1249         {
1250           characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo();
1251         }
1252       }
1253     }
1254
1255     if( NULL != characterLayoutInfo.mGradientInfo )
1256     {
1257       characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor;
1258       characterLayoutInfo.mGradientInfo->mStartPoint = startPoint;
1259       characterLayoutInfo.mGradientInfo->mEndPoint = endPoint;
1260     }
1261   }
1262   else
1263   {
1264     characterLayoutInfo.mIsVisible = false;
1265   }
1266 }
1267
1268 bool CalculateVisibilityForEllipsizeEndOriginal( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1269                                                  const EllipsizeParameters& ellipsizeParameters )
1270 {
1271   bool isPartiallyVisible = false;
1272
1273   if( !IsVisible( ellipsizeParameters.mPosition,
1274                   characterLayoutInfo.mSize,
1275                   ellipsizeParameters.mEllipsizeBoundary,
1276                   FULLY_VISIBLE_WIDTH ) )
1277   {
1278     // The character doesn't fit in the text-view's width.
1279     characterLayoutInfo.mIsVisible = false;
1280
1281     // Checks if the character is partially visible (it's cut by the boundary)
1282     isPartiallyVisible = IsVisible( ellipsizeParameters.mPosition,
1283                                     characterLayoutInfo.mSize,
1284                                     ellipsizeParameters.mEllipsizeBoundary,
1285                                     PARTIALLY_VISIBLE_WIDTH );
1286   }
1287   else
1288   {
1289     // The character fits in the text-view's width. Set it to visible.
1290     characterLayoutInfo.mIsVisible = true;
1291   }
1292
1293   return isPartiallyVisible;
1294 }
1295
1296 bool CalculateVisibilityForEllipsizeEnd( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1297                                          const EllipsizeParameters& ellipsizeParameters )
1298 {
1299   bool isPartiallyVisible = false;
1300
1301   if( !IsVisible( ellipsizeParameters.mPosition,
1302                   characterLayoutInfo.mSize,
1303                   ellipsizeParameters.mEllipsizeBoundary,
1304                   FULLY_VISIBLE ) )
1305   {
1306     // The character is not fully visible. Needs to check if it's partially visible.
1307     characterLayoutInfo.mIsVisible = false;
1308
1309     // Checks if the character doesn't cut the bottom edge of the text-view.
1310     const bool fullyVisibleHeight = IsVisible( ellipsizeParameters.mPosition,
1311                                                characterLayoutInfo.mSize,
1312                                                ellipsizeParameters.mEllipsizeBoundary,
1313                                                FULLY_VISIBLE_HEIGHT );
1314
1315     // Checks if the character cuts the right edge of the text-view.
1316     const bool partiallyVisibleWidth = IsVisible( ellipsizeParameters.mPosition,
1317                                                   characterLayoutInfo.mSize,
1318                                                   ellipsizeParameters.mEllipsizeBoundary,
1319                                                   PARTIALLY_VISIBLE_WIDTH );
1320
1321     // Character will be ellipsized if it cuts the right edge of the text-view but fits completely in the text-view's height.
1322     isPartiallyVisible = ( fullyVisibleHeight && partiallyVisibleWidth );
1323   }
1324   else
1325   {
1326     // The character fits in the boundary of the text-view. Set it to visible.
1327     characterLayoutInfo.mIsVisible = true;
1328   }
1329
1330   return isPartiallyVisible;
1331 }
1332
1333 void CalculateVisibilityForEllipsize( const Internal::TextView::LayoutParameters& layoutParameters,
1334                                       TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo,
1335                                       EllipsizeParameters& ellipsizeParameters,
1336                                       TextView::RelayoutData& relayoutData )
1337 {
1338   // Calculates visibility for EllipsizeEnd exceed policies.
1339
1340   // It defines a boundary on the right side of the text-view by substracting the ellipsize-text's size (...) to the text-view's size.
1341   // If a character is cut by this boundary and the whole line (if the multi-line policy is split-by-new-line-char)
1342   // or the whole word (if the multi-line policy is split-by-word) doesn't fit in the text-view's width, then it's replaced by the ellipsize-text.
1343
1344   // Position of the character used to do the visibility test.
1345   ellipsizeParameters.mPosition = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1346                                            characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1347                                            characterLayoutInfo.mPosition.z );
1348
1349   // Text will be ellipsized if a character is partially visible (it's cut by the boundary defined in the right side of the text-view).
1350   bool isPartiallyVisible = false;
1351
1352   // Checks if the whole line or the whole word fits in the text-view's width accordingly with the multiline policy.
1353   const bool fitsInWidth = ( Toolkit::TextView::SplitByNewLineChar == layoutParameters.mMultilinePolicy ) ? ellipsizeParameters.mLineFits: ellipsizeParameters.mWordFits;
1354
1355   // Will only ellipsize the text if it cuts the right vertical edge and it doesn't fit in the text-view's width.
1356   if( fitsInWidth )
1357   {
1358     // The line or word fits completely inside the text-view's width. Nothing else to do.
1359     characterLayoutInfo.mIsVisible = true;
1360   }
1361   else
1362   {
1363     // The line or word doesn't fit in the text-view's width.
1364
1365     // Calculates visibility for each type of ellipsize policies.
1366     switch( layoutParameters.mExceedPolicy )
1367     {
1368       case TextView::EllipsizeEndOriginal:
1369       {
1370         // Ellipsizes the text if it doesn't fit in the width but it doesn't ellipsize if the text doesn't fit in the height.
1371
1372         isPartiallyVisible = CalculateVisibilityForEllipsizeEndOriginal( characterLayoutInfo,
1373                                                                          ellipsizeParameters );
1374
1375         break;
1376       }
1377       case TextView::SplitEllipsizeEnd:
1378       case TextView::EllipsizeEnd:
1379       {
1380         // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1381
1382         isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1383                                                                  ellipsizeParameters );
1384
1385         break;
1386       }
1387       default:
1388       {
1389         DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1390         break;
1391       }
1392     }
1393   }
1394
1395   // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1396   // In that case, the charater needs to be replaced by the ellipsize text.
1397   ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1398 }
1399
1400 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1401                                TextView::RelayoutData& relayoutData )
1402 {
1403   // The default ellipsize text is '...' and all dots have the same style. However, a differernt ellipsize text could be set and it can have characters with differernt styles.
1404   // The code bellow creates the text-actors needed for the ellipsize text.
1405
1406   // Set ellipsize's position by the end of visible text.
1407   Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1408   // Stores current ellipsize text.
1409   Text ellipsizeText;
1410   // Stores current ellipsize style.
1411   TextStyle ellipsizeStyle;
1412   // Stores the current size.
1413   Size ellipsizeSize;
1414   //Whether current glyph is an emoticon.
1415   bool isColorGlyph = false;
1416
1417   float bearingOffset = 0.f;
1418
1419   // Create ellipsize text-actor.
1420   std::size_t characterIndex = 0u;
1421   for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1422          endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1423        ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1424        ++ellipsizeCharacterLayoutIt, ++characterIndex )
1425   {
1426     const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1427     const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) );
1428
1429     if( isColorGlyph ||
1430         ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) ||
1431         ( ellipsizeStyle != style ) )
1432     {
1433       // The style is different, so a new text-actor is needed.
1434       if( !ellipsizeText.IsEmpty() )
1435       {
1436         // It only creates a text-actor if there is any text.
1437         RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1438         ellipsizeGlyphActor.SetSize( ellipsizeSize );
1439         ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1440
1441         // Updates the position for the next text-actor.
1442         ellipsizePosition.x += ellipsizeSize.width;
1443
1444         // Adds the text-actor to the list.
1445         relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1446       }
1447
1448       // Resets the current ellipsize info.
1449       ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1450       ellipsizeStyle = style;
1451       ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1452       isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph;
1453
1454       bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1455     }
1456     else
1457     {
1458       // Updates text and size with the new character.
1459       ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] );
1460       TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1461     }
1462   }
1463
1464   if( !ellipsizeText.IsEmpty() )
1465   {
1466     // Creates the last glyph-actor.
1467     RenderableActor ellipsizeGlyphActor = CreateGlyphActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1468     ellipsizeGlyphActor.SetSize( ellipsizeSize );
1469     ellipsizeGlyphActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1470
1471     // Adds the glyph-actor to the list.
1472     relayoutData.mEllipsizedGlyphActors.push_back( ellipsizeGlyphActor );
1473   }
1474 }
1475
1476 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1477                     EllipsizeParameters& ellipsizeParameters,
1478                     TextView::RelayoutData& relayoutData )
1479 {
1480   // Traverses the text layout info from the first character of the line
1481   // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1482
1483   // Indices to the first character of the line.
1484   TextViewProcessor::TextInfoIndices firstIndices;
1485   TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1486                                                          relayoutData.mTextLayoutInfo,
1487                                                          firstIndices );
1488
1489   // Indices to the last character of the line.
1490   TextViewProcessor::TextInfoIndices lastIndices;
1491   TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1492                                                          relayoutData.mTextLayoutInfo,
1493                                                          lastIndices );
1494
1495   // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1496   // This is the boundary used to check if a character have to be ellipsized.
1497   ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1498   ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1499
1500   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex,
1501          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u;
1502        paragraphLayoutIt != endParagraphLayoutIt;
1503        ++paragraphLayoutIt )
1504   {
1505     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1506
1507     ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1508
1509     if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1510     {
1511       ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1512     }
1513
1514     bool firstWord = true;
1515     bool lastWord = false;
1516
1517     std::size_t wordCount = 0u;
1518
1519     const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1520     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1521
1522     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex,
1523            endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u;
1524          wordLayoutIt != endWordLayoutIt;
1525          ++wordLayoutIt, ++wordCount )
1526     {
1527       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1528
1529       if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex )
1530       {
1531         lastWord = true;
1532       }
1533
1534       const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1535       const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u;
1536       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1537              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u;
1538            characterLayoutIt != endCharacterLayoutIt;
1539            ++characterLayoutIt )
1540       {
1541         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1542
1543         if( ellipsizeParameters.mEllipsizeLine )
1544         {
1545           // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1546           CalculateVisibilityForEllipsize( layoutParameters,
1547                                            characterLayoutInfo,
1548                                            ellipsizeParameters,
1549                                            relayoutData );
1550
1551           if( ellipsizeParameters.mCreateEllipsizedTextActors )
1552           {
1553             // Create ellipsize text-actors if the character needs to be replaced.
1554             CreateEllipsizeTextActor( ellipsizeParameters,
1555                                       relayoutData );
1556           }
1557         }
1558         else
1559         {
1560           if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1561               ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ))
1562           {
1563             if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1564             {
1565               // Make characters invisible.
1566               characterLayoutInfo.mIsVisible = false;
1567             }
1568           }
1569         }
1570       } // end characters
1571       firstWord = false;
1572     } // end words
1573   } // end paragraphs
1574 }
1575
1576 void SetTextVisible( TextView::RelayoutData& relayoutData )
1577 {
1578   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1579          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1580        paragraphLayoutIt != endParagraphLayoutIt;
1581        ++paragraphLayoutIt )
1582   {
1583     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1584     std::size_t characterIndex = 0u;
1585
1586     const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1587     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1588
1589     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1590            endWordLayoutIt = wordsLayoutInfo.end();
1591          wordLayoutIt != endWordLayoutIt;
1592          ++wordLayoutIt )
1593     {
1594       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1595
1596       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1597              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1598            characterLayoutIt != endCharacterLayoutIt;
1599            ++characterLayoutIt, ++characterIndex )
1600       {
1601         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1602
1603         characterLayoutInfo.mIsVisible = true;
1604         delete characterLayoutInfo.mGradientInfo;
1605         characterLayoutInfo.mGradientInfo = NULL;
1606         characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a;
1607       } // end characters
1608     } // end words
1609   } // end paragraphs
1610
1611   // Updates the visibility for text-input..
1612   for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1613          endIt = relayoutData.mCharacterLayoutInfoTable.end();
1614        it != endIt;
1615        ++it )
1616   {
1617     Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1618
1619     characterLayoutInfo.mIsVisible = true;
1620   }
1621 }
1622
1623 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1624                               const TextView::VisualParameters& visualParameters,
1625                               TextView::RelayoutData& relayoutData )
1626 {
1627   RelayoutParameters relayoutParameters;
1628   FadeParameters fadeParameters;
1629
1630   // Calculates the fade thresholds (from where the text starts to fade out). If any of the fade boundaries is zero, it sets a very small value just to avoid a zero division.
1631   fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1632   fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1633   fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1634   fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1635   fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1636   fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1637   fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1638   fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1639   fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1640   fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1641   fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1642   fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1643   fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1644   fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1645   fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1646   fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1647
1648   // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1649   fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1650   fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1651   fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1652   fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1653
1654   // Traverses all characters and calculates the visibility.
1655
1656   std::size_t infoTableCharacterIndex = 0u;
1657
1658   relayoutParameters.mIndices.mParagraphIndex = 0u;
1659
1660   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
1661          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
1662        paragraphLayoutIt != endParagraphLayoutIt;
1663        ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
1664   {
1665     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
1666
1667     std::size_t characterIndex = 0u;
1668     relayoutParameters.mIndices.mWordIndex = 0u;
1669
1670     const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
1671     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
1672
1673     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
1674            endWordLayoutIt = wordsLayoutInfo.end();
1675          wordLayoutIt != endWordLayoutIt;
1676          ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1677     {
1678       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1679
1680       relayoutParameters.mIsFirstCharacterOfWord = true;
1681       relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1682       relayoutParameters.mIndices.mCharacterIndex = 0u;
1683
1684       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1685              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1686            characterLayoutIt != endCharacterLayoutIt;
1687            ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex )
1688       {
1689         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1690
1691         relayoutParameters.mIsVisible = true;
1692         fadeParameters.mIsPartiallyVisible = false;
1693
1694         // Calculates the visibility for the current character.
1695         CalculateVisibilityForFade( layoutParameters,
1696                                     characterLayoutInfo,
1697                                     *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ),
1698                                     relayoutParameters,
1699                                     fadeParameters,
1700                                     relayoutData );
1701
1702         // Updates the visibility for text-input..
1703         std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + relayoutData.mCharacterVisualToLogicalMap[infoTableCharacterIndex];
1704
1705         Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1706
1707         characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1708
1709         relayoutParameters.mIsFirstCharacterOfWord = false;
1710       } // end character
1711     } // end words
1712   } // end paragraphs
1713 }
1714
1715 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1716                                    const TextView::VisualParameters& visualParameters,
1717                                    TextView::RelayoutData& relayoutData )
1718 {
1719   // TODO check ellipsis with rtl text.
1720
1721   // Traverses the lines and checks which ones doesn't fit in the text-view's boundary.
1722   for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1723        lineInfoIt != endLineInfoIt;
1724        ++lineInfoIt )
1725   {
1726     const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1727
1728     // To check if a line fits in the text-view's boundary,
1729     // get the position of the first character is needed and do the test
1730     // with the line size.
1731
1732     // An bearing offset may have been applied to the first character so it's needed to
1733     // get the start position of the line.
1734
1735     // Some parameters used in the CalculateVisibilityForEllipsize() function.
1736     EllipsizeParameters ellipsizeParameters;
1737
1738     // Retrieves the first index and the last index of the line.
1739     ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1740     ellipsizeParameters.mLastIndex = 0u;
1741     if( ( lineInfoIt + 1u ) != endLineInfoIt )
1742     {
1743       const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) );
1744       ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u;
1745     }
1746     else
1747     {
1748       ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u;
1749     }
1750
1751     // Retrieves the first character of the line and build the position of the line with the bearing.
1752     const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1753
1754     // Calculates the bearing offset applied to the first character.
1755     const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1756
1757     // Build the position of the line by removing the bearing offset from the first character's position.
1758     const Vector3 position( characterInfo.mPosition.x,
1759                             characterInfo.mPosition.y + bearingOffset,
1760                             characterInfo.mPosition.z );
1761
1762     // Checks if the line needs to be ellipsized,
1763     ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1764                                                               lineInfo.mSize,
1765                                                               relayoutData.mTextViewSize,
1766                                                               FULLY_VISIBLE_WIDTH );
1767
1768     // If the exceed policy is EllipsizeEndOriginal it's enough to check
1769     // if the line fits in the width.
1770     ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1771
1772     // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1773     // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1774     ellipsizeParameters.mIsLineHeightFullyVisible = true;
1775     ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1776     if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) ||
1777         ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy ) )
1778     {
1779       // Need to check if there is lines which doesn't fit in the height.
1780
1781       ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1782                                                                  lineInfo.mSize,
1783                                                                  relayoutData.mTextViewSize,
1784                                                                  FULLY_VISIBLE_HEIGHT );
1785
1786       ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1787
1788       if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1789       {
1790         // Current line is not ellipsized.
1791         // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1792         Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u;
1793         if( nextLineInfoIt != endLineInfoIt )
1794         {
1795           // Retrives the position of the first character of the line and remove
1796           // the bearing offset to build to build the position of the line.
1797           const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1798           const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1799
1800           const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1801
1802           const Vector3 position( characterInfo.mPosition.x,
1803                                   characterInfo.mPosition.y + bearingOffset,
1804                                   characterInfo.mPosition.z );
1805
1806           ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1807                                                                          nextLineInfo.mSize,
1808                                                                          relayoutData.mTextViewSize,
1809                                                                          FULLY_VISIBLE_HEIGHT );
1810
1811           // If the next line is not visible, current line have to be ellipsized.
1812           ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1813         }
1814       }
1815     }
1816
1817     if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1818     {
1819       ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1820     }
1821
1822     // Sets the line descender.
1823     ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1824
1825     // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1826     EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1827   }
1828 }
1829
1830 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1831                        const TextView::VisualParameters& visualParameters,
1832                        TextView::RelayoutData& relayoutData )
1833 {
1834   switch( layoutParameters.mExceedPolicy )
1835   {
1836     case TextView::FadeOriginal:
1837     case TextView::OriginalFade:
1838     case TextView::Fade:
1839     case TextView::SplitFade: // Fall through
1840     {
1841       UpdateVisibilityForFade( layoutParameters,
1842                                visualParameters,
1843                                relayoutData );
1844       break;
1845     }
1846     case TextView::EllipsizeEndOriginal:
1847     case TextView::SplitEllipsizeEnd:
1848     case TextView::EllipsizeEnd: // Fall through
1849     {
1850       // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1851       SetTextVisible( relayoutData );
1852
1853       UpdateVisibilityForEllipsize( layoutParameters,
1854                                     visualParameters,
1855                                     relayoutData );
1856       break;
1857     }
1858     default:
1859     {
1860       SetTextVisible( relayoutData );
1861       break;
1862     }
1863   }
1864 }
1865
1866 /**
1867  * Creates an image actor for the emoticon.
1868  *
1869  * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1870  * @param[in,out] characterLayout Layout info for the character.
1871  * @param[in] character The character.
1872  */
1873 void CreateEmoticon( const TextView::VisualParameters& visualParameters,
1874                      TextViewProcessor::CharacterLayoutInfo& characterLayout,
1875                      const Character& character )
1876 {
1877   // The character is an emoticon.
1878   ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1879   if( !imageActor )
1880   {
1881     imageActor = ImageActor::New();
1882
1883     GlyphImage image = GlyphImage::New( character );
1884
1885     if( image )
1886     {
1887       imageActor.SetImage( image );
1888     }
1889   }
1890
1891   imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x,
1892                                    characterLayout.mPosition.y + characterLayout.mOffset.y,
1893                                    characterLayout.mPosition.z ) );
1894   imageActor.SetSize( characterLayout.mSize );
1895
1896   // Sets the sort modifier value.
1897   imageActor.SetSortModifier( visualParameters.mSortModifier );
1898
1899   characterLayout.mGlyphActor = imageActor;
1900 }
1901
1902 /**
1903  * Creates text-actors for the given text.
1904  *
1905  * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
1906  * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
1907  * @param[in,out] paragraph Layout info for the paragraph.
1908  * @param[in,out] wordLayout Layout info for the word.
1909  * @param[in,out] characterLayout Layout info for the character.
1910  * @param[in] character The character.
1911  * @param[in] style The character's style.
1912  * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set.
1913  * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
1914  * @param[in,out] textActorCreated Whether a text-actor
1915  */
1916 void CreateTextActor( const TextView::VisualParameters& visualParameters,
1917                       TextView::RelayoutData& relayoutData,
1918                       const TextViewProcessor::ParagraphLayoutInfo& paragraph,
1919                       TextViewProcessor::WordLayoutInfo& wordLayout,
1920                       TextViewProcessor::CharacterLayoutInfo& characterLayout,
1921                       const Character& character,
1922                       const TextStyle& style,
1923                       CurrentTextActorInfo& currentTextActorInfo,
1924                       bool createGlyphActors,
1925                       bool& textActorCreated )
1926 {
1927   textActorCreated = false;
1928
1929   // Set the text-actor for the current traversed text.
1930   if( currentTextActorInfo.textActor )
1931   {
1932     if( ( NULL != currentTextActorInfo.characterLayout ) &&
1933         currentTextActorInfo.characterLayout->mSetText )
1934     {
1935       currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1936       currentTextActorInfo.characterLayout->mSetText = false;
1937     }
1938     currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1939     currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1940
1941     SetVisualParameters( currentTextActorInfo,
1942                          visualParameters,
1943                          relayoutData,
1944                          paragraph.mSize.height );
1945   }
1946
1947   float rightToLeftOffset = 0.f;
1948   if( character.IsWhiteSpace() )
1949   {
1950     // In left to right text, a word never starts with a white space but
1951     // it may happen in right to left text as the text is reversed.
1952     // The text alignment and justification offset is calculated without this white space.
1953     // It causes a missalignment which can be corrected by removing the size of the white space.
1954     rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor;
1955   }
1956
1957   // Whether this word is not a white space or if it is, it is underlined.
1958   // Don't want to create text-actors for white spaces unless they are underlined.
1959   bool isNotWhiteSpace = ( TextViewProcessor::NoSeparator == wordLayout.mType ) || ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() );
1960
1961   if( isNotWhiteSpace )
1962   {
1963     currentTextActorInfo.text = Text( character );
1964   }
1965   else
1966   {
1967     currentTextActorInfo.text = Text();
1968   }
1969   currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset,
1970                                            characterLayout.mPosition.y + characterLayout.mOffset.y,
1971                                            characterLayout.mPosition.z );
1972   currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor;
1973
1974   currentTextActorInfo.color = style.GetTextColor();
1975   currentTextActorInfo.color.a = characterLayout.mColorAlpha;
1976
1977   TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1978
1979   if( createGlyphActors &&  isNotWhiteSpace )
1980   {
1981     textActorCreated = true;
1982     if( textActor )
1983     {
1984       // Try to reuse first the text-actor of this character.
1985       textActor.SetTextStyle( style );
1986     }
1987     else
1988     {
1989       // If there is no text-actor, try to retrieve one from the cache.
1990       textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1991
1992       // If still there is no text-actor, create one.
1993       if( !textActor )
1994       {
1995         TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
1996         textActor = TextActor::New( Text(), parameters );
1997       }
1998       else
1999       {
2000         textActor.SetTextStyle( style );
2001       }
2002     }
2003     characterLayout.mSetText = true;
2004     currentTextActorInfo.characterLayout = &characterLayout;
2005
2006     characterLayout.mGlyphActor = textActor;
2007   }
2008
2009   // Update the current text-actor.
2010   currentTextActorInfo.textActor = textActor;
2011 }
2012
2013 /**
2014  * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position.
2015  *
2016  * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending).
2017  * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info.
2018  * @param[in,out] paragraph Layout info for the paragraph.
2019  * @param[in,out] characterGlobalIndex Index to the character within the whole text.
2020  * @param[in,out] lineLayoutInfoIndex Index to the table of lines.
2021  * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles.
2022  */
2023 void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters,
2024                                       TextView::RelayoutData& relayoutData,
2025                                       TextViewProcessor::ParagraphLayoutInfo& paragraphLayout,
2026                                       std::size_t& characterGlobalIndex,
2027                                       std::size_t& lineLayoutInfoIndex,
2028                                       bool createGlyphActors )
2029 {
2030   CurrentTextActorInfo currentTextActorInfo;
2031   currentTextActorInfo.characterLayout = NULL;
2032
2033   const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines.
2034   bool lineLayoutEnd = false;    // Whether lineLayoutInfoIndex points at the last line.
2035   bool textActorCreated = false; // Whether a text actor has been created for this the current group of characters traversed.
2036
2037   TextStyle currentStyle;        // style for the current text-actor.
2038
2039   TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor.
2040                                                                // start point for the current text-actor.
2041                                                                // end point for the current text-actor.
2042
2043   bool currentIsColorGlyph = false;      // Whether current glyph is an emoticon.
2044
2045   std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
2046
2047   // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2048   const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout;
2049
2050   TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo;
2051   Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText;
2052   Vector<TextStyle*>& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles;
2053
2054   // In case the previous right to left layout has been cleared, all text-actors have been removed as well. If this bool is set to true, text-actors will be created again.
2055   createGlyphActors = createGlyphActors || ( ( isRightToLeftLayout ) ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false );
2056
2057   std::size_t characterParagraphIndex = 0u;   // Index to the character (within the paragraph).
2058   for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2059        wordIt != wordEndIt;
2060        ++wordIt )
2061   {
2062     TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt );
2063
2064     for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end();
2065          characterIt != characterEndIt;
2066          ++characterIt )
2067     {
2068       TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt );
2069
2070       // Check if there is a new line.
2071       const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
2072
2073       if( newLine )
2074       {
2075         // Point to the next line.
2076         ++lineLayoutInfoIndex;
2077         if( lineLayoutInfoIndex >= lineLayoutInfoSize )
2078         {
2079           // Arrived at last line.
2080           lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
2081         }
2082         textActorCreated = false;
2083       }
2084
2085       // Do not create a glyph-actor if there is no text.
2086       const Character character = text[characterParagraphIndex];
2087       const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) );
2088
2089       // Check if the character has the same gradient info than the current one.
2090       bool differentGradientInfo = false;
2091       if( characterLayout.mGradientInfo && currentGradientInfo )
2092       {
2093               differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) ||
2094                 ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) ||
2095                 ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint );
2096       }
2097       else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) )
2098       {
2099               differentGradientInfo = true;
2100       }
2101
2102       if( ( createGlyphActors && !textActorCreated ) ||
2103           characterLayout.mIsColorGlyph ||
2104           differentGradientInfo ||
2105           ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) ||
2106           ( style != currentStyle ) )
2107       {
2108         characterLayout.mSetText = false;
2109         characterLayout.mSetStyle = false;
2110
2111         if( characterLayout.mIsColorGlyph )
2112         {
2113           CreateEmoticon( visualParameters,
2114                           characterLayout,
2115                           character );
2116
2117           characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2118           characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2119         }
2120         else
2121         {
2122           // There is a new style or a new line.
2123
2124           CreateTextActor( visualParameters,
2125                            relayoutData,
2126                            paragraphLayout,
2127                            wordLayout,
2128                            characterLayout,
2129                            character,
2130                            style,
2131                            currentTextActorInfo,
2132                            createGlyphActors,
2133                            textActorCreated );
2134
2135           if( textActorCreated )
2136           {
2137             characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2138             characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2139           }
2140         }
2141
2142         // Update style to be checked with next characters.
2143         currentStyle = style;
2144         currentGradientInfo = characterLayout.mGradientInfo;
2145         currentIsColorGlyph = characterLayout.mIsColorGlyph;
2146       }
2147       else
2148       {
2149         DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
2150
2151         // Same style than previous one.
2152
2153         // Add the character to the current text-actor and update the size.
2154         if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) )
2155         {
2156           currentTextActorInfo.text.Append( character );
2157
2158           currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) );
2159           currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor;
2160           currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor );
2161         }
2162       }
2163
2164       if( ( createGlyphActors ) &&
2165           !characterLayout.mIsColorGlyph &&
2166           !textActorCreated )
2167       {
2168         TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
2169         if( textActor )
2170         {
2171           // There is a previously created text-actor for this character.
2172           // If this character has another one put it into the cache.
2173           textActor.SetText( "" );
2174           textActorsToRemove.push_back( textActor );
2175         }
2176
2177         if( characterLayout.mGlyphActor )
2178         {
2179           characterLayout.mGlyphActor.Reset();
2180         }
2181       }
2182       ++characterGlobalIndex;
2183       ++characterParagraphIndex;
2184     } // characters
2185   } // words
2186
2187   if( !currentTextActorInfo.text.IsEmpty() )
2188   {
2189     if( currentTextActorInfo.textActor )
2190     {
2191       if( ( NULL != currentTextActorInfo.characterLayout ) &&
2192           currentTextActorInfo.characterLayout->mSetText )
2193       {
2194         currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
2195         currentTextActorInfo.characterLayout->mSetText = false;
2196       }
2197       currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
2198       currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
2199
2200       SetVisualParameters( currentTextActorInfo,
2201                            visualParameters,
2202                            relayoutData,
2203                            paragraphLayout.mSize.height );
2204     }
2205   }
2206
2207   // Insert the spare text-actors into the cache.
2208   relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
2209 }
2210
2211 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
2212                           TextView::RelayoutData& relayoutData,
2213                           bool createGlyphActors )
2214 {
2215   if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
2216   {
2217     // nothing to do if there is no paragraphs.
2218     return;
2219   }
2220
2221   std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text).
2222   std::size_t lineLayoutInfoIndex = 0u;  // Index to the line info.
2223
2224   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2225        paragraphIt != paragraphEndIt;
2226        ++paragraphIt )
2227   {
2228     TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2229
2230     UpdateTextActorInfoForParagraph( visualParameters,
2231                                      relayoutData,
2232                                      paragraph,
2233                                      characterGlobalIndex,
2234                                      lineLayoutInfoIndex,
2235                                      createGlyphActors );
2236   } // paragraphs
2237
2238   // Set visual parameters for ellipsis renderable actors.
2239   for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2240          endIt = relayoutData.mEllipsizedGlyphActors.end();
2241        it != endIt;
2242        ++it )
2243   {
2244     RenderableActor glyphActor = ( *it );
2245
2246     glyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
2247     glyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
2248
2249     // Sets the sort modifier value.
2250     glyphActor.SetSortModifier( visualParameters.mSortModifier );
2251
2252     // Enables or disables the blending.
2253     glyphActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
2254   }
2255 }
2256
2257 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
2258 {
2259   // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2260   //
2261   // Note that relayoutData.mTextLayoutInfo contains layout info per paragraph but these paragraphs are the result of split the whole text every time a '\n' is found.
2262   // According with the layout option, one of this paragraphs could be laid-out in more than one line.
2263
2264   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2265        paragraphIt != paragraphEndIt;
2266        ++paragraphIt )
2267   {
2268     TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2269
2270     std::size_t characterIndex = 0u;
2271
2272     const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2273     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2274
2275     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2276          wordIt != wordEndIt;
2277          ++wordIt )
2278     {
2279       TextViewProcessor::WordLayoutInfo& word( *wordIt );
2280
2281       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2282            characterIt != characterEndIt;
2283            ++characterIt, ++characterIndex )
2284       {
2285         TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2286         const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2287
2288         // Check if current character is the first of a new line
2289         const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
2290           ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
2291         if( isNewLine )
2292         {
2293           ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2294         }
2295
2296         if( style.IsUnderlineEnabled() )
2297         {
2298           if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
2299               isNewLine )                                     // Current character is underlined and is the first of current line.
2300           {
2301             // Create a new underline info for the current underlined characters.
2302             UnderlineInfo underlineInfo;
2303             underlineInfo.mMaxHeight = character.mSize.height;
2304             underlineInfo.mMaxThickness = character.mUnderlineThickness;
2305             underlineInfo.mPosition = character.mUnderlinePosition;
2306
2307             textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
2308
2309             textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
2310           }
2311           else
2312           {
2313             // Retrieve last underline info and update it if current underline thickness is bigger.
2314             UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) );
2315
2316             underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height );
2317
2318             if( character.mUnderlineThickness > underlineInfo.mMaxThickness )
2319             {
2320               underlineInfo.mMaxThickness = character.mUnderlineThickness;
2321               underlineInfo.mPosition = character.mUnderlinePosition;
2322             }
2323           }
2324         }
2325         else
2326         {
2327           textUnderlineStatus.mCurrentUnderlineStatus = false;
2328         }
2329
2330         ++textUnderlineStatus.mCharacterGlobalIndex;
2331       } // end characters.
2332     } // end words.
2333   } // end paragraphs.
2334 }
2335
2336 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
2337 {
2338   // Stores for each group of consecutive underlined characters in each line its maximum thicknes, its position of that thickness and the maximum character's height.
2339   TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
2340
2341   // Traverse the whole text to find all groups of consecutive underlined characters in the same line.
2342   CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
2343
2344   if( textUnderlineStatus.mUnderlineInfo.empty() )
2345   {
2346     // There is no underlined text. Just exit.
2347     return;
2348   }
2349
2350   // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
2351   // Traverse the whole text and set the previously stored underline info in the text style.
2352
2353   std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
2354   std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
2355
2356   UnderlineInfo underlineInfo;
2357
2358   if( underlineInfoIt < underlineInfoEndIt )
2359   {
2360     underlineInfo = ( *underlineInfoIt );
2361   }
2362
2363   // Whether current text is underlined.
2364   textUnderlineStatus.mCurrentUnderlineStatus = false;
2365   textUnderlineStatus.mCharacterGlobalIndex = 0u;
2366   textUnderlineStatus.mLineGlobalIndex = 0u;
2367
2368   float currentLineHeight = 0.f;
2369   float currentLineAscender = 0.f;
2370
2371   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2372        paragraphIt != paragraphEndIt;
2373        ++paragraphIt )
2374   {
2375     TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt );
2376     std::size_t characterIndex = 0u;
2377
2378     const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout;
2379     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo;
2380
2381     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end();
2382          wordIt != wordEndIt;
2383          ++wordIt )
2384     {
2385       TextViewProcessor::WordLayoutInfo& word( *wordIt );
2386
2387       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
2388            characterIt != characterEndIt;
2389            ++characterIt, ++characterIndex )
2390       {
2391         TextViewProcessor::CharacterLayoutInfo& character( *characterIt );
2392         TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) );
2393
2394         // Check if current character is the first of a new line
2395
2396         bool isNewLine = false;
2397
2398         if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
2399         {
2400           const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
2401           isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
2402
2403           if( isNewLine )
2404           {
2405             currentLineHeight = lineLayoutInfo.mSize.height;
2406             currentLineAscender = lineLayoutInfo.mAscender;
2407             ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
2408           }
2409         }
2410
2411         if( style.IsUnderlineEnabled() )
2412         {
2413           if( textUnderlineStatus.mCurrentUnderlineStatus )
2414           {
2415             if( isNewLine )
2416             {
2417               // Retrieves the thickness and position for the next piece of underlined text.
2418               if( underlineInfoIt < underlineInfoEndIt )
2419               {
2420                 ++underlineInfoIt;
2421                 if( underlineInfoIt < underlineInfoEndIt )
2422                 {
2423                   underlineInfo = *underlineInfoIt;
2424                 }
2425               }
2426             }
2427           }
2428
2429           textUnderlineStatus.mCurrentUnderlineStatus = true;
2430
2431           // Before setting the position it needs to be adjusted to match the base line.
2432           const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender );
2433           const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset;
2434
2435           // Sets the underline's parameters.
2436           style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset );
2437
2438           // Mark the character to be set the new style into the text-actor.
2439           character.mSetStyle = true;
2440         }
2441         else
2442         {
2443           if( textUnderlineStatus.mCurrentUnderlineStatus )
2444           {
2445             textUnderlineStatus.mCurrentUnderlineStatus = false;
2446
2447             // Retrieves the thickness and position for the next piece of underlined text.
2448             if( underlineInfoIt < underlineInfoEndIt )
2449             {
2450               ++underlineInfoIt;
2451               if( underlineInfoIt < underlineInfoEndIt )
2452               {
2453                 underlineInfo = *underlineInfoIt;
2454               }
2455             }
2456           }
2457         }
2458
2459         ++textUnderlineStatus.mCharacterGlobalIndex;
2460       } // end of characters.
2461     } // end of word.
2462   } // end of paragraphs.
2463 }
2464
2465 void RemoveGlyphActors( Actor textView,
2466                         const std::vector<RenderableActor>& glyphActors )
2467 {
2468   // Removes previously inserted renderable-actors.
2469   // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
2470   // renderable-actors to the text-view. A handle to these renderable-actors are stored and passed to this function
2471   // in order to remove 'only' renderable-actors added by these functions.
2472   // Any other actor added by a programmer or application won't be removed.
2473
2474   for( std::vector<RenderableActor>::const_reverse_iterator it = glyphActors.rbegin(), endIt = glyphActors.rend(); it != endIt; ++it )
2475   {
2476     textView.Remove( *it );
2477   }
2478 }
2479
2480 void InsertToTextView( Actor textView,
2481                        TextView::RelayoutData& relayoutData )
2482 {
2483   // Add text-actors to the text-view.
2484
2485   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
2486          endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
2487        paragraphLayoutIt != endParagraphLayoutIt;
2488        ++paragraphLayoutIt )
2489   {
2490     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
2491
2492     // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout.
2493     const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout;
2494     TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo;
2495
2496     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(),
2497            endWordLayoutIt = wordsLayoutInfo.end();
2498          wordLayoutIt != endWordLayoutIt;
2499          ++wordLayoutIt )
2500     {
2501       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
2502
2503       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
2504              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
2505            characterLayoutIt != endCharacterLayoutIt;
2506            ++characterLayoutIt )
2507       {
2508         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
2509
2510         if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor.
2511         {
2512           //Add to the text-view.
2513           textView.Add( characterLayoutInfo.mGlyphActor );
2514           relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor );
2515         }
2516       } // end character
2517     } // end words
2518   } // end paragraphs
2519
2520   for( std::vector<RenderableActor>::iterator it = relayoutData.mEllipsizedGlyphActors.begin(),
2521          endIt = relayoutData.mEllipsizedGlyphActors.end();
2522        it != endIt;
2523        ++it )
2524   {
2525     RenderableActor glyphActor = ( *it );
2526
2527     //Add to the text-view.
2528     textView.Add( glyphActor );
2529     relayoutData.mGlyphActors.push_back( glyphActor );
2530   }
2531   relayoutData.mEllipsizedGlyphActors.clear();
2532 }
2533
2534 RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, TextActorCache& cache )
2535 {
2536   TextActor textActor = cache.RetrieveTextActor();
2537
2538   if( textActor )
2539   {
2540     // Update the text-actor.
2541     textActor.SetText( text );
2542     textActor.SetTextStyle( style );
2543   }
2544   else
2545   {
2546     // The text-actor cache is empty. Create a new one.
2547     TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF );
2548     textActor = TextActor::New( text, parameters );
2549   }
2550
2551   return textActor;
2552 }
2553
2554 } // namespace TextViewRelayout
2555
2556 } // namespace Internal
2557
2558 } // namespace Toolkit
2559
2560 } // namespace Dali