[SRUK] Initial copy from Tizen 2.2 version
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / text-view / relayout-utilities.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // FILE HEADER
18
19 #include "relayout-utilities.h"
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/public-api/controls/text-view/text-view.h>
26 #include "text-view-line-processor.h"
27 #include "text-view-word-processor.h"
28 #include "text-view-processor-helper-functions.h"
29 #include "text-view-processor-dbg.h"
30
31 namespace Dali
32 {
33
34 namespace Toolkit
35 {
36
37 namespace Internal
38 {
39
40 namespace TextViewRelayout
41 {
42
43 const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same as the text-view boundary, this constant reduces it in order to avoid a zero division.
44
45 RelayoutParameters::RelayoutParameters()
46 : mPositionOffset(),
47   mLineSize(),
48   mWordSize(),
49   mCharacterSize(),
50   mIndices(),
51   mCharacterGlobalIndex( 0u ),
52   mIsFirstCharacter( false ),
53   mIsFirstCharacterOfWord( false ),
54   mIsNewLine( false ),
55   mIsNewLineCharacter( false ),
56   mIsWhiteSpace( false ),
57   mIsVisible( false )
58 {
59 }
60
61 RelayoutParameters::~RelayoutParameters()
62 {
63 }
64
65 FadeParameters::FadeParameters()
66 : mRightFadeBoundary( 0.f ),
67   mRightFadeThreshold( 0.f ),
68   mRightFadeBoundaryOffset( 0.f ),
69   mRightFadeThresholdOffset( 0.f ),
70   mRightAlphaCoeficients(),
71   mLeftFadeBoundary( 0.f ),
72   mLeftFadeThreshold( 0.f ),
73   mLeftFadeBoundaryOffset( 0.f ),
74   mLeftFadeThresholdOffset( 0.f ),
75   mLeftAlphaCoeficients(),
76   mTopFadeBoundary( 0.f ),
77   mTopFadeThreshold( 0.f ),
78   mTopFadeBoundaryOffset( 0.f ),
79   mTopFadeThresholdOffset( 0.f ),
80   mTopAlphaCoeficients(),
81   mBottomFadeBoundary( 0.f ),
82   mBottomFadeThreshold( 0.f ),
83   mBottomFadeBoundaryOffset( 0.f ),
84   mBottomFadeThresholdOffset( 0.f ),
85   mBottomAlphaCoeficients(),
86   mIsPartiallyVisible( false )
87 {
88 }
89
90 FadeParameters::~FadeParameters()
91 {
92 }
93
94 EllipsizeParameters::EllipsizeParameters()
95 : mPosition(),
96   mLineDescender( 0.f ),
97   mLineWidth( 0.f ),
98   mEllipsizeBoundary(),
99   mFirstIndex( 0u ),
100   mLastIndex( 0u ),
101   mEllipsizeLine( false ),
102   mIsLineWidthFullyVisible( false ),
103   mIsLineHeightFullyVisible( false ),
104   mIsNextLineFullyVisibleHeight( false ),
105   mCreateEllipsizedTextActors( false ),
106   mLineFits( false ),
107   mWordFits( false )
108 {
109 }
110
111 EllipsizeParameters::~EllipsizeParameters()
112 {
113 }
114
115 UnderlineInfo::UnderlineInfo()
116 : mMaxHeight( 0.f ),
117   mMaxThickness( 0.f ),
118   mPosition( 0.f )
119 {
120 }
121
122 UnderlineInfo::~UnderlineInfo()
123 {
124 }
125
126 TextUnderlineStatus::TextUnderlineStatus()
127 : mUnderlineInfo(),
128   mCharacterGlobalIndex( 0u ),
129   mLineGlobalIndex( 0u ),
130   mCurrentUnderlineStatus( false )
131 {
132 }
133
134 TextUnderlineStatus::~TextUnderlineStatus()
135 {
136 }
137
138 SubLineLayoutInfo::SubLineLayoutInfo()
139 : mLineLength( 0.f ),
140   mMaxCharHeight( 0.f ),
141   mMaxAscender( 0.f )
142 {
143 }
144
145 SubLineLayoutInfo::~SubLineLayoutInfo()
146 {
147 }
148
149 /**
150  * Whether the given text-actor exceeds the left or the right boundary of the text-view.
151  *
152  * @param[in] position The position of the text-actor.
153  * @param[in] size The size of the text-actor.
154  * @param[in] parantSize The size of the text-view.
155  *
156  * @return \e true if the text-actor exceeds the left or the right boundary of the text-view.
157  */
158 bool IsExceedingWidth( const Vector3& position, const Size& size, const Size& parentSize )
159 {
160   return ( ( position.x < 0.f ) ||
161            ( position.x + size.width > parentSize.width ) );
162 }
163
164 /**
165  * Whether the given text-actor exceeds the top or the bottom boundary of the text-view.
166  *
167  * @param[in] position The position of the text-actor.
168  * @param[in] size The size of the text-actor.
169  * @param[in] parantSize The size of the text-view.
170  *
171  * @return \e true if the text-actor exceeds the top or the bottom boundary of the text-view.
172  */
173 bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& parentSize )
174 {
175   return ( ( position.y > parentSize.height ) ||
176            ( position.y < size.height ) );
177 }
178
179 /**
180  * Calculates the line length adding the new word or character width.
181  *
182  * It also returns the length of white spaces if they are at the end of the line.
183  *
184  * @param[in] isWhiteSpace Whether the word is a white space.
185  * @param[in] width The width of the character or word.
186  * @param[in] parentWidth The parent width.
187  * @param[out] found Whether the sum of the new character or word is exceding the parent's width.
188  * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width
189  * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line.
190  */
191 void CalculateLineLength( const bool isWhiteSpace, const float width, const float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength )
192 {
193   if( lineLength + width > parentWidth )
194   {
195     found = true;
196     lineLength -= endWhiteSpaceLength;
197   }
198   else
199   {
200     lineLength += width;
201
202     if( isWhiteSpace )
203     {
204       endWhiteSpaceLength += width;
205     }
206     else
207     {
208       endWhiteSpaceLength = 0.f;
209     }
210   }
211 }
212
213 struct CurrentTextActorInfo
214 {
215   TextActor textActor;
216   Text text;
217   Vector3 position;
218   Size size;
219   Vector4 color;
220   Vector4 gradientColor;
221   Vector2 startPoint;
222   Vector2 endPoint;
223 };
224
225 void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo,
226                           const TextView::VisualParameters& visualParameters,
227                           TextView::RelayoutData& relayoutData,
228                           const float lineHeight )
229 {
230   currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color );
231   currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientColor );
232   currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.startPoint );
233   currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.endPoint );
234
235   // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary
236   // due to the trick used to implement it.
237   const Radian& italicsAngle = currentTextActorInfo.textActor.GetItalicsAngle();
238   const float italicsOffset = lineHeight * std::tan( italicsAngle );
239   relayoutData.mTextLayoutInfo.mMaxItalicsOffset = std::max( relayoutData.mTextLayoutInfo.mMaxItalicsOffset, italicsOffset );
240
241   // Sets the sort modifier value.
242   currentTextActorInfo.textActor.SetSortModifier( visualParameters.mSortModifier );
243
244   // Enables or disables the blending.
245   currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
246 }
247
248 void CalculateSubLineLayout( const float parentWidth,
249                              const TextViewProcessor::TextInfoIndices& indices,
250                              const TextViewProcessor::LineLayoutInfo& lineLayoutInfo,
251                              const HorizontalWrapType splitPolicy,
252                              const float shrinkFactor,
253                              SubLineLayoutInfo& subLineInfo )
254 {
255   subLineInfo.mLineLength = 0.f;
256   subLineInfo.mMaxCharHeight = 0.f;
257   subLineInfo.mMaxAscender = 0.f;
258
259   float endWhiteSpaceLength = 0.f;
260
261   std::size_t wordIndex = indices.mWordIndex;
262   std::size_t characterIndex = indices.mCharacterIndex;
263   float lineOffset = 0.f;
264   bool found = false;
265   bool isFirstCharacter = true;
266   for( TextViewProcessor::WordGroupLayoutInfoContainer::const_iterator wordGroupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex,
267          wordGroupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
268        ( wordGroupIt != wordGroupEndIt ) && !found;
269        ++wordGroupIt )
270   {
271     const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *wordGroupIt );
272
273     for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex,
274            wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
275          ( wordIt != wordEndIt ) && !found;
276          ++wordIt )
277     {
278       const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
279
280       const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
281
282       bool splitByCharacter = false;
283
284       switch( splitPolicy )
285       {
286         case WrapByCharacter:
287         {
288           splitByCharacter = true;
289           break;
290         }
291         case WrapByWord:
292         case WrapByLine: // Fall through
293         {
294           splitByCharacter = false;
295           break;
296         }
297         case WrapByWordAndSplit:
298         {
299           splitByCharacter = ( wordLayoutInfo.mSize.width * shrinkFactor > parentWidth );
300           break;
301         }
302         case WrapByLineAndSplit:
303         {
304           if( ( 0 != characterIndex ) ||
305               ( ( 0 == characterIndex ) && ( lineOffset + wordLayoutInfo.mSize.width * shrinkFactor > parentWidth ) ) )
306           {
307             splitByCharacter = true;
308           }
309           else
310           {
311             lineOffset += wordLayoutInfo.mSize.width * shrinkFactor;
312             splitByCharacter = false;
313           }
314         }
315       }
316
317       if( splitByCharacter )
318       {
319         for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex,
320                charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
321              ( charIt != charEndIt ) && !found;
322              ++charIt )
323         {
324           const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
325           CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
326           if( !found || isFirstCharacter )
327           {
328             subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height );
329             subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender );
330           }
331
332           // All characters for word 'wordIndex' have been processed.
333           // Next word need to process all characters, so the characterIndex is reset to 0.
334           characterIndex = 0;
335           isFirstCharacter = false;
336         }
337
338         lineOffset += subLineInfo.mLineLength;
339       }
340       else
341       {
342         CalculateLineLength( isWhiteSpace, wordLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength );
343         if( !found || isFirstCharacter )
344         {
345           subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height );
346           subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender );
347         }
348         isFirstCharacter = false;
349       }
350     }
351
352     // All words for group 'groupIndex' have been processed.
353     // Next group need to process all words, so the wordIndex is reset to 0.
354     wordIndex = 0;
355   }
356
357   subLineInfo.mMaxCharHeight *= shrinkFactor;
358   subLineInfo.mMaxAscender *= shrinkFactor;
359 }
360
361 float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, const float parentWidth, const float wholeTextWidth )
362 {
363   float xOffset( 0.f );
364   switch( horizontalTextAlignment )
365   {
366     case Toolkit::Alignment::HorizontalLeft:
367     {
368       // nothing to do.
369       break;
370     }
371     case Toolkit::Alignment::HorizontalCenter:
372     {
373       xOffset = 0.5f * ( parentWidth - wholeTextWidth );
374       break;
375     }
376     case Toolkit::Alignment::HorizontalRight:
377     {
378       xOffset = parentWidth - wholeTextWidth;
379       break;
380     }
381     default:
382     {
383       DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong horizontal text alignment. Did you set a vertical one?" );
384     }
385   }
386
387   return xOffset;
388 }
389
390 float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, const float parentHeight, const float wholeTextHeight )
391 {
392   float yOffset( 0.f );
393   switch( verticalTextAlignment )
394   {
395     case Toolkit::Alignment::VerticalTop:
396     {
397       // nothing to do.
398       break;
399     }
400     case Toolkit::Alignment::VerticalCenter:
401     {
402       yOffset = 0.5f * ( parentHeight - wholeTextHeight );
403       break;
404     }
405     case Toolkit::Alignment::VerticalBottom:
406     {
407       yOffset = parentHeight - wholeTextHeight;
408       break;
409     }
410     default:
411     {
412       DALI_ASSERT_ALWAYS( !"TextViewRelayout::CalculateXoffset: Wrong vertical text alignment. Did you set an horizontal one?" );
413     }
414   }
415
416   return yOffset;
417 }
418
419 float CalculateJustificationOffset( const Toolkit::TextView::LineJustification justification, const float wholeTextWidth, const float lineLength )
420 {
421   float offset = 0.f;
422   switch( justification )
423   {
424     case Toolkit::TextView::Left:
425     {
426       offset = 0.f;
427       break;
428     }
429     case Toolkit::TextView::Center:
430     {
431       offset = 0.5f * ( wholeTextWidth - lineLength );
432       break;
433     }
434     case Toolkit::TextView::Right:
435     {
436       offset = wholeTextWidth - lineLength;
437       break;
438     }
439     case Toolkit::TextView::Justified:
440     {
441       offset = 0.f;
442       break;
443     }
444   }
445
446   return offset;
447 }
448
449 bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type )
450 {
451   bool visible = false;
452
453   switch( type )
454   {
455     case FULLY_VISIBLE:
456     {
457       // Whether the text-actor is fully inside the boundaries of the text-view.
458       visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) &&
459                   ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
460       break;
461     }
462     case FULLY_VISIBLE_WIDTH:
463     {
464       // Whether the text-actor is between the left and right boundaries of the text-view.
465       visible = ( ( position.x >= 0.f ) && ( position.x + size.width <= parentSize.width ) );
466       break;
467     }
468     case FULLY_VISIBLE_HEIGHT:
469     {
470       // Whether the text-actor is between the top and bottom boundaries of the text-view.
471       visible = ( ( position.y >= size.height ) && ( position.y <= parentSize.height ) );
472       break;
473     }
474     case PARTIALLY_VISIBLE:
475     {
476       // Whether the text-actor is partially inside the boundaries of the text-view.
477       visible = ( ( position.x < parentSize.width ) &&
478                   ( position.x + size.width > 0.f ) &&
479                   ( position.y > 0.f ) &&
480                   ( position.y - size.height < parentSize.height ) );
481       break;
482     }
483     case PARTIALLY_VISIBLE_WIDTH:
484     {
485       // Whether the text-actor is partially inside the area defined by the left and the right boundaries of the text-view.
486       // It may not be partially inside the text-view.
487       visible = ( ( position.x < parentSize.width ) &&
488                   ( position.x + size.width > 0.f ) );
489       break;
490     }
491     case PARTIALLY_VISIBLE_HEIGHT:
492     {
493       // Whether the text-actor is partially inside the area defined by the top and the bottom boundaries of the text-view.
494       // It may not be partially inside the text-view.
495       visible = ( ( position.y > 0.f ) &&
496                   ( position.y - size.height < parentSize.height ) );
497       break;
498     }
499   }
500
501   return visible;
502 }
503
504 Vector2 CalculateRectParameters( const Vector2& p0, const Vector2& p1 )
505 {
506   const float gradient = ( p1.y - p0.y ) / ( p1.x - p0.x );
507
508   return Vector2( gradient, p0.y - gradient * p0.x );
509 }
510
511 void UpdateAlignment( const TextView::LayoutParameters& layoutParameters,
512                       TextView::RelayoutData& relayoutData )
513 {
514   // Calculates an offset to align the whole text within the text-view's boundary accordingly with the set alignment and justification options.
515   // The offset could be negative if the whole text is bigger than the boundary of the text-view.
516
517   // If the exceed policy is ellipsize at the end, negative offsets are not wanted.
518   // In that case, it will align the line to the left and/or top, and ellipsize the end.
519   const bool ellipsizeAlignToLeft = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEndOriginal ) || ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd );
520   const bool ellipsizeAlignToTop = ( layoutParameters.mExceedPolicy == TextView::EllipsizeEnd );
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::EllipsizeEnd:
1012       {
1013         // Ellipsizes the text if it doesn't fit in the width and fully fits in the text-view's height.
1014
1015         isPartiallyVisible = CalculateVisibilityForEllipsizeEnd( characterLayoutInfo,
1016                                                                  ellipsizeParameters );
1017
1018         break;
1019       }
1020       default:
1021       {
1022         DALI_ASSERT_DEBUG( !"TextViewRelayout::CalculateVisibilityForEllipsize. Wrong exceed value." );
1023         break;
1024       }
1025     }
1026   }
1027
1028   // If the current character is not fully visible but is partially visible, it is cut by the boundary of the text-view.
1029   // In that case, the charater needs to be replaced by the ellipsize text.
1030   ellipsizeParameters.mCreateEllipsizedTextActors = ( !characterLayoutInfo.mIsVisible && isPartiallyVisible );
1031 }
1032
1033 void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters,
1034                                TextView::RelayoutData& relayoutData )
1035 {
1036   // 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.
1037   // The code bellow creates the text-actors needed for the ellipsize text.
1038
1039   // Set ellipsize's position by the end of visible text.
1040   Vector3 ellipsizePosition = ellipsizeParameters.mPosition;
1041   // Stores current ellipsize text.
1042   Text ellipsizeText;
1043   // Stores current ellipsize style.
1044   TextStyle ellipsizeStyle;
1045   // Stores the current size.
1046   Size ellipsizeSize;
1047
1048   float bearingOffset = 0.f;
1049
1050   // Create ellipsize text-actor.
1051   for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(),
1052          endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end();
1053        ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt;
1054        ++ellipsizeCharacterLayoutIt )
1055   {
1056     const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt );
1057
1058     if( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle )
1059     {
1060       // The style is different, so a new text-actor is needed.
1061       if( !ellipsizeText.IsEmpty() )
1062       {
1063         // It only creates a text-actor if there is any text.
1064         TextActor ellipsizeTextActor = CreateTextActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1065         ellipsizeTextActor.SetSize( ellipsizeSize );
1066         ellipsizeTextActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1067
1068         // Updates the position for the next text-actor.
1069         ellipsizePosition.x += ellipsizeSize.width;
1070
1071         // Adds the text-actor to the list.
1072         relayoutData.mEllipsizedTextActors.push_back( ellipsizeTextActor );
1073       }
1074
1075       // Resets the current ellipsize info.
1076       ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText;
1077       ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle;
1078       ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize;
1079
1080       bearingOffset = ( ellipsizeParameters.mLineDescender - ( ellipsizeCharacterLayoutInfo.mSize.height - ellipsizeCharacterLayoutInfo.mAscender ) ) * relayoutData.mShrinkFactor;
1081     }
1082     else
1083     {
1084       // Updates text and size with the new character.
1085       ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText );
1086       TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize );
1087     }
1088
1089   }
1090
1091   if( !ellipsizeText.IsEmpty() )
1092   {
1093     // Creates the last text-actor.
1094     TextActor ellipsizeTextActor = CreateTextActor( ellipsizeText, ellipsizeStyle, relayoutData.mTextActorCache );
1095     ellipsizeTextActor.SetSize( ellipsizeSize );
1096     ellipsizeTextActor.SetPosition( Vector3( ellipsizePosition.x, ellipsizePosition.y - bearingOffset, ellipsizePosition.z ) );
1097
1098     // Adds the text-actor to the list.
1099     relayoutData.mEllipsizedTextActors.push_back( ellipsizeTextActor );
1100   }
1101 }
1102
1103 void EllipsizeLine( const TextView::LayoutParameters& layoutParameters,
1104                     EllipsizeParameters& ellipsizeParameters,
1105                     TextView::RelayoutData& relayoutData )
1106 {
1107   // Traverses the text layout info from the first character of the laid out line
1108   // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...).
1109
1110   // Indices to the first character of the laid out line.
1111   TextViewProcessor::TextInfoIndices firstIndices;
1112   TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex,
1113                                                          relayoutData.mTextLayoutInfo,
1114                                                          firstIndices );
1115
1116   // Indices to the last character of the laid out line.
1117   TextViewProcessor::TextInfoIndices lastIndices;
1118   TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex,
1119                                                          relayoutData.mTextLayoutInfo,
1120                                                          lastIndices );
1121
1122   // Defines a boundary by substracting the ellipsize-text's width to the text-view's width.
1123   // This is the boundary used to check if a character have to be ellipsized.
1124   ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize;
1125   ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1126
1127   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + firstIndices.mLineIndex,
1128          endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lastIndices.mLineIndex + 1;
1129        lineLayoutIt != endLineLayoutIt;
1130        ++lineLayoutIt )
1131   {
1132     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1133
1134     ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1135
1136     if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1137     {
1138       ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth;
1139     }
1140
1141     bool firstGroup = true;
1142     bool lastGroup = false;
1143     std::size_t groupCount = 0;
1144
1145     bool firstWord = true;
1146     bool lastWord = false;
1147
1148     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + firstIndices.mGroupIndex,
1149            endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + lastIndices.mGroupIndex + 1;
1150          groupLayoutIt != endGroupLayoutIt;
1151          ++groupLayoutIt, ++groupCount )
1152     {
1153       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1154
1155       if( groupCount == lastIndices.mGroupIndex - firstIndices.mGroupIndex )
1156       {
1157         lastGroup = true;
1158       }
1159
1160       std::size_t wordCount = 0;
1161       const std::size_t firstWordIndex = firstGroup ? firstIndices.mWordIndex : 0u;
1162       const std::size_t lastWordIndex = lastGroup ? lastIndices.mWordIndex : wordGroupLayoutInfo.mWordsLayoutInfo.size() - 1;
1163
1164       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + firstWordIndex,
1165              endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + lastWordIndex + 1;
1166            wordLayoutIt != endWordLayoutIt;
1167            ++wordLayoutIt, ++wordCount )
1168       {
1169         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1170
1171         if( lastGroup && ( wordCount == lastIndices.mWordIndex - firstWordIndex ) )
1172         {
1173           lastWord = true;
1174         }
1175
1176         const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u;
1177         const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1;
1178         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex,
1179                endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1;
1180              characterLayoutIt != endCharacterLayoutIt;
1181              ++characterLayoutIt )
1182         {
1183           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1184
1185           if( ellipsizeParameters.mEllipsizeLine )
1186           {
1187             // Calculates the character visibility and whether it needs to be replace by ellipsized text.
1188             CalculateVisibilityForEllipsize( layoutParameters,
1189                                              characterLayoutInfo,
1190                                              ellipsizeParameters,
1191                                              relayoutData );
1192
1193             if( ellipsizeParameters.mCreateEllipsizedTextActors )
1194             {
1195               // Create ellipsize text-actors if the character needs to be replaced.
1196               CreateEllipsizeTextActor( ellipsizeParameters,
1197                                         relayoutData );
1198             }
1199           }
1200           else
1201           {
1202             if( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy )
1203             {
1204               if( !ellipsizeParameters.mIsLineHeightFullyVisible )
1205               {
1206                 // Make characters invisible.
1207                 characterLayoutInfo.mIsVisible = false;
1208               }
1209             }
1210           }
1211         } // end characters
1212         firstWord = false;
1213       } // end words
1214       firstGroup = false;
1215     } // end groups
1216   } // end lines
1217 }
1218
1219 void SetTextVisible( TextView::RelayoutData& relayoutData )
1220 {
1221   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1222          endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1223        lineLayoutIt != endLineLayoutIt;
1224        ++lineLayoutIt )
1225   {
1226     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1227
1228     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1229            endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1230          groupLayoutIt != endGroupLayoutIt;
1231          ++groupLayoutIt )
1232     {
1233       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1234
1235       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1236              endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1237            wordLayoutIt != endWordLayoutIt;
1238            ++wordLayoutIt )
1239       {
1240         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1241
1242         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1243                endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1244              characterLayoutIt != endCharacterLayoutIt;
1245              ++characterLayoutIt )
1246         {
1247           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1248
1249           characterLayoutInfo.mIsVisible = true;
1250           characterLayoutInfo.mGradientColor = Vector4::ZERO;
1251           characterLayoutInfo.mStartPoint = Vector2::ZERO;
1252           characterLayoutInfo.mEndPoint = Vector2::ZERO;
1253         } // end characters
1254       } // end words
1255     } // end group of words
1256   } // end lines
1257
1258   // Updates the visibility for text-input..
1259   for( std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(),
1260          endIt = relayoutData.mCharacterLayoutInfoTable.end();
1261        it != endIt;
1262        ++it )
1263   {
1264     Toolkit::TextView::CharacterLayoutInfo& characterLayoutInfo( *it );
1265
1266     characterLayoutInfo.mIsVisible = true;
1267   }
1268 }
1269
1270 void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters,
1271                               const TextView::VisualParameters& visualParameters,
1272                               TextView::RelayoutData& relayoutData )
1273 {
1274   RelayoutParameters relayoutParameters;
1275   FadeParameters fadeParameters;
1276
1277   // 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.
1278   fadeParameters.mRightFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mRight );
1279   fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0 ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY );
1280   fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary;
1281   fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset;
1282   fadeParameters.mLeftFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mLeft );
1283   fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0 ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY );
1284   fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary;
1285   fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset;
1286   fadeParameters.mTopFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mTop );
1287   fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0 ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY );
1288   fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary;
1289   fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset;
1290   fadeParameters.mBottomFadeBoundary = static_cast<float>( visualParameters.mFadeBoundary.mBottom );
1291   fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0 ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY );
1292   fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary;
1293   fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset;
1294
1295   // Calculates the fade out rect coeficients for the right, left, top and bottom sides of the text-view.
1296   fadeParameters.mRightAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mRightFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.width, 0.f ) );
1297   fadeParameters.mLeftAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mLeftFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1298   fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) );
1299   fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) );
1300
1301   // Traverses all groups of characters and calculates the visibility.
1302
1303   std::size_t infoTableCharacterIndex = 0;
1304
1305   relayoutParameters.mIndices.mLineIndex = 0;
1306
1307   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1308          endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1309        lineLayoutIt != endLineLayoutIt;
1310        ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
1311   {
1312     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1313
1314     relayoutParameters.mIndices.mGroupIndex = 0;
1315
1316     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1317            endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1318          groupLayoutIt != endGroupLayoutIt;
1319          ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
1320     {
1321       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1322
1323       relayoutParameters.mIndices.mWordIndex = 0;
1324
1325       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1326              endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1327            wordLayoutIt != endWordLayoutIt;
1328            ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
1329       {
1330         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1331
1332         relayoutParameters.mIsFirstCharacterOfWord = true;
1333         relayoutParameters.mWordSize = wordLayoutInfo.mSize;
1334         relayoutParameters.mIndices.mCharacterIndex = 0;
1335
1336         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1337                endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1338              characterLayoutIt != endCharacterLayoutIt;
1339              ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex )
1340         {
1341           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1342
1343           relayoutParameters.mIsVisible = true;
1344           fadeParameters.mIsPartiallyVisible = false;
1345
1346           // Calculates the visibility for the current group of characters.
1347           CalculateVisibilityForFade( layoutParameters,
1348                                       characterLayoutInfo,
1349                                       relayoutParameters,
1350                                       fadeParameters,
1351                                       relayoutData );
1352
1353           // Updates the visibility for text-input..
1354           std::vector<Toolkit::TextView::CharacterLayoutInfo>::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex;
1355
1356           Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it );
1357
1358           characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible;
1359
1360           relayoutParameters.mIsFirstCharacterOfWord = false;
1361         } // end group of character
1362       } // end words
1363     } // end group of words
1364   } // end lines
1365 }
1366
1367 void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters,
1368                                    const TextView::VisualParameters& visualParameters,
1369                                    TextView::RelayoutData& relayoutData )
1370 {
1371   // Traverses the laid-out lines and checks which ones doesn't fit in the text-view's boundary.
1372   for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end();
1373        lineInfoIt != endLineInfoIt;
1374        ++lineInfoIt )
1375   {
1376     const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt );
1377
1378     // To check if a laid-out line fits in the text-view's boundary,
1379     // get the position of the first character is needed and do the test
1380     // with the laid-out line size.
1381
1382     // An bearing offset may have been applied to the first character so it's needed to
1383     // get the start position of the line.
1384
1385     // Some parameters used in the CalculateVisibilityForEllipsize() function.
1386     EllipsizeParameters ellipsizeParameters;
1387
1388     // Retrieves the first index and the last index of the line.
1389     ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex;
1390     ellipsizeParameters.mLastIndex = 0;
1391     if( ( lineInfoIt + 1 ) != endLineInfoIt )
1392     {
1393       const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1 ) );
1394       ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1;
1395     }
1396     else
1397     {
1398       ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1;
1399     }
1400
1401     // Retrieves the first character of the line and build the position of the line with the bearing.
1402     const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + ellipsizeParameters.mFirstIndex );
1403
1404     // Calculates the bearing offset applied to the first character.
1405     const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender;
1406
1407     // Build the position of the line by removing the bearing offset from the first character's position.
1408     const Vector3 position( characterInfo.mPosition.x,
1409                             characterInfo.mPosition.y + bearingOffset,
1410                             characterInfo.mPosition.z );
1411
1412     // Checks if the line needs to be ellipsized,
1413     ellipsizeParameters.mIsLineWidthFullyVisible = IsVisible( position,
1414                                                               lineInfo.mSize,
1415                                                               relayoutData.mTextViewSize,
1416                                                               FULLY_VISIBLE_WIDTH );
1417
1418     // If the exceed policy is EllipsizeEndOriginal it's enough to check
1419     // if the line fits in the width.
1420     ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsLineWidthFullyVisible;
1421
1422     // If the exceed policy is EllipsizeEnd, it's needed to check if the next line exceeds the text-view's height.
1423     // If the next line exceeds the text-view height then it's going to be invisible and current line needs to be ellipsized.
1424     ellipsizeParameters.mIsLineHeightFullyVisible = true;
1425     ellipsizeParameters.mIsNextLineFullyVisibleHeight = true;
1426     if( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy )
1427     {
1428       // Need to check if there is lines which doesn't fit in the height.
1429
1430       ellipsizeParameters.mIsLineHeightFullyVisible = IsVisible( position,
1431                                                                  lineInfo.mSize,
1432                                                                  relayoutData.mTextViewSize,
1433                                                                  FULLY_VISIBLE_HEIGHT );
1434
1435       ellipsizeParameters.mEllipsizeLine = ellipsizeParameters.mEllipsizeLine && ellipsizeParameters.mIsLineHeightFullyVisible;
1436
1437       if( ellipsizeParameters.mIsLineHeightFullyVisible && !ellipsizeParameters.mEllipsizeLine )
1438       {
1439         // Current line is not ellipsized.
1440         // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized.
1441         Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1;
1442         if( nextLineInfoIt != endLineInfoIt )
1443         {
1444           // Retrives the position of the first character of the line and remove
1445           // the bearing offset to build to build the position of the line.
1446           const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *nextLineInfoIt );
1447           const Toolkit::TextView::CharacterLayoutInfo& characterInfo = *( relayoutData.mCharacterLayoutInfoTable.begin() + nextLineInfo.mCharacterGlobalIndex );
1448
1449           const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - characterInfo.mDescender ) * relayoutData.mShrinkFactor;
1450
1451           const Vector3 position( characterInfo.mPosition.x,
1452                                   characterInfo.mPosition.y + bearingOffset,
1453                                   characterInfo.mPosition.z );
1454
1455           ellipsizeParameters.mIsNextLineFullyVisibleHeight = IsVisible( position,
1456                                                                          nextLineInfo.mSize,
1457                                                                          relayoutData.mTextViewSize,
1458                                                                          FULLY_VISIBLE_HEIGHT );
1459
1460           // If the next line is not visible, current line have to be ellipsized.
1461           ellipsizeParameters.mEllipsizeLine = !ellipsizeParameters.mIsNextLineFullyVisibleHeight;
1462         }
1463       }
1464     }
1465
1466     if( !ellipsizeParameters.mIsNextLineFullyVisibleHeight )
1467     {
1468       ellipsizeParameters.mLineWidth = position.x + lineInfo.mSize.width - relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width;
1469     }
1470
1471     // Sets the line descender.
1472     ellipsizeParameters.mLineDescender = lineInfo.mSize.height - lineInfo.mAscender;
1473
1474     // At this point, ellipsizeLine distinguish if a piece of line have to be ellipsized or not.
1475     EllipsizeLine( layoutParameters, ellipsizeParameters, relayoutData );
1476   }
1477 }
1478
1479 void UpdateVisibility( const TextView::LayoutParameters& layoutParameters,
1480                        const TextView::VisualParameters& visualParameters,
1481                        TextView::RelayoutData& relayoutData )
1482 {
1483   switch( layoutParameters.mExceedPolicy )
1484   {
1485     case TextView::FadeOriginal:
1486     case TextView::OriginalFade:
1487     case TextView::Fade:
1488     case TextView::SplitFade: // Fall through
1489     {
1490       UpdateVisibilityForFade( layoutParameters,
1491                                visualParameters,
1492                                relayoutData );
1493       break;
1494     }
1495     case TextView::EllipsizeEndOriginal:
1496     case TextView::EllipsizeEnd: // Fall through
1497     {
1498       // Set first all characters to visible as UpdateVisibilityForEllipsize() doesn't traverse all of them.
1499       SetTextVisible( relayoutData );
1500
1501       UpdateVisibilityForEllipsize( layoutParameters,
1502                                     visualParameters,
1503                                     relayoutData );
1504       break;
1505     }
1506     default:
1507     {
1508       SetTextVisible( relayoutData );
1509       break;
1510     }
1511   }
1512 }
1513
1514 void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters,
1515                           TextView::RelayoutData& relayoutData )
1516 {
1517   CurrentTextActorInfo currentTextActorInfo;
1518
1519   // Traverses the text-actor and layout info data structures.
1520   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1521          endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1522        lineLayoutIt != endLineLayoutIt;
1523        ++lineLayoutIt )
1524   {
1525     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1526
1527     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1528            endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1529          groupLayoutIt != endGroupLayoutIt;
1530          ++groupLayoutIt )
1531     {
1532       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1533
1534       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1535              endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1536            wordLayoutIt != endWordLayoutIt;
1537            ++wordLayoutIt )
1538       {
1539         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1540
1541         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1542                endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1543              characterLayoutIt != endCharacterLayoutIt;
1544              ++characterLayoutIt )
1545         {
1546           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1547
1548           if( characterLayoutInfo.mTextActor )
1549           {
1550               // There is a new text-actor. Set text and everything to the previous one.
1551             if( currentTextActorInfo.textActor )
1552             {
1553               currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1554               currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1555               currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1556
1557               SetVisualParameters( currentTextActorInfo,
1558                                    visualParameters,
1559                                    relayoutData,
1560                                    lineLayoutInfo.mSize.height );
1561             }
1562
1563             currentTextActorInfo.text = characterLayoutInfo.mStyledText.mText;
1564             currentTextActorInfo.position = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x,
1565                                                      characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y,
1566                                                      characterLayoutInfo.mPosition.z );
1567             currentTextActorInfo.size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor;
1568
1569             currentTextActorInfo.color = characterLayoutInfo.mStyledText.mStyle.GetTextColor();
1570             currentTextActorInfo.color.a = characterLayoutInfo.mColorAlpha;
1571
1572             currentTextActorInfo.gradientColor = characterLayoutInfo.mGradientColor;
1573             currentTextActorInfo.startPoint = characterLayoutInfo.mStartPoint;
1574             currentTextActorInfo.endPoint = characterLayoutInfo.mEndPoint;
1575
1576             // Update the current text-actor.
1577             currentTextActorInfo.textActor = characterLayoutInfo.mTextActor;
1578           }
1579           else
1580           {
1581             // If this character layout has no text-actor is because this character has the same style than previous one.
1582             // Add the character to the current text-actor and update the size.
1583             if( characterLayoutInfo.mIsVisible && ( TextViewProcessor::LineSeparator != wordLayoutInfo.mType ) )
1584             {
1585               currentTextActorInfo.text.Append( characterLayoutInfo.mStyledText.mText );
1586
1587               currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y ) );
1588               currentTextActorInfo.size.width += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor;
1589               currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor );
1590             }
1591           }
1592         } // end characters
1593       } // end words
1594
1595       if( !currentTextActorInfo.text.IsEmpty() )
1596       {
1597         if( currentTextActorInfo.textActor )
1598         {
1599           currentTextActorInfo.textActor.SetText( currentTextActorInfo.text );
1600           currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position );
1601           currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size );
1602
1603           SetVisualParameters( currentTextActorInfo,
1604                                visualParameters,
1605                                relayoutData,
1606                                lineLayoutInfo.mSize.height );
1607         }
1608       }
1609     } //end groups of words
1610   } // end lines
1611
1612   for( std::vector<TextActor>::iterator it = relayoutData.mEllipsizedTextActors.begin(),
1613          endIt = relayoutData.mEllipsizedTextActors.end();
1614        it != endIt;
1615        ++it )
1616   {
1617     TextActor textActor = ( *it );
1618
1619     textActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1620     textActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1621
1622     // Sets the sort modifier value.
1623     textActor.SetSortModifier( visualParameters.mSortModifier );
1624
1625     // Enables or disables the blending.
1626     textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF );
1627   }
1628 }
1629
1630 void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus )
1631 {
1632   // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1633   //
1634   // 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.
1635   // According with the layout option, one of this lines could be laid-out in more than one.
1636
1637   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1638        lineIt != lineEndIt;
1639        ++lineIt )
1640   {
1641     TextViewProcessor::LineLayoutInfo& line( *lineIt );
1642
1643     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1644          groupIt != groupEndIt;
1645          ++groupIt )
1646     {
1647       TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1648
1649       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1650            wordIt != wordEndIt;
1651            ++wordIt )
1652       {
1653         TextViewProcessor::WordLayoutInfo& word( *wordIt );
1654
1655         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1656              characterIt != characterEndIt;
1657              ++characterIt )
1658         {
1659           TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1660
1661           // Check if current character is the first of a new laid-out line
1662           const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) &&
1663                                  ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex );
1664           if( isNewLine )
1665           {
1666             ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1667           }
1668
1669           if( characterGroup.mStyledText.mStyle.GetUnderline() )
1670           {
1671             if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't.
1672                 isNewLine )                                     // Current character is underlined and is the first of current laid-out line.
1673             {
1674               // Create a new underline info for the current underlined characters.
1675               UnderlineInfo underlineInfo;
1676               underlineInfo.mMaxHeight = characterGroup.mSize.height;
1677               underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1678               underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1679
1680               textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo );
1681
1682               textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined.
1683             }
1684             else
1685             {
1686               // Retrieve last underline info and update it if current underline thickness is bigger.
1687               UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1 ) );
1688
1689               underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, characterGroup.mSize.height );
1690
1691               if( characterGroup.mUnderlineThickness > underlineInfo.mMaxThickness )
1692               {
1693                 underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness;
1694                 underlineInfo.mPosition = characterGroup.mUnderlinePosition;
1695               }
1696             }
1697           }
1698           else
1699           {
1700             textUnderlineStatus.mCurrentUnderlineStatus = false;
1701           }
1702
1703           ++textUnderlineStatus.mCharacterGlobalIndex;
1704         } // end group of characters.
1705       } // end words.
1706     } // end group of words.
1707   } // end lines.
1708 }
1709
1710 void SetUnderlineInfo( TextView::RelayoutData& relayoutData )
1711 {
1712   // 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.
1713   TextViewRelayout::TextUnderlineStatus textUnderlineStatus;
1714
1715   // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line.
1716   CalculateUnderlineInfo( relayoutData, textUnderlineStatus );
1717
1718   if( textUnderlineStatus.mUnderlineInfo.empty() )
1719   {
1720     // There is no underlined text. Just exit.
1721     return;
1722   }
1723
1724   // At this point textUnderlineStatus.mUnderlineInfo has for each group of consecutive underlined characters their maximum thickness, position and maximum height.
1725   // Traverse the whole text and set the previously stored underline info in the text style.
1726
1727   std::vector<UnderlineInfo>::const_iterator underlineInfoIt = textUnderlineStatus.mUnderlineInfo.begin();
1728   std::vector<UnderlineInfo>::const_iterator underlineInfoEndIt = textUnderlineStatus.mUnderlineInfo.end();
1729
1730   UnderlineInfo underlineInfo;
1731
1732   if( underlineInfoIt < underlineInfoEndIt )
1733   {
1734     underlineInfo = ( *underlineInfoIt );
1735   }
1736
1737   // Whether current text is underlined.
1738   textUnderlineStatus.mCurrentUnderlineStatus = false;
1739   textUnderlineStatus.mCharacterGlobalIndex = 0;
1740   textUnderlineStatus.mLineGlobalIndex = 0;
1741
1742   float currentLineHeight = 0.f;
1743   float currentLineAscender = 0.f;
1744
1745   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1746        lineIt != lineEndIt;
1747        ++lineIt )
1748   {
1749     TextViewProcessor::LineLayoutInfo& line( *lineIt );
1750
1751     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1752          groupIt != groupEndIt;
1753          ++groupIt )
1754     {
1755       TextViewProcessor::WordGroupLayoutInfo& group( *groupIt );
1756
1757       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1758            wordIt != wordEndIt;
1759            ++wordIt )
1760       {
1761         TextViewProcessor::WordLayoutInfo& word( *wordIt );
1762
1763         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1764              characterIt != characterEndIt;
1765              ++characterIt )
1766         {
1767           TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt );
1768
1769           // Check if current character is the first of a new laid-out line
1770
1771           bool isNewLine = false;
1772
1773           if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() )
1774           {
1775             const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) );
1776             isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex );
1777
1778             if( isNewLine )
1779             {
1780               currentLineHeight = lineLayoutInfo.mSize.height;
1781               currentLineAscender = lineLayoutInfo.mAscender;
1782               ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one.
1783             }
1784           }
1785
1786           if( characterGroup.mStyledText.mStyle.GetUnderline() )
1787           {
1788             if( textUnderlineStatus.mCurrentUnderlineStatus )
1789             {
1790               if( isNewLine )
1791               {
1792                 // Retrieves the thickness and position for the next piece of underlined text.
1793                 if( underlineInfoIt < underlineInfoEndIt )
1794                 {
1795                   ++underlineInfoIt;
1796                   if( underlineInfoIt < underlineInfoEndIt )
1797                   {
1798                     underlineInfo = *underlineInfoIt;
1799                   }
1800                 }
1801               }
1802             }
1803
1804             textUnderlineStatus.mCurrentUnderlineStatus = true;
1805
1806             // Sets the underline's thickness.
1807             characterGroup.mStyledText.mStyle.SetUnderlineThickness( underlineInfo.mMaxThickness );
1808
1809             // Before setting the position it needs to be adjusted to match the base line.
1810             const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( characterGroup.mSize.height - characterGroup.mAscender );
1811             const float positionOffset = ( underlineInfo.mMaxHeight - characterGroup.mSize.height ) - bearingOffset;
1812
1813             // Sets the underline's position.
1814             characterGroup.mStyledText.mStyle.SetUnderlinePosition( underlineInfo.mPosition - positionOffset );
1815
1816             // Mark the group of characters to be set the new style into the text-actor.
1817             characterGroup.mSetStyle = true;
1818           }
1819           else
1820           {
1821             if( textUnderlineStatus.mCurrentUnderlineStatus )
1822             {
1823               textUnderlineStatus.mCurrentUnderlineStatus = false;
1824
1825               // Retrieves the thickness and position for the next piece of underlined text.
1826               if( underlineInfoIt < underlineInfoEndIt )
1827               {
1828                 ++underlineInfoIt;
1829                 if( underlineInfoIt < underlineInfoEndIt )
1830                 {
1831                   underlineInfo = *underlineInfoIt;
1832                 }
1833               }
1834             }
1835           }
1836
1837           ++textUnderlineStatus.mCharacterGlobalIndex;
1838         } // end of group of characters.
1839       } // end of word.
1840     } // end of group of words.
1841   } // end of lines.
1842 }
1843
1844 void RemoveTextActors( Actor textView,
1845                        const std::vector<TextActor>& textActors )
1846 {
1847   // Removes previously inserted text-actors.
1848   // The SplitByNewLineChar::Relayout(), SplitByWord::Relayout() and SplitByChar::Relayout() functions add
1849   // text-actors to the text-view. A handle to these text-actors are stored and passed to this function
1850   // in order to remove 'only' text-actors added by these functions.
1851   // Any other actor added by a programmer or application won't be removed.
1852
1853   for( std::vector<TextActor>::const_reverse_iterator it = textActors.rbegin(), endIt = textActors.rend(); it != endIt; ++it )
1854   {
1855     textView.Remove( *it );
1856   }
1857 }
1858
1859 void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMask,
1860                        Actor textView,
1861                        TextView::RelayoutData& relayoutData )
1862 {
1863   const bool insertToTextView = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW;
1864   const bool insertToTextActorList = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST;
1865
1866   // Add text-actors to the text-view.
1867
1868   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
1869          endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1870        lineLayoutIt != endLineLayoutIt;
1871        ++lineLayoutIt )
1872   {
1873     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
1874
1875     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
1876            endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
1877          groupLayoutIt != endGroupLayoutIt;
1878          ++groupLayoutIt )
1879     {
1880       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
1881
1882       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
1883              endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
1884            wordLayoutIt != endWordLayoutIt;
1885            ++wordLayoutIt )
1886       {
1887         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
1888
1889         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
1890                endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
1891              characterLayoutIt != endCharacterLayoutIt;
1892              ++characterLayoutIt )
1893         {
1894           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
1895
1896           if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mTextActor ) // White spaces and '\n' characters doesn't have a text-actor.
1897           {
1898             //Add to the text-view.
1899             if( insertToTextView )
1900             {
1901               textView.Add( characterLayoutInfo.mTextActor );
1902             }
1903             if( insertToTextActorList )
1904             {
1905               relayoutData.mTextActors.push_back( characterLayoutInfo.mTextActor );
1906             }
1907           }
1908         } // end group of character
1909       } // end words
1910     } // end group of words
1911   } // end lines
1912
1913   for( std::vector<TextActor>::iterator it = relayoutData.mEllipsizedTextActors.begin(),
1914          endIt = relayoutData.mEllipsizedTextActors.end();
1915        it != endIt;
1916        ++it )
1917   {
1918     TextActor textActor = ( *it );
1919
1920     //Add to the text-view.
1921     if( insertToTextView )
1922     {
1923       textView.Add( textActor );
1924     }
1925     if( insertToTextActorList )
1926     {
1927       relayoutData.mTextActors.push_back( textActor );
1928     }
1929   }
1930   relayoutData.mEllipsizedTextActors.clear();
1931 }
1932
1933 TextActor CreateTextActor( const Text& text, const TextStyle& style, TextActorCache& cache )
1934 {
1935   TextActor textActor = cache.RetrieveTextActor();
1936
1937   if( textActor )
1938   {
1939     // Update the text-actor.
1940     textActor.SetText( text );
1941     textActor.SetTextStyle( style );
1942   }
1943   else
1944   {
1945     // The text-actor cache is empty. Create a new one.
1946     textActor = TextActor::New( text, style, false, true );
1947   }
1948
1949   return textActor;
1950 }
1951
1952 } // namespace TextViewRelayout
1953
1954 } // namespace Internal
1955
1956 } // namespace Toolkit
1957
1958 } // namespace Dali