Split dali-toolkit into Base & Optional
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / text-view-processor.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 // INTERNAL INCLUDES
18 #include <dali/integration-api/debug.h>
19 #include "text-view-processor.h"
20 #include "text-view-word-processor.h"
21 #include "text-view-word-group-processor.h"
22 #include "text-view-line-processor.h"
23 #include "text-view-processor-helper-functions.h"
24 #include "text-processor.h"
25 #include "text-view-processor-dbg.h"
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace TextViewProcessor
37 {
38
39 namespace
40 {
41 /**
42  * Update text layout info.
43  *
44  * Updates the size of the whole text, the maximum width of all words and the number of characters.
45  *
46  * @param[in,out] textLayoutInfo
47  */
48 void UpdateTextLayoutInfo( TextLayoutInfo& textLayoutInfo )
49 {
50   // Initialize members to be updated.
51   textLayoutInfo.mWholeTextSize = Size();
52   textLayoutInfo.mMaxWordWidth = 0.f;
53   textLayoutInfo.mNumberOfCharacters = 0;
54
55   // Traverse all text updating values.
56   for( LineLayoutInfoContainer::const_iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
57        lineIt != lineEndIt;
58        ++lineIt )
59   {
60     const LineLayoutInfo& line( *lineIt );
61
62     // Updates text size with the size of all lines.
63     UpdateSize( textLayoutInfo.mWholeTextSize, line.mSize, GrowHeight );
64
65     // Updates number of characters.
66     textLayoutInfo.mNumberOfCharacters += line.mNumberOfCharacters;
67
68     // Updates the max word's width.
69     for( WordGroupLayoutInfoContainer::const_iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
70          groupIt != groupEndIt;
71          ++groupIt )
72     {
73       const WordGroupLayoutInfo& group( *groupIt );
74       for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
75            wordIt != wordEndIt;
76            ++wordIt )
77       {
78         const WordLayoutInfo& word( *wordIt );
79
80         textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, word.mSize.width );
81       }
82     }
83   }
84 }
85
86 } // namespace
87
88 // Constructors and assignment operators
89
90 TextInfoIndices::TextInfoIndices()
91 : mLineIndex( 0 ),
92   mGroupIndex( 0 ),
93   mWordIndex( 0 ),
94   mCharacterIndex( 0 )
95 {
96 }
97
98 TextInfoIndices::TextInfoIndices( const std::size_t lineIndex,
99                                   const std::size_t groupIndex,
100                                   const std::size_t wordIndex,
101                                   const std::size_t characterIndex )
102 : mLineIndex( lineIndex ),
103   mGroupIndex( groupIndex ),
104   mWordIndex( wordIndex ),
105   mCharacterIndex( characterIndex )
106 {
107 }
108
109 bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const
110 {
111   return ( ( mLineIndex == indices.mLineIndex ) &&
112            ( mGroupIndex == indices.mGroupIndex ) &&
113            ( mWordIndex == indices.mWordIndex ) &&
114            ( mCharacterIndex == indices.mCharacterIndex ) );
115 }
116
117 /////////////////////
118 // Layout info.
119 /////////////////////
120
121 TextLayoutInfo::TextLayoutInfo()
122 : mWholeTextSize(),
123   mMaxWordWidth( 0.f ),
124   mLinesLayoutInfo(),
125   mNumberOfCharacters( 0 ),
126   mMaxItalicsOffset( 0.f ),
127   mEllipsizeLayoutInfo()
128 {
129 }
130
131 TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
132 : mWholeTextSize( text.mWholeTextSize ),
133   mMaxWordWidth( text.mMaxWordWidth ),
134   mLinesLayoutInfo( text.mLinesLayoutInfo ),
135   mNumberOfCharacters( text.mNumberOfCharacters ),
136   mMaxItalicsOffset( text.mMaxItalicsOffset ),
137   mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
138 {
139 }
140
141 TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
142 {
143   mWholeTextSize = text.mWholeTextSize;
144   mMaxWordWidth = text.mMaxWordWidth;
145   mLinesLayoutInfo = text.mLinesLayoutInfo;
146   mNumberOfCharacters = text.mNumberOfCharacters;
147   mMaxItalicsOffset = text.mMaxItalicsOffset;
148   mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo;
149
150   return *this;
151 }
152
153 /////////////////////////////////////////////////////////////////////////////////////////////
154
155 void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
156                      const TextView::LayoutParameters& layoutParameters,
157                      TextView::RelayoutData& relayoutData )
158 {
159   // * Traverse the given text spliting it in lines, each line in groups of words and each group of words in words.
160   // * If possible, it joins characters with same style in one text-actor.
161   // * White spaces and new line characters are alone in one word.
162   // * Bidirectional text is processed in each line.
163   // * A group of words contains text in only one direction (Left to Right or Right to Left but not a mix of both).
164   // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
165   // * Generates a text-actor data structure to store text, style and text-actors.
166   // TODO: finish and test the bidirectional implementation.
167
168   // Collect previously created text-actors.
169   std::vector<TextActor> textActors;
170   CollectTextActorsFromLines( textActors, relayoutData.mTextLayoutInfo, 0, relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() );
171
172   if( !textActors.empty() )
173   {
174     // Add text-actors to the cache.
175     relayoutData.mTextActorCache.InsertTextActors( textActors );
176     relayoutData.mTextActorCache.ClearTexts();
177   }
178
179   // Store the ellipsize layout info before clearing the previous created info.
180   const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
181
182   // clear previous created info.
183   relayoutData.mTextLayoutInfo = TextLayoutInfo();
184   relayoutData.mCharacterLogicalToVisualMap.clear();
185   relayoutData.mCharacterVisualToLogicalMap.clear();
186
187   // Sets the ellipsize layout info.
188   relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
189
190   // Split the whole text in lines.
191   std::vector<MarkupProcessor::StyledTextArray> lines;
192   TextProcessor::SplitInLines( text,
193                                lines );
194
195   // Traverse all lines
196   for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator lineIt = lines.begin(), lineEndIt = lines.end(); lineIt != lineEndIt; ++lineIt )
197   {
198     const MarkupProcessor::StyledTextArray& line( *lineIt );
199
200     // Data structures for the new line
201     LineLayoutInfo lineLayoutInfo;
202
203     // Fills the line data structures with the layout info.
204     CreateLineInfo( line,
205                     relayoutData,
206                     lineLayoutInfo );
207
208     if( 0 < lineLayoutInfo.mNumberOfCharacters )
209     {
210       // do not add the line offset if the line has no characters.
211       lineLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
212       lineLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
213     }
214     else
215     {
216       // line height needs to be added for the last line.
217
218       float lineHeight = 0.f;
219       // Get the last character of the last line.
220       if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
221       {
222         const LineLayoutInfo& lineInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
223
224         const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( lineInfo );
225
226         lineHeight = characterInfo.mSize.height;
227       }
228
229       lineLayoutInfo.mSize.height = lineHeight;
230     }
231
232     // Update layout info for the whole text.
233     UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, lineLayoutInfo.mSize, GrowHeight );
234     relayoutData.mTextLayoutInfo.mNumberOfCharacters += lineLayoutInfo.mNumberOfCharacters;
235
236     // Add the line to the current text.
237     relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lineLayoutInfo );
238   } // end of lines
239 }
240
241 void UpdateTextInfo( const std::size_t position,
242                      const MarkupProcessor::StyledTextArray& text,
243                      const TextView::LayoutParameters& layoutParameters,
244                      TextView::RelayoutData& relayoutData )
245 {
246   // Update current internal data structure with added text.
247
248   // * Creates layout info for the given text.
249   // * With the given position, find where to add the text.
250   // * If the new text is not added at the end of current text, a line need to be split.
251   // * Merge the last line of the new text to the last part or the split line.
252   // * Add lines between first and last of the new text.
253   // * Merge the first part of the split line with the first line of the new text.
254   // * Update layout info and create new text actors if needed.
255
256   // Early returns:
257
258   if( text.empty() )
259   {
260     // nothing to do if the input text is empty.
261     return;
262   }
263
264   if( 0 == relayoutData.mTextLayoutInfo.mNumberOfCharacters )
265   {
266     // Current text is empty. There is no need to update current data structure,
267     // just create a new one with the new input text.
268     CreateTextInfo( text,
269                     layoutParameters,
270                     relayoutData );
271     return;
272   }
273
274   // initial checks.
275   if( position > relayoutData.mTextLayoutInfo.mNumberOfCharacters )
276   {
277     // Asserts if text is to be added out of bounds.
278     DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
279   }
280
281   TextView::RelayoutData relayoutDataForNewText;
282
283   // Creates layout info for the given text.
284   // It doesn't create text-actors as text could be added to an existing one.
285   CreateTextInfo( text,
286                   layoutParameters,
287                   relayoutDataForNewText );
288
289   // Update logical-to-visual and visual-to-logical tables.
290   // TODO: check that for mixed RTL/LTR text.
291   std::size_t index = 0;
292   for( std::size_t i = 0; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
293   {
294     relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
295     relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
296     ++index;
297   }
298
299   // If a line is split, it stores the last part of the line.
300   LineLayoutInfo lastLineLayoutInfo;
301
302   // Stores indices to the line, group of words, word and character of the given position.
303   TextInfoIndices textInfoIndices;
304
305   if( position < relayoutData.mTextLayoutInfo.mNumberOfCharacters )
306   {
307     // Get line, group, word and character indices for given position.
308     GetIndicesFromGlobalCharacterIndex( position,
309                                         relayoutData.mTextLayoutInfo,
310                                         textInfoIndices );
311
312     // 1) Split the line
313
314     // Split a line in two is needed, then merge the first part of the split line
315     // with the first line of the new text, add subsequent lines and merge the last line
316     // of the new text with the last part of the split line.
317
318     // Implementation notes!
319     //
320     // These references to the first line are declared in this scope because if new lines are inserted in step 2,
321     // they become invalid, making the algorithm to crash if used again.
322     // In the step 3, references to the first line are needed and declared again.
323
324     // Stores the first part of the split line.
325     LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
326
327     SplitLine( textInfoIndices,
328                PointSize( layoutParameters.mLineHeightOffset ),
329                firstLineLayoutInfo,
330                lastLineLayoutInfo );
331   }
332   else
333   {
334     // Position is just after the last character.
335     // Calculates indices for that position.
336     if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
337     {
338       textInfoIndices.mLineIndex = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() - 1;
339       const LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
340
341       if( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() )
342       {
343         textInfoIndices.mGroupIndex = lineLayoutInfo.mWordGroupsLayoutInfo.size() - 1;
344         const WordGroupLayoutInfo& groupLayoutInfo( *( lineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) );
345
346         if( !groupLayoutInfo.mWordsLayoutInfo.empty() )
347         {
348           textInfoIndices.mWordIndex = groupLayoutInfo.mWordsLayoutInfo.size() - 1;
349
350           const WordLayoutInfo& wordLayoutInfo( *( groupLayoutInfo.mWordsLayoutInfo.end() - 1 ) );
351           textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
352         }
353       }
354     }
355   }
356
357   // 2) If the new text has more than 1 line, merge the last line of the input text with the last part of the split line.
358   //TODO check this cases ( num lines ==1, >1, >2 ) if it could be simplified.
359   if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 1 )
360   {
361     LineLayoutInfo& lastInputLineLayoutInfo( *( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
362
363     MergeLine( lastInputLineLayoutInfo,
364                lastLineLayoutInfo );
365
366     if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 2 )
367     {
368       // Insert all lines except first and last in the text.
369       relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + 1,
370                                                             relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() + 1,
371                                                             relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 );
372     }
373
374     // Insert the last line to the text
375     relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() - 1,
376                                                           lastInputLineLayoutInfo );
377   }
378   else
379   {
380     // Merge the new line to the last part of the split line.
381     LineLayoutInfo& inputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
382
383     MergeLine( inputLineLayoutInfo,
384                lastLineLayoutInfo );
385   }
386
387   // 3) Merge the first line of the split text with the first line of the input text.
388   LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
389   LineLayoutInfo& firstInputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
390
391   MergeLine( firstLineLayoutInfo,
392              firstInputLineLayoutInfo );
393
394   // 4) Update text info.
395
396   // Updates the whole text size, maximum word size, etc.
397   UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
398 }
399
400 void UpdateTextInfo( const std::size_t position,
401                      const std::size_t numberOfCharacters,
402                      const TextView::LayoutParameters& layoutParameters,
403                      TextView::RelayoutData& relayoutData,
404                      const TextOperationOnRemove clearText )
405 {
406   // Removes 'numberOfCharacters' starting from 'position'.
407
408   // * It checks if text to be deleted is in the same line or not:
409   // *   If it is not, check which lines need to be split/merged or deleted.
410   // *   If it is but all characters of the line are going to be deleted, just delete the line (nothing needs to be split/merged)
411   // *   If only some characters of the same line are going to be deleted, proceed similarly: check if text to be deleted is in the same group of words.
412   // *     If it is not, check which groups of words need to be split/merged or deleted. Two groups of words can't be merged if they contain text with different direction (Left to Right / Right to Left)
413   // *     If it is but all characters of the group are going to be deleted, delete the group. TODO: Check if previous and following group need to be merged.
414   // *     If only some characters of the same group of words need to be deleted, proceed similarly: check if text to be deleted is in the same word.
415   // *       If it is not, split/merge words.
416   // *       Check if the whole word needs to be deleted.
417   // *       Check if only some characters of the word need to be deleted.
418   // * Updates layout info.
419
420   // * The algorithm checks if a word separator is deleted (in that case, different words need to be merged) and if a new line separator is deleted (two lines need to be merged).
421
422   // Early return
423
424   if( 0 == numberOfCharacters )
425   {
426     DALI_ASSERT_DEBUG( !"TextViewProcessor::UpdateTextInfo. WARNING: trying to delete 0 characters!" )
427
428     // nothing to do if no characters are deleted.
429     return;
430   }
431
432   // Asserts if trying to delete text out of bounds.
433   DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
434
435   // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
436   relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
437   relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
438
439   // Get line, group of words, word and character indices for the given start position.
440   TextInfoIndices textInfoIndicesBegin;
441   GetIndicesFromGlobalCharacterIndex( position,
442                                       relayoutData.mTextLayoutInfo,
443                                       textInfoIndicesBegin );
444
445   // Get line, group of words, word and character indices for the given end position (start position + number of characters to be deleted).
446   TextInfoIndices textInfoIndicesEnd;
447   GetIndicesFromGlobalCharacterIndex( position + numberOfCharacters - 1,
448                                       relayoutData.mTextLayoutInfo,
449                                       textInfoIndicesEnd );
450
451   // Vectors used to temporary store text-actors removed from text.
452   // Three vectors are needed because text-actors are not removed in order
453   // but insert them in order is required to reuse them later.
454   std::vector<TextActor> removedTextActorsFromBegin;
455   std::vector<TextActor> removedTextActorsFromMid;
456   std::vector<TextActor> removedTextActorsFromEnd;
457
458   // Whether lines, group of words and words need to be merged.
459   bool mergeLines = false;
460   bool mergeGroups = false;
461   bool mergeWords = false;
462
463   // Indices of the lines, group of words and words to be merged.
464   TextInfoIndices textInfoMergeIndicesBegin;
465   TextInfoIndices textInfoMergeIndicesEnd;
466
467   const LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) ); // used to check the number of characters of the line
468                                                                                                                                     // if all characters to be deleted are in the same line.
469   if( textInfoIndicesBegin.mLineIndex < textInfoIndicesEnd.mLineIndex )
470   {
471     // Deleted text is from different lines. It may need to split two lines, and merge first part of the first one with last part of the last one.
472
473     // whether first or last line need to be split and merged with the last part.
474     bool mergeFirstLine = false;
475     bool mergeLastLine = true;
476
477     textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
478     textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
479
480     if( ( textInfoIndicesBegin.mGroupIndex > 0 ) || ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
481     {
482       // first character to be deleted is not the first one of the current line.
483       ++textInfoIndicesBegin.mLineIndex; // won't delete current line
484
485       // As some characters remain, this line could be merged with the last one.
486       mergeFirstLine = true;
487     }
488
489     // Check if all characters of the last line are going to be deleted.
490     bool wholeLinedeleted = false;
491     const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex ) );
492     if( textInfoIndicesEnd.mGroupIndex + 1 == lastLineLayout.mWordGroupsLayoutInfo.size() )
493     {
494       const WordGroupLayoutInfo& lastGroupLayout( *( lastLineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
495       if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
496       {
497         const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
498         if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
499         {
500           // All characters of the last line are going to be deleted.
501           ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
502
503           // the whole last line is deleted. Need to check if the next line could be merged.
504           mergeLastLine = false;
505           wholeLinedeleted = true;
506         }
507       }
508     }
509
510     if( wholeLinedeleted )
511     {
512       // It means the whole last line is deleted completely.
513       // It's needed to check if there is another line after that could be merged.
514       if( textInfoIndicesEnd.mLineIndex < relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() )
515       {
516           mergeLastLine = true;
517
518           // Point the first characters of the next line.
519           textInfoIndicesEnd.mGroupIndex = 0;
520           textInfoIndicesEnd.mWordIndex = 0;
521           textInfoIndicesEnd.mCharacterIndex = 0;
522           textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
523       }
524     }
525
526     // If some characters remain in the first and last line, they need to be merged.
527     mergeLines = mergeFirstLine && mergeLastLine;
528
529     if( mergeLines )
530     {
531       // last line is going to be merged with the first one, so is not needed.
532       ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
533     }
534
535     if( mergeFirstLine )
536     {
537       // Remove characters from the first line.
538
539       // Vectors used to temporary store text-actors removed from the line.
540       // Three vectors are needed because text-actors are not removed in order
541       // but insert them in order is required to reuse them later.
542       std::vector<TextActor> removedTextActorsFromFirstWord;
543       std::vector<TextActor> removedTextActorsFromFirstGroup;
544       std::vector<TextActor> removedTextActorsFromGroups;
545
546       // As lineIndexBegin has been increased just to not to remove the line, decrease now is needed to access it.
547       LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex - 1 ) );
548
549       if( textInfoIndicesBegin.mGroupIndex + 1 < lineLayout.mWordGroupsLayoutInfo.size() )
550       {
551         // Store text-actors before removing them.
552         CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, textInfoIndicesBegin.mGroupIndex + 1, lineLayout.mWordGroupsLayoutInfo.size() );
553
554         // Remove extra groups. If a line has left to right and right to left text, groups after current one could be removed.
555         RemoveWordGroupsFromLine( textInfoIndicesBegin.mGroupIndex + 1,
556                                   lineLayout.mWordGroupsLayoutInfo.size() - ( textInfoIndicesBegin.mGroupIndex + 1 ),
557                                   PointSize( layoutParameters.mLineHeightOffset ),
558                                   lineLayout );
559       }
560
561       WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
562
563       if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
564       {
565         // Remove extra words within current group of words. (and current word if whole characters are removed)
566         // 0 == characterIndexBegin means the whole word is deleted.
567         const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
568
569         // Store text-actors before removing them.
570         CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
571
572         const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
573         RemoveWordsFromWordGroup( wordIndex,
574                                   groupLayout.mWordsLayoutInfo.size() - wordIndex,
575                                   groupLayout );
576
577         // discount the removed number of characters.
578         lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
579       }
580
581       if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
582       {
583         // Only some characters of the word need to be removed.
584         WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
585
586         // Store text-actors before removing them.
587         CollectTextActors( removedTextActorsFromFirstWord, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
588
589         const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
590         RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
591                                   wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
592                                   wordLayout );
593
594         // discount the removed number of characters.
595         const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
596         groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
597         lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
598       }
599       UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
600
601       // Insert the text-actors in order.
602       removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
603       removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
604       removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
605     }
606
607     if( mergeLastLine && !wholeLinedeleted )
608     {
609       // Some characters from the last line need to be removed.
610
611       // Vectors used to temporary store text-actors removed from the group.
612       // Three vectors are needed because text-actors are not removed in order
613       // but insert them in order is required to reuse them later.
614       std::vector<TextActor> removedTextActorsFromFirstWord;
615       std::vector<TextActor> removedTextActorsFromFirstGroup;
616       std::vector<TextActor> removedTextActorsFromGroups;
617
618       // lineIndexEnd was increased to delete the last line if lines need to be merged.
619       // To access now the last line we need to decrease the index.
620       const std::size_t lineIndex = ( mergeLines ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex );
621
622       // Get the last line.
623       LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lineIndex ) );
624
625       if( textInfoIndicesEnd.mGroupIndex > 0 )
626       {
627         // Store text-actors before removing them.
628         CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, 0, textInfoIndicesEnd.mGroupIndex );
629
630         // Remove extra groups from the beginning of the line to the current group of words.
631         RemoveWordGroupsFromLine( 0,
632                                   textInfoIndicesEnd.mGroupIndex,
633                                   PointSize( layoutParameters.mLineHeightOffset ),
634                                   lineLayout );
635       }
636
637       // The group of characters which contains the characters to be removed is now the first one.
638       WordGroupLayoutInfo& groupLayout( *lineLayout.mWordGroupsLayoutInfo.begin() );
639
640       // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
641       const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
642       bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
643
644       if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
645       {
646         // Store text-actors before removing them.
647         CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
648
649         // Remove extra words. (and current word if whole characters are removed)
650         const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
651         RemoveWordsFromWordGroup( 0,
652                                   ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
653                                   groupLayout );
654
655         // discount the removed number of characters.
656         lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
657       }
658
659       if( !removeWholeWord )
660       {
661         // Only some characters of the word need to be deleted.
662
663         // After removing all extra words. The word with the characters to be removed is the first one.
664         WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
665
666         // Store text-actors before removing them.
667         CollectTextActors( removedTextActorsFromFirstWord, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
668
669         const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
670         RemoveCharactersFromWord( 0,
671                                   textInfoIndicesEnd.mCharacterIndex + 1,
672                                   wordLayout );
673
674         // discount the removed number of characters.
675         const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
676         groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
677         lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
678         UpdateGroupLayoutInfo( groupLayout );
679       }
680       UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
681
682       // Insert the text-actors in order.
683       removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
684       removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
685       removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
686     }
687   } // end delete text from different lines
688   else if( ( textInfoIndicesBegin.mLineIndex == textInfoIndicesEnd.mLineIndex ) && ( lineLayout.mNumberOfCharacters == numberOfCharacters ) )
689   {
690     // the whole line needs to be deleted.
691     ++textInfoIndicesEnd.mLineIndex; // will delete current line.
692   }
693   else
694   {
695     // deleted text is within the same line. (merge lines could be needed if the line separator character is deleted)
696
697     // Line which contains the characters to be deleted.
698     LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) );
699
700     const WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) ); // used to check the number of characters of the group of words
701                                                                                                                                 // if all characters to be deleted are in the same group of words.
702     if( textInfoIndicesBegin.mGroupIndex < textInfoIndicesEnd.mGroupIndex )
703     {
704       // Deleted text is from different group of words. The two different group of words may be merged if they have text with same direction.
705
706       // whether first or last group of words need to be split and merged with the last part.
707       bool splitFirstGroup = false;
708       bool splitLastGroup = true;
709
710       textInfoMergeIndicesBegin.mGroupIndex = textInfoIndicesBegin.mGroupIndex;
711       textInfoMergeIndicesEnd.mGroupIndex = textInfoIndicesEnd.mGroupIndex;
712
713       if( ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
714       {
715         // first character to be deleted is not the first one of the current group.
716         ++textInfoIndicesBegin.mGroupIndex; // won't delete current group
717
718         // As some characters remain, this group needs to be split and could be merged with the last one.
719         splitFirstGroup = true;
720       }
721
722       // Check if all characters of the last group are going to be deleted.
723       const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
724       if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
725       {
726         const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
727         if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
728         {
729           // All characters of the last group are going to be deleted.
730           ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
731
732           // The whole last group is deleted. No need to merge groups.
733           splitLastGroup = false;
734         }
735       }
736
737       // Only merge two groups if they are not deleted completely and they have same direction.
738       mergeGroups = ( splitFirstGroup && splitLastGroup ) && ( groupLayout.mDirection == lastGroupLayout.mDirection );
739
740       if( mergeGroups )
741       {
742         // last group is going to be merged.
743         ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
744       }
745
746       if( splitFirstGroup )
747       {
748         // Remove characters from the first group.
749
750         // As wordGroupIndexBegin has been increased just to not to remove the group of words, decrease now is needed to access it.
751         WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex - 1 ) );
752
753         if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
754         {
755           // Remove extra words within current group of words. (and current word if whole characters are removed)
756           // 0 == characterIndexBegin means the whole word is deleted.
757           const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
758
759           // Store text-actors before removing them.
760           CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
761
762           RemoveWordsFromWordGroup( wordIndex,
763                                     groupLayout.mWordsLayoutInfo.size() - wordIndex,
764                                     groupLayout );
765         }
766
767         if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
768         {
769           // Only some characters of the word need to be removed.
770           WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
771
772           // Store text-actors before removing them.
773           CollectTextActors( removedTextActorsFromBegin, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
774
775           RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
776                                     wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
777                                     wordLayout );
778         }
779       }
780
781       if( splitLastGroup )
782       {
783         // Some characters from the last group of words need to be removed.
784
785         // textInfoIndicesEnd.mGroupIndex was increased to delete the last group of words if groups need to be merged.
786         // To access now the last group of words we need to decrease the index.
787         std::size_t index = mergeGroups ? textInfoIndicesEnd.mGroupIndex - 1 : textInfoIndicesEnd.mGroupIndex;
788
789         // Get the last group of words.
790         WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + index ) );
791
792         // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
793         const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
794         bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
795
796         if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
797         {
798           // Store text-actors before removing them.
799           CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
800
801           // Remove extra words. (and current word if whole characters are removed)
802           RemoveWordsFromWordGroup( 0,
803                                     ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
804                                     groupLayout );
805         }
806
807         if( !removeWholeWord )
808         {
809           // Only some characters of the word need to be deleted.
810
811           // After removing all extra words. The word with the characters to be removed is the first one.
812           WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
813
814           // Store text-actors before removing them.
815           CollectTextActors( removedTextActorsFromBegin, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
816
817           RemoveCharactersFromWord( 0,
818                                     textInfoIndicesEnd.mCharacterIndex + 1,
819                                     wordLayout );
820         }
821       }
822     } // end of remove from different groups
823     else if( ( textInfoIndicesBegin.mGroupIndex == textInfoIndicesEnd.mGroupIndex ) && ( groupLayout.mNumberOfCharacters == numberOfCharacters ) )
824     {
825       // The whole group is deleted.
826       ++textInfoIndicesEnd.mGroupIndex; // will delete current group.
827       // TODO group before and group after need to be merged!!!
828     }
829     else
830     {
831       // characters to be deleted are on the same group of words. (words may need to be merged)
832
833       // Group of words which contains the characters to be deleted.
834       WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
835
836       RemoveCharactersFromWordGroupInfo( relayoutData,
837                                          numberOfCharacters,
838                                          mergeWords,
839                                          mergeLines,
840                                          textInfoIndicesBegin,
841                                          textInfoIndicesEnd,
842                                          textInfoMergeIndicesBegin,
843                                          textInfoMergeIndicesEnd,
844                                          groupLayout,
845                                          removedTextActorsFromBegin,
846                                          removedTextActorsFromEnd );
847
848       if( mergeWords )
849       {
850         // Merges words pointed by textInfoMergeIndicesBegin.mWordIndex and textInfoMergeIndicesEnd.mWordIndex calculated previously.
851         DALI_ASSERT_DEBUG( ( textInfoMergeIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (begin) out of bounds." );
852         DALI_ASSERT_DEBUG( ( textInfoMergeIndicesEnd.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (end) out of bounds." );
853
854         WordLayoutInfo& firstWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesBegin.mWordIndex ) );
855         WordLayoutInfo& lastWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesEnd.mWordIndex ) );
856
857         MergeWord( firstWordLayout,
858                    lastWordLayout );
859       }
860
861       // Store text-actors before removing them.
862       const std::size_t endIndex = ( mergeWords && ( textInfoIndicesEnd.mWordIndex > 0 ) ) ? textInfoIndicesEnd.mWordIndex - 1 : textInfoIndicesEnd.mWordIndex; // text-actors from the last word may have been added in the merge above.
863       CollectTextActorsFromWords( removedTextActorsFromMid, groupLayout, textInfoIndicesBegin.mWordIndex, endIndex );
864
865       // Remove unwanted words using previously calculated indices. (including the last part of the merged word)
866       groupLayout.mWordsLayoutInfo.erase( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex, groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex );
867
868       // Update group of words info
869       groupLayout.mNumberOfCharacters -= numberOfCharacters;
870       groupLayout.mSize = Size();
871       groupLayout.mAscender = 0;
872       for( WordLayoutInfoContainer::const_iterator it = groupLayout.mWordsLayoutInfo.begin(), endIt = groupLayout.mWordsLayoutInfo.end();
873            it != endIt;
874            ++it )
875       {
876         const WordLayoutInfo& layoutInfo( *it );
877         UpdateSize( groupLayout.mSize, layoutInfo.mSize );
878         groupLayout.mAscender = std::max( groupLayout.mAscender, layoutInfo.mAscender );
879       }
880     } // end of remove from same group
881
882     if( mergeGroups )
883     {
884       // Merges group of words pointed by textInfoMergeIndicesBegin.mGroupIndex and textInfoMergeIndicesEnd.mGroupIndex calculated previously.
885
886       WordGroupLayoutInfo& firstGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesBegin.mGroupIndex ) );
887
888       const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesEnd.mGroupIndex ) );
889
890       MergeWordGroup( firstGroupLayout,
891                       lastGroupLayout );
892     }
893
894     // Remove unwanted groups of words using previously calculated indices. (including the last part of the merged group of words)
895     lineLayout.mWordGroupsLayoutInfo.erase( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex, lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex );
896
897     // Update line info.
898     lineLayout.mNumberOfCharacters -= numberOfCharacters;
899     lineLayout.mSize = Size();
900     lineLayout.mAscender = 0;
901     for( WordGroupLayoutInfoContainer::const_iterator it = lineLayout.mWordGroupsLayoutInfo.begin(), endIt = lineLayout.mWordGroupsLayoutInfo.end();
902          it != endIt;
903          ++it )
904     {
905       const WordGroupLayoutInfo& layoutInfo( *it );
906       UpdateSize( lineLayout.mSize, layoutInfo.mSize );
907       lineLayout.mAscender = std::max( lineLayout.mAscender, layoutInfo.mAscender );
908     }
909     lineLayout.mSize.height += layoutParameters.mLineHeightOffset;
910     lineLayout.mLineHeightOffset = layoutParameters.mLineHeightOffset;
911   }// end delete text from same line.
912
913   if( mergeLines )
914   {
915     // Merges lines pointed by textInfoMergeIndicesBegin.mLineIndex and textInfoMergeIndicesEnd.mLineIndex calculated previously.
916
917     LineLayoutInfo& firstLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesBegin.mLineIndex ) );
918
919     const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesEnd.mLineIndex ) );
920
921     MergeLine( firstLineLayout,
922                lastLineLayout );
923   }
924
925   // Store text-actors before removing them.
926   const std::size_t endIndex = ( mergeLines && ( textInfoIndicesEnd.mLineIndex > 0 ) ) ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex; // text-actors from the last line may have been added in the merge above.
927   CollectTextActorsFromLines( removedTextActorsFromMid,
928                               relayoutData.mTextLayoutInfo,
929                               textInfoIndicesBegin.mLineIndex,
930                               endIndex );
931
932   // Remove unwanted lines using previously calculated indices. (including the last part of the merged line)
933   relayoutData.mTextLayoutInfo.mLinesLayoutInfo.erase( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex,
934                                                        relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex );
935
936   // Update text info.
937   UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
938
939   // If the last character of the last line is a new line character, an empty line need to be added.
940   if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
941   {
942     const WordLayoutInfo lastWordLayout = GetLastWordLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
943
944     if( LineSeparator == lastWordLayout.mType )
945     {
946       LineLayoutInfo lastLineLayout;
947
948       const CharacterLayoutInfo layoutInfo = GetLastCharacterLayoutInfo( lastWordLayout );
949       lastLineLayout.mSize.height = layoutInfo.mSize.height;
950
951       relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lastLineLayout );
952
953       relayoutData.mTextLayoutInfo.mWholeTextSize.height += layoutInfo.mSize.height;
954     }
955   }
956
957   // Clear the text from the text-actors if required.
958   if( CLEAR_TEXT == clearText )
959   {
960     ClearText( removedTextActorsFromEnd );
961     ClearText( removedTextActorsFromMid );
962     ClearText( removedTextActorsFromBegin );
963   }
964
965   // Insert text-actors into the cache.
966   // Text-actors are inserted in reverse order to use first the first removed.
967   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromEnd );
968   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromMid );
969   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
970 }
971
972 void UpdateTextInfo( const std::size_t position,
973                      const std::size_t numberOfCharacters,
974                      const MarkupProcessor::StyledTextArray& text,
975                      const TextView::LayoutParameters& layoutParameters,
976                      TextView::RelayoutData& relayoutData )
977 {
978   // Replaces 'numberOfCharacters' of text starting from 'position' with the given text.
979
980   // TODO: Temporary implementation with remove and insert.
981
982   // Remove.
983   UpdateTextInfo( position,
984                   numberOfCharacters,
985                   layoutParameters,
986                   relayoutData,
987                   KEEP_TEXT ); // Do not clear the text from the text-actors.
988
989   // Insert.
990   UpdateTextInfo( position,
991                   text,
992                   layoutParameters,
993                   relayoutData );
994 }
995
996 void UpdateTextInfo( const float lineHeightOffset,
997                      TextLayoutInfo& textLayoutInfo )
998 {
999   // Updates the space between lines with the new offset value.
1000
1001   float newTextHeight = 0.f;
1002
1003   for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1004        lineIt != lineEndIt;
1005        ++lineIt )
1006   {
1007     LineLayoutInfo& lineLayoutInfo( *lineIt );
1008
1009     lineLayoutInfo.mSize.height += ( lineHeightOffset - lineLayoutInfo.mLineHeightOffset );
1010     newTextHeight += lineLayoutInfo.mSize.height;
1011
1012     lineLayoutInfo.mLineHeightOffset = lineHeightOffset;
1013   }
1014
1015   textLayoutInfo.mWholeTextSize.height = newTextHeight;
1016 }
1017
1018 void UpdateTextInfo( const TextStyle& style,
1019                      const TextStyle::Mask mask,
1020                      TextView::RelayoutData& relayoutData )
1021 {
1022   // Change text style for all text-actors.
1023
1024   for( LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1025        lineIt != lineEndIt;
1026        ++lineIt )
1027   {
1028     LineLayoutInfo& line( *lineIt );
1029
1030     for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1031          groupIt != groupEndIt;
1032          ++groupIt )
1033     {
1034       WordGroupLayoutInfo& group( *groupIt );
1035
1036       for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1037            wordIt != wordEndIt;
1038            ++wordIt )
1039       {
1040         WordLayoutInfo& word( *wordIt );
1041
1042         for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1043              characterIt != characterEndIt;
1044              ++characterIt )
1045         {
1046           CharacterLayoutInfo& characterLayout( *characterIt );
1047
1048           characterLayout.mStyledText.mStyle.Copy( style, mask );
1049
1050           // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
1051           ChooseFontFamilyName( characterLayout.mStyledText );
1052
1053           // Mark the character to be set the new style into the text-actor.
1054           characterLayout.mSetStyle = true;
1055         } // end characters
1056       } // end words
1057     } // end group of words
1058   } // end lines
1059 }
1060
1061 void InitializeTextActorInfo( TextView::RelayoutData& relayoutData )
1062 {
1063   TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
1064   if( textLayoutInfo.mLinesLayoutInfo.empty() )
1065   {
1066     // nothing to do if there is no lines.
1067     return;
1068   }
1069
1070   std::size_t characterGlobalIndex = 0;  // Index to the global character (within the whole text).
1071   std::size_t lineLayoutInfoIndex = 0;   // Index to the laid out line info.
1072   const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
1073   bool lineLayoutEnd = false;            // Whether lineLayoutInfoIndex points at the last laid out line.
1074   bool glyphActorCreatedForLine = false; // Whether a renderable actor has been created for this line.
1075
1076   RenderableActor currentGlyphActor;      // text-actor used when the edit mode is disabled.
1077   TextStyle currentStyle;                // style for the current text-actor.
1078   Vector4 currentGradientColor;          // gradient color for the current text-actor.
1079   Vector2 currentStartPoint;             // start point for the current text-actor.
1080   Vector2 currentEndPoint;               // end point for the current text-actor.
1081   bool currentIsColorGlyph = false;      // Whether current glyph is an emoticon.
1082
1083   std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
1084
1085   for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1086        lineIt != lineEndIt;
1087        ++lineIt )
1088   {
1089     LineLayoutInfo& line( *lineIt );
1090
1091     for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1092          groupIt != groupEndIt;
1093          ++groupIt )
1094     {
1095       WordGroupLayoutInfo& group( *groupIt );
1096
1097       for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1098            wordIt != wordEndIt;
1099            ++wordIt )
1100       {
1101         WordLayoutInfo& word( *wordIt );
1102
1103         for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1104              characterIt != characterEndIt;
1105              ++characterIt )
1106         {
1107           CharacterLayoutInfo& characterLayout( *characterIt );
1108
1109           // Check if there is a new line.
1110           const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
1111
1112           if( newLine )
1113           {
1114             // Point to the next line.
1115             ++lineLayoutInfoIndex;
1116             if( lineLayoutInfoIndex >= lineLayoutInfoSize )
1117             {
1118               // Arrived at last line.
1119               lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
1120             }
1121             glyphActorCreatedForLine = false;
1122           }
1123
1124           if( !characterLayout.mStyledText.mText.IsEmpty() )
1125           {
1126             // Do not create a glyph-actor if there is no text.
1127             const Character character = characterLayout.mStyledText.mText[0]; // there are only one character per character layout.
1128
1129             if( characterLayout.mIsColorGlyph ||
1130                 !character.IsWhiteSpace() || // A new line character is also a white space.
1131                 ( character.IsWhiteSpace() && characterLayout.mStyledText.mStyle.GetUnderline() ) )
1132             {
1133               // Do not create a glyph-actor if it's a white space (without underline) or a new line character.
1134
1135               // Creates one glyph-actor per each counsecutive group of characters, with the same style, per line, or if it's an emoticon.
1136
1137               if( !glyphActorCreatedForLine ||
1138                   characterLayout.mIsColorGlyph ||
1139                   ( characterLayout.mStyledText.mStyle != currentStyle ) ||
1140                   ( characterLayout.mGradientColor != currentGradientColor ) ||
1141                   ( characterLayout.mStartPoint != currentStartPoint ) ||
1142                   ( characterLayout.mEndPoint != currentEndPoint ) ||
1143                   ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) )
1144               {
1145                 characterLayout.mSetText = false;
1146                 characterLayout.mSetStyle = false;
1147
1148                 // There is a new style or a new line.
1149                 glyphActorCreatedForLine = true;
1150
1151                 if( characterLayout.mIsColorGlyph )
1152                 {
1153                   ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1154                   if( !imageActor )
1155                   {
1156                     characterLayout.mGlyphActor = ImageActor::New();
1157                     characterLayout.mSetText = true;
1158                   }
1159                 }
1160                 else
1161                 {
1162                   TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1163
1164                   if( textActor )
1165                   {
1166                     // Try to reuse first the text-actor of this character.
1167                     textActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1168                     currentGlyphActor = textActor;
1169                   }
1170                   else
1171                   {
1172                     // If there is no text-actor, try to retrieve one from the cache.
1173                     textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1174
1175                     // If still there is no text-actor, create one.
1176                     if( !textActor )
1177                     {
1178                       textActor = TextActor::New( Text(), characterLayout.mStyledText.mStyle, false, true );
1179                     }
1180                     else
1181                     {
1182                       textActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1183                     }
1184
1185                     currentGlyphActor = textActor;
1186                   }
1187                   characterLayout.mGlyphActor = currentGlyphActor;
1188                 }
1189
1190                 // Update style to be checked with next characters.
1191                 currentStyle = characterLayout.mStyledText.mStyle;
1192                 currentGradientColor = characterLayout.mGradientColor;
1193                 currentStartPoint = characterLayout.mStartPoint;
1194                 currentEndPoint = characterLayout.mEndPoint;
1195                 currentIsColorGlyph = characterLayout.mIsColorGlyph;
1196
1197                 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1198                 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1199               }
1200               else
1201               {
1202                 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
1203
1204                 // Same style than previous one.
1205                 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1206                 if( textActor )
1207                 {
1208                   // There is a previously created text-actor for this character.
1209                   // If this character has another one put it into the cache.
1210                   textActor.SetText( "" );
1211                   textActorsToRemove.push_back( textActor );
1212                 }
1213
1214                 if( characterLayout.mGlyphActor )
1215                 {
1216                   characterLayout.mGlyphActor.Reset();
1217                 }
1218               }
1219             } // no white space / new line char
1220           } // text not empty
1221
1222           ++characterGlobalIndex;
1223         } // characters
1224       } // words
1225     } // groups
1226   } // lines
1227
1228   // Insert the spare text-actors into the cache.
1229   relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
1230 }
1231
1232 } // namespace TextViewProcessor
1233
1234 } // namespace Internal
1235
1236 } // namespace Toolkit
1237
1238 } // namespace Dali