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