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