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