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