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