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