2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/integration-api/debug.h>
20 #include "text-view-processor.h"
21 #include "text-view-word-processor.h"
22 #include "text-view-word-group-processor.h"
23 #include "text-view-line-processor.h"
24 #include "text-view-processor-helper-functions.h"
25 #include "text-processor.h"
26 #include "text-view-processor-dbg.h"
37 namespace TextViewProcessor
43 * Update text layout info.
45 * Updates the size of the whole text, the maximum width of all words and the number of characters.
47 * @param[in,out] textLayoutInfo
49 void UpdateTextLayoutInfo( TextLayoutInfo& textLayoutInfo )
51 // Initialize members to be updated.
52 textLayoutInfo.mWholeTextSize = Size();
53 textLayoutInfo.mMaxWordWidth = 0.f;
54 textLayoutInfo.mNumberOfCharacters = 0;
56 // Traverse all text updating values.
57 for( LineLayoutInfoContainer::const_iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
61 const LineLayoutInfo& line( *lineIt );
63 // Updates text size with the size of all lines.
64 UpdateSize( textLayoutInfo.mWholeTextSize, line.mSize, GrowHeight );
66 // Updates number of characters.
67 textLayoutInfo.mNumberOfCharacters += line.mNumberOfCharacters;
69 // Updates the max word's width.
70 for( WordGroupLayoutInfoContainer::const_iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
71 groupIt != groupEndIt;
74 const WordGroupLayoutInfo& group( *groupIt );
75 for( WordLayoutInfoContainer::const_iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
79 const WordLayoutInfo& word( *wordIt );
81 textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, word.mSize.width );
89 // Constructors and assignment operators
91 TextInfoIndices::TextInfoIndices()
99 TextInfoIndices::TextInfoIndices( const std::size_t lineIndex,
100 const std::size_t groupIndex,
101 const std::size_t wordIndex,
102 const std::size_t characterIndex )
103 : mLineIndex( lineIndex ),
104 mGroupIndex( groupIndex ),
105 mWordIndex( wordIndex ),
106 mCharacterIndex( characterIndex )
110 bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const
112 return ( ( mLineIndex == indices.mLineIndex ) &&
113 ( mGroupIndex == indices.mGroupIndex ) &&
114 ( mWordIndex == indices.mWordIndex ) &&
115 ( mCharacterIndex == indices.mCharacterIndex ) );
118 /////////////////////
120 /////////////////////
122 TextLayoutInfo::TextLayoutInfo()
124 mMaxWordWidth( 0.f ),
126 mNumberOfCharacters( 0 ),
127 mMaxItalicsOffset( 0.f ),
128 mEllipsizeLayoutInfo()
132 TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
133 : mWholeTextSize( text.mWholeTextSize ),
134 mMaxWordWidth( text.mMaxWordWidth ),
135 mLinesLayoutInfo( text.mLinesLayoutInfo ),
136 mNumberOfCharacters( text.mNumberOfCharacters ),
137 mMaxItalicsOffset( text.mMaxItalicsOffset ),
138 mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
142 TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
144 mWholeTextSize = text.mWholeTextSize;
145 mMaxWordWidth = text.mMaxWordWidth;
146 mLinesLayoutInfo = text.mLinesLayoutInfo;
147 mNumberOfCharacters = text.mNumberOfCharacters;
148 mMaxItalicsOffset = text.mMaxItalicsOffset;
149 mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo;
154 /////////////////////////////////////////////////////////////////////////////////////////////
156 void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
157 const TextView::LayoutParameters& layoutParameters,
158 TextView::RelayoutData& relayoutData )
160 // * Traverse the given text spliting it in lines, each line in groups of words and each group of words in words.
161 // * If possible, it joins characters with same style in one text-actor.
162 // * White spaces and new line characters are alone in one word.
163 // * Bidirectional text is processed in each line.
164 // * A group of words contains text in only one direction (Left to Right or Right to Left but not a mix of both).
165 // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
166 // * Generates a text-actor data structure to store text, style and text-actors.
167 // TODO: finish and test the bidirectional implementation.
169 // Collect previously created text-actors.
170 std::vector<TextActor> textActors;
171 CollectTextActorsFromLines( textActors, relayoutData.mTextLayoutInfo, 0, relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() );
173 if( !textActors.empty() )
175 // Add text-actors to the cache.
176 relayoutData.mTextActorCache.InsertTextActors( textActors );
177 relayoutData.mTextActorCache.ClearTexts();
180 // Store the ellipsize layout info before clearing the previous created info.
181 const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
183 // clear previous created info.
184 relayoutData.mTextLayoutInfo = TextLayoutInfo();
185 relayoutData.mCharacterLogicalToVisualMap.clear();
186 relayoutData.mCharacterVisualToLogicalMap.clear();
188 // Sets the ellipsize layout info.
189 relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
191 // Split the whole text in lines.
192 std::vector<MarkupProcessor::StyledTextArray> lines;
193 TextProcessor::SplitInLines( text,
196 // Traverse all lines
197 for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator lineIt = lines.begin(), lineEndIt = lines.end(); lineIt != lineEndIt; ++lineIt )
199 const MarkupProcessor::StyledTextArray& line( *lineIt );
201 // Data structures for the new line
202 LineLayoutInfo lineLayoutInfo;
204 // Fills the line data structures with the layout info.
205 CreateLineInfo( line,
209 if( 0 < lineLayoutInfo.mNumberOfCharacters )
211 // do not add the line offset if the line has no characters.
212 lineLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
213 lineLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
217 // line height needs to be added for the last line.
219 float lineHeight = 0.f;
220 // Get the last character of the last line.
221 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
223 const LineLayoutInfo& lineInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
225 const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( lineInfo );
227 lineHeight = characterInfo.mSize.height;
230 lineLayoutInfo.mSize.height = lineHeight;
233 // Update layout info for the whole text.
234 UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, lineLayoutInfo.mSize, GrowHeight );
235 relayoutData.mTextLayoutInfo.mNumberOfCharacters += lineLayoutInfo.mNumberOfCharacters;
237 // Add the line to the current text.
238 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lineLayoutInfo );
242 void UpdateTextInfo( const std::size_t position,
243 const MarkupProcessor::StyledTextArray& text,
244 const TextView::LayoutParameters& layoutParameters,
245 TextView::RelayoutData& relayoutData )
247 // Update current internal data structure with added text.
249 // * Creates layout info for the given text.
250 // * With the given position, find where to add the text.
251 // * If the new text is not added at the end of current text, a line need to be split.
252 // * Merge the last line of the new text to the last part or the split line.
253 // * Add lines between first and last of the new text.
254 // * Merge the first part of the split line with the first line of the new text.
255 // * Update layout info and create new text actors if needed.
261 // nothing to do if the input text is empty.
265 if( 0 == relayoutData.mTextLayoutInfo.mNumberOfCharacters )
267 // Current text is empty. There is no need to update current data structure,
268 // just create a new one with the new input text.
269 CreateTextInfo( text,
276 if( position > relayoutData.mTextLayoutInfo.mNumberOfCharacters )
278 // Asserts if text is to be added out of bounds.
279 DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
282 TextView::RelayoutData relayoutDataForNewText;
284 // Creates layout info for the given text.
285 // It doesn't create text-actors as text could be added to an existing one.
286 CreateTextInfo( text,
288 relayoutDataForNewText );
290 // Update logical-to-visual and visual-to-logical tables.
291 // TODO: check that for mixed RTL/LTR text.
292 std::size_t index = 0;
293 for( std::size_t i = 0; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
295 relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
296 relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
300 // If a line is split, it stores the last part of the line.
301 LineLayoutInfo lastLineLayoutInfo;
303 // Stores indices to the line, group of words, word and character of the given position.
304 TextInfoIndices textInfoIndices;
306 if( position < relayoutData.mTextLayoutInfo.mNumberOfCharacters )
308 // Get line, group, word and character indices for given position.
309 GetIndicesFromGlobalCharacterIndex( position,
310 relayoutData.mTextLayoutInfo,
315 // Split a line in two is needed, then merge the first part of the split line
316 // with the first line of the new text, add subsequent lines and merge the last line
317 // of the new text with the last part of the split line.
319 // Implementation notes!
321 // These references to the first line are declared in this scope because if new lines are inserted in step 2,
322 // they become invalid, making the algorithm to crash if used again.
323 // In the step 3, references to the first line are needed and declared again.
325 // Stores the first part of the split line.
326 LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
328 SplitLine( textInfoIndices,
329 PointSize( layoutParameters.mLineHeightOffset ),
331 lastLineLayoutInfo );
335 // Position is just after the last character.
336 // Calculates indices for that position.
337 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
339 textInfoIndices.mLineIndex = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() - 1;
340 const LineLayoutInfo& lineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
342 if( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() )
344 textInfoIndices.mGroupIndex = lineLayoutInfo.mWordGroupsLayoutInfo.size() - 1;
345 const WordGroupLayoutInfo& groupLayoutInfo( *( lineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) );
347 if( !groupLayoutInfo.mWordsLayoutInfo.empty() )
349 textInfoIndices.mWordIndex = groupLayoutInfo.mWordsLayoutInfo.size() - 1;
351 const WordLayoutInfo& wordLayoutInfo( *( groupLayoutInfo.mWordsLayoutInfo.end() - 1 ) );
352 textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
358 // 2) If the new text has more than 1 line, merge the last line of the input text with the last part of the split line.
359 //TODO check this cases ( num lines ==1, >1, >2 ) if it could be simplified.
360 if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 1 )
362 LineLayoutInfo& lastInputLineLayoutInfo( *( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
364 MergeLine( lastInputLineLayoutInfo,
365 lastLineLayoutInfo );
367 if( relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() > 2 )
369 // Insert all lines except first and last in the text.
370 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + 1,
371 relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() + 1,
372 relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 );
375 // Insert the last line to the text
376 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.insert( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex + relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.size() - 1,
377 lastInputLineLayoutInfo );
381 // Merge the new line to the last part of the split line.
382 LineLayoutInfo& inputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
384 MergeLine( inputLineLayoutInfo,
385 lastLineLayoutInfo );
388 // 3) Merge the first line of the split text with the first line of the input text.
389 LineLayoutInfo& firstLineLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndices.mLineIndex ) );
390 LineLayoutInfo& firstInputLineLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mLinesLayoutInfo.begin() );
392 MergeLine( firstLineLayoutInfo,
393 firstInputLineLayoutInfo );
395 // 4) Update text info.
397 // Updates the whole text size, maximum word size, etc.
398 UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
401 void UpdateTextInfo( const std::size_t position,
402 const std::size_t numberOfCharacters,
403 const TextView::LayoutParameters& layoutParameters,
404 TextView::RelayoutData& relayoutData,
405 const TextOperationOnRemove clearText )
407 // Removes 'numberOfCharacters' starting from 'position'.
409 // * It checks if text to be deleted is in the same line or not:
410 // * If it is not, check which lines need to be split/merged or deleted.
411 // * If it is but all characters of the line are going to be deleted, just delete the line (nothing needs to be split/merged)
412 // * If only some characters of the same line are going to be deleted, proceed similarly: check if text to be deleted is in the same group of words.
413 // * If it is not, check which groups of words need to be split/merged or deleted. Two groups of words can't be merged if they contain text with different direction (Left to Right / Right to Left)
414 // * If it is but all characters of the group are going to be deleted, delete the group. TODO: Check if previous and following group need to be merged.
415 // * If only some characters of the same group of words need to be deleted, proceed similarly: check if text to be deleted is in the same word.
416 // * If it is not, split/merge words.
417 // * Check if the whole word needs to be deleted.
418 // * Check if only some characters of the word need to be deleted.
419 // * Updates layout info.
421 // * The algorithm checks if a word separator is deleted (in that case, different words need to be merged) and if a new line separator is deleted (two lines need to be merged).
425 if( 0 == numberOfCharacters )
427 DALI_ASSERT_DEBUG( !"TextViewProcessor::UpdateTextInfo. WARNING: trying to delete 0 characters!" )
429 // nothing to do if no characters are deleted.
433 // Asserts if trying to delete text out of bounds.
434 DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
436 // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
437 relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
438 relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
440 // Get line, group of words, word and character indices for the given start position.
441 TextInfoIndices textInfoIndicesBegin;
442 GetIndicesFromGlobalCharacterIndex( position,
443 relayoutData.mTextLayoutInfo,
444 textInfoIndicesBegin );
446 // Get line, group of words, word and character indices for the given end position (start position + number of characters to be deleted).
447 TextInfoIndices textInfoIndicesEnd;
448 GetIndicesFromGlobalCharacterIndex( position + numberOfCharacters - 1,
449 relayoutData.mTextLayoutInfo,
450 textInfoIndicesEnd );
452 // Vectors used to temporary store text-actors removed from text.
453 // Three vectors are needed because text-actors are not removed in order
454 // but insert them in order is required to reuse them later.
455 std::vector<TextActor> removedTextActorsFromBegin;
456 std::vector<TextActor> removedTextActorsFromMid;
457 std::vector<TextActor> removedTextActorsFromEnd;
459 // Whether lines, group of words and words need to be merged.
460 bool mergeLines = false;
461 bool mergeGroups = false;
462 bool mergeWords = false;
464 // Indices of the lines, group of words and words to be merged.
465 TextInfoIndices textInfoMergeIndicesBegin;
466 TextInfoIndices textInfoMergeIndicesEnd;
468 const LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) ); // used to check the number of characters of the line
469 // if all characters to be deleted are in the same line.
470 if( textInfoIndicesBegin.mLineIndex < textInfoIndicesEnd.mLineIndex )
472 // Deleted text is from different lines. It may need to split two lines, and merge first part of the first one with last part of the last one.
474 // whether first or last line need to be split and merged with the last part.
475 bool mergeFirstLine = false;
476 bool mergeLastLine = true;
478 textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex;
479 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
481 if( ( textInfoIndicesBegin.mGroupIndex > 0 ) || ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
483 // first character to be deleted is not the first one of the current line.
484 ++textInfoIndicesBegin.mLineIndex; // won't delete current line
486 // As some characters remain, this line could be merged with the last one.
487 mergeFirstLine = true;
490 // Check if all characters of the last line are going to be deleted.
491 bool wholeLinedeleted = false;
492 const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex ) );
493 if( textInfoIndicesEnd.mGroupIndex + 1 == lastLineLayout.mWordGroupsLayoutInfo.size() )
495 const WordGroupLayoutInfo& lastGroupLayout( *( lastLineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
496 if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
498 const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
499 if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
501 // All characters of the last line are going to be deleted.
502 ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
504 // the whole last line is deleted. Need to check if the next line could be merged.
505 mergeLastLine = false;
506 wholeLinedeleted = true;
511 if( wholeLinedeleted )
513 // It means the whole last line is deleted completely.
514 // It's needed to check if there is another line after that could be merged.
515 if( textInfoIndicesEnd.mLineIndex < relayoutData.mTextLayoutInfo.mLinesLayoutInfo.size() )
517 mergeLastLine = true;
519 // Point the first characters of the next line.
520 textInfoIndicesEnd.mGroupIndex = 0;
521 textInfoIndicesEnd.mWordIndex = 0;
522 textInfoIndicesEnd.mCharacterIndex = 0;
523 textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesEnd.mLineIndex;
527 // If some characters remain in the first and last line, they need to be merged.
528 mergeLines = mergeFirstLine && mergeLastLine;
532 // last line is going to be merged with the first one, so is not needed.
533 ++textInfoIndicesEnd.mLineIndex; // will delete the last line.
538 // Remove characters from the first line.
540 // Vectors used to temporary store text-actors removed from the line.
541 // Three vectors are needed because text-actors are not removed in order
542 // but insert them in order is required to reuse them later.
543 std::vector<TextActor> removedTextActorsFromFirstWord;
544 std::vector<TextActor> removedTextActorsFromFirstGroup;
545 std::vector<TextActor> removedTextActorsFromGroups;
547 // As lineIndexBegin has been increased just to not to remove the line, decrease now is needed to access it.
548 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex - 1 ) );
550 if( textInfoIndicesBegin.mGroupIndex + 1 < lineLayout.mWordGroupsLayoutInfo.size() )
552 // Store text-actors before removing them.
553 CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, textInfoIndicesBegin.mGroupIndex + 1, lineLayout.mWordGroupsLayoutInfo.size() );
555 // Remove extra groups. If a line has left to right and right to left text, groups after current one could be removed.
556 RemoveWordGroupsFromLine( textInfoIndicesBegin.mGroupIndex + 1,
557 lineLayout.mWordGroupsLayoutInfo.size() - ( textInfoIndicesBegin.mGroupIndex + 1 ),
558 PointSize( layoutParameters.mLineHeightOffset ),
562 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
564 if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
566 // Remove extra words within current group of words. (and current word if whole characters are removed)
567 // 0 == characterIndexBegin means the whole word is deleted.
568 const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
570 // Store text-actors before removing them.
571 CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
573 const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
574 RemoveWordsFromWordGroup( wordIndex,
575 groupLayout.mWordsLayoutInfo.size() - wordIndex,
578 // discount the removed number of characters.
579 lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
582 if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
584 // Only some characters of the word need to be removed.
585 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
587 // Store text-actors before removing them.
588 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
590 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
591 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
592 wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
595 // discount the removed number of characters.
596 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
597 groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
598 lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
600 UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
602 // Insert the text-actors in order.
603 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
604 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
605 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
608 if( mergeLastLine && !wholeLinedeleted )
610 // Some characters from the last line need to be removed.
612 // Vectors used to temporary store text-actors removed from the group.
613 // Three vectors are needed because text-actors are not removed in order
614 // but insert them in order is required to reuse them later.
615 std::vector<TextActor> removedTextActorsFromFirstWord;
616 std::vector<TextActor> removedTextActorsFromFirstGroup;
617 std::vector<TextActor> removedTextActorsFromGroups;
619 // lineIndexEnd was increased to delete the last line if lines need to be merged.
620 // To access now the last line we need to decrease the index.
621 const std::size_t lineIndex = ( mergeLines ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex );
623 // Get the last line.
624 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lineIndex ) );
626 if( textInfoIndicesEnd.mGroupIndex > 0 )
628 // Store text-actors before removing them.
629 CollectTextActorsFromGroups( removedTextActorsFromGroups, lineLayout, 0, textInfoIndicesEnd.mGroupIndex );
631 // Remove extra groups from the beginning of the line to the current group of words.
632 RemoveWordGroupsFromLine( 0,
633 textInfoIndicesEnd.mGroupIndex,
634 PointSize( layoutParameters.mLineHeightOffset ),
638 // The group of characters which contains the characters to be removed is now the first one.
639 WordGroupLayoutInfo& groupLayout( *lineLayout.mWordGroupsLayoutInfo.begin() );
641 // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
642 const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
643 bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
645 if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
647 // Store text-actors before removing them.
648 CollectTextActorsFromWords( removedTextActorsFromFirstGroup, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
650 // Remove extra words. (and current word if whole characters are removed)
651 const std::size_t groupNumberCharacters = groupLayout.mNumberOfCharacters;
652 RemoveWordsFromWordGroup( 0,
653 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
656 // discount the removed number of characters.
657 lineLayout.mNumberOfCharacters -= ( groupNumberCharacters - groupLayout.mNumberOfCharacters );
660 if( !removeWholeWord )
662 // Only some characters of the word need to be deleted.
664 // After removing all extra words. The word with the characters to be removed is the first one.
665 WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
667 // Store text-actors before removing them.
668 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
670 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
671 RemoveCharactersFromWord( 0,
672 textInfoIndicesEnd.mCharacterIndex + 1,
675 // discount the removed number of characters.
676 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
677 groupLayout.mNumberOfCharacters -= removedNumberOfCharacters;
678 lineLayout.mNumberOfCharacters -= removedNumberOfCharacters;
679 UpdateGroupLayoutInfo( groupLayout );
681 UpdateLineLayoutInfo( lineLayout, layoutParameters.mLineHeightOffset );
683 // Insert the text-actors in order.
684 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
685 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstGroup.begin(), removedTextActorsFromFirstGroup.end() );
686 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromGroups.begin(), removedTextActorsFromGroups.end() );
688 } // end delete text from different lines
689 else if( ( textInfoIndicesBegin.mLineIndex == textInfoIndicesEnd.mLineIndex ) && ( lineLayout.mNumberOfCharacters == numberOfCharacters ) )
691 // the whole line needs to be deleted.
692 ++textInfoIndicesEnd.mLineIndex; // will delete current line.
696 // deleted text is within the same line. (merge lines could be needed if the line separator character is deleted)
698 // Line which contains the characters to be deleted.
699 LineLayoutInfo& lineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex ) );
701 const WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) ); // used to check the number of characters of the group of words
702 // if all characters to be deleted are in the same group of words.
703 if( textInfoIndicesBegin.mGroupIndex < textInfoIndicesEnd.mGroupIndex )
705 // Deleted text is from different group of words. The two different group of words may be merged if they have text with same direction.
707 // whether first or last group of words need to be split and merged with the last part.
708 bool splitFirstGroup = false;
709 bool splitLastGroup = true;
711 textInfoMergeIndicesBegin.mGroupIndex = textInfoIndicesBegin.mGroupIndex;
712 textInfoMergeIndicesEnd.mGroupIndex = textInfoIndicesEnd.mGroupIndex;
714 if( ( textInfoIndicesBegin.mWordIndex > 0 ) || ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
716 // first character to be deleted is not the first one of the current group.
717 ++textInfoIndicesBegin.mGroupIndex; // won't delete current group
719 // As some characters remain, this group needs to be split and could be merged with the last one.
720 splitFirstGroup = true;
723 // Check if all characters of the last group are going to be deleted.
724 const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex ) );
725 if( textInfoIndicesEnd.mWordIndex + 1 == lastGroupLayout.mWordsLayoutInfo.size() )
727 const WordLayoutInfo& lastWordLayout( *( lastGroupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
728 if( textInfoIndicesEnd.mCharacterIndex + 1 == lastWordLayout.mCharactersLayoutInfo.size() )
730 // All characters of the last group are going to be deleted.
731 ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
733 // The whole last group is deleted. No need to merge groups.
734 splitLastGroup = false;
738 // Only merge two groups if they are not deleted completely and they have same direction.
739 mergeGroups = ( splitFirstGroup && splitLastGroup ) && ( groupLayout.mDirection == lastGroupLayout.mDirection );
743 // last group is going to be merged.
744 ++textInfoIndicesEnd.mGroupIndex; // will delete the last group.
747 if( splitFirstGroup )
749 // Remove characters from the first group.
751 // As wordGroupIndexBegin has been increased just to not to remove the group of words, decrease now is needed to access it.
752 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex - 1 ) );
754 if( ( textInfoIndicesBegin.mWordIndex + 1 < groupLayout.mWordsLayoutInfo.size() ) || ( 0 == textInfoIndicesBegin.mCharacterIndex ) )
756 // Remove extra words within current group of words. (and current word if whole characters are removed)
757 // 0 == characterIndexBegin means the whole word is deleted.
758 const std::size_t wordIndex = ( ( 0 == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1 );
760 // Store text-actors before removing them.
761 CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, wordIndex, groupLayout.mWordsLayoutInfo.size() );
763 RemoveWordsFromWordGroup( wordIndex,
764 groupLayout.mWordsLayoutInfo.size() - wordIndex,
768 if( ( textInfoIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0 ) )
770 // Only some characters of the word need to be removed.
771 WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
773 // Store text-actors before removing them.
774 CollectTextActors( removedTextActorsFromBegin, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
776 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
777 wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
784 // Some characters from the last group of words need to be removed.
786 // textInfoIndicesEnd.mGroupIndex was increased to delete the last group of words if groups need to be merged.
787 // To access now the last group of words we need to decrease the index.
788 std::size_t index = mergeGroups ? textInfoIndicesEnd.mGroupIndex - 1 : textInfoIndicesEnd.mGroupIndex;
790 // Get the last group of words.
791 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + index ) );
793 // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
794 const WordLayoutInfo& wordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
795 bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1;
797 if( ( textInfoIndicesEnd.mWordIndex > 0 ) || ( removeWholeWord ) )
799 // Store text-actors before removing them.
800 CollectTextActorsFromWords( removedTextActorsFromBegin, groupLayout, 0, ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex );
802 // Remove extra words. (and current word if whole characters are removed)
803 RemoveWordsFromWordGroup( 0,
804 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1 : textInfoIndicesEnd.mWordIndex,
808 if( !removeWholeWord )
810 // Only some characters of the word need to be deleted.
812 // After removing all extra words. The word with the characters to be removed is the first one.
813 WordLayoutInfo& wordLayout( *groupLayout.mWordsLayoutInfo.begin() );
815 // Store text-actors before removing them.
816 CollectTextActors( removedTextActorsFromBegin, wordLayout, 0, textInfoIndicesEnd.mCharacterIndex + 1 );
818 RemoveCharactersFromWord( 0,
819 textInfoIndicesEnd.mCharacterIndex + 1,
823 } // end of remove from different groups
824 else if( ( textInfoIndicesBegin.mGroupIndex == textInfoIndicesEnd.mGroupIndex ) && ( groupLayout.mNumberOfCharacters == numberOfCharacters ) )
826 // The whole group is deleted.
827 ++textInfoIndicesEnd.mGroupIndex; // will delete current group.
828 // TODO group before and group after need to be merged!!!
832 // characters to be deleted are on the same group of words. (words may need to be merged)
834 // Group of words which contains the characters to be deleted.
835 WordGroupLayoutInfo& groupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex ) );
837 RemoveCharactersFromWordGroupInfo( relayoutData,
841 textInfoIndicesBegin,
843 textInfoMergeIndicesBegin,
844 textInfoMergeIndicesEnd,
846 removedTextActorsFromBegin,
847 removedTextActorsFromEnd );
851 // Merges words pointed by textInfoMergeIndicesBegin.mWordIndex and textInfoMergeIndicesEnd.mWordIndex calculated previously.
852 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesBegin.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (begin) out of bounds." );
853 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesEnd.mWordIndex < groupLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (end) out of bounds." );
855 WordLayoutInfo& firstWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesBegin.mWordIndex ) );
856 WordLayoutInfo& lastWordLayout( *( groupLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesEnd.mWordIndex ) );
858 MergeWord( firstWordLayout,
862 // Store text-actors before removing them.
863 const std::size_t endIndex = ( mergeWords && ( textInfoIndicesEnd.mWordIndex > 0 ) ) ? textInfoIndicesEnd.mWordIndex - 1 : textInfoIndicesEnd.mWordIndex; // text-actors from the last word may have been added in the merge above.
864 CollectTextActorsFromWords( removedTextActorsFromMid, groupLayout, textInfoIndicesBegin.mWordIndex, endIndex );
866 // Remove unwanted words using previously calculated indices. (including the last part of the merged word)
867 groupLayout.mWordsLayoutInfo.erase( groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex, groupLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex );
869 // Update group of words info
870 groupLayout.mNumberOfCharacters -= numberOfCharacters;
871 groupLayout.mSize = Size();
872 groupLayout.mAscender = 0;
873 for( WordLayoutInfoContainer::const_iterator it = groupLayout.mWordsLayoutInfo.begin(), endIt = groupLayout.mWordsLayoutInfo.end();
877 const WordLayoutInfo& layoutInfo( *it );
878 UpdateSize( groupLayout.mSize, layoutInfo.mSize );
879 groupLayout.mAscender = std::max( groupLayout.mAscender, layoutInfo.mAscender );
881 } // end of remove from same group
885 // Merges group of words pointed by textInfoMergeIndicesBegin.mGroupIndex and textInfoMergeIndicesEnd.mGroupIndex calculated previously.
887 WordGroupLayoutInfo& firstGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesBegin.mGroupIndex ) );
889 const WordGroupLayoutInfo& lastGroupLayout( *( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoMergeIndicesEnd.mGroupIndex ) );
891 MergeWordGroup( firstGroupLayout,
895 // Remove unwanted groups of words using previously calculated indices. (including the last part of the merged group of words)
896 lineLayout.mWordGroupsLayoutInfo.erase( lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesBegin.mGroupIndex, lineLayout.mWordGroupsLayoutInfo.begin() + textInfoIndicesEnd.mGroupIndex );
899 lineLayout.mNumberOfCharacters -= numberOfCharacters;
900 lineLayout.mSize = Size();
901 lineLayout.mAscender = 0;
902 for( WordGroupLayoutInfoContainer::const_iterator it = lineLayout.mWordGroupsLayoutInfo.begin(), endIt = lineLayout.mWordGroupsLayoutInfo.end();
906 const WordGroupLayoutInfo& layoutInfo( *it );
907 UpdateSize( lineLayout.mSize, layoutInfo.mSize );
908 lineLayout.mAscender = std::max( lineLayout.mAscender, layoutInfo.mAscender );
910 lineLayout.mSize.height += layoutParameters.mLineHeightOffset;
911 lineLayout.mLineHeightOffset = layoutParameters.mLineHeightOffset;
912 }// end delete text from same line.
916 // Merges lines pointed by textInfoMergeIndicesBegin.mLineIndex and textInfoMergeIndicesEnd.mLineIndex calculated previously.
918 LineLayoutInfo& firstLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesBegin.mLineIndex ) );
920 const LineLayoutInfo& lastLineLayout( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoMergeIndicesEnd.mLineIndex ) );
922 MergeLine( firstLineLayout,
926 // Store text-actors before removing them.
927 const std::size_t endIndex = ( mergeLines && ( textInfoIndicesEnd.mLineIndex > 0 ) ) ? textInfoIndicesEnd.mLineIndex - 1 : textInfoIndicesEnd.mLineIndex; // text-actors from the last line may have been added in the merge above.
928 CollectTextActorsFromLines( removedTextActorsFromMid,
929 relayoutData.mTextLayoutInfo,
930 textInfoIndicesBegin.mLineIndex,
933 // Remove unwanted lines using previously calculated indices. (including the last part of the merged line)
934 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.erase( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesBegin.mLineIndex,
935 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + textInfoIndicesEnd.mLineIndex );
938 UpdateTextLayoutInfo( relayoutData.mTextLayoutInfo );
940 // If the last character of the last line is a new line character, an empty line need to be added.
941 if( !relayoutData.mTextLayoutInfo.mLinesLayoutInfo.empty() )
943 const WordLayoutInfo lastWordLayout = GetLastWordLayoutInfo( *( relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end() - 1 ) );
945 if( LineSeparator == lastWordLayout.mType )
947 LineLayoutInfo lastLineLayout;
949 const CharacterLayoutInfo layoutInfo = GetLastCharacterLayoutInfo( lastWordLayout );
950 lastLineLayout.mSize.height = layoutInfo.mSize.height;
952 relayoutData.mTextLayoutInfo.mLinesLayoutInfo.push_back( lastLineLayout );
954 relayoutData.mTextLayoutInfo.mWholeTextSize.height += layoutInfo.mSize.height;
958 // Clear the text from the text-actors if required.
959 if( CLEAR_TEXT == clearText )
961 ClearText( removedTextActorsFromEnd );
962 ClearText( removedTextActorsFromMid );
963 ClearText( removedTextActorsFromBegin );
966 // Insert text-actors into the cache.
967 // Text-actors are inserted in reverse order to use first the first removed.
968 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromEnd );
969 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromMid );
970 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
973 void UpdateTextInfo( const std::size_t position,
974 const std::size_t numberOfCharacters,
975 const MarkupProcessor::StyledTextArray& text,
976 const TextView::LayoutParameters& layoutParameters,
977 TextView::RelayoutData& relayoutData )
979 // Replaces 'numberOfCharacters' of text starting from 'position' with the given text.
981 // TODO: Temporary implementation with remove and insert.
984 UpdateTextInfo( position,
988 KEEP_TEXT ); // Do not clear the text from the text-actors.
991 UpdateTextInfo( position,
997 void UpdateTextInfo( const float lineHeightOffset,
998 TextLayoutInfo& textLayoutInfo )
1000 // Updates the space between lines with the new offset value.
1002 float newTextHeight = 0.f;
1004 for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1005 lineIt != lineEndIt;
1008 LineLayoutInfo& lineLayoutInfo( *lineIt );
1010 lineLayoutInfo.mSize.height += ( lineHeightOffset - lineLayoutInfo.mLineHeightOffset );
1011 newTextHeight += lineLayoutInfo.mSize.height;
1013 lineLayoutInfo.mLineHeightOffset = lineHeightOffset;
1016 textLayoutInfo.mWholeTextSize.height = newTextHeight;
1019 void UpdateTextInfo( const TextStyle& style,
1020 const TextStyle::Mask mask,
1021 TextView::RelayoutData& relayoutData )
1023 // Change text style for all text-actors.
1025 for( LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end();
1026 lineIt != lineEndIt;
1029 LineLayoutInfo& line( *lineIt );
1031 for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1032 groupIt != groupEndIt;
1035 WordGroupLayoutInfo& group( *groupIt );
1037 for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1038 wordIt != wordEndIt;
1041 WordLayoutInfo& word( *wordIt );
1043 for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1044 characterIt != characterEndIt;
1047 CharacterLayoutInfo& characterLayout( *characterIt );
1049 characterLayout.mStyledText.mStyle.Copy( style, mask );
1051 // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
1052 ChooseFontFamilyName( characterLayout.mStyledText );
1054 // Mark the character to be set the new style into the text-actor.
1055 characterLayout.mSetStyle = true;
1058 } // end group of words
1062 void InitializeTextActorInfo( TextView::RelayoutData& relayoutData )
1064 TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
1065 if( textLayoutInfo.mLinesLayoutInfo.empty() )
1067 // nothing to do if there is no lines.
1071 std::size_t characterGlobalIndex = 0; // Index to the global character (within the whole text).
1072 std::size_t lineLayoutInfoIndex = 0; // Index to the laid out line info.
1073 const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines.
1074 bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line.
1075 bool glyphActorCreatedForLine = false; // Whether a renderable actor has been created for this line.
1077 RenderableActor currentGlyphActor; // text-actor used when the edit mode is disabled.
1078 TextStyle currentStyle; // style for the current text-actor.
1079 Vector4 currentGradientColor; // gradient color for the current text-actor.
1080 Vector2 currentStartPoint; // start point for the current text-actor.
1081 Vector2 currentEndPoint; // end point for the current text-actor.
1082 bool currentIsColorGlyph = false; // Whether current glyph is an emoticon.
1084 std::vector<TextActor> textActorsToRemove; // Keep a vector of text-actors to be included into the cache.
1086 for( LineLayoutInfoContainer::iterator lineIt = textLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = textLayoutInfo.mLinesLayoutInfo.end();
1087 lineIt != lineEndIt;
1090 LineLayoutInfo& line( *lineIt );
1092 for( WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end();
1093 groupIt != groupEndIt;
1096 WordGroupLayoutInfo& group( *groupIt );
1098 for( WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end();
1099 wordIt != wordEndIt;
1102 WordLayoutInfo& word( *wordIt );
1104 for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
1105 characterIt != characterEndIt;
1108 CharacterLayoutInfo& characterLayout( *characterIt );
1110 // Check if there is a new line.
1111 const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex );
1115 // Point to the next line.
1116 ++lineLayoutInfoIndex;
1117 if( lineLayoutInfoIndex >= lineLayoutInfoSize )
1119 // Arrived at last line.
1120 lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector.
1122 glyphActorCreatedForLine = false;
1125 if( !characterLayout.mStyledText.mText.IsEmpty() )
1127 // Do not create a glyph-actor if there is no text.
1128 const Character character = characterLayout.mStyledText.mText[0]; // there are only one character per character layout.
1130 if( characterLayout.mIsColorGlyph ||
1131 !character.IsWhiteSpace() || // A new line character is also a white space.
1132 ( character.IsWhiteSpace() && characterLayout.mStyledText.mStyle.GetUnderline() ) )
1134 // Do not create a glyph-actor if it's a white space (without underline) or a new line character.
1136 // Creates one glyph-actor per each counsecutive group of characters, with the same style, per line, or if it's an emoticon.
1138 if( !glyphActorCreatedForLine ||
1139 characterLayout.mIsColorGlyph ||
1140 ( characterLayout.mStyledText.mStyle != currentStyle ) ||
1141 ( characterLayout.mGradientColor != currentGradientColor ) ||
1142 ( characterLayout.mStartPoint != currentStartPoint ) ||
1143 ( characterLayout.mEndPoint != currentEndPoint ) ||
1144 ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) )
1146 characterLayout.mSetText = false;
1147 characterLayout.mSetStyle = false;
1149 // There is a new style or a new line.
1150 glyphActorCreatedForLine = true;
1152 if( characterLayout.mIsColorGlyph )
1154 ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor );
1157 characterLayout.mGlyphActor = ImageActor::New();
1158 characterLayout.mSetText = true;
1163 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1167 // Try to reuse first the text-actor of this character.
1168 textActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1169 currentGlyphActor = textActor;
1173 // If there is no text-actor, try to retrieve one from the cache.
1174 textActor = relayoutData.mTextActorCache.RetrieveTextActor();
1176 // If still there is no text-actor, create one.
1179 textActor = TextActor::New( Text(), characterLayout.mStyledText.mStyle, false, true );
1183 textActor.SetTextStyle( characterLayout.mStyledText.mStyle );
1186 currentGlyphActor = textActor;
1188 characterLayout.mGlyphActor = currentGlyphActor;
1191 // Update style to be checked with next characters.
1192 currentStyle = characterLayout.mStyledText.mStyle;
1193 currentGradientColor = characterLayout.mGradientColor;
1194 currentStartPoint = characterLayout.mStartPoint;
1195 currentEndPoint = characterLayout.mEndPoint;
1196 currentIsColorGlyph = characterLayout.mIsColorGlyph;
1198 characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
1199 characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
1203 DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." );
1205 // Same style than previous one.
1206 TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor );
1209 // There is a previously created text-actor for this character.
1210 // If this character has another one put it into the cache.
1211 textActor.SetText( "" );
1212 textActorsToRemove.push_back( textActor );
1215 if( characterLayout.mGlyphActor )
1217 characterLayout.mGlyphActor.Reset();
1220 } // no white space / new line char
1223 ++characterGlobalIndex;
1229 // Insert the spare text-actors into the cache.
1230 relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove );
1233 } // namespace TextViewProcessor
1235 } // namespace Internal
1237 } // namespace Toolkit