2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
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.
18 #include <dali/integration-api/debug.h>
19 #include "text-view-processor.h"
20 #include "text-view-word-processor.h"
21 #include "text-view-word-group-processor.h"
22 #include "text-view-line-processor.h"
23 #include "text-view-processor-helper-functions.h"
24 #include "text-processor.h"
25 #include "text-view-processor-dbg.h"
36 namespace TextViewProcessor
42 * Update text layout info.
44 * Updates the size of the whole text, the maximum width of all words and the number of characters.
46 * @param[in,out] textLayoutInfo
48 void UpdateTextLayoutInfo( TextLayoutInfo& textLayoutInfo )
50 // Initialize members to be updated.
51 textLayoutInfo.mWholeTextSize = Size();
52 textLayoutInfo.mMaxWordWidth = 0.f;
53 textLayoutInfo.mNumberOfCharacters = 0;
55 // Traverse all text updating values.
56 for( LineLayoutInfoContainer::const_iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
60 const LineLayoutInfo& line( *lineIt );
62 // Updates text size with the size of all lines.
63 UpdateSize( textLayoutInfo.mWholeTextSize, line.mSize, GrowHeight );
65 // Updates number of characters.
66 textLayoutInfo.mNumberOfCharacters += line.mNumberOfCharacters;
68 // Updates the max word's width.
69 for( WordGroupLayoutInfoContainer::const_iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
70 groupIt != groupEndIt;
73 const WordGroupLayoutInfo& group( *groupIt );
74 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
78 const WordLayoutInfo& word( *wordIt );
80 textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, word.mSize.width );
88 // Constructors and assignment operators
90 TextInfoIndices::TextInfoIndices()
98 TextInfoIndices::TextInfoIndices( const std::size_t lineIndex,
99 const std::size_t groupIndex,
100 const std::size_t wordIndex,
101 const std::size_t characterIndex )
102 : mLineIndex( lineIndex ),
103 mGroupIndex( groupIndex ),
104 mWordIndex( wordIndex ),
105 mCharacterIndex( characterIndex )
109 bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const
111 return ( ( mLineIndex == indices.mLineIndex ) &&
112 ( mGroupIndex == indices.mGroupIndex ) &&
113 ( mWordIndex == indices.mWordIndex ) &&
114 ( mCharacterIndex == indices.mCharacterIndex ) );
117 /////////////////////
119 /////////////////////
121 TextLayoutInfo::TextLayoutInfo()
123 mMaxWordWidth( 0.f ),
125 mNumberOfCharacters( 0 ),
126 mMaxItalicsOffset( 0.f ),
127 mEllipsizeLayoutInfo()
131 TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
132 : mWholeTextSize( text.mWholeTextSize ),
133 mMaxWordWidth( text.mMaxWordWidth ),
134 mLinesLayoutInfo( text.mLinesLayoutInfo ),
135 mNumberOfCharacters( text.mNumberOfCharacters ),
136 mMaxItalicsOffset( text.mMaxItalicsOffset ),
137 mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
141 TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
143 mWholeTextSize = text.mWholeTextSize;
144 mMaxWordWidth = text.mMaxWordWidth;
145 mLinesLayoutInfo = text.mLinesLayoutInfo;
146 mNumberOfCharacters = text.mNumberOfCharacters;
147 mMaxItalicsOffset = text.mMaxItalicsOffset;
148 mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo;
153 /////////////////////////////////////////////////////////////////////////////////////////////
155 void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
156 const TextView::LayoutParameters& layoutParameters,
157 TextView::RelayoutData& relayoutData )
159 // * Traverse the given text spliting it in lines, each line in groups of words and each group of words in words.
160 // * If possible, it joins characters with same style in one text-actor.
161 // * White spaces and new line characters are alone in one word.
162 // * Bidirectional text is processed in each line.
163 // * A group of words contains text in only one direction (Left to Right or Right to Left but not a mix of both).
164 // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
165 // * Generates a text-actor data structure to store text, style and text-actors.
166 // TODO: finish and test the bidirectional implementation.
168 // Collect previously created text-actors.
169 std::vector<TextActor> textActors;
170 CollectTextActorsFromLines( textActors, relayoutData.mTextLayoutInfo, 0, relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() );
172 if( !textActors.empty() )
174 // Add text-actors to the cache.
175 relayoutData.mTextActorCache.InsertTextActors( textActors );
176 relayoutData.mTextActorCache.ClearTexts();
179 // Store the ellipsize layout info before clearing the previous created info.
180 const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
182 // clear previous created info.
183 relayoutData.mTextLayoutInfo = TextLayoutInfo();
184 relayoutData.mCharacterLogicalToVisualMap.clear();
185 relayoutData.mCharacterVisualToLogicalMap.clear();
187 // Sets the ellipsize layout info.
188 relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
190 // Split the whole text in lines.
191 std::vector<MarkupProcessor::StyledTextArray> lines;
192 TextProcessor::SplitInLines( text,
195 // Traverse all lines
196 for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator lineIt = lines.begin(), lineEndIt = lines.end(); lineIt != lineEndIt; ++lineIt )
198 const MarkupProcessor::StyledTextArray& line( *lineIt );
200 // Data structures for the new line
201 LineLayoutInfo lineLayoutInfo;
203 // Fills the line data structures with the layout info.
204 CreateLineInfo( line,
208 if( 0 < lineLayoutInfo.mNumberOfCharacters )
210 // do not add the line offset if the line has no characters.
211 lineLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
212 lineLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
216 // line height needs to be added for the last line.
218 float lineHeight = 0.f;
219 // Get the last character of the last line.
220 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
222 const LineLayoutInfo& lineInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
224 const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( lineInfo );
226 lineHeight = characterInfo.mSize.height;
229 lineLayoutInfo.mSize.height = lineHeight;
232 // Update layout info for the whole text.
233 UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, lineLayoutInfo.mSize, GrowHeight );
234 relayoutData.mTextLayoutInfo.mNumberOfCharacters += lineLayoutInfo.mNumberOfCharacters;
236 // Add the line to the current text.
237 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lineLayoutInfo );
241 void UpdateTextInfo( const std::size_t position,
242 const MarkupProcessor::StyledTextArray& text,
243 const TextView::LayoutParameters& layoutParameters,
244 TextView::RelayoutData& relayoutData )
246 // Update current internal data structure with added text.
248 // * Creates layout info for the given text.
249 // * With the given position, find where to add the text.
250 // * If the new text is not added at the end of current text, a line need to be split.
251 // * Merge the last line of the new text to the last part or the split line.
252 // * Add lines between first and last of the new text.
253 // * Merge the first part of the split line with the first line of the new text.
254 // * Update layout info and create new text actors if needed.
260 // nothing to do if the input text is empty.
264 if( 0 == relayoutData.mTextLayoutInfo.mNumberOfCharacters )
266 // Current text is empty. There is no need to update current data structure,
267 // just create a new one with the new input text.
268 CreateTextInfo( text,
275 if( position > relayoutData.mTextLayoutInfo.mNumberOfCharacters )
277 // Asserts if text is to be added out of bounds.
278 DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
281 TextView::RelayoutData relayoutDataForNewText;
283 // Creates layout info for the given text.
284 // It doesn't create text-actors as text could be added to an existing one.
285 CreateTextInfo( text,
287 relayoutDataForNewText );
289 // Update logical-to-visual and visual-to-logical tables.
290 // TODO: check that for mixed RTL/LTR text.
291 std::size_t index = 0;
292 for( std::size_t i = 0; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
294 relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
295 relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
299 // If a line is split, it stores the last part of the line.
300 LineLayoutInfo lastLineLayoutInfo;
302 // Stores indices to the line, group of words, word and character of the given position.
303 TextInfoIndices textInfoIndices;
305 if( position < relayoutData.mTextLayoutInfo.mNumberOfCharacters )
307 // Get line, group, word and character indices for given position.
308 GetIndicesFromGlobalCharacterIndex( position,
309 relayoutData.mTextLayoutInfo,
314 // Split a line in two is needed, then merge the first part of the split line
315 // with the first line of the new text, add subsequent lines and merge the last line
316 // of the new text with the last part of the split line.
318 // Implementation notes!
320 // These references to the first line are declared in this scope because if new lines are inserted in step 2,
321 // they become invalid, making the algorithm to crash if used again.
322 // In the step 3, references to the first line are needed and declared again.
324 // Stores the first part of the split line.
325 LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
327 SplitLine( textInfoIndices,
328 PointSize( layoutParameters.mLineHeightOffset ),
330 lastLineLayoutInfo );
334 // Position is just after the last character.
335 // Calculates indices for that position.
336 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
338 textInfoIndices.mLineIndex = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() - 1;
339 const LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
341 if( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() )
343 textInfoIndices.mGroupIndex = lineLayoutInfo.mWordGroupsLayoutInfo.size() - 1;
344 const WordGroupLayoutInfo& groupLayoutInfo( *( lineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) );
346 if( !groupLayoutInfo.mWordsLayoutInfo.empty() )
348 textInfoIndices.mWordIndex = groupLayoutInfo.mWordsLayoutInfo.size() - 1;
350 const WordLayoutInfo& wordLayoutInfo( *( groupLayoutInfo.mWordsLayoutInfo.end() - 1 ) );
351 textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
357 // 2) If the new text has more than 1 line, merge the last line of the input text with the last part of the split line.
358 //TODO check this cases ( num lines ==1, >1, >2 ) if it could be simplified.
359 if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 1 )
361 LineLayoutInfo& lastInputLineLayoutInfo( *( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
363 MergeLine( lastInputLineLayoutInfo,
364 lastLineLayoutInfo );
366 if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 2 )
368 // Insert all lines except first and last in the text.
369 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + 1,
370 relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() + 1,
371 relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 );
374 // Insert the last line to the text
375 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() - 1,
376 lastInputLineLayoutInfo );
380 // Merge the new line to the last part of the split line.
381 LineLayoutInfo& inputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
383 MergeLine( inputLineLayoutInfo,
384 lastLineLayoutInfo );
387 // 3) Merge the first line of the split text with the first line of the input text.
388 LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
389 LineLayoutInfo& firstInputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
391 MergeLine( firstLineLayoutInfo,
392 firstInputLineLayoutInfo );
394 // 4) Update text info.
396 // Updates the whole text size, maximum word size, etc.
397 UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
400 void UpdateTextInfo( const std::size_t position,
401 const std::size_t numberOfCharacters,
402 const TextView::LayoutParameters& layoutParameters,
403 TextView::RelayoutData& relayoutData,
404 const TextOperationOnRemove clearText )
406 // Removes 'numberOfCharacters' starting from 'position'.
408 // * It checks if text to be deleted is in the same line or not:
409 // * If it is not, check which lines need to be split/merged or deleted.
410 // * If it is but all characters of the line are going to be deleted, just delete the line (nothing needs to be split/merged)
411 // * If only some characters of the same line are going to be deleted, proceed similarly: check if text to be deleted is in the same group of words.
412 // * If it is not, check which groups of words need to be split/merged or deleted. Two groups of words can't be merged if they contain text with different direction (Left to Right / Right to Left)
413 // * If it is but all characters of the group are going to be deleted, delete the group. TODO: Check if previous and following group need to be merged.
414 // * If only some characters of the same group of words need to be deleted, proceed similarly: check if text to be deleted is in the same word.
415 // * If it is not, split/merge words.
416 // * Check if the whole word needs to be deleted.
417 // * Check if only some characters of the word need to be deleted.
418 // * Updates layout info.
420 // * The algorithm checks if a word separator is deleted (in that case, different words need to be merged) and if a new line separator is deleted (two lines need to be merged).
424 if( 0 == numberOfCharacters )
426 DALI_ASSERT_DEBUG( !"TextViewProcessor::UpdateTextInfo. WARNING: trying to delete 0 characters!" )
428 // nothing to do if no characters are deleted.
432 // Asserts if trying to delete text out of bounds.
433 DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
435 // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
436 relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
437 relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
439 // Get line, group of words, word and character indices for the given start position.
440 TextInfoIndices textInfoIndicesBegin;
441 GetIndicesFromGlobalCharacterIndex( position,
442 relayoutData.mTextLayoutInfo,
443 textInfoIndicesBegin );
445 // Get line, group of words, word and character indices for the given end position (start position + number of characters to be deleted).
446 TextInfoIndices textInfoIndicesEnd;
447 GetIndicesFromGlobalCharacterIndex( position + numberOfCharacters - 1,
448 relayoutData.mTextLayoutInfo,
449 textInfoIndicesEnd );
451 // Vectors used to temporary store text-actors removed from text.
452 // Three vectors are needed because text-actors are not removed in order
453 // but insert them in order is required to reuse them later.
454 std::vector<TextActor> removedTextActorsFromBegin;
455 std::vector<TextActor> removedTextActorsFromMid;
456 std::vector<TextActor> removedTextActorsFromEnd;
458 // Whether lines, group of words and words need to be merged.
459 bool mergeLines = false;
460 bool mergeGroups = false;
461 bool mergeWords = false;
463 // Indices of the lines, group of words and words to be merged.
464 TextInfoIndices textInfoMergeIndicesBegin;
465 TextInfoIndices textInfoMergeIndicesEnd;
467 const LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) ); // used to check the number of characters of the line
468 // if all characters to be deleted are in the same line.
469 if( textInfoIndicesBegin.mLineIndex < textInfoIndicesEnd.mLineIndex )
471 // Deleted text is from different lines. It may need to split two lines, and merge first part of the first one with last part of the last one.
473 // whether first or last line need to be split and merged with the last part.
474 bool mergeFirstLine = false;
475 bool mergeLastLine = true;
477 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
478 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
480 if( ( textInfoIndicesBegin.mGroupIndex > 0 ) || ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
482 // first character to be deleted is not the first one of the current line.
483 ++textInfoIndicesBegin.mLineIndex; // won't delete current line
485 // As some characters remain, this line could be merged with the last one.
486 mergeFirstLine = true;
489 // Check if all characters of the last line are going to be deleted.
490 bool wholeLinedeleted = false;
491 const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex ) );
492 if( textInfoIndicesEnd.mGroupIndex + 1 == lastLineLayout.mWordGroupsLayoutInfo.size() )
494 const WordGroupLayoutInfo& lastGroupLayout( *( lastLineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
495 if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
497 const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
498 if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
500 // All characters of the last line are going to be deleted.
501 ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
503 // the whole last line is deleted. Need to check if the next line could be merged.
504 mergeLastLine = false;
505 wholeLinedeleted = true;
510 if( wholeLinedeleted )
512 // It means the whole last line is deleted completely.
513 // It's needed to check if there is another line after that could be merged.
514 if( textInfoIndicesEnd.mLineIndex < relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() )
516 mergeLastLine = true;
518 // Point the first characters of the next line.
519 textInfoIndicesEnd.mGroupIndex = 0;
520 textInfoIndicesEnd.mWordIndex = 0;
521 textInfoIndicesEnd.mCharacterIndex = 0;
522 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
526 // If some characters remain in the first and last line, they need to be merged.
527 mergeLines = mergeFirstLine && mergeLastLine;
531 // last line is going to be merged with the first one, so is not needed.
532 ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
537 // Remove characters from the first line.
539 // Vectors used to temporary store text-actors removed from the line.
540 // Three vectors are needed because text-actors are not removed in order
541 // but insert them in order is required to reuse them later.
542 std::vector<TextActor> removedTextActorsFromFirstWord;
543 std::vector<TextActor> removedTextActorsFromFirstGroup;
544 std::vector<TextActor> removedTextActorsFromGroups;
546 // As lineIndexBegin has been increased just to not to remove the line, decrease now is needed to access it.
547 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex - 1 ) );
549 if( textInfoIndicesBegin.mGroupIndex + 1 < lineLayout.mWordGroupsLayoutInfo.size() )
551 // Store text-actors before removing them.
552 CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, textInfoIndicesBegin.mGroupIndex + 1, lineLayout.mWordGroupsLayoutInfo.size() );
554 // Remove extra groups. If a line has left to right and right to left text, groups after current one could be removed.
555 RemoveWordGroupsFromLine( textInfoIndicesBegin.mGroupIndex + 1,
556 lineLayout.mWordGroupsLayoutInfo.size() - ( textInfoIndicesBegin.mGroupIndex + 1 ),
557 PointSize( layoutParameters.mLineHeightOffset ),
561 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
563 if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
565 // Remove extra words within current group of words. (and current word if whole characters are removed)
566 // 0 == characterIndexBegin means the whole word is deleted.
567 const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
569 // Store text-actors before removing them.
570 CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
572 const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
573 RemoveWordsFromWordGroup( wordIndex,
574 groupLayout.mWordsLayoutInfo.size() - wordIndex,
577 // discount the removed number of characters.
578 lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
581 if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
583 // Only some characters of the word need to be removed.
584 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
586 // Store text-actors before removing them.
587 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
589 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
590 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
591 wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
594 // discount the removed number of characters.
595 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
596 groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
597 lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
599 UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
601 // Insert the text-actors in order.
602 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
603 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
604 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
607 if( mergeLastLine && !wholeLinedeleted )
609 // Some characters from the last line need to be removed.
611 // Vectors used to temporary store text-actors removed from the group.
612 // Three vectors are needed because text-actors are not removed in order
613 // but insert them in order is required to reuse them later.
614 std::vector<TextActor> removedTextActorsFromFirstWord;
615 std::vector<TextActor> removedTextActorsFromFirstGroup;
616 std::vector<TextActor> removedTextActorsFromGroups;
618 // lineIndexEnd was increased to delete the last line if lines need to be merged.
619 // To access now the last line we need to decrease the index.
620 const std::size_t lineIndex = ( mergeLines ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex );
622 // Get the last line.
623 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lineIndex ) );
625 if( textInfoIndicesEnd.mGroupIndex > 0 )
627 // Store text-actors before removing them.
628 CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, 0, textInfoIndicesEnd.mGroupIndex );
630 // Remove extra groups from the beginning of the line to the current group of words.
631 RemoveWordGroupsFromLine( 0,
632 textInfoIndicesEnd.mGroupIndex,
633 PointSize( layoutParameters.mLineHeightOffset ),
637 // The group of characters which contains the characters to be removed is now the first one.
638 WordGroupLayoutInfo& groupLayout( *lineLayout.mWordGroupsLayoutInfo.begin() );
640 // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
641 const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
642 bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
644 if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
646 // Store text-actors before removing them.
647 CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
649 // Remove extra words. (and current word if whole characters are removed)
650 const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
651 RemoveWordsFromWordGroup( 0,
652 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
655 // discount the removed number of characters.
656 lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
659 if( !removeWholeWord )
661 // Only some characters of the word need to be deleted.
663 // After removing all extra words. The word with the characters to be removed is the first one.
664 WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
666 // Store text-actors before removing them.
667 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
669 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
670 RemoveCharactersFromWord( 0,
671 textInfoIndicesEnd.mCharacterIndex + 1,
674 // discount the removed number of characters.
675 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
676 groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
677 lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
678 UpdateGroupLayoutInfo( groupLayout );
680 UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
682 // Insert the text-actors in order.
683 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
684 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
685 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
687 } // end delete text from different lines
688 else if( ( textInfoIndicesBegin.mLineIndex == textInfoIndicesEnd.mLineIndex ) && ( lineLayout.mNumberOfCharacters == numberOfCharacters ) )
690 // the whole line needs to be deleted.
691 ++textInfoIndicesEnd.mLineIndex; // will delete current line.
695 // deleted text is within the same line. (merge lines could be needed if the line separator character is deleted)
697 // Line which contains the characters to be deleted.
698 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) );
700 const WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) ); // used to check the number of characters of the group of words
701 // if all characters to be deleted are in the same group of words.
702 if( textInfoIndicesBegin.mGroupIndex < textInfoIndicesEnd.mGroupIndex )
704 // Deleted text is from different group of words. The two different group of words may be merged if they have text with same direction.
706 // whether first or last group of words need to be split and merged with the last part.
707 bool splitFirstGroup = false;
708 bool splitLastGroup = true;
710 textInfoMergeIndicesBegin.mGroupIndex = textInfoIndicesBegin.mGroupIndex;
711 textInfoMergeIndicesEnd.mGroupIndex = textInfoIndicesEnd.mGroupIndex;
713 if( ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
715 // first character to be deleted is not the first one of the current group.
716 ++textInfoIndicesBegin.mGroupIndex; // won't delete current group
718 // As some characters remain, this group needs to be split and could be merged with the last one.
719 splitFirstGroup = true;
722 // Check if all characters of the last group are going to be deleted.
723 const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
724 if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
726 const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
727 if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
729 // All characters of the last group are going to be deleted.
730 ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
732 // The whole last group is deleted. No need to merge groups.
733 splitLastGroup = false;
737 // Only merge two groups if they are not deleted completely and they have same direction.
738 mergeGroups = ( splitFirstGroup && splitLastGroup ) && ( groupLayout.mDirection == lastGroupLayout.mDirection );
742 // last group is going to be merged.
743 ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
746 if( splitFirstGroup )
748 // Remove characters from the first group.
750 // As wordGroupIndexBegin has been increased just to not to remove the group of words, decrease now is needed to access it.
751 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex - 1 ) );
753 if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
755 // Remove extra words within current group of words. (and current word if whole characters are removed)
756 // 0 == characterIndexBegin means the whole word is deleted.
757 const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
759 // Store text-actors before removing them.
760 CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
762 RemoveWordsFromWordGroup( wordIndex,
763 groupLayout.mWordsLayoutInfo.size() - wordIndex,
767 if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
769 // Only some characters of the word need to be removed.
770 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
772 // Store text-actors before removing them.
773 CollectTextActors( removedTextActorsFromBegin, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
775 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
776 wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
783 // Some characters from the last group of words need to be removed.
785 // textInfoIndicesEnd.mGroupIndex was increased to delete the last group of words if groups need to be merged.
786 // To access now the last group of words we need to decrease the index.
787 std::size_t index = mergeGroups ? textInfoIndicesEnd.mGroupIndex - 1 : textInfoIndicesEnd.mGroupIndex;
789 // Get the last group of words.
790 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + index ) );
792 // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
793 const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
794 bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
796 if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
798 // Store text-actors before removing them.
799 CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
801 // Remove extra words. (and current word if whole characters are removed)
802 RemoveWordsFromWordGroup( 0,
803 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
807 if( !removeWholeWord )
809 // Only some characters of the word need to be deleted.
811 // After removing all extra words. The word with the characters to be removed is the first one.
812 WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
814 // Store text-actors before removing them.
815 CollectTextActors( removedTextActorsFromBegin, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
817 RemoveCharactersFromWord( 0,
818 textInfoIndicesEnd.mCharacterIndex + 1,
822 } // end of remove from different groups
823 else if( ( textInfoIndicesBegin.mGroupIndex == textInfoIndicesEnd.mGroupIndex ) && ( groupLayout.mNumberOfCharacters == numberOfCharacters ) )
825 // The whole group is deleted.
826 ++textInfoIndicesEnd.mGroupIndex; // will delete current group.
827 // TODO group before and group after need to be merged!!!
831 // characters to be deleted are on the same group of words. (words may need to be merged)
833 // Group of words which contains the characters to be deleted.
834 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
836 RemoveCharactersFromWordGroupInfo( relayoutData,
840 textInfoIndicesBegin,
842 textInfoMergeIndicesBegin,
843 textInfoMergeIndicesEnd,
845 removedTextActorsFromBegin,
846 removedTextActorsFromEnd );
850 // Merges words pointed by textInfoMergeIndicesBegin.mWordIndex and textInfoMergeIndicesEnd.mWordIndex calculated previously.
851 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (begin) out of bounds." );
852 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesEnd.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (end) out of bounds." );
854 WordLayoutInfo& firstWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesBegin.mWordIndex ) );
855 WordLayoutInfo& lastWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesEnd.mWordIndex ) );
857 MergeWord( firstWordLayout,
861 // Store text-actors before removing them.
862 const std::size_t endIndex = ( mergeWords && ( textInfoIndicesEnd.mWordIndex > 0 ) ) ? textInfoIndicesEnd.mWordIndex - 1 : textInfoIndicesEnd.mWordIndex; // text-actors from the last word may have been added in the merge above.
863 CollectTextActorsFromWords( removedTextActorsFromMid, groupLayout, textInfoIndicesBegin.mWordIndex, endIndex );
865 // Remove unwanted words using previously calculated indices. (including the last part of the merged word)
866 groupLayout.mWordsLayoutInfo.erase( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex, groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex );
868 // Update group of words info
869 groupLayout.mNumberOfCharacters -= numberOfCharacters;
870 groupLayout.mSize = Size();
871 groupLayout.mAscender = 0;
872 for( WordLayoutInfoContainer::const_iterator it = groupLayout.mWordsLayoutInfo.begin(), endIt = groupLayout.mWordsLayoutInfo.end();
876 const WordLayoutInfo& layoutInfo( *it );
877 UpdateSize( groupLayout.mSize, layoutInfo.mSize );
878 groupLayout.mAscender = std::max( groupLayout.mAscender, layoutInfo.mAscender );
880 } // end of remove from same group
884 // Merges group of words pointed by textInfoMergeIndicesBegin.mGroupIndex and textInfoMergeIndicesEnd.mGroupIndex calculated previously.
886 WordGroupLayoutInfo& firstGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesBegin.mGroupIndex ) );
888 const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesEnd.mGroupIndex ) );
890 MergeWordGroup( firstGroupLayout,
894 // Remove unwanted groups of words using previously calculated indices. (including the last part of the merged group of words)
895 lineLayout.mWordGroupsLayoutInfo.erase( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex, lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex );
898 lineLayout.mNumberOfCharacters -= numberOfCharacters;
899 lineLayout.mSize = Size();
900 lineLayout.mAscender = 0;
901 for( WordGroupLayoutInfoContainer::const_iterator it = lineLayout.mWordGroupsLayoutInfo.begin(), endIt = lineLayout.mWordGroupsLayoutInfo.end();
905 const WordGroupLayoutInfo& layoutInfo( *it );
906 UpdateSize( lineLayout.mSize, layoutInfo.mSize );
907 lineLayout.mAscender = std::max( lineLayout.mAscender, layoutInfo.mAscender );
909 lineLayout.mSize.height += layoutParameters.mLineHeightOffset;
910 lineLayout.mLineHeightOffset = layoutParameters.mLineHeightOffset;
911 }// end delete text from same line.
915 // Merges lines pointed by textInfoMergeIndicesBegin.mLineIndex and textInfoMergeIndicesEnd.mLineIndex calculated previously.
917 LineLayoutInfo& firstLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesBegin.mLineIndex ) );
919 const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesEnd.mLineIndex ) );
921 MergeLine( firstLineLayout,
925 // Store text-actors before removing them.
926 const std::size_t endIndex = ( mergeLines && ( textInfoIndicesEnd.mLineIndex > 0 ) ) ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex; // text-actors from the last line may have been added in the merge above.
927 CollectTextActorsFromLines( removedTextActorsFromMid,
928 relayoutData.mTextLayoutInfo,
929 textInfoIndicesBegin.mLineIndex,
932 // Remove unwanted lines using previously calculated indices. (including the last part of the merged line)
933 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.erase( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex,
934 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex );
937 UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
939 // If the last character of the last line is a new line character, an empty line need to be added.
940 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
942 const WordLayoutInfo lastWordLayout = GetLastWordLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
944 if( LineSeparator == lastWordLayout.mType )
946 LineLayoutInfo lastLineLayout;
948 const CharacterLayoutInfo layoutInfo = GetLastCharacterLayoutInfo( lastWordLayout );
949 lastLineLayout.mSize.height = layoutInfo.mSize.height;
951 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lastLineLayout );
953 relayoutData.mTextLayoutInfo.mWholeTextSize.height += layoutInfo.mSize.height;
957 // Clear the text from the text-actors if required.
958 if( CLEAR_TEXT == clearText )
960 ClearText( removedTextActorsFromEnd );
961 ClearText( removedTextActorsFromMid );
962 ClearText( removedTextActorsFromBegin );
965 // Insert text-actors into the cache.
966 // Text-actors are inserted in reverse order to use first the first removed.
967 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromEnd );
968 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromMid );
969 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
972 void UpdateTextInfo( const std::size_t position,
973 const std::size_t numberOfCharacters,
974 const MarkupProcessor::StyledTextArray& text,
975 const TextView::LayoutParameters& layoutParameters,
976 TextView::RelayoutData& relayoutData )
978 // Replaces 'numberOfCharacters' of text starting from 'position' with the given text.
980 // TODO: Temporary implementation with remove and insert.
983 UpdateTextInfo( position,
987 KEEP_TEXT ); // Do not clear the text from the text-actors.
990 UpdateTextInfo( position,
996 void UpdateTextInfo( const float lineHeightOffset,
997 TextLayoutInfo& textLayoutInfo )
999 // Updates the space between lines with the new offset value.
1001 float newTextHeight = 0.f;
1003 for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1004 lineIt != lineEndIt;
1007 LineLayoutInfo& lineLayoutInfo( *lineIt );
1009 lineLayoutInfo.mSize.height += ( lineHeightOffset - lineLayoutInfo.mLineHeightOffset );
1010 newTextHeight += lineLayoutInfo.mSize.height;
1012 lineLayoutInfo.mLineHeightOffset = lineHeightOffset;
1015 textLayoutInfo.mWholeTextSize.height = newTextHeight;
1018 void UpdateTextInfo( const TextStyle& style,
1019 const TextStyle::Mask mask,
1020 TextView::RelayoutData& relayoutData )
1022 // Change text style for all text-actors.
1024 for( LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1025 lineIt != lineEndIt;
1028 LineLayoutInfo& line( *lineIt );
1030 for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1031 groupIt != groupEndIt;
1034 WordGroupLayoutInfo& group( *groupIt );
1036 for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1037 wordIt != wordEndIt;
1040 WordLayoutInfo& word( *wordIt );
1042 for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1043 characterIt != characterEndIt;
1046 CharacterLayoutInfo& characterLayout( *characterIt );
1048 characterLayout.mStyledText.mStyle.Copy( style, mask );
1050 // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
1051 ChooseFontFamilyName( characterLayout.mStyledText );
1053 // Mark the character to be set the new style into the text-actor.
1054 characterLayout.mSetStyle = true;
1057 } // end group of words
1061 void InitializeTextActorInfo( TextView::RelayoutData& relayoutData )
1063 TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
1064 if( textLayoutInfo.mLinesLayoutInfo.empty() )
1066 // nothing to do if there is no lines.
1070 std::size_t characterGlobalIndex = 0; // Index to the global character (within the whole text).
1071 std::size_t lineLayoutInfoIndex = 0; // Index to the laid out line info.
1072 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
1073 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
1075 TextActor currentTextActor; // text-actor used when the edit mode is disabled.
1076 TextStyle currentStyle; // style for the current text-actor.
1077 Vector4 currentGradientColor; // gradient color for the current text-actor.
1078 Vector2 currentStartPoint; // start point for the current text-actor.
1079 Vector2 currentEndPoint; // end point for the current text-actor.
1081 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
1083 for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1084 lineIt != lineEndIt;
1087 LineLayoutInfo& line( *lineIt );
1089 for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1090 groupIt != groupEndIt;
1093 WordGroupLayoutInfo& group( *groupIt );
1095 for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1096 wordIt != wordEndIt;
1099 WordLayoutInfo& word( *wordIt );
1101 for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1102 characterIt != characterEndIt;
1105 CharacterLayoutInfo& characterLayout( *characterIt );
1107 if( !characterLayout.mStyledText.mText.IsEmpty() )
1109 // Do not create a text-actor if there is no text.
1110 const std::size_t length = characterLayout.mStyledText.mText.GetLength();
1111 const Character character = characterLayout.mStyledText.mText[0];
1113 if( ( 1 < length ) ||
1114 ( ( 1 == length ) && character.IsWhiteSpace() && characterLayout.mStyledText.mStyle.GetUnderline() ) ||
1115 ( ( 1 == length ) && !character.IsNewLine() && !character.IsWhiteSpace() ) )
1117 // Do not create a text-actor if it's a white space (without underline) or a new line character.
1119 // Creates one text-actor per each counsecutive group of characters, with the same style, per line.
1121 // Check if there is a new line.
1122 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
1124 if( ( characterLayout.mStyledText.mStyle != currentStyle ) ||
1125 ( characterLayout.mGradientColor != currentGradientColor ) ||
1126 ( characterLayout.mStartPoint != currentStartPoint ) ||
1127 ( characterLayout.mEndPoint != currentEndPoint ) ||
1130 // There is a new style or a new line.
1133 // Point to the next line.
1134 ++lineLayoutInfoIndex;
1135 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
1137 // Arrived at last line.
1138 lineLayoutEnd = true;
1142 if( characterLayout.mTextActor )
1144 // Try to reuse first the text-actor of this character.
1145 currentTextActor = characterLayout.mTextActor;
1146 currentTextActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1150 // If there is no text-actor, try to retrieve one from the cache.
1151 currentTextActor = relayoutData.mTextActorCache.RetrieveTextActor();
1153 // If still there is no text-actor, create one.
1154 if( !currentTextActor )
1156 currentTextActor = TextActor::New( Text(), characterLayout.mStyledText.mStyle, false, true );
1160 currentTextActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1164 // Update style to be checked with next characters.
1165 currentStyle = characterLayout.mStyledText.mStyle;
1166 currentGradientColor = characterLayout.mGradientColor;
1167 currentStartPoint = characterLayout.mStartPoint;
1168 currentEndPoint = characterLayout.mEndPoint;
1170 characterLayout.mSetText = false;
1171 characterLayout.mSetStyle = false;
1173 characterLayout.mTextActor = currentTextActor;
1174 characterLayout.mTextActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1175 characterLayout.mTextActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1179 // Same style than previous one.
1180 if( characterLayout.mTextActor )
1182 // There is a previously created text-actor for this character.
1183 // If this character has another one put it into the cache.
1184 characterLayout.mTextActor.SetText( "" );
1185 textActorsToRemove.push_back( characterLayout.mTextActor );
1186 characterLayout.mTextActor.Reset();
1189 } // no white space / new line char
1192 ++characterGlobalIndex;
1198 // Insert the spare text-actors into the cache.
1199 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
1202 } // namespace TextViewProcessor
1204 } // namespace Internal
1206 } // namespace Toolkit