TextView - Right to Left implementation.
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / split-by-word-policies.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // FILE HEADER
19 #include <dali-toolkit/internal/controls/text-view/split-by-word-policies.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali-toolkit/internal/controls/text-view/relayout-utilities.h>
24 #include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 namespace SplitByWord
36 {
37
38 namespace
39 {
40
41 Vector3 OriginalPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
42                           const TextView::LayoutParameters& layoutParameters,
43                           TextView::RelayoutData& relayoutData )
44 {
45   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.x );
46   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
47
48   if( relayoutParameters.mIsNewLine ||
49       relayoutParameters.mIsFirstCharacter ||
50       ( relayoutParameters.mIsFirstCharacterOfWord && ( wordOffset + relayoutParameters.mWordSize.width > relayoutData.mTextViewSize.width ) ) )
51   {
52     if( !relayoutParameters.mIsNewLine &&
53         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewParagraphCharacter ) )
54     {
55       // Current character is a white space. Don't want to move a white space to the next line.
56       // These white spaces are placed just in the edge.
57       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
58     }
59     else
60     {
61       // Calculates the length of the portion of the paragraph which doesn't exceed the text-view's width and the max character height for the current line.
62       TextViewRelayout::LineLayoutInfo subLineInfo;
63       subLineInfo.mLineLength = 0.f;
64       subLineInfo.mMaxCharHeight = 0.f;
65       subLineInfo.mMaxAscender = 0.f;
66       const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + relayoutParameters.mIndices.mParagraphIndex ) );
67
68       TextViewRelayout::CalculateLineLayout( relayoutData.mTextViewSize.width,
69                                              relayoutParameters.mIndices,
70                                              paragraphLayoutInfo,
71                                              TextViewRelayout::WrapByWord,
72                                              1.f, // Shrink factor
73                                              subLineInfo );
74
75       if( subLineInfo.mLineLength < Math::MACHINE_EPSILON_1000 )
76       {
77         // It may mean there is a word which is actually longer than the width of the text-view.
78         // In that case the length of this word is needed.
79         if( !paragraphLayoutInfo.mWordsLayoutInfo.empty() )
80         {
81           const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + relayoutParameters.mIndices.mWordIndex ) );
82           subLineInfo.mLineLength = wordLayoutInfo.mSize.width;
83         }
84       }
85
86       Toolkit::TextView::LineLayoutInfo lineInfo;
87       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
88       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
89       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
90       relayoutData.mLines.push_back( lineInfo );
91
92       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
93     }
94   }
95   else
96   {
97     return Vector3( wordOffset, previousPositionY, 0.f );
98   }
99 }
100
101 /**
102  * Calculates character position.
103  * @param[in] relayoutParameters Temporary layout parameters (previous size, previous position, ... )
104  * @param[in] layoutParameters The layout parameters.
105  * @param[in] relayoutData The text-view's data structures.
106  * @return The character's position.
107  */
108 Vector3 SplitWhenExceedPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
109                                  const TextView::LayoutParameters& layoutParameters,
110                                  TextView::RelayoutData& relayoutData )
111 {
112   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f :  relayoutParameters.mPositionOffset.x );
113   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
114
115   if( ( relayoutParameters.mIsNewLine || relayoutParameters.mIsFirstCharacter ) ||
116       ( relayoutParameters.mIsFirstCharacterOfWord && ( wordOffset + relayoutParameters.mWordSize.width > relayoutData.mTextViewSize.width ) ) ||
117       ( wordOffset + relayoutParameters.mCharacterSize.width > relayoutData.mTextViewSize.width ) )
118   {
119     if( !relayoutParameters.mIsNewLine &&
120         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewParagraphCharacter ) )
121     {
122       // Current character is a white space. Don't want to move a white space to the next line.
123       // These white spaces are placed just in the edge.
124       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
125     }
126     else
127     {
128       // Calculates the line length and the max character height for the current line.
129       TextViewRelayout::LineLayoutInfo subLineInfo;
130       subLineInfo.mLineLength = 0.f;
131       subLineInfo.mMaxCharHeight = 0.f;
132       subLineInfo.mMaxAscender = 0.f;
133       const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + relayoutParameters.mIndices.mParagraphIndex ) );
134
135       TextViewRelayout::CalculateLineLayout( relayoutData.mTextViewSize.width,
136                                              relayoutParameters.mIndices,
137                                              paragraphLayoutInfo,
138                                              TextViewRelayout::WrapByWordAndSplit,
139                                              1.f, // Shrink factor.
140                                              subLineInfo );
141
142       Toolkit::TextView::LineLayoutInfo lineInfo;
143       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
144       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
145       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
146       relayoutData.mLines.push_back( lineInfo );
147
148       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
149     }
150   }
151   else
152   {
153     return Vector3( wordOffset, previousPositionY, 0.f );
154   }
155 }
156
157 /**
158  * Calculates character position.
159  * @param[in] relayoutParameters Temporary layout parameters (previous size, previous position, ... )
160  * @param[in] layoutParameters The layout parameters.
161  * @param[in] relayoutData The text-view's data structures.
162  * @return The character's position.
163  */
164 Vector3 ShrinkWidthWhenExceedPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
165                                        const TextView::LayoutParameters& layoutParameters,
166                                        TextView::RelayoutData& relayoutData )
167 {
168   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.x );
169   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
170   const Size wordSize = relayoutParameters.mWordSize * relayoutData.mShrinkFactor;
171
172   if( ( relayoutParameters.mIsNewLine || relayoutParameters.mIsFirstCharacter ) ||                                           // isNewLine is true when '\n' is found.
173       ( relayoutParameters.mIsFirstCharacterOfWord && ( wordOffset + wordSize.width > relayoutData.mTextViewSize.width ) ) ) // The word doesn't fit in the parent width.
174   {
175     if( !relayoutParameters.mIsNewLine &&
176         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewParagraphCharacter ) )
177     {
178       // Current character is a white space. Don't want to move a white space to the next line.
179       // These white spaces are placed just in the edge.
180       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
181     }
182     else
183     {
184       // Calculates the line length and the max character height for the current line.
185       TextViewRelayout::LineLayoutInfo subLineInfo;
186       subLineInfo.mLineLength = 0.f;
187       subLineInfo.mMaxCharHeight = 0.f;
188       subLineInfo.mMaxAscender = 0.f;
189       const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + relayoutParameters.mIndices.mParagraphIndex ) );
190
191       TextViewRelayout::CalculateLineLayout( relayoutData.mTextViewSize.width,
192                                              relayoutParameters.mIndices,
193                                              paragraphLayoutInfo,
194                                              TextViewRelayout::WrapByWord,
195                                              relayoutData.mShrinkFactor,
196                                              subLineInfo );
197
198       Toolkit::TextView::LineLayoutInfo lineInfo;
199       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
200       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
201       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
202       relayoutData.mLines.push_back( lineInfo );
203
204       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * relayoutData.mShrinkFactor, 0.f );
205     }
206   }
207   else
208   {
209     return Vector3( wordOffset, previousPositionY, 0.f );
210   }
211 }
212
213 void CalculatePositionsForShrinkWhenExceed( TextView::RelayoutData& relayoutData,
214                                             const TextView::LayoutParameters& layoutParameters,
215                                             const float shrinkFactor,
216                                             float& newTextHeight )
217 {
218   const float parentWidth = relayoutData.mTextViewSize.width;
219   TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
220
221   // Reset the text height. This value is returned in order to shrink further or not the text.
222   newTextHeight = 0.f;
223
224   // Whether the first character is being processed.
225   bool isFirstChar = true;
226
227   // Stores the size of the previous character.
228   Size previousSize;
229   // Stores the position of the previous character.
230   Vector3 previousPosition;
231
232   // Reset the index of paragraphs.
233   TextViewProcessor::TextInfoIndices indices;
234
235   // Whether the last character of the whole text is a new paragraph char.
236   // This information is used to increase or not the height of the whole text by one line.
237   // Increase the whole text's height by one line is useful i.e. in TextInput to place the cursor
238   // after pressing 'Enter' in the last paragraph.
239   bool isLastCharacterNewParagraphChar = false;
240   // Stores the height of the last character. This height used to be added to the whole text height if
241   // isLastCharacterNewParagraphChar is true.
242   float lastCharHeight = 0.f;
243
244   relayoutData.mLines.clear();
245   std::size_t characterGlobalIndex = 0u;
246
247   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = textLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = textLayoutInfo.mParagraphsLayoutInfo.end();
248        paragraphIt != paragraphEndIt;
249        ++paragraphIt, ++indices.mParagraphIndex )
250   {
251     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphIt );
252
253     // The next character is in a new line.
254     bool isNewLine = true;
255
256     // Reset the index of words.
257     indices.mWordIndex = 0u;
258
259     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(), wordEndIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
260          wordIt != wordEndIt;
261          ++wordIt, ++indices.mWordIndex )
262     {
263       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
264
265       // Reset the index of the character.
266       indices.mCharacterIndex = 0u;
267
268       // Whether current character is the first of the word.
269       bool isFirstCharOfWord = true;
270       const float wordOffset = previousPosition.x + previousSize.width;
271
272       isLastCharacterNewParagraphChar = ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType );
273
274       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
275            charIt != charEndIt;
276            ++charIt, ++indices.mCharacterIndex )
277       {
278         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
279         lastCharHeight = characterLayoutInfo.mSize.height * shrinkFactor;
280
281         const float previousPositionY = isFirstChar ? 0.f : previousPosition.y;
282
283         if( ( isNewLine || isFirstChar ) ||
284             ( isFirstCharOfWord && ( wordOffset + wordLayoutInfo.mSize.width * shrinkFactor > parentWidth ) ) )
285         {
286           isFirstChar = false;
287
288           // Calculates the line length and the max character height for the current line.
289           TextViewRelayout::LineLayoutInfo subLineInfo;
290           subLineInfo.mLineLength = 0.f;
291           subLineInfo.mMaxCharHeight = 0.f;
292           subLineInfo.mMaxAscender = 0.f;
293           TextViewRelayout::CalculateLineLayout( parentWidth,
294                                                  indices,
295                                                  paragraphLayoutInfo,
296                                                  TextViewRelayout::WrapByWord,
297                                                  shrinkFactor,
298                                                  subLineInfo );
299
300           characterLayoutInfo.mPosition = Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor, 0.f );
301
302           newTextHeight += subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor;
303
304           Toolkit::TextView::LineLayoutInfo lineInfo;
305           lineInfo.mCharacterGlobalIndex = characterGlobalIndex;                        // Index to the first character of the next line.
306           lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph.
307           lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of paragraph.
308           relayoutData.mLines.push_back( lineInfo );
309         }
310         else
311         {
312           characterLayoutInfo.mPosition = previousPosition + Vector3( previousSize.width, 0.f, 0.f );
313         }
314
315         // Get last line info and calculate the bearing.
316         const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) );
317         const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender ) ) * shrinkFactor;
318
319         previousSize = characterLayoutInfo.mSize * shrinkFactor;
320         previousPosition = characterLayoutInfo.mPosition;
321         characterLayoutInfo.mPosition.y -= bearingOffset;
322         isFirstCharOfWord = false;
323         isNewLine = false;
324
325         ++characterGlobalIndex;
326       }
327     }
328   }
329
330   if( isLastCharacterNewParagraphChar )
331   {
332     newTextHeight += lastCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor;
333   }
334 }
335
336 float RelayoutForShrinkToFit( TextView::RelayoutData& relayoutData,
337                               const TextView::LayoutParameters& layoutParameters )
338 {
339   const Size& textViewSize = relayoutData.mTextViewSize;
340   TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
341
342   // First step is assure the longest word fits in the text view width.
343   float shrinkFactor = ( textLayoutInfo.mMaxWordWidth > textViewSize.width ? textViewSize.width / textLayoutInfo.mMaxWordWidth : 1.f );
344
345   // Out parameter. Will store the new text height after relayout the text.
346   float newTextHeight = 0.f;
347
348   // Relayout the text for the given character's sizes.
349   CalculatePositionsForShrinkWhenExceed( relayoutData,
350                                          layoutParameters,
351                                          shrinkFactor,
352                                          newTextHeight );
353
354   if( newTextHeight > textViewSize.height )
355   {
356     // After relayouting, the text exceeds the text view height.
357     // Find a new scale factor to fit all the text in the text view size is needed.
358
359     // The next algorithm does some iterations to calculate an acceptable scale factor.
360     // Some magic numbers are defined.
361
362     const float MIN_RATIO( 0.90f );         // The algorithm finishes if the ratio
363     const float MAX_RATIO( 1.00f );         // new_text_height / text_view_height is between this two values
364     const unsigned int MAX_ITERATIONS( 8u ); // or max_iteration is reached.
365
366     float ratio = newTextHeight / textViewSize.height;
367
368     float maxScaleFactor = shrinkFactor;                        // bigger scale factors than maxScaleFactor will produce a too big text.
369     float minScaleFactor = shrinkFactor * ( textViewSize.height / newTextHeight ); // smaller scale factors than minScaleFactor will produce a too small text.
370
371     for( unsigned int iterations = 0u; ( ( MIN_RATIO > ratio ) || ( ratio > MAX_RATIO )  ) && ( iterations < MAX_ITERATIONS ); ++iterations )
372     {
373       // Calculates the new scale factor.
374       // The new scale factor is always between the min and max scale factors.
375       // If ratio < 1 it means the text is too small and a bigger scale factor is needed. In this case the algorithm selects a new scale factor close to
376       // minScaleFactor. Alternatively if the text is too big a new scale factor close to maxScaleFactor is selected.
377       // This allows the text shrink or grow smoothly.
378       shrinkFactor = minScaleFactor + ( ratio < 1.f ? 0.4f : 0.6f ) * ( maxScaleFactor - minScaleFactor );
379
380       CalculatePositionsForShrinkWhenExceed( relayoutData, // Relayout the text for the given character's sizes.
381                                              layoutParameters,
382                                              shrinkFactor,
383                                              newTextHeight );
384
385       // Calculates the new text size ratio. It allows update the min and max scale factors.
386       // If the ratio is not good enough a new scale factor between min and max could be used in next iteration.
387       ratio = newTextHeight / textViewSize.height;
388       if( ratio < 1.f )
389       {
390         minScaleFactor = shrinkFactor;
391       }
392       else
393       {
394         maxScaleFactor = shrinkFactor;
395       }
396     }
397
398     if( ratio > MAX_RATIO )
399     {
400       // The algorithm didn't find an acceptable scale factor.
401       // In that case the text is shrunk to fit in the boundaries of the text view actor.
402       shrinkFactor = minScaleFactor;
403
404       CalculatePositionsForShrinkWhenExceed( relayoutData,
405                                              layoutParameters,
406                                              shrinkFactor,
407                                              newTextHeight );
408     }
409   }
410
411   return shrinkFactor;
412 }
413
414 void CalculateSizeAndPosition( const TextView::LayoutParameters& layoutParameters,
415                                TextView::RelayoutData& relayoutData )
416 {
417   TextViewRelayout::RelayoutParameters relayoutParameters;
418
419   // clear
420   relayoutData.mCharacterLayoutInfoTable.clear();
421   relayoutData.mLines.clear();
422   relayoutData.mTextSizeForRelayoutOption = Size();
423
424   // Calculates the text size for split by char.
425   Vector4 minMaxXY( std::numeric_limits<float>::max(),
426                     std::numeric_limits<float>::max(),
427                     std::numeric_limits<float>::min(),
428                     std::numeric_limits<float>::min() );
429
430   relayoutData.mShrinkFactor = 1.f; // Shrink factor used when the exceed policy contains ShrinkToFit
431
432   if( TextView::Shrink == layoutParameters.mExceedPolicy )
433   {
434     // Relays-out the text for the shrink to fit policy.
435     relayoutData.mShrinkFactor = RelayoutForShrinkToFit( relayoutData, layoutParameters );
436   }
437   else if( TextView::ShrinkOriginal == layoutParameters.mExceedPolicy )
438   {
439     relayoutData.mShrinkFactor = ( relayoutData.mTextLayoutInfo.mMaxWordWidth > relayoutData.mTextViewSize.width ? relayoutData.mTextViewSize.width / relayoutData.mTextLayoutInfo.mMaxWordWidth : 1.f );
440   }
441
442   relayoutParameters.mPositionOffset = Vector3::ZERO;
443   relayoutParameters.mIsFirstCharacter = true;
444   relayoutParameters.mIndices.mParagraphIndex = 0u;
445   relayoutParameters.mCharacterGlobalIndex = 0u;
446
447   for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(),
448        endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
449        paragraphLayoutIt != endParagraphLayoutIt;
450        ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex )
451   {
452     TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt );
453
454     relayoutParameters.mIsNewLine = true;
455     relayoutParameters.mParagraphSize = paragraphLayoutInfo.mSize;
456     relayoutParameters.mIndices.mWordIndex = 0u;
457
458     for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(),
459            endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
460          wordLayoutIt != endWordLayoutIt;
461          ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
462     {
463       TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
464       relayoutParameters.mIsWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
465       relayoutParameters.mIsNewParagraphCharacter = TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType;
466
467       relayoutParameters.mIsFirstCharacterOfWord = true;
468       relayoutParameters.mWordSize = wordLayoutInfo.mSize;
469       relayoutParameters.mIndices.mCharacterIndex = 0u;
470
471       for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
472              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
473            ( characterLayoutIt != endCharacterLayoutIt );
474            ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex )
475       {
476         TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
477
478         relayoutParameters.mCharacterSize = characterLayoutInfo.mSize;
479
480         switch( layoutParameters.mExceedPolicy )
481         {
482           case TextView::OriginalShrink:
483           case TextView::SplitShrink:
484           case TextView::ShrinkFade:
485           {
486             DALI_LOG_WARNING( "SplitByWord::CalculateSizeAndPosition() policy not implemented.\n" );
487             break;
488           }
489           case TextView::Original:
490           case TextView::OriginalFade:
491           case TextView::FadeOriginal:
492           case TextView::Fade:
493           case TextView::EllipsizeEndOriginal:
494           case TextView::EllipsizeEnd: // Fall Through
495           {
496             characterLayoutInfo.mPosition = OriginalPosition( relayoutParameters,
497                                                               layoutParameters,
498                                                               relayoutData );
499
500             relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
501             break;
502           }
503           case TextView::SplitOriginal:
504           case TextView::SplitFade:
505           case TextView::SplitEllipsizeEnd:
506           {
507             characterLayoutInfo.mPosition = SplitWhenExceedPosition( relayoutParameters,
508                                                                      layoutParameters,
509                                                                      relayoutData );
510
511             relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
512             break;
513           }
514           case TextView::ShrinkOriginal:
515           {
516             characterLayoutInfo.mPosition = ShrinkWidthWhenExceedPosition( relayoutParameters,
517                                                                            layoutParameters,
518                                                                            relayoutData );
519
520             relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor, 0.f, 0.f );
521             break;
522           }
523           case TextView::Shrink:
524           {
525             // Does nothing. All the job has been done in the RelayoutForShrinkToFit() function.
526             break;
527           }
528           default:
529           {
530             DALI_LOG_WARNING( "SplitByWord::CalculateSizeAndPosition() policy combination not possible.\n" );
531           }
532         }
533
534         // Get last line info and calculate the bearing (used to align glyphs with the baseline).
535         if( TextView::Shrink != layoutParameters.mExceedPolicy )
536         {
537           TextViewRelayout::CalculateBearing( characterLayoutInfo, relayoutData );
538         }
539
540         // updates min and max position to calculate the text size for split by word.
541         TextViewRelayout::UpdateLayoutInfoTable( minMaxXY,
542                                                  wordLayoutInfo,
543                                                  characterLayoutInfo,
544                                                  relayoutParameters,
545                                                  relayoutData );
546
547         ++relayoutParameters.mCharacterGlobalIndex;
548         relayoutParameters.mIsFirstCharacter = false;
549         relayoutParameters.mIsFirstCharacterOfWord = false;
550         relayoutParameters.mIsNewLine = false;
551       } // end characters
552     } // end words
553   } // end paragraphs
554
555   if( relayoutData.mCharacterLayoutInfoTable.empty() )
556   {
557     relayoutData.mTextSizeForRelayoutOption = Size();
558   }
559   else
560   {
561     relayoutData.mTextSizeForRelayoutOption.width = minMaxXY.z - minMaxXY.x;
562     relayoutData.mTextSizeForRelayoutOption.height = minMaxXY.w - minMaxXY.y;
563   }
564
565   // Check if the last character is a new paragraph character. In that case the height should be added.
566   if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
567   {
568     const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
569
570     if( paragraphLayoutInfo.mWordsLayoutInfo.empty() ) // if it's empty, it means the last character is a new paragraph character.
571     {
572       relayoutData.mTextSizeForRelayoutOption.height += paragraphLayoutInfo.mSize.height * relayoutData.mShrinkFactor;
573     }
574   }
575 }
576
577 } // namespace
578
579 void Relayout( Actor textView,
580                TextView::RelayoutOperationMask relayoutOperationMask,
581                const TextView::LayoutParameters& layoutParameters,
582                const TextView::VisualParameters& visualParameters,
583                TextView::RelayoutData& relayoutData )
584 {
585   if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
586   {
587     CalculateSizeAndPosition( layoutParameters,
588                               relayoutData );
589
590     TextViewRelayout::ReorderRightToLeftLayout( relayoutData );
591
592     TextViewRelayout::SetUnderlineInfo( relayoutData );
593   }
594
595   if( relayoutOperationMask & TextView::RELAYOUT_ALIGNMENT )
596   {
597     TextViewRelayout::UpdateAlignment( layoutParameters,
598                                        relayoutData );
599   }
600
601   if( relayoutOperationMask & TextView::RELAYOUT_VISIBILITY )
602   {
603     TextViewRelayout::UpdateVisibility( layoutParameters,
604                                         visualParameters,
605                                         relayoutData );
606   }
607   const bool initializeTextActors = relayoutOperationMask & TextView::RELAYOUT_INITIALIZE_TEXT_ACTORS;
608   const bool updateTextActors = relayoutOperationMask & TextView::RELAYOUT_TEXT_ACTOR_UPDATE;
609   if( initializeTextActors || updateTextActors )
610   {
611     TextViewRelayout::UpdateTextActorInfo( visualParameters,
612                                            relayoutData,
613                                            initializeTextActors );
614   }
615
616   if( relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW )
617   {
618     TextViewRelayout::InsertToTextView( textView,
619                                         relayoutData );
620   }
621 }
622
623 } // namespace SplitByWord
624
625 } // namespace Internal
626
627 } // namespace Toolkit
628
629 } // namespace Dali