Conversion to Apache 2.0 license
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / text-view-word-group-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 "text-view-word-group-processor.h"
20 #include "text-view-word-processor.h"
21 #include "text-view-processor-helper-functions.h"
22 #include "text-processor.h"
23
24 namespace Dali
25 {
26
27 namespace Toolkit
28 {
29
30 namespace Internal
31 {
32
33 namespace TextViewProcessor
34 {
35
36 /////////////////////
37 // Layout info.
38 /////////////////////
39
40 WordGroupLayoutInfo::WordGroupLayoutInfo()
41 : mSize(),
42   mAscender( 0.f ),
43   mDirection( LTR ),
44   mWordsLayoutInfo(),
45   mNumberOfCharacters( 0 )
46 {
47 }
48
49 WordGroupLayoutInfo::WordGroupLayoutInfo( const WordGroupLayoutInfo& group )
50 : mSize( group.mSize ),
51   mAscender( group.mAscender ),
52   mDirection( group.mDirection ),
53   mWordsLayoutInfo( group.mWordsLayoutInfo ),
54   mNumberOfCharacters( group.mNumberOfCharacters )
55 {
56 }
57
58 WordGroupLayoutInfo& WordGroupLayoutInfo::operator=( const WordGroupLayoutInfo& group )
59 {
60   mSize = group.mSize;
61   mAscender = group.mAscender;
62   mDirection = group.mDirection;
63   mWordsLayoutInfo = group.mWordsLayoutInfo;
64   mNumberOfCharacters = group.mNumberOfCharacters;
65
66   return *this;
67 }
68
69 void UpdateGroupLayoutInfo( TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo )
70 {
71   wordGroupLayoutInfo.mSize = Size();
72
73   for( WordLayoutInfoContainer::iterator it = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), endIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
74        it != endIt;
75        ++it )
76   {
77     WordLayoutInfo& layoutInfo( *it );
78
79     UpdateSize( wordGroupLayoutInfo.mSize, layoutInfo.mSize );
80   }
81 }
82
83 void CreateWordGroupInfo( const MarkupProcessor::StyledTextArray& wordGroup,
84                           TextViewProcessor::TextLayoutInfo& textLayoutInfo,
85                           TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo )
86 {
87   // Set the direction of the group.
88   wordGroupLayoutInfo.mDirection = ( TextProcessor::BeginsRightToLeftCharacter( wordGroup ) ? TextViewProcessor::RTL : TextViewProcessor::LTR );
89
90   // Split the group of words in words
91   std::vector<MarkupProcessor::StyledTextArray> words;
92   TextProcessor::SplitInWords( wordGroup, words );
93
94   // if last word has a new line separator, create a new word.
95   if( !words.empty() )
96   {
97     MarkupProcessor::StyledTextArray& word( *( words.end() - 1 ) );
98     if( word.size() > 1 )
99     {
100       // do nothing if the word has only one character.
101       MarkupProcessor::StyledText& styledText( *( word.end() - 1 ) );
102       if( !styledText.mText.IsEmpty() )
103       {
104         const std::size_t length = styledText.mText.GetLength();
105         if( styledText.mText[length-1].IsNewLine() )
106         {
107           // Last character of this word is a new line character.
108
109           // Remove line separator character from current word.
110           styledText.mText.Remove( length - 1, 1 );
111
112           // Create a new word with the line separator character.
113           MarkupProcessor::StyledText newLineText( Text( styledText.mText[length-1] ), styledText.mStyle );
114
115           MarkupProcessor::StyledTextArray newLineWord;
116           newLineWord.push_back( newLineText );
117
118           words.push_back( newLineWord );
119         }
120       }
121     }
122   }
123
124   // Reverse if right to left.
125   if( TextViewProcessor::RTL == wordGroupLayoutInfo.mDirection )
126   {
127     std::reverse( words.begin(), words.end() );
128   }
129
130   std::string lastCharacterFont; // Keeps the font used by the last character. It's used to set the font to a word separator.
131
132   // Traverse all words.
133   for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator wordIt = words.begin(), wordEndIt = words.end(); wordIt != wordEndIt; ++wordIt )
134   {
135     const MarkupProcessor::StyledTextArray& word( *wordIt );
136
137     // Data structures for the new word.
138     WordLayoutInfo wordLayoutInfo;
139
140     CreateWordTextInfo( word,
141                         wordLayoutInfo );
142
143     // White space's size could be different depending on the type of font. It's important to use the same font than the previous character to
144     // avoid 'jumps' of characters when there is a switch between one text-actor per character and one text-actor per line and/or style.
145     if( WordSeparator == wordLayoutInfo.mType )
146     {
147       // If current word is a word separator (white space) then the font of the last character is set.
148       for( CharacterLayoutInfoContainer::iterator characterIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), characterEndIt = wordLayoutInfo.mCharactersLayoutInfo.end();
149            characterIt != characterEndIt;
150            ++characterIt )
151       {
152         CharacterLayoutInfo& characterLayout( *characterIt );
153
154         characterLayout.mStyledText.mStyle.SetFontName( lastCharacterFont );
155       }
156     }
157     else
158     {
159       // kepps the font of the last character.
160       if( !wordLayoutInfo.mCharactersLayoutInfo.empty() )
161       {
162         lastCharacterFont = ( *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1 ) ).mStyledText.mStyle.GetFontName();
163       }
164     }
165
166     // Update layout info for the current group of words.
167     wordGroupLayoutInfo.mNumberOfCharacters += wordLayoutInfo.mCharactersLayoutInfo.size();
168     UpdateSize( wordGroupLayoutInfo.mSize, wordLayoutInfo.mSize );
169     wordGroupLayoutInfo.mAscender = std::max( wordGroupLayoutInfo.mAscender, wordLayoutInfo.mAscender );
170
171     // Add current word to the group of words.
172     wordGroupLayoutInfo.mWordsLayoutInfo.push_back( wordLayoutInfo );
173
174     // Update the max word width figure.
175     textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width );
176   } // end of words
177 }
178
179 void RemoveCharactersFromWordGroupInfo( TextView::RelayoutData& relayoutData,
180                                         const std::size_t numberOfCharacters,
181                                         bool& mergeWords,
182                                         bool& mergeLines,
183                                         TextViewProcessor::TextInfoIndices& textInfoIndicesBegin,
184                                         TextViewProcessor::TextInfoIndices& textInfoIndicesEnd,
185                                         TextViewProcessor::TextInfoIndices& textInfoMergeIndicesBegin,
186                                         TextViewProcessor::TextInfoIndices& textInfoMergeIndicesEnd,
187                                         TextViewProcessor::WordGroupLayoutInfo& groupLayout,
188                                         std::vector<TextActor>& removedTextActorsFromFirstWord,
189                                         std::vector<TextActor>& removedTextActorsFromLastWord )
190 {
191   const TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
192
193   if( textInfoIndicesBegin.mWordIndex < textInfoIndicesEnd.mWordIndex )
194   {
195     // Deleted text is from different words. The two different words may be merged.
196
197     // Get first word.
198     WordLayoutInfo& firstWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
199
200     // Get last word.
201     WordLayoutInfo& lastWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
202
203     // whether first or last word need to be split and merged.
204     bool mergeFromBegin = false;
205     bool mergeToEnd = false;
206
207     if( textInfoIndicesBegin.mCharacterIndex > 0 )
208     {
209       // First word is going to be split. It could be merged with the last word.
210       mergeFromBegin = true;
211       textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex;
212     }
213     else if( ( textInfoIndicesBegin.mCharacterIndex == 0 ) && ( textInfoIndicesBegin.mWordIndex > 0 ) )
214     {
215       // First word is going to be removed completely.
216       // Check if previous word could be merged.
217
218       // Get word before.
219       WordLayoutInfo& previousWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1 ) );
220       if( WordSeparator != previousWordLayout.mType )
221       {
222         // Previous word is not a word separator, so could be merged.
223         mergeFromBegin = true;
224         textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1;
225       }
226     }
227
228     if( mergeFromBegin )
229     {
230       // First word (or previous one) could be merged. Check if last one could be merged as well.
231
232       if( textInfoIndicesEnd.mCharacterIndex + 1 < lastWordLayout.mCharactersLayoutInfo.size() )
233       {
234         // Last word is going to be split. It could be merged with the first word.
235         mergeToEnd = true;
236         textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex;
237       }
238       else if( ( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) )
239       {
240         // Last word is going to be removed completely.
241         // Check if the word after could be merged.
242
243         // Get word after.
244         WordLayoutInfo& afterWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex + 1 ) );
245         if( WordSeparator != afterWordLayout.mType )
246         {
247           // The word after is not a word separator, so could be merged.
248           mergeToEnd = true;
249           textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex + 1;
250         }
251       }
252
253       // Merge words only if both words could be merged.
254       mergeWords = mergeFromBegin && mergeToEnd;
255     }
256
257     if( ( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1 == groupLayout.mWordsLayoutInfo.size() ) )
258     {
259       // Last word of the line is going to be removed completely.
260       // Check if it's a line separator.
261
262       if( LineSeparator == lastWordLayout.mType )
263       {
264         // The line separator is going to be removed.
265         if( textInfoIndicesBegin.mLineIndex + 1 < textLayoutInfo.mLinesLayoutInfo.size() )
266         {
267           //  Line need to be merged.
268           textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
269           textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1;
270           mergeLines= true;
271
272           ++textInfoIndicesBegin.mLineIndex; // increase both indices,
273           textInfoIndicesEnd.mLineIndex +=2; // will delete last line.
274         }
275       }
276     }
277
278     if( textInfoIndicesBegin.mCharacterIndex > 0 )
279     {
280       // First word needs to be split.
281
282       // Store text-actors before removing them.
283       CollectTextActors( removedTextActorsFromFirstWord, firstWordLayout, textInfoIndicesBegin.mCharacterIndex, firstWordLayout.mCharactersLayoutInfo.size() );
284
285       RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
286                                 firstWordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
287                                 firstWordLayout );
288
289       ++textInfoIndicesBegin.mWordIndex; // will delete from the word after.
290     }
291
292     if( textInfoIndicesEnd.mCharacterIndex + 1 < lastWordLayout.mCharactersLayoutInfo.size() )
293     {
294       // Last word needs to be split.
295
296       // Store text-actors before removing them.
297       CollectTextActors( removedTextActorsFromLastWord, lastWordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
298
299       RemoveCharactersFromWord( 0,
300                                 textInfoIndicesEnd.mCharacterIndex + 1,
301                                 lastWordLayout );
302
303       if( mergeWords )
304       {
305         // This word is going to be merged, so is not needed.
306         ++textInfoIndicesEnd.mWordIndex; // will delete the last word.
307       }
308     }
309     else if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
310     {
311       // The whole last word is going to be removed.
312       ++textInfoIndicesEnd.mWordIndex; // will delete the last word.
313
314       if( ( WordSeparator == lastWordLayout.mType ) && mergeWords )
315       {
316         // The last word is a word separator and the word after is going to be merged so is not needed.
317         ++textInfoIndicesEnd.mWordIndex; // will delete the word after the last one.
318       }
319     }
320   }
321   else
322   {
323     // Chraracters to be removed are from the same word.
324
325     RemoveCharactersFromWordInfo( relayoutData,
326                                   numberOfCharacters,
327                                   mergeWords,
328                                   mergeLines,
329                                   textInfoIndicesBegin,
330                                   textInfoIndicesEnd,
331                                   textInfoMergeIndicesBegin,
332                                   textInfoMergeIndicesEnd,
333                                   groupLayout,
334                                   removedTextActorsFromFirstWord );
335   } // word indices
336 }
337
338 void RemoveWordsFromWordGroup( const std::size_t wordIndex,
339                                const std::size_t numberOfWords,
340                                WordGroupLayoutInfo& wordGroupLayoutInfo )
341 {
342   // Removes words from a group of words.
343
344   // * Check if words or lines can be merged after removing a word or line separator have to be done outside this method.
345
346   // * Note: Currently it's only used to remove a number of words from the beginning, or
347   //         from wordIndex index to the end. This function doesn't merge words (if a white space is removed)
348   //         TODO: merge words if required.
349
350   const std::size_t wordEndIndex = wordIndex + numberOfWords;
351
352   // Remove words from layout info.
353   wordGroupLayoutInfo.mWordsLayoutInfo.erase( wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex,
354                                               wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordEndIndex );
355
356   // update layout info
357   wordGroupLayoutInfo.mSize = Size();
358   wordGroupLayoutInfo.mAscender = 0.f;
359   wordGroupLayoutInfo.mNumberOfCharacters = 0;
360   for( WordLayoutInfoContainer::const_iterator it = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), endIt = wordGroupLayoutInfo.mWordsLayoutInfo.end();
361        it != endIt;
362        ++it )
363   {
364     const WordLayoutInfo& info( *it );
365
366     UpdateSize( wordGroupLayoutInfo.mSize, info.mSize );
367     wordGroupLayoutInfo.mAscender = std::max( wordGroupLayoutInfo.mAscender, info.mAscender );
368     wordGroupLayoutInfo.mNumberOfCharacters += info.mCharactersLayoutInfo.size();
369   }
370 }
371
372 void SplitWordGroup( const TextInfoIndices& indices,
373                      WordGroupLayoutInfo& firstWordGroupLayoutInfo,
374                      WordGroupLayoutInfo& lastWordGroupLayoutInfo )
375 {
376   // Splits a group of words in two.
377   // A word may be split in two as well.
378
379   // * Split the word pointed by indices.mWordIndex using the indices.mCharacterIndex index.
380   // * Add the last part of the word as first word of the last part of the group of words.
381   // * Add folliwing words to the last part of the new group of words.
382   // * Remove from the first part of the group of words all words added to the last part of the group of words.
383   // * Update layout info.
384
385   //early returns
386   if( ( 0 == indices.mWordIndex ) && ( 0 == indices.mCharacterIndex ) )
387   {
388     // the whole group of words goes to the last part of the group.
389     lastWordGroupLayoutInfo = firstWordGroupLayoutInfo;
390
391     firstWordGroupLayoutInfo = WordGroupLayoutInfo();
392
393     return;
394   }
395
396   if( !firstWordGroupLayoutInfo.mWordsLayoutInfo.empty() )
397   {
398     const std::size_t numberOfWords = firstWordGroupLayoutInfo.mWordsLayoutInfo.size();
399     if( indices.mWordIndex == numberOfWords - 1 )
400     {
401       const WordLayoutInfo& word( *( firstWordGroupLayoutInfo.mWordsLayoutInfo.end() - 1 ) );
402       if( indices.mCharacterIndex == word.mCharactersLayoutInfo.size() )
403       {
404         // the whole group of words goes to the first part.
405
406         // Just delete whatever there is in the last part of the group of words.
407         lastWordGroupLayoutInfo = WordGroupLayoutInfo();
408
409         return;
410       }
411     }
412   }
413
414   lastWordGroupLayoutInfo = WordGroupLayoutInfo();
415
416   // 1) Split the word within the group of words to be split.
417   WordLayoutInfo& firstWordLayoutInfo( *( firstWordGroupLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex ) );
418   WordLayoutInfo lastWordLayoutInfo;
419
420   SplitWord( indices.mCharacterIndex,
421              firstWordLayoutInfo,
422              lastWordLayoutInfo );
423
424   // 2) Add last part of the word to the new group of words.
425   if( !lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
426   {
427     lastWordGroupLayoutInfo.mWordsLayoutInfo.push_back( lastWordLayoutInfo );
428   }
429
430   // 3) Add words from word-position + 1 to the end.
431   lastWordGroupLayoutInfo.mWordsLayoutInfo.insert( lastWordGroupLayoutInfo.mWordsLayoutInfo.end(),
432                                                    firstWordGroupLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex + 1, firstWordGroupLayoutInfo.mWordsLayoutInfo.end() );
433
434   // 4) update layout info of the last group of words.
435   lastWordGroupLayoutInfo.mDirection = firstWordGroupLayoutInfo.mDirection;
436
437   for( WordLayoutInfoContainer::iterator it = lastWordGroupLayoutInfo.mWordsLayoutInfo.begin(), endIt = lastWordGroupLayoutInfo.mWordsLayoutInfo.end();
438        it != endIt;
439        ++it )
440   {
441     WordLayoutInfo& layoutInfo( *it );
442
443     UpdateSize( lastWordGroupLayoutInfo.mSize, layoutInfo.mSize );
444     lastWordGroupLayoutInfo.mNumberOfCharacters += layoutInfo.mCharactersLayoutInfo.size();
445     lastWordGroupLayoutInfo.mAscender = std::max( lastWordGroupLayoutInfo.mAscender, layoutInfo.mAscender );
446   }
447
448   // 5) Remove words added to the last part of the group of words from the first group of words.
449
450   // if the number of characters of the last word of the first group is zero, it should be removed.
451   const std::size_t index = ( firstWordLayoutInfo.mCharactersLayoutInfo.empty() ? indices.mWordIndex : indices.mWordIndex + 1 );
452
453   firstWordGroupLayoutInfo.mWordsLayoutInfo.erase( firstWordGroupLayoutInfo.mWordsLayoutInfo.begin() + index, firstWordGroupLayoutInfo.mWordsLayoutInfo.end() );
454
455   // 6) update layout info of the first group of words.
456   firstWordGroupLayoutInfo.mSize = Size();
457   firstWordGroupLayoutInfo.mAscender = 0.f;
458   firstWordGroupLayoutInfo.mNumberOfCharacters = 0;
459   for( WordLayoutInfoContainer::iterator it = firstWordGroupLayoutInfo.mWordsLayoutInfo.begin(), endIt = firstWordGroupLayoutInfo.mWordsLayoutInfo.end();
460        it != endIt;
461        ++it )
462   {
463     WordLayoutInfo& layoutInfo( *it );
464
465     UpdateSize( firstWordGroupLayoutInfo.mSize, layoutInfo.mSize );
466     firstWordGroupLayoutInfo.mNumberOfCharacters += layoutInfo.mCharactersLayoutInfo.size();
467     firstWordGroupLayoutInfo.mAscender = std::max( firstWordGroupLayoutInfo.mAscender, layoutInfo.mAscender );
468   }
469 }
470
471 void MergeWordGroup( WordGroupLayoutInfo& firstWordGroupLayoutInfo,
472                      const WordGroupLayoutInfo& lastWordGroupLayoutInfo )
473 {
474   // Merges two given groups of words.
475   //
476   // Can't merge two groups if they have text with different directions (RTL , LTR )
477   // or if the last word of the first one is a line separator (new line character)
478
479   // Early returns
480
481   if( lastWordGroupLayoutInfo.mWordsLayoutInfo.empty() )
482   {
483     // Nothing to merge if last group is empty.
484     return;
485   }
486
487   if( firstWordGroupLayoutInfo.mWordsLayoutInfo.empty() )
488   {
489     // If first group is empty, just copy the last group to the first one.
490     firstWordGroupLayoutInfo = lastWordGroupLayoutInfo;
491
492     return;
493   }
494
495   // Check both groups have the same direction.
496   if( firstWordGroupLayoutInfo.mDirection != lastWordGroupLayoutInfo.mDirection )
497   {
498     DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWordGroup(). ERROR: groups with different direction can't be merged." );
499   }
500
501   // Check first group doesn't finish with a new line character.
502   WordLayoutInfo& lastWordLayout( *( firstWordGroupLayoutInfo.mWordsLayoutInfo.end() - 1 ) );
503   if( LineSeparator == lastWordLayout.mType )
504   {
505     DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeWordGroup(). ERROR: A group of words can't be merged to another group which finishes with a new line character." );
506   }
507
508   // If the las word of the first group or the first word of the last group is a white space, both groups can be concatenated.
509   // Otherwise both words need to be merged first.
510   const WordLayoutInfo& firstWordLayout( *lastWordGroupLayoutInfo.mWordsLayoutInfo.begin() );
511
512   std::size_t index = 0;
513   if( ( WordSeparator != lastWordLayout.mType ) && ( WordSeparator != firstWordLayout.mType ) && ( LineSeparator != firstWordLayout.mType ) )
514   {
515     // Last word of the first group is not a word separator and first word of the last group is not a word or line separator.
516     // Words need to be merged.
517
518     MergeWord( lastWordLayout,
519                firstWordLayout );
520
521     // After merging two words, the rest of the words need to be added.
522     ++index; // By increasing this index the word already merged won't be added again.
523   }
524
525   // Merge layout info
526   firstWordGroupLayoutInfo.mWordsLayoutInfo.insert( firstWordGroupLayoutInfo.mWordsLayoutInfo.end(),
527                                                     lastWordGroupLayoutInfo.mWordsLayoutInfo.begin() + index, lastWordGroupLayoutInfo.mWordsLayoutInfo.end() );
528   UpdateSize( firstWordGroupLayoutInfo.mSize, lastWordGroupLayoutInfo.mSize );
529   firstWordGroupLayoutInfo.mAscender = std::max( firstWordGroupLayoutInfo.mAscender, lastWordGroupLayoutInfo.mAscender );
530   firstWordGroupLayoutInfo.mNumberOfCharacters += lastWordGroupLayoutInfo.mNumberOfCharacters;
531 }
532
533 void CollectTextActorsFromGroups( std::vector<TextActor>& textActors, const LineLayoutInfo& line, const std::size_t groupIndexBegin, const std::size_t groupIndexEnd )
534 {
535   for( WordGroupLayoutInfoContainer::const_iterator groupIt = line.mWordGroupsLayoutInfo.begin() + groupIndexBegin, groupEndIt = line.mWordGroupsLayoutInfo.begin() + groupIndexEnd;
536        groupIt != groupEndIt;
537        ++groupIt )
538   {
539     const WordGroupLayoutInfo& group( *groupIt );
540
541     CollectTextActorsFromWords( textActors, group, 0, group.mWordsLayoutInfo.size() );
542   }
543 }
544
545 } //namespace TextViewProcessor
546
547 } //namespace Internal
548
549 } //namespace Toolkit
550
551 } //namespace Dali