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