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