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