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