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