Fixes TextView's includes.
[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.mIsNewLineCharacter ) )
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 line which doesn't exceed the text-view's width and the max character height for the current line.
62       TextViewRelayout::SubLineLayoutInfo subLineInfo;
63       subLineInfo.mLineLength = 0.f;
64       subLineInfo.mMaxCharHeight = 0.f;
65       subLineInfo.mMaxAscender = 0.f;
66       const TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + relayoutParameters.mIndices.mLineIndex ) );
67
68       TextViewRelayout::CalculateSubLineLayout( relayoutData.mTextViewSize.width,
69                                                 relayoutParameters.mIndices,
70                                                 lineLayoutInfo,
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( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() )
80         {
81           const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *( lineLayoutInfo.mWordGroupsLayoutInfo.begin() + relayoutParameters.mIndices.mGroupIndex ) );
82           if( !wordGroupLayoutInfo.mWordsLayoutInfo.empty() )
83           {
84             const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *( wordGroupLayoutInfo.mWordsLayoutInfo.begin() + relayoutParameters.mIndices.mWordIndex ) );
85             subLineInfo.mLineLength = wordLayoutInfo.mSize.width;
86           }
87         }
88       }
89
90       // Stores some info to calculate the line justification in a post-process.
91       TextView::LineJustificationInfo justificationInfo;
92
93       justificationInfo.mIndices = relayoutParameters.mIndices;
94       justificationInfo.mLineLength = subLineInfo.mLineLength;
95
96       relayoutData.mLineJustificationInfo.push_back( justificationInfo );
97
98       Toolkit::TextView::LineLayoutInfo lineInfo;
99       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
100       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of line.
101       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of line.
102       relayoutData.mLines.push_back( lineInfo );
103
104       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
105     }
106   }
107   else
108   {
109     return Vector3( wordOffset, previousPositionY, 0.f );
110   }
111 }
112
113 /**
114  * Calculates character position.
115  * @param[in] relayoutParameters Temporary layout parameters (previous size, previous position, ... )
116  * @param[in] layoutParameters The layout parameters.
117  * @param[in] relayoutData The text-view's data structures.
118  * @return The character's position.
119  */
120 Vector3 SplitWhenExceedPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
121                                  const TextView::LayoutParameters& layoutParameters,
122                                  TextView::RelayoutData& relayoutData )
123 {
124   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f :  relayoutParameters.mPositionOffset.x );
125   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
126
127   if( ( relayoutParameters.mIsNewLine || relayoutParameters.mIsFirstCharacter ) ||
128       ( relayoutParameters.mIsFirstCharacterOfWord && ( wordOffset + relayoutParameters.mWordSize.width > relayoutData.mTextViewSize.width ) ) ||
129       ( wordOffset + relayoutParameters.mCharacterSize.width > relayoutData.mTextViewSize.width ) )
130   {
131     if( !relayoutParameters.mIsNewLine &&
132         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewLineCharacter ) )
133     {
134       // Current character is a white space. Don't want to move a white space to the next line.
135       // These white spaces are placed just in the edge.
136       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
137     }
138     else
139     {
140       // Calculates the line length and the max character height for the current line.
141       TextViewRelayout::SubLineLayoutInfo subLineInfo;
142       subLineInfo.mLineLength = 0.f;
143       subLineInfo.mMaxCharHeight = 0.f;
144       subLineInfo.mMaxAscender = 0.f;
145       const TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + relayoutParameters.mIndices.mLineIndex ) );
146
147       TextViewRelayout::CalculateSubLineLayout( relayoutData.mTextViewSize.width,
148                                                 relayoutParameters.mIndices,
149                                                 lineLayoutInfo,
150                                                 TextViewRelayout::WrapByWordAndSplit,
151                                                 1.f, // Shrink factor.
152                                                 subLineInfo );
153
154       // Stores some info to calculate the line justification in a post-process.
155       TextView::LineJustificationInfo justificationInfo;
156
157       justificationInfo.mIndices = relayoutParameters.mIndices;
158       justificationInfo.mLineLength = subLineInfo.mLineLength;
159
160       relayoutData.mLineJustificationInfo.push_back( justificationInfo );
161
162       Toolkit::TextView::LineLayoutInfo lineInfo;
163       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
164       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of line.
165       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of line.
166       relayoutData.mLines.push_back( lineInfo );
167
168       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset, 0.f );
169     }
170   }
171   else
172   {
173     return Vector3( wordOffset, previousPositionY, 0.f );
174   }
175 }
176
177 /**
178  * Calculates character position.
179  * @param[in] relayoutParameters Temporary layout parameters (previous size, previous position, ... )
180  * @param[in] layoutParameters The layout parameters.
181  * @param[in] relayoutData The text-view's data structures.
182  * @return The character's position.
183  */
184 Vector3 ShrinkWidthWhenExceedPosition( const TextViewRelayout::RelayoutParameters& relayoutParameters,
185                                        const TextView::LayoutParameters& layoutParameters,
186                                        TextView::RelayoutData& relayoutData )
187 {
188   const float wordOffset = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.x );
189   const float previousPositionY = ( relayoutParameters.mIsFirstCharacter ? 0.f : relayoutParameters.mPositionOffset.y );
190   const Size wordSize = relayoutParameters.mWordSize * relayoutData.mShrinkFactor;
191
192   if( ( relayoutParameters.mIsNewLine || relayoutParameters.mIsFirstCharacter ) ||                                           // isNewLine is true when '\n' is found.
193       ( relayoutParameters.mIsFirstCharacterOfWord && ( wordOffset + wordSize.width > relayoutData.mTextViewSize.width ) ) ) // The word doesn't fit in the parent width.
194   {
195     if( !relayoutParameters.mIsNewLine &&
196         ( relayoutParameters.mIsWhiteSpace || relayoutParameters.mIsNewLineCharacter ) )
197     {
198       // Current character is a white space. Don't want to move a white space to the next line.
199       // These white spaces are placed just in the edge.
200       return Vector3( relayoutData.mTextViewSize.width - relayoutParameters.mWordSize.width, relayoutParameters.mPositionOffset.y, 0.f );
201     }
202     else
203     {
204       // Calculates the line length and the max character height for the current line.
205       TextViewRelayout::SubLineLayoutInfo subLineInfo;
206       subLineInfo.mLineLength = 0.f;
207       subLineInfo.mMaxCharHeight = 0.f;
208       subLineInfo.mMaxAscender = 0.f;
209       const TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + relayoutParameters.mIndices.mLineIndex ) );
210
211       TextViewRelayout::CalculateSubLineLayout( relayoutData.mTextViewSize.width,
212                                                 relayoutParameters.mIndices,
213                                                 lineLayoutInfo,
214                                                 TextViewRelayout::WrapByWord,
215                                                 relayoutData.mShrinkFactor,
216                                                 subLineInfo );
217
218       // Stores some info to calculate the line justification in a post-process.
219       TextView::LineJustificationInfo justificationInfo;
220
221       justificationInfo.mIndices = relayoutParameters.mIndices;
222       justificationInfo.mLineLength = subLineInfo.mLineLength;
223
224       relayoutData.mLineJustificationInfo.push_back( justificationInfo );
225
226       Toolkit::TextView::LineLayoutInfo lineInfo;
227       lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex;    // Index to the first character of the next line.
228       lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of line.
229       lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of line.
230       relayoutData.mLines.push_back( lineInfo );
231
232       return Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * relayoutData.mShrinkFactor, 0.f );
233     }
234   }
235   else
236   {
237     return Vector3( wordOffset, previousPositionY, 0.f );
238   }
239 }
240
241 void CalculatePositionsForShrinkWhenExceed( TextView::RelayoutData& relayoutData,
242                                             const TextView::LayoutParameters& layoutParameters,
243                                             const float shrinkFactor,
244                                             float& newTextHeight )
245 {
246   const float parentWidth = relayoutData.mTextViewSize.width;
247   TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
248
249   relayoutData.mLineJustificationInfo.clear();
250
251   // Reset the text height. This value is returned in order to shrink further or not the text.
252   newTextHeight = 0.f;
253
254   // Whether the first character is being processed.
255   bool isFirstChar = true;
256
257   // Stores the size of the previous character.
258   Size previousSize;
259   // Stores the position of the previous character.
260   Vector3 previousPosition;
261
262   // Reset the index of lines.
263   TextViewProcessor::TextInfoIndices indices;
264
265   // Whether the last character of the whole text is a new line char.
266   // This information is used to increase or not the height of the whole text by one line.
267   // Increase the whole text's height by one line is useful i.e. in TextInput to place the cursor
268   // after pressing 'Enter' in the last line.
269   bool isLastCharacterNewLineChar = false;
270   // Stores the height of the last character. This height used to be added to the whole text height if
271   // isLastCharacterNewLineChar is true.
272   float lastCharHeight = 0.f;
273
274   relayoutData.mLines.clear();
275   std::size_t characterGlobalIndex = 0;
276
277   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
278        lineIt != lineEndIt;
279        ++lineIt, ++indices.mLineIndex )
280   {
281     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineIt );
282
283     // The next character is in a new line.
284     bool isNewLine = true;
285
286     // Reset the index of groups of words.
287     indices.mGroupIndex = 0;
288
289     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), groupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
290          groupIt != groupEndIt;
291          ++groupIt, ++indices.mGroupIndex )
292     {
293       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupIt );
294
295       // Reset the index of words.
296       indices.mWordIndex = 0;
297
298       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
299            wordIt != wordEndIt;
300            ++wordIt, ++indices.mWordIndex )
301       {
302         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt );
303
304         // Reset the index of the character.
305         indices.mCharacterIndex = 0;
306
307         // Whether current character is the first of the word.
308         bool isFirstCharOfWord = true;
309         const float wordOffset = previousPosition.x + previousSize.width;
310
311         isLastCharacterNewLineChar = ( TextViewProcessor::LineSeparator == wordLayoutInfo.mType );
312
313         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
314              charIt != charEndIt;
315              ++charIt, ++indices.mCharacterIndex )
316         {
317           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt );
318           lastCharHeight = characterLayoutInfo.mSize.height * shrinkFactor;
319
320           const float previousPositionY = isFirstChar ? 0.f : previousPosition.y;
321
322           if( ( isNewLine || isFirstChar ) ||
323               ( isFirstCharOfWord && ( wordOffset + wordLayoutInfo.mSize.width * shrinkFactor > parentWidth ) ) )
324           {
325             isFirstChar = false;
326
327             // Calculates the line length and the max character height for the current line.
328             TextViewRelayout::SubLineLayoutInfo subLineInfo;
329             subLineInfo.mLineLength = 0.f;
330             subLineInfo.mMaxCharHeight = 0.f;
331             subLineInfo.mMaxAscender = 0.f;
332             TextViewRelayout::CalculateSubLineLayout( parentWidth,
333                                                       indices,
334                                                       lineLayoutInfo,
335                                                       TextViewRelayout::WrapByWord,
336                                                       shrinkFactor,
337                                                       subLineInfo );
338
339             characterLayoutInfo.mPosition = Vector3( 0.f, previousPositionY + subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor, 0.f );
340
341             newTextHeight += subLineInfo.mMaxCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor;
342
343             Toolkit::TextView::LineLayoutInfo lineInfo;
344             lineInfo.mCharacterGlobalIndex = characterGlobalIndex;                        // Index to the first character of the next line.
345             lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of line.
346             lineInfo.mAscender = subLineInfo.mMaxAscender;                                // Ascender of this piece of line.
347             relayoutData.mLines.push_back( lineInfo );
348
349
350             // Stores some info to calculate the line justification in a post-process.
351             TextView::LineJustificationInfo justificationInfo;
352
353             justificationInfo.mIndices = indices;
354             justificationInfo.mLineLength = subLineInfo.mLineLength;
355
356             relayoutData.mLineJustificationInfo.push_back( justificationInfo );
357           }
358           else
359           {
360             characterLayoutInfo.mPosition = previousPosition + Vector3( previousSize.width, 0.f, 0.f );
361           }
362
363           // Get last line info and calculate the bearing.
364           const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1 ) );
365           const float bearingOffset = ( ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender ) ) * shrinkFactor;
366
367           previousSize = characterLayoutInfo.mSize * shrinkFactor;
368           previousPosition = characterLayoutInfo.mPosition;
369           characterLayoutInfo.mPosition.y -= bearingOffset;
370           isFirstCharOfWord = false;
371           isNewLine = false;
372
373           ++characterGlobalIndex;
374         }
375       }
376     }
377   }
378
379   if( isLastCharacterNewLineChar )
380   {
381     newTextHeight += lastCharHeight + layoutParameters.mLineHeightOffset * shrinkFactor;
382   }
383 }
384
385 float RelayoutForShrinkToFit( TextView::RelayoutData& relayoutData,
386                               const TextView::LayoutParameters& layoutParameters )
387 {
388   const Size& textViewSize = relayoutData.mTextViewSize;
389   TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
390
391   // First step is assure the longest word fits in the text view width.
392   float shrinkFactor = ( textLayoutInfo.mMaxWordWidth > textViewSize.width ? textViewSize.width / textLayoutInfo.mMaxWordWidth : 1.f );
393
394   // Out parameter. Will store the new text height after relayout the text.
395   float newTextHeight = 0.f;
396
397   // Relayout the text for the given character's sizes.
398   CalculatePositionsForShrinkWhenExceed( relayoutData,
399                                          layoutParameters,
400                                          shrinkFactor,
401                                          newTextHeight );
402
403   if( newTextHeight > textViewSize.height )
404   {
405     // After relayouting, the text exceeds the text view height.
406     // Find a new scale factor to fit all the text in the text view size is needed.
407
408     // The next algorithm does some iterations to calculate an acceptable scale factor.
409     // Some magic numbers are defined.
410
411     const float MIN_RATIO( 0.90f );         // The algorithm finishes if the ratio
412     const float MAX_RATIO( 1.00f );         // new_text_height / text_view_height is between this two values
413     const unsigned int MAX_ITERATIONS( 8 ); // or max_iteration is reached.
414
415     float ratio = newTextHeight / textViewSize.height;
416
417     float maxScaleFactor = shrinkFactor;                        // bigger scale factors than maxScaleFactor will produce a too big text.
418     float minScaleFactor = shrinkFactor * ( textViewSize.height / newTextHeight ); // smaller scale factors than minScaleFactor will produce a too small text.
419
420     for( unsigned int iterations = 0; ( ( MIN_RATIO > ratio ) || ( ratio > MAX_RATIO )  ) && ( iterations < MAX_ITERATIONS ); ++iterations )
421     {
422       // Calculates the new scale factor.
423       // The new scale factor is always between the min and max scale factors.
424       // 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
425       // minScaleFactor. Alternatively if the text is too big a new scale factor close to maxScaleFactor is selected.
426       // This allows the text shrink or grow smoothly.
427       shrinkFactor = minScaleFactor + ( ratio < 1.f ? 0.4f : 0.6f ) * ( maxScaleFactor - minScaleFactor );
428
429       CalculatePositionsForShrinkWhenExceed( relayoutData, // Relayout the text for the given character's sizes.
430                                              layoutParameters,
431                                              shrinkFactor,
432                                              newTextHeight );
433
434       // Calculates the new text size ratio. It allows update the min and max scale factors.
435       // If the ratio is not good enough a new scale factor between min and max could be used in next iteration.
436       ratio = newTextHeight / textViewSize.height;
437       if( ratio < 1.f )
438       {
439         minScaleFactor = shrinkFactor;
440       }
441       else
442       {
443         maxScaleFactor = shrinkFactor;
444       }
445     }
446
447     if( ratio > MAX_RATIO )
448     {
449       // The algorithm didn't find an acceptable scale factor.
450       // In that case the text is shrunk to fit in the boundaries of the text view actor.
451       shrinkFactor = minScaleFactor;
452
453       CalculatePositionsForShrinkWhenExceed( relayoutData,
454                                              layoutParameters,
455                                              shrinkFactor,
456                                              newTextHeight );
457     }
458   }
459
460   return shrinkFactor;
461 }
462
463 void CalculateSizeAndPosition( const TextView::LayoutParameters& layoutParameters,
464                                TextView::RelayoutData& relayoutData )
465 {
466   TextViewRelayout::RelayoutParameters relayoutParameters;
467
468   // clear
469   relayoutData.mCharacterLayoutInfoTable.clear();
470   relayoutData.mLines.clear();
471   relayoutData.mTextSizeForRelayoutOption = Size();
472
473   // Calculates the text size for split by char.
474   Vector4 minMaxXY( std::numeric_limits<float>::max(),
475                     std::numeric_limits<float>::max(),
476                     std::numeric_limits<float>::min(),
477                     std::numeric_limits<float>::min() );
478
479   relayoutData.mShrinkFactor = 1.f; // Shrink factor used when the exceed policy contains ShrinkToFit
480
481   if( TextView::Shrink== layoutParameters.mExceedPolicy )
482   {
483     // Relays-out the text for the shrink to fit policy.
484     relayoutData.mShrinkFactor = RelayoutForShrinkToFit( relayoutData, layoutParameters );
485   }
486   else if( TextView::ShrinkOriginal == layoutParameters.mExceedPolicy )
487   {
488     relayoutData.mShrinkFactor = ( relayoutData.mTextLayoutInfo.mMaxWordWidth > relayoutData.mTextViewSize.width ? relayoutData.mTextViewSize.width / relayoutData.mTextLayoutInfo.mMaxWordWidth : 1.f );
489   }
490
491   relayoutParameters.mPositionOffset = Vector3::ZERO;
492   relayoutParameters.mIsFirstCharacter = true;
493   relayoutParameters.mIndices.mLineIndex = 0;
494   relayoutParameters.mCharacterGlobalIndex = 0;
495
496   for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(),
497        endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
498        lineLayoutIt != endLineLayoutIt;
499        ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex )
500   {
501     TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt );
502
503     relayoutParameters.mIsNewLine = true;
504     relayoutParameters.mLineSize = lineLayoutInfo.mSize;
505     relayoutParameters.mIndices.mGroupIndex = 0;
506
507     for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(),
508          endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end();
509          groupLayoutIt != endGroupLayoutIt;
510          ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex )
511     {
512       TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt );
513
514       relayoutParameters.mIndices.mWordIndex = 0;
515
516       for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(),
517            endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
518            wordLayoutIt != endWordLayoutIt;
519            ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex )
520       {
521         TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt );
522         relayoutParameters.mIsWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType;
523         relayoutParameters.mIsNewLineCharacter = TextViewProcessor::LineSeparator == wordLayoutInfo.mType;
524
525         relayoutParameters.mIsFirstCharacterOfWord = true;
526         relayoutParameters.mWordSize = wordLayoutInfo.mSize;
527         relayoutParameters.mIndices.mCharacterIndex = 0;
528
529         for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(),
530              endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end();
531              ( characterLayoutIt != endCharacterLayoutIt );
532              ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex )
533         {
534           TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt );
535
536           relayoutParameters.mCharacterSize = characterLayoutInfo.mSize;
537
538           switch( layoutParameters.mExceedPolicy )
539           {
540             case TextView::OriginalShrink:
541             case TextView::SplitShrink:
542             case TextView::ShrinkFade:
543             {
544               DALI_LOG_WARNING( "SplitByWord::CalculateSizeAndPosition() policy not implemented.\n" );
545               break;
546             }
547             case TextView::Original:
548             case TextView::OriginalFade:
549             case TextView::FadeOriginal:
550             case TextView::Fade:
551             case TextView::EllipsizeEndOriginal:
552             case TextView::EllipsizeEnd: // Fall Through
553             {
554               characterLayoutInfo.mPosition = OriginalPosition( relayoutParameters,
555                                                                 layoutParameters,
556                                                                 relayoutData );
557
558               relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
559               break;
560             }
561             case TextView::SplitOriginal:
562             case TextView::SplitFade:
563             case TextView::SplitEllipsizeEnd:
564             {
565               characterLayoutInfo.mPosition = SplitWhenExceedPosition( relayoutParameters,
566                                                                        layoutParameters,
567                                                                        relayoutData );
568
569               relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width, 0.f, 0.f );
570               break;
571             }
572             case TextView::ShrinkOriginal:
573             {
574               characterLayoutInfo.mPosition = ShrinkWidthWhenExceedPosition( relayoutParameters,
575                                                                              layoutParameters,
576                                                                              relayoutData );
577
578               relayoutParameters.mPositionOffset = characterLayoutInfo.mPosition + Vector3( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor, 0.f, 0.f );
579               break;
580             }
581             case TextView::Shrink:
582             {
583               // Does nothing. All the job has been done in the RelayoutForShrinkToFit() function.
584               break;
585             }
586             default:
587             {
588               DALI_LOG_WARNING( "SplitByWord::CalculateSizeAndPosition() policy combination not possible.\n" );
589             }
590           }
591
592           // Get last line info and calculate the bearing (used to align glyphs with the baseline).
593           if( TextView::Shrink != layoutParameters.mExceedPolicy )
594           {
595             TextViewRelayout::CalculateBearing( characterLayoutInfo, relayoutData );
596           }
597
598           // updates min and max position to calculate the text size for split by word.
599           TextViewRelayout::UpdateLayoutInfoTable( minMaxXY,
600                                                    wordGroupLayoutInfo,
601                                                    wordLayoutInfo,
602                                                    characterLayoutInfo,
603                                                    relayoutParameters,
604                                                    relayoutData );
605
606           ++relayoutParameters.mCharacterGlobalIndex;
607           relayoutParameters.mIsFirstCharacter = false;
608           relayoutParameters.mIsFirstCharacterOfWord = false;
609           relayoutParameters.mIsNewLine = false;
610         } // end characters
611       } // end words
612     } // end group of words
613   } // end lines
614
615   if( relayoutData.mCharacterLayoutInfoTable.empty() )
616   {
617     relayoutData.mTextSizeForRelayoutOption = Size();
618   }
619   else
620   {
621     relayoutData.mTextSizeForRelayoutOption.width = minMaxXY.z - minMaxXY.x;
622     relayoutData.mTextSizeForRelayoutOption.height = minMaxXY.w - minMaxXY.y;
623   }
624
625   // Check if the last character is a new line character. In that case the height should be added.
626   if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
627   {
628     const TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
629
630     if( lineLayoutInfo.mWordGroupsLayoutInfo.empty() ) // if it's empty, it means the last character is a new line character.
631     {
632       relayoutData.mTextSizeForRelayoutOption.height += lineLayoutInfo.mSize.height * relayoutData.mShrinkFactor;
633     }
634   }
635 }
636
637 } // namespace
638
639 void Relayout( Actor textView,
640                TextView::RelayoutOperationMask relayoutOperationMask,
641                const TextView::LayoutParameters& layoutParameters,
642                const TextView::VisualParameters& visualParameters,
643                TextView::RelayoutData& relayoutData )
644 {
645   if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION )
646   {
647     relayoutData.mLineJustificationInfo.clear();
648     CalculateSizeAndPosition( layoutParameters,
649                               relayoutData );
650
651     TextViewRelayout::SetUnderlineInfo( relayoutData );
652   }
653
654   if( relayoutOperationMask & TextView::RELAYOUT_ALIGNMENT )
655   {
656     TextViewRelayout::UpdateAlignment( layoutParameters,
657                                        relayoutData );
658   }
659
660   if( relayoutOperationMask & TextView::RELAYOUT_VISIBILITY )
661   {
662     TextViewRelayout::UpdateVisibility( layoutParameters,
663                                         visualParameters,
664                                         relayoutData );
665   }
666
667   if( relayoutOperationMask & TextView::RELAYOUT_INITIALIZE_TEXT_ACTORS )
668   {
669     TextViewProcessor::InitializeTextActorInfo( relayoutData );
670   }
671
672   if( relayoutOperationMask & TextView::RELAYOUT_TEXT_ACTOR_UPDATE )
673   {
674     TextViewRelayout::UpdateTextActorInfo( visualParameters,
675                                            relayoutData );
676   }
677
678   if( ( relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW ) ||
679       ( relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST ) )
680   {
681     TextViewRelayout::InsertToTextView( relayoutOperationMask,
682                                         textView,
683                                         relayoutData );
684   }
685 }
686
687 } // namespace SplitByWord
688
689 } // namespace Internal
690
691 } // namespace Toolkit
692
693 } // namespace Dali