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