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