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