7ffbe3b6b5a990bd1a000edd6815ef05e974298b
[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 // FILE HEADER
19 #include <dali-toolkit/internal/controls/text-view/text-view-processor.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
23 #include <dali-toolkit/internal/controls/text-view/text-view-line-processor.h>
24 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
25 #include <dali-toolkit/internal/controls/text-view/text-processor.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 UpdateLayoutInfo( TextLayoutInfo& textLayoutInfo )
49 {
50   // Initialize members to be updated.
51   textLayoutInfo.mWholeTextSize = Size::ZERO;
52   textLayoutInfo.mMaxWordWidth = 0.f;
53   textLayoutInfo.mNumberOfCharacters = 0u;
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     for( WordLayoutInfoContainer::const_iterator wordIt = line.mWordsLayoutInfo.begin(), wordEndIt = line.mWordsLayoutInfo.end();
69          wordIt != wordEndIt;
70          ++wordIt )
71     {
72       const WordLayoutInfo& word( *wordIt );
73
74       textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, word.mSize.width );
75     }
76   }
77 }
78
79 } // namespace
80
81 // Constructors and assignment operators
82
83 TextInfoIndices::TextInfoIndices()
84 : mLineIndex( 0u ),
85   mWordIndex( 0u ),
86   mCharacterIndex( 0u )
87 {
88 }
89
90 TextInfoIndices::TextInfoIndices( const std::size_t lineIndex,
91                                   const std::size_t wordIndex,
92                                   const std::size_t characterIndex )
93 : mLineIndex( lineIndex ),
94   mWordIndex( wordIndex ),
95   mCharacterIndex( characterIndex )
96 {
97 }
98
99 bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const
100 {
101   return ( ( mLineIndex == indices.mLineIndex ) &&
102            ( mWordIndex == indices.mWordIndex ) &&
103            ( mCharacterIndex == indices.mCharacterIndex ) );
104 }
105
106 /////////////////////
107 // Layout info.
108 /////////////////////
109
110 TextLayoutInfo::TextLayoutInfo()
111 : mWholeTextSize(),
112   mMaxWordWidth( 0.f ),
113   mLinesLayoutInfo(),
114   mNumberOfCharacters( 0u ),
115   mMaxItalicsOffset( 0.f ),
116   mEllipsizeLayoutInfo()
117 {
118 }
119
120 TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
121 : mWholeTextSize( text.mWholeTextSize ),
122   mMaxWordWidth( text.mMaxWordWidth ),
123   mLinesLayoutInfo( text.mLinesLayoutInfo ),
124   mNumberOfCharacters( text.mNumberOfCharacters ),
125   mMaxItalicsOffset( text.mMaxItalicsOffset ),
126   mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
127 {
128 }
129
130 TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
131 {
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   return *this;
140 }
141
142 /////////////////////////////////////////////////////////////////////////////////////////////
143
144 void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
145                      const TextView::LayoutParameters& layoutParameters,
146                      TextView::RelayoutData& relayoutData )
147 {
148   // * Traverse the given text spliting it in lines and each line in words.
149   // * White spaces and new line characters are alone in one word.
150   // * Bidirectional text is processed in each line.
151   // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
152   // * Generates a text-actor data structure to store text, style and text-actors.
153   // TODO: finish and test the bidirectional implementation.
154
155   // Collect previously created text-actors.
156   std::vector<TextActor> textActors;
157   CollectTextActorsFromLines( textActors, relayoutData.mTextLayoutInfo, 0u, relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() );
158
159   if( !textActors.empty() )
160   {
161     // Add text-actors to the cache.
162     relayoutData.mTextActorCache.InsertTextActors( textActors );
163     relayoutData.mTextActorCache.ClearTexts();
164   }
165
166   // Store the ellipsize layout info before clearing the previous created info.
167   const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
168
169   // clear previous created info.
170   relayoutData.mTextLayoutInfo = TextLayoutInfo();
171   relayoutData.mCharacterLogicalToVisualMap.clear();
172   relayoutData.mCharacterVisualToLogicalMap.clear();
173
174   // Sets the ellipsize layout info.
175   relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
176
177   // Split the whole text in lines.
178   std::vector<MarkupProcessor::StyledTextArray> lines;
179   TextProcessor::SplitInLines( text,
180                                lines );
181
182   // Traverse all lines
183   for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator lineIt = lines.begin(), lineEndIt = lines.end(); lineIt != lineEndIt; ++lineIt )
184   {
185     const MarkupProcessor::StyledTextArray& line( *lineIt );
186
187     // Data structures for the new line
188     LineLayoutInfo lineLayoutInfo;
189
190     // Fills the line data structures with the layout info.
191     CreateLineInfo( line,
192                     relayoutData,
193                     lineLayoutInfo );
194
195     if( 0u < lineLayoutInfo.mNumberOfCharacters )
196     {
197       // do not add the line offset if the line has no characters.
198       lineLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
199       lineLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
200     }
201     else
202     {
203       // line height needs to be added for the last line.
204
205       float lineHeight = 0.f;
206       // Get the last character of the last line.
207       if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
208       {
209         const LineLayoutInfo& lineInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1u ) );
210
211         const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( lineInfo );
212
213         lineHeight = characterInfo.mSize.height;
214       }
215
216       lineLayoutInfo.mSize.height = lineHeight;
217     }
218
219     // Update layout info for the whole text.
220     UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, lineLayoutInfo.mSize, GrowHeight );
221     relayoutData.mTextLayoutInfo.mNumberOfCharacters += lineLayoutInfo.mNumberOfCharacters;
222
223     // Add the line to the current text.
224     relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lineLayoutInfo );
225   } // end of lines
226 }
227
228 void UpdateTextInfo( const std::size_t position,
229                      const MarkupProcessor::StyledTextArray& text,
230                      const TextView::LayoutParameters& layoutParameters,
231                      TextView::RelayoutData& relayoutData )
232 {
233   // Update current internal data structure with added text.
234
235   // * Creates layout info for the given text.
236   // * With the given position, find where to add the text.
237   // * If the new text is not added at the end of current text, a line need to be split.
238   // * Merge the last line of the new text to the last part or the split line.
239   // * Add lines between first and last of the new text.
240   // * Merge the first part of the split line with the first line of the new text.
241   // * Update layout info and create new text actors if needed.
242
243   // Early returns:
244
245   if( text.empty() )
246   {
247     // nothing to do if the input text is empty.
248     return;
249   }
250
251   if( 0u == relayoutData.mTextLayoutInfo.mNumberOfCharacters )
252   {
253     // Current text is empty. There is no need to update current data structure,
254     // just create a new one with the new input text.
255     CreateTextInfo( text,
256                     layoutParameters,
257                     relayoutData );
258     return;
259   }
260
261   // initial checks.
262   if( position > relayoutData.mTextLayoutInfo.mNumberOfCharacters )
263   {
264     // Asserts if text is to be added out of bounds.
265     DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
266   }
267
268   TextView::RelayoutData relayoutDataForNewText;
269
270   // Creates layout info for the given text.
271   // It doesn't create text-actors as text could be added to an existing one.
272   CreateTextInfo( text,
273                   layoutParameters,
274                   relayoutDataForNewText );
275
276   // Update logical-to-visual and visual-to-logical tables.
277   // TODO: check that for mixed RTL/LTR text.
278   std::size_t index = 0u;
279   for( std::size_t i = 0u; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
280   {
281     relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
282     relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
283     ++index;
284   }
285
286   // If a line is split, it stores the last part of the line.
287   LineLayoutInfo lastLineLayoutInfo;
288
289   // Stores indices to the line, word and character of the given position.
290   TextInfoIndices textInfoIndices;
291
292   if( position < relayoutData.mTextLayoutInfo.mNumberOfCharacters )
293   {
294     // Get line, word and character indices for given position.
295     GetIndicesFromGlobalCharacterIndex( position,
296                                         relayoutData.mTextLayoutInfo,
297                                         textInfoIndices );
298
299     // 1) Split the line
300
301     // Split a line in two is needed, then merge the first part of the split line
302     // with the first line of the new text, add subsequent lines and merge the last line
303     // of the new text with the last part of the split line.
304
305     // Implementation notes!
306     //
307     // These references to the first line are declared in this scope because if new lines are inserted in step 2,
308     // they become invalid, making the algorithm to crash if used again.
309     // In the step 3, references to the first line are needed and declared again.
310
311     // Stores the first part of the split line.
312     LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
313
314     SplitLine( textInfoIndices,
315                PointSize( layoutParameters.mLineHeightOffset ),
316                firstLineLayoutInfo,
317                lastLineLayoutInfo );
318   }
319   else
320   {
321     // Position is just after the last character.
322     // Calculates indices for that position.
323     if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
324     {
325       textInfoIndices.mLineIndex = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() - 1u;
326       const LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1u ) );
327
328       if( !lineLayoutInfo.mWordsLayoutInfo.empty() )
329       {
330         textInfoIndices.mWordIndex = lineLayoutInfo.mWordsLayoutInfo.size() - 1u;
331
332         const WordLayoutInfo& wordLayoutInfo( *( lineLayoutInfo.mWordsLayoutInfo.end() - 1u ) );
333         textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
334       }
335     }
336   }
337
338   // 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.
339   //TODO check this cases ( num lines ==1, >1, >2 ) if it could be simplified.
340   if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 1u )
341   {
342     LineLayoutInfo& lastInputLineLayoutInfo( *( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1u ) );
343
344     MergeLine( lastInputLineLayoutInfo,
345                lastLineLayoutInfo );
346
347     if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 2u )
348     {
349       // Insert all lines except first and last in the text.
350       relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + 1u,
351                                                             relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() + 1u,
352                                                             relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1u );
353     }
354
355     // Insert the last line to the text
356     relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() - 1u,
357                                                           lastInputLineLayoutInfo );
358   }
359   else
360   {
361     // Merge the new line to the last part of the split line.
362     LineLayoutInfo& inputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
363
364     MergeLine( inputLineLayoutInfo,
365                lastLineLayoutInfo );
366   }
367
368   // 3) Merge the first line of the split text with the first line of the input text.
369   LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
370   LineLayoutInfo& firstInputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
371
372   MergeLine( firstLineLayoutInfo,
373              firstInputLineLayoutInfo );
374
375   // 4) Update text info.
376
377   // Updates the whole text size, maximum word size, etc.
378   UpdateLayoutInfo( relayoutData.mTextLayoutInfo );
379 }
380
381 void UpdateTextInfo( const std::size_t position,
382                      const std::size_t numberOfCharacters,
383                      const TextView::LayoutParameters& layoutParameters,
384                      TextView::RelayoutData& relayoutData,
385                      const TextOperationOnRemove clearText )
386 {
387   // Removes 'numberOfCharacters' starting from 'position'.
388
389   // * It checks if text to be deleted is in the same line or not:
390   // *   If it is not, check which lines need to be split/merged or deleted.
391   // *   If it is but all characters of the line are going to be deleted, just delete the line (nothing needs to be split/merged)
392   // *   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 word.
393   // *     If it is not, split/merge words.
394   // *     Check if the whole word needs to be deleted.
395   // *     Check if only some characters of the word need to be deleted.
396   // * Updates layout info.
397
398   // * 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).
399
400   // Early return
401
402   if( 0u == numberOfCharacters )
403   {
404     DALI_ASSERT_DEBUG( !"TextViewProcessor::UpdateTextInfo. WARNING: trying to delete 0 characters!" );
405
406     // nothing to do if no characters are deleted.
407     return;
408   }
409
410   // Asserts if trying to delete text out of bounds.
411   DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
412
413   // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
414   relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
415   relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
416
417   // Get line, word and character indices for the given start position.
418   TextInfoIndices textInfoIndicesBegin;
419   GetIndicesFromGlobalCharacterIndex( position,
420                                       relayoutData.mTextLayoutInfo,
421                                       textInfoIndicesBegin );
422
423   // Get line, word and character indices for the given end position (start position + number of characters to be deleted).
424   TextInfoIndices textInfoIndicesEnd;
425   GetIndicesFromGlobalCharacterIndex( position + numberOfCharacters - 1u,
426                                       relayoutData.mTextLayoutInfo,
427                                       textInfoIndicesEnd );
428
429   // Vectors used to temporary store text-actors removed from text.
430   // Three vectors are needed because text-actors are not removed in order
431   // but insert them in order is required to reuse them later.
432   std::vector<TextActor> removedTextActorsFromBegin;
433   std::vector<TextActor> removedTextActorsFromMid;
434   std::vector<TextActor> removedTextActorsFromEnd;
435
436   // Whether lines and words need to be merged.
437   bool mergeLines = false;
438   bool mergeWords = false;
439
440   // Indices of the lines and words to be merged.
441   TextInfoIndices textInfoMergeIndicesBegin;
442   TextInfoIndices textInfoMergeIndicesEnd;
443
444   const LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) ); // used to check the number of characters of the line
445                                                                                                                                     // if all characters to be deleted are in the same line.
446   if( textInfoIndicesBegin.mLineIndex < textInfoIndicesEnd.mLineIndex )
447   {
448     // 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.
449
450     // whether first or last line need to be split and merged with the last part.
451     bool mergeFirstLine = false;
452     bool mergeLastLine = true;
453
454     textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
455     textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
456
457     if( ( textInfoIndicesBegin.mWordIndex > 0u ) || ( textInfoIndicesBegin.mCharacterIndex > 0u ) )
458     {
459       // first character to be deleted is not the first one of the current line.
460       ++textInfoIndicesBegin.mLineIndex; // won't delete current line
461
462       // As some characters remain, this line could be merged with the last one.
463       mergeFirstLine = true;
464     }
465
466     // Check if all characters of the last line are going to be deleted.
467     bool wholeLineDeleted = false;
468     const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex ) );
469     if( textInfoIndicesEnd.mWordIndex + 1u == lastLineLayout.mWordsLayoutInfo.size() )
470     {
471       const WordLayoutInfo& lastWordLayout( *( lastLineLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
472       if( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() )
473       {
474         // All characters of the last line are going to be deleted.
475         ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
476
477         // the whole last line is deleted. Need to check if the next line could be merged.
478         mergeLastLine = false;
479         wholeLineDeleted = true;
480       }
481     }
482
483     if( wholeLineDeleted )
484     {
485       // It means the whole last line is deleted completely.
486       // It's needed to check if there is another line after that could be merged.
487       if( textInfoIndicesEnd.mLineIndex < relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() )
488       {
489         mergeLastLine = true;
490
491         // Point the first characters of the next line.
492         textInfoIndicesEnd.mWordIndex = 0u;
493         textInfoIndicesEnd.mCharacterIndex = 0u;
494         textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
495       }
496     }
497
498     // If some characters remain in the first and last line, they need to be merged.
499     mergeLines = mergeFirstLine && mergeLastLine;
500
501     if( mergeLines )
502     {
503       // last line is going to be merged with the first one, so is not needed.
504       ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
505     }
506
507     if( mergeFirstLine )
508     {
509       // Remove characters from the first line.
510
511       // Vectors used to temporary store text-actors removed from the line.
512       // Three vectors are needed because text-actors are not removed in order
513       // but insert them in order is required to reuse them later.
514       std::vector<TextActor> removedTextActorsFromFirstWord;
515       std::vector<TextActor> removedTextActorsFromFirstLine;
516
517       // As lineIndexBegin has been increased just to not to remove the line, decrease now is needed to access it.
518       LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex - 1u ) );
519
520       if( ( textInfoIndicesBegin.mWordIndex + 1u < lineLayout.mWordsLayoutInfo.size() ) || ( 0u == textInfoIndicesBegin.mCharacterIndex ) )
521       {
522         // Remove extra words within current line. (and current word if whole characters are removed)
523         // 0 == characterIndexBegin means the whole word is deleted.
524         const std::size_t wordIndex = ( ( 0u == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1u );
525
526         // Store text-actors before removing them.
527         CollectTextActorsFromWords( removedTextActorsFromFirstLine, lineLayout, wordIndex, lineLayout.mWordsLayoutInfo.size() );
528
529         RemoveWordsFromLine( wordIndex,
530                              lineLayout.mWordsLayoutInfo.size() - wordIndex,
531                              layoutParameters.mLineHeightOffset,
532                              lineLayout );
533       }
534
535       if( ( textInfoIndicesBegin.mWordIndex < lineLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0u ) )
536       {
537         // Only some characters of the word need to be removed.
538         WordLayoutInfo& wordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
539
540         // Store text-actors before removing them.
541         CollectTextActors( removedTextActorsFromFirstWord, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
542
543         const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
544         RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
545                                   wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
546                                   wordLayout );
547
548         // discount the removed number of characters.
549         const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
550         lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
551       }
552       UpdateLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
553
554       // Insert the text-actors in order.
555       removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
556       removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstLine.begin(), removedTextActorsFromFirstLine.end() );
557     }
558
559     if( mergeLastLine && !wholeLineDeleted )
560     {
561       // Some characters from the last line need to be removed.
562
563       // Vectors used to temporary store text-actors removed from the line.
564       // Three vectors are needed because text-actors are not removed in order
565       // but insert them in order is required to reuse them later.
566       std::vector<TextActor> removedTextActorsFromFirstWord;
567       std::vector<TextActor> removedTextActorsFromFirstLine;
568
569       // lineIndexEnd was increased to delete the last line if lines need to be merged.
570       // To access now the last line we need to decrease the index.
571       const std::size_t lineIndex = ( mergeLines ? textInfoIndicesEnd.mLineIndex - 1u : textInfoIndicesEnd.mLineIndex );
572
573       // Get the last line.
574       LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lineIndex ) );
575
576       // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
577       const WordLayoutInfo& wordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
578       bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1u;
579
580       if( ( textInfoIndicesEnd.mWordIndex > 0u ) || ( removeWholeWord ) )
581       {
582         // Store text-actors before removing them.
583         CollectTextActorsFromWords( removedTextActorsFromFirstLine,
584                                     lineLayout,
585                                     0u,
586                                     ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1u : textInfoIndicesEnd.mWordIndex );
587
588         // Remove extra words. (and current word if whole characters are removed)
589         RemoveWordsFromLine( 0u,
590                              ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1u : textInfoIndicesEnd.mWordIndex,
591                              layoutParameters.mLineHeightOffset,
592                              lineLayout );
593       }
594
595       if( !removeWholeWord )
596       {
597         // Only some characters of the word need to be deleted.
598
599         // After removing all extra words. The word with the characters to be removed is the first one.
600         WordLayoutInfo& wordLayout( *lineLayout.mWordsLayoutInfo.begin() );
601
602         // Store text-actors before removing them.
603         CollectTextActors( removedTextActorsFromFirstWord, wordLayout, 0u, textInfoIndicesEnd.mCharacterIndex + 1u );
604
605         const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
606         RemoveCharactersFromWord( 0u,
607                                   textInfoIndicesEnd.mCharacterIndex + 1u,
608                                   wordLayout );
609
610         // discount the removed number of characters.
611         const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
612         lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
613       }
614       UpdateLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
615
616       // Insert the text-actors in order.
617       removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
618       removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstLine.begin(), removedTextActorsFromFirstLine.end() );
619     }
620   } // end delete text from different lines
621   else if( ( textInfoIndicesBegin.mLineIndex == textInfoIndicesEnd.mLineIndex ) && ( lineLayout.mNumberOfCharacters == numberOfCharacters ) )
622   {
623     // the whole line needs to be deleted.
624     ++textInfoIndicesEnd.mLineIndex; // will delete current line.
625   }
626   else
627   {
628     // deleted text is within the same line. (merge lines could be needed if the line separator character is deleted)
629
630     // Line which contains the characters to be deleted.
631     LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) );
632
633     // Remove the characters from the line layout info. It returns whether the current line can be merged with the next one.
634     RemoveCharactersFromLineInfo( relayoutData,
635                                   numberOfCharacters,
636                                   mergeWords,
637                                   mergeLines,
638                                   textInfoIndicesBegin,
639                                   textInfoIndicesEnd,
640                                   textInfoMergeIndicesBegin,
641                                   textInfoMergeIndicesEnd,
642                                   lineLayout,
643                                   removedTextActorsFromBegin,
644                                   removedTextActorsFromEnd );
645
646     if( mergeWords )
647     {
648       // Merges words pointed by textInfoMergeIndicesBegin.mWordIndex and textInfoMergeIndicesEnd.mWordIndex calculated previously.
649       DALI_ASSERT_DEBUG( ( textInfoMergeIndicesBegin.mWordIndex < lineLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (begin) out of bounds." );
650       DALI_ASSERT_DEBUG( ( textInfoMergeIndicesEnd.mWordIndex < lineLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (end) out of bounds." );
651
652       WordLayoutInfo& firstWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesBegin.mWordIndex ) );
653       WordLayoutInfo& lastWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesEnd.mWordIndex ) );
654
655       MergeWord( firstWordLayout,
656                  lastWordLayout );
657     }
658
659     // Store text-actors before removing them.
660     const std::size_t endIndex = ( mergeWords && ( textInfoIndicesEnd.mWordIndex > 0u ) ) ? textInfoIndicesEnd.mWordIndex - 1u : textInfoIndicesEnd.mWordIndex; // text-actors from the last word may have been added in the merge above.
661     CollectTextActorsFromWords( removedTextActorsFromMid, lineLayout, textInfoIndicesBegin.mWordIndex, endIndex );
662
663     // Remove unwanted words using previously calculated indices. (including the last part of the merged word)
664     lineLayout.mWordsLayoutInfo.erase( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex, lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex );
665
666     // Update line info.
667     UpdateLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
668   }// end delete text from same line.
669
670   if( mergeLines )
671   {
672     // Merges lines pointed by textInfoMergeIndicesBegin.mLineIndex and textInfoMergeIndicesEnd.mLineIndex calculated previously.
673
674     LineLayoutInfo& firstLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesBegin.mLineIndex ) );
675
676     const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesEnd.mLineIndex ) );
677
678     MergeLine( firstLineLayout,
679                lastLineLayout );
680   }
681
682   // Store text-actors before removing them.
683   const std::size_t endIndex = ( mergeLines && ( textInfoIndicesEnd.mLineIndex > 0u ) ) ? textInfoIndicesEnd.mLineIndex - 1u : textInfoIndicesEnd.mLineIndex; // text-actors from the last line may have been added in the merge above.
684   CollectTextActorsFromLines( removedTextActorsFromMid,
685                               relayoutData.mTextLayoutInfo,
686                               textInfoIndicesBegin.mLineIndex,
687                               endIndex );
688
689   // Remove unwanted lines using previously calculated indices. (including the last part of the merged line)
690   relayoutData.mTextLayoutInfo.mLinesLayoutInfo.erase( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex,
691                                                        relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex );
692
693   // Update text info.
694   UpdateLayoutInfo( relayoutData.mTextLayoutInfo );
695
696   // If the last character of the last line is a new line character, an empty line need to be added.
697   if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
698   {
699     const WordLayoutInfo lastWordLayout = GetLastWordLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1u ) );
700
701     if( LineSeparator == lastWordLayout.mType )
702     {
703       LineLayoutInfo lastLineLayout;
704
705       const CharacterLayoutInfo layoutInfo = GetLastCharacterLayoutInfo( lastWordLayout );
706       lastLineLayout.mSize.height = layoutInfo.mSize.height;
707
708       relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lastLineLayout );
709
710       relayoutData.mTextLayoutInfo.mWholeTextSize.height += layoutInfo.mSize.height;
711     }
712   }
713
714   // Clear the text from the text-actors if required.
715   if( CLEAR_TEXT == clearText )
716   {
717     ClearText( removedTextActorsFromEnd );
718     ClearText( removedTextActorsFromMid );
719     ClearText( removedTextActorsFromBegin );
720   }
721
722   // Insert text-actors into the cache.
723   // Text-actors are inserted in reverse order to use first the first removed.
724   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromEnd );
725   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromMid );
726   relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
727 }
728
729 void UpdateTextInfo( const std::size_t position,
730                      const std::size_t numberOfCharacters,
731                      const MarkupProcessor::StyledTextArray& text,
732                      const TextView::LayoutParameters& layoutParameters,
733                      TextView::RelayoutData& relayoutData )
734 {
735   // Replaces 'numberOfCharacters' of text starting from 'position' with the given text.
736
737   // TODO: Temporary implementation with remove and insert.
738
739   // Remove.
740   UpdateTextInfo( position,
741                   numberOfCharacters,
742                   layoutParameters,
743                   relayoutData,
744                   KEEP_TEXT ); // Do not clear the text from the text-actors.
745
746   // Insert.
747   UpdateTextInfo( position,
748                   text,
749                   layoutParameters,
750                   relayoutData );
751 }
752
753 void UpdateTextInfo( const float lineHeightOffset,
754                      TextLayoutInfo& textLayoutInfo )
755 {
756   // Updates the space between lines with the new offset value.
757
758   float newTextHeight = 0.f;
759
760   for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
761        lineIt != lineEndIt;
762        ++lineIt )
763   {
764     LineLayoutInfo& lineLayoutInfo( *lineIt );
765
766     lineLayoutInfo.mSize.height += ( lineHeightOffset - lineLayoutInfo.mLineHeightOffset );
767     newTextHeight += lineLayoutInfo.mSize.height;
768
769     lineLayoutInfo.mLineHeightOffset = lineHeightOffset;
770   }
771
772   textLayoutInfo.mWholeTextSize.height = newTextHeight;
773 }
774
775 void UpdateTextInfo( const TextStyle& style,
776                      const TextStyle::Mask mask,
777                      TextView::RelayoutData& relayoutData )
778 {
779   // Change text style for all text-actors.
780
781   for( LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
782        lineIt != lineEndIt;
783        ++lineIt )
784   {
785     LineLayoutInfo& line( *lineIt );
786
787     for( WordLayoutInfoContainer::iterator wordIt = line.mWordsLayoutInfo.begin(), wordEndIt = line.mWordsLayoutInfo.end();
788          wordIt != wordEndIt;
789          ++wordIt )
790     {
791       WordLayoutInfo& word( *wordIt );
792
793       for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
794            characterIt != characterEndIt;
795            ++characterIt )
796       {
797         CharacterLayoutInfo& characterLayout( *characterIt );
798
799         characterLayout.mStyledText.mStyle.Copy( style, mask );
800
801         // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
802         ChooseFontFamilyName( characterLayout.mStyledText );
803
804         // Mark the character to be set the new style into the text-actor.
805         characterLayout.mSetStyle = true;
806       } // end characters
807     } // end words
808   } // end lines
809 }
810
811 } // namespace TextViewProcessor
812
813 } // namespace Internal
814
815 } // namespace Toolkit
816
817 } // namespace Dali