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-toolkit/internal/controls/text-view/text-view-processor.h>
22 #include <dali-toolkit/internal/controls/text-view/text-view-word-processor.h>
23 #include <dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h>
24 #include <dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h>
25 #include <dali-toolkit/internal/controls/text-view/text-processor.h>
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 UpdateLayoutInfo( TextLayoutInfo& textLayoutInfo )
50 // Initialize members to be updated.
51 textLayoutInfo.mWholeTextSize = Size::ZERO;
52 textLayoutInfo.mMaxWordWidth = 0.f;
53 textLayoutInfo.mNumberOfCharacters = 0u;
55 // Traverse all text updating values.
56 for( ParagraphLayoutInfoContainer::const_iterator paragraphIt = textLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = textLayoutInfo.mParagraphsLayoutInfo.end();
57 paragraphIt != paragraphEndIt;
60 const ParagraphLayoutInfo& paragraph( *paragraphIt );
62 // Updates text size with the size of all paragraphs.
63 UpdateSize( textLayoutInfo.mWholeTextSize, paragraph.mSize, GrowHeight );
65 // Updates number of characters.
66 textLayoutInfo.mNumberOfCharacters += paragraph.mNumberOfCharacters;
68 // Updates the max word's width.
69 for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
73 const WordLayoutInfo& word( *wordIt );
75 textLayoutInfo.mMaxWordWidth = std::max( textLayoutInfo.mMaxWordWidth, word.mSize.width );
82 // Constructors and assignment operators
84 TextInfoIndices::TextInfoIndices()
85 : mParagraphIndex( 0u ),
91 TextInfoIndices::TextInfoIndices( const std::size_t paragraphIndex,
92 const std::size_t wordIndex,
93 const std::size_t characterIndex )
94 : mParagraphIndex( paragraphIndex ),
95 mWordIndex( wordIndex ),
96 mCharacterIndex( characterIndex )
100 bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const
102 return ( ( mParagraphIndex == indices.mParagraphIndex ) &&
103 ( mWordIndex == indices.mWordIndex ) &&
104 ( mCharacterIndex == indices.mCharacterIndex ) );
107 /////////////////////
109 /////////////////////
111 TextLayoutInfo::TextLayoutInfo()
113 mMaxWordWidth( 0.f ),
114 mMaxItalicsOffset( 0.f ),
115 mNumberOfCharacters( 0u ),
116 mParagraphsLayoutInfo(),
117 mEllipsizeLayoutInfo()
121 TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text )
122 : mWholeTextSize( text.mWholeTextSize ),
123 mMaxWordWidth( text.mMaxWordWidth ),
124 mMaxItalicsOffset( text.mMaxItalicsOffset ),
125 mNumberOfCharacters( text.mNumberOfCharacters ),
126 mParagraphsLayoutInfo( text.mParagraphsLayoutInfo ),
127 mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo )
131 TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text )
135 mWholeTextSize = text.mWholeTextSize;
136 mMaxWordWidth = text.mMaxWordWidth;
137 mMaxItalicsOffset = text.mMaxItalicsOffset;
138 mNumberOfCharacters = text.mNumberOfCharacters;
139 mParagraphsLayoutInfo = text.mParagraphsLayoutInfo;
140 mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo;
146 /////////////////////////////////////////////////////////////////////////////////////////////
148 void CreateTextInfo( const MarkupProcessor::StyledTextArray& text,
149 const TextView::LayoutParameters& layoutParameters,
150 TextView::RelayoutData& relayoutData )
152 // * Traverse the given text spliting it in paragraphs and each paragraph in words.
153 // * White spaces and new paragraph characters are alone in one word.
154 // * Bidirectional text is processed in each paragraph.
155 // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters.
156 // * Generates a text-actor data structure to store text, style and text-actors.
157 // TODO: finish and test the bidirectional implementation.
159 // Collect previously created text-actors.
160 std::vector<TextActor> textActors;
161 CollectTextActorsFromParagraphs( textActors, relayoutData.mTextLayoutInfo, 0u, relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.size() );
163 if( !textActors.empty() )
165 // Add text-actors to the cache.
166 relayoutData.mTextActorCache.InsertTextActors( textActors );
167 relayoutData.mTextActorCache.ClearTexts();
170 // Store the ellipsize layout info before clearing the previous created info.
171 const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo;
173 // clear previous created info.
174 relayoutData.mTextLayoutInfo = TextLayoutInfo();
175 relayoutData.mCharacterLogicalToVisualMap.clear();
176 relayoutData.mCharacterVisualToLogicalMap.clear();
178 // Sets the ellipsize layout info.
179 relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo;
181 // Split the whole text in paragraphs.
182 std::vector<MarkupProcessor::StyledTextArray> paragraphs;
183 TextProcessor::SplitInParagraphs( text,
186 // Traverse all paragraphs
187 for( std::vector<MarkupProcessor::StyledTextArray>::const_iterator paragraphIt = paragraphs.begin(), paragraphEndIt = paragraphs.end(); paragraphIt != paragraphEndIt; ++paragraphIt )
189 const MarkupProcessor::StyledTextArray& paragraph( *paragraphIt );
191 // Data structures for the new paragraph
192 ParagraphLayoutInfo paragraphLayoutInfo;
194 // Fills the paragraph data structures with the layout info.
195 CreateParagraphInfo( paragraph,
197 paragraphLayoutInfo );
199 if( 0u < paragraphLayoutInfo.mNumberOfCharacters )
201 // do not add the line offset if the paragraph has no characters.
202 paragraphLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset;
203 paragraphLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset;
207 // line height needs to be added for the last paragraph.
209 float lineHeight = 0.f;
210 // Get the last character of the last paragraph.
211 if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
213 const ParagraphLayoutInfo& paragraphInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
215 const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( paragraphInfo );
217 lineHeight = characterInfo.mSize.height;
220 paragraphLayoutInfo.mSize.height = lineHeight;
223 // Update layout info for the whole text.
224 UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, paragraphLayoutInfo.mSize, GrowHeight );
225 relayoutData.mTextLayoutInfo.mNumberOfCharacters += paragraphLayoutInfo.mNumberOfCharacters;
227 // Add the paragraph to the current text.
228 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.push_back( paragraphLayoutInfo );
229 } // end of paragraphs
232 void UpdateTextInfo( const std::size_t position,
233 const MarkupProcessor::StyledTextArray& text,
234 const TextView::LayoutParameters& layoutParameters,
235 TextView::RelayoutData& relayoutData )
237 // Update current internal data structure with added text.
239 // * Creates layout info for the given text.
240 // * With the given position, find where to add the text.
241 // * If the new text is not added at the end of current text, a paragraph need to be split.
242 // * Merge the last paragraph of the new text to the last part or the split paragraph.
243 // * Add paragraphs between first and last of the new text.
244 // * Merge the first part of the split paragraph with the first paragraph of the new text.
245 // * Update layout info and create new text actors if needed.
251 // nothing to do if the input text is empty.
255 if( 0u == relayoutData.mTextLayoutInfo.mNumberOfCharacters )
257 // Current text is empty. There is no need to update current data structure,
258 // just create a new one with the new input text.
259 CreateTextInfo( text,
266 if( position > relayoutData.mTextLayoutInfo.mNumberOfCharacters )
268 // Asserts if text is to be added out of bounds.
269 DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." );
272 TextView::RelayoutData relayoutDataForNewText;
274 // Creates layout info for the given text.
275 // It doesn't create text-actors as text could be added to an existing one.
276 CreateTextInfo( text,
278 relayoutDataForNewText );
280 // Update logical-to-visual and visual-to-logical tables.
281 // TODO: check that for mixed RTL/LTR text.
282 std::size_t index = 0u;
283 for( std::size_t i = 0u; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i )
285 relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
286 relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index );
290 // If a paragraph is split, it stores the last part of the paragraph.
291 ParagraphLayoutInfo lastParagraphLayoutInfo;
293 // Stores indices to the paragraph, word and character of the given position.
294 TextInfoIndices textInfoIndices;
296 if( position < relayoutData.mTextLayoutInfo.mNumberOfCharacters )
298 // Get paragraph, word and character indices for given position.
299 GetIndicesFromGlobalCharacterIndex( position,
300 relayoutData.mTextLayoutInfo,
303 // 1) Split the paragraph
305 // Split a paragraph in two is needed, then merge the first part of the split paragraph
306 // with the first paragraph of the new text, add subsequent paragraphs and merge the last paragraph
307 // of the new text with the last part of the split paragraph.
309 // Implementation notes!
311 // These references to the first paragraph are declared in this scope because if new paragraphs are inserted in step 2,
312 // they become invalid, making the algorithm to crash if used again.
313 // In the step 3, references to the first paragraph are needed and declared again.
315 // Stores the first part of the split paragraph.
316 ParagraphLayoutInfo& firstParagraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndices.mParagraphIndex ) );
318 SplitParagraph( textInfoIndices,
319 PointSize( layoutParameters.mLineHeightOffset ),
320 firstParagraphLayoutInfo,
321 lastParagraphLayoutInfo );
325 // Position is just after the last character.
326 // Calculates indices for that position.
327 if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
329 textInfoIndices.mParagraphIndex = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.size() - 1u;
330 const ParagraphLayoutInfo& paragraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
332 if( !paragraphLayoutInfo.mWordsLayoutInfo.empty() )
334 textInfoIndices.mWordIndex = paragraphLayoutInfo.mWordsLayoutInfo.size() - 1u;
336 const WordLayoutInfo& wordLayoutInfo( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) );
337 textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size();
342 // 2) If the new text has more than 1 paragraph, merge the last paragraph of the input text with the last part of the split paragraph.
343 //TODO check this cases ( num paragraphs ==1, >1, >2 ) if it could be simplified.
344 if( relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.size() > 1u )
346 ParagraphLayoutInfo& lastInputParagraphLayoutInfo( *( relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
348 MergeParagraph( lastInputParagraphLayoutInfo,
349 lastParagraphLayoutInfo );
351 if( relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.size() > 2u )
353 // Insert all paragraphs except first and last in the text.
354 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.insert( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndices.mParagraphIndex + 1u,
355 relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + 1u,
356 relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u );
359 // Insert the last paragraph to the text
360 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.insert( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndices.mParagraphIndex + relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.size() - 1u,
361 lastInputParagraphLayoutInfo );
365 // Merge the new paragraph to the last part of the split paragraph.
366 ParagraphLayoutInfo& inputParagraphLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.begin() );
368 MergeParagraph( inputParagraphLayoutInfo,
369 lastParagraphLayoutInfo );
372 // 3) Merge the first paragraph of the split text with the first paragraph of the input text.
373 ParagraphLayoutInfo& firstParagraphLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndices.mParagraphIndex ) );
374 ParagraphLayoutInfo& firstInputParagraphLayoutInfo( *relayoutDataForNewText.mTextLayoutInfo.mParagraphsLayoutInfo.begin() );
376 MergeParagraph( firstParagraphLayoutInfo,
377 firstInputParagraphLayoutInfo );
379 // 4) Update text info.
381 // Updates the whole text size, maximum word size, etc.
382 UpdateLayoutInfo( relayoutData.mTextLayoutInfo );
385 void UpdateTextInfo( const std::size_t position,
386 const std::size_t numberOfCharacters,
387 const TextView::LayoutParameters& layoutParameters,
388 TextView::RelayoutData& relayoutData,
389 const TextOperationOnRemove clearText )
391 // Removes 'numberOfCharacters' starting from 'position'.
393 // * It checks if text to be deleted is in the same paragraph or not:
394 // * If it is not, check which paragraphs need to be split/merged or deleted.
395 // * If it is but all characters of the paragraph are going to be deleted, just delete the paragraph (nothing needs to be split/merged)
396 // * If only some characters of the same paragraph are going to be deleted, proceed similarly: check if text to be deleted is in the same word.
397 // * If it is not, split/merge words.
398 // * Check if the whole word needs to be deleted.
399 // * Check if only some characters of the word need to be deleted.
400 // * Updates layout info.
402 // * The algorithm checks if a word separator is deleted (in that case, different words need to be merged) and if a new paragraph separator is deleted (two paragraphs need to be merged).
406 if( 0u == numberOfCharacters )
408 DALI_ASSERT_DEBUG( !"TextViewProcessor::UpdateTextInfo. WARNING: trying to delete 0 characters!" );
410 // nothing to do if no characters are deleted.
414 // Asserts if trying to delete text out of bounds.
415 DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" );
417 // Remove characters from character to visual map and vs //TODO: check this for RTL text!!
418 relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() );
419 relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() );
421 // Get paragraph, word and character indices for the given start position.
422 TextInfoIndices textInfoIndicesBegin;
423 GetIndicesFromGlobalCharacterIndex( position,
424 relayoutData.mTextLayoutInfo,
425 textInfoIndicesBegin );
427 // Get paragraph, word and character indices for the given end position (start position + number of characters to be deleted).
428 TextInfoIndices textInfoIndicesEnd;
429 GetIndicesFromGlobalCharacterIndex( position + numberOfCharacters - 1u,
430 relayoutData.mTextLayoutInfo,
431 textInfoIndicesEnd );
433 // Vectors used to temporary store text-actors removed from text.
434 // Three vectors are needed because text-actors are not removed in order
435 // but insert them in order is required to reuse them later.
436 std::vector<TextActor> removedTextActorsFromBegin;
437 std::vector<TextActor> removedTextActorsFromMid;
438 std::vector<TextActor> removedTextActorsFromEnd;
440 // Whether paragraphs and words need to be merged.
441 bool mergeParagraphs = false;
442 bool mergeWords = false;
444 // Indices of the paragraphs and words to be merged.
445 TextInfoIndices textInfoMergeIndicesBegin;
446 TextInfoIndices textInfoMergeIndicesEnd;
448 const ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex ) ); // used to check the number of characters of the paragraph
449 // if all characters to be deleted are in the same paragraph.
450 if( textInfoIndicesBegin.mParagraphIndex < textInfoIndicesEnd.mParagraphIndex )
452 // Deleted text is from different paragraphs. It may need to split two paragraphs, and merge first part of the first one with last part of the last one.
454 // whether first or last paragraph need to be split and merged with the last part.
455 bool mergeFirstParagraph = false;
456 bool mergeLastParagraph = true;
458 textInfoMergeIndicesBegin.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex;
459 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesEnd.mParagraphIndex;
461 if( ( textInfoIndicesBegin.mWordIndex > 0u ) || ( textInfoIndicesBegin.mCharacterIndex > 0u ) )
463 // first character to be deleted is not the first one of the current paragraph.
464 ++textInfoIndicesBegin.mParagraphIndex; // won't delete current paragraph
466 // As some characters remain, this paragraph could be merged with the last one.
467 mergeFirstParagraph = true;
470 // Check if all characters of the last paragraph are going to be deleted.
471 bool wholeParagraphDeleted = false;
472 const ParagraphLayoutInfo& lastParagraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesEnd.mParagraphIndex ) );
473 if( textInfoIndicesEnd.mWordIndex + 1u == lastParagraphLayout.mWordsLayoutInfo.size() )
475 const WordLayoutInfo& lastWordLayout( *( lastParagraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
476 if( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() )
478 // All characters of the last paragraph are going to be deleted.
479 ++textInfoIndicesEnd.mParagraphIndex; // will delete the last paragraph.
481 // the whole last paragraph is deleted. Need to check if the next paragraph could be merged.
482 mergeLastParagraph = false;
483 wholeParagraphDeleted = true;
487 if( wholeParagraphDeleted )
489 // It means the whole last paragraph is deleted completely.
490 // It's needed to check if there is another paragraph after that could be merged.
491 if( textInfoIndicesEnd.mParagraphIndex < relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.size() )
493 mergeLastParagraph = true;
495 // Point the first characters of the next paragraph.
496 textInfoIndicesEnd.mWordIndex = 0u;
497 textInfoIndicesEnd.mCharacterIndex = 0u;
498 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesEnd.mParagraphIndex;
502 // If some characters remain in the first and last paragraph, they need to be merged.
503 mergeParagraphs = mergeFirstParagraph && mergeLastParagraph;
505 if( mergeParagraphs )
507 // last paragraph is going to be merged with the first one, so is not needed.
508 ++textInfoIndicesEnd.mParagraphIndex; // will delete the last paragraph.
511 if( mergeFirstParagraph )
513 // Remove characters from the first paragraph.
515 // Vectors used to temporary store text-actors removed from the paragraph.
516 // Three vectors are needed because text-actors are not removed in order
517 // but insert them in order is required to reuse them later.
518 std::vector<TextActor> removedTextActorsFromFirstWord;
519 std::vector<TextActor> removedTextActorsFromFirstParagraph;
521 // As paragraphIndexBegin has been increased just to not to remove the paragraph, decrease now is needed to access it.
522 ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex - 1u ) );
524 if( ( textInfoIndicesBegin.mWordIndex + 1u < paragraphLayout.mWordsLayoutInfo.size() ) || ( 0u == textInfoIndicesBegin.mCharacterIndex ) )
526 // Remove extra words within current paragraph. (and current word if whole characters are removed)
527 // 0 == characterIndexBegin means the whole word is deleted.
528 const std::size_t wordIndex = ( ( 0u == textInfoIndicesBegin.mCharacterIndex ) ? textInfoIndicesBegin.mWordIndex : textInfoIndicesBegin.mWordIndex + 1u );
530 // Store text-actors before removing them.
531 CollectTextActorsFromWords( removedTextActorsFromFirstParagraph, paragraphLayout, wordIndex, paragraphLayout.mWordsLayoutInfo.size() );
533 RemoveWordsFromParagraph( wordIndex,
534 paragraphLayout.mWordsLayoutInfo.size() - wordIndex,
535 layoutParameters.mLineHeightOffset,
539 if( ( textInfoIndicesBegin.mWordIndex < paragraphLayout.mWordsLayoutInfo.size() ) && ( textInfoIndicesBegin.mCharacterIndex > 0u ) )
541 // Only some characters of the word need to be removed.
542 WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
544 // Store text-actors before removing them.
545 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, textInfoIndicesBegin.mCharacterIndex, wordLayout.mCharactersLayoutInfo.size() );
547 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
548 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
549 wordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
552 // discount the removed number of characters.
553 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
554 paragraphLayout.mNumberOfCharacters -= removedNumberOfCharacters;
556 UpdateLayoutInfo( paragraphLayout, layoutParameters.mLineHeightOffset );
558 // Insert the text-actors in order.
559 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
560 removedTextActorsFromBegin.insert( removedTextActorsFromBegin.end(), removedTextActorsFromFirstParagraph.begin(), removedTextActorsFromFirstParagraph.end() );
563 if( mergeLastParagraph && !wholeParagraphDeleted )
565 // Some characters from the last paragraph need to be removed.
567 // Vectors used to temporary store text-actors removed from the paragraph.
568 // Three vectors are needed because text-actors are not removed in order
569 // but insert them in order is required to reuse them later.
570 std::vector<TextActor> removedTextActorsFromFirstWord;
571 std::vector<TextActor> removedTextActorsFromFirstParagraph;
573 // paragraphIndexEnd was increased to delete the last paragraph if paragraphs need to be merged.
574 // To access now the last paragraph we need to decrease the index.
575 const std::size_t paragraphIndex = ( mergeParagraphs ? textInfoIndicesEnd.mParagraphIndex - 1u : textInfoIndicesEnd.mParagraphIndex );
577 // Get the last paragraph.
578 ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndex ) );
580 // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word)
581 const WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
582 bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1u;
584 if( ( textInfoIndicesEnd.mWordIndex > 0u ) || ( removeWholeWord ) )
586 // Store text-actors before removing them.
587 CollectTextActorsFromWords( removedTextActorsFromFirstParagraph,
590 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1u : textInfoIndicesEnd.mWordIndex );
592 // Remove extra words. (and current word if whole characters are removed)
593 RemoveWordsFromParagraph( 0u,
594 ( removeWholeWord ) ? textInfoIndicesEnd.mWordIndex + 1u : textInfoIndicesEnd.mWordIndex,
595 layoutParameters.mLineHeightOffset,
599 if( !removeWholeWord )
601 // Only some characters of the word need to be deleted.
603 // After removing all extra words. The word with the characters to be removed is the first one.
604 WordLayoutInfo& wordLayout( *paragraphLayout.mWordsLayoutInfo.begin() );
606 // Store text-actors before removing them.
607 CollectTextActors( removedTextActorsFromFirstWord, wordLayout, 0u, textInfoIndicesEnd.mCharacterIndex + 1u );
609 const std::size_t wordNumberCharacters = wordLayout.mCharactersLayoutInfo.size();
610 RemoveCharactersFromWord( 0u,
611 textInfoIndicesEnd.mCharacterIndex + 1u,
614 // discount the removed number of characters.
615 const std::size_t removedNumberOfCharacters = ( wordNumberCharacters - wordLayout.mCharactersLayoutInfo.size() );
616 paragraphLayout.mNumberOfCharacters -= removedNumberOfCharacters;
618 UpdateLayoutInfo( paragraphLayout, layoutParameters.mLineHeightOffset );
620 // Insert the text-actors in order.
621 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstWord.begin(), removedTextActorsFromFirstWord.end() );
622 removedTextActorsFromEnd.insert( removedTextActorsFromEnd.end(), removedTextActorsFromFirstParagraph.begin(), removedTextActorsFromFirstParagraph.end() );
624 } // end delete text from different paragraphs
625 else if( ( textInfoIndicesBegin.mParagraphIndex == textInfoIndicesEnd.mParagraphIndex ) && ( paragraphLayout.mNumberOfCharacters == numberOfCharacters ) )
627 // the whole paragraph needs to be deleted.
628 ++textInfoIndicesEnd.mParagraphIndex; // will delete current paragraph.
632 // deleted text is within the same paragraph. (merge paragraphs could be needed if the paragraph separator character is deleted)
634 // Paragraph which contains the characters to be deleted.
635 ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex ) );
637 // Remove the characters from the paragraph layout info. It returns whether the current paragraph can be merged with the next one.
638 RemoveCharactersFromParagraphInfo( relayoutData,
642 textInfoIndicesBegin,
644 textInfoMergeIndicesBegin,
645 textInfoMergeIndicesEnd,
647 removedTextActorsFromBegin,
648 removedTextActorsFromEnd );
652 // Merges words pointed by textInfoMergeIndicesBegin.mWordIndex and textInfoMergeIndicesEnd.mWordIndex calculated previously.
653 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesBegin.mWordIndex < paragraphLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (begin) out of bounds." );
654 DALI_ASSERT_DEBUG( ( textInfoMergeIndicesEnd.mWordIndex < paragraphLayout.mWordsLayoutInfo.size() ) && "TextViewProcessor::UpdateTextInfo (delete). Word index (end) out of bounds." );
656 WordLayoutInfo& firstWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesBegin.mWordIndex ) );
657 WordLayoutInfo& lastWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoMergeIndicesEnd.mWordIndex ) );
659 MergeWord( firstWordLayout,
663 // Store text-actors before removing them.
664 const std::size_t endIndex = ( mergeWords && ( textInfoIndicesEnd.mWordIndex > 0u ) ) ? textInfoIndicesEnd.mWordIndex - 1u : textInfoIndicesEnd.mWordIndex; // text-actors from the last word may have been added in the merge above.
665 CollectTextActorsFromWords( removedTextActorsFromMid, paragraphLayout, textInfoIndicesBegin.mWordIndex, endIndex );
667 // Remove unwanted words using previously calculated indices. (including the last part of the merged word)
668 paragraphLayout.mWordsLayoutInfo.erase( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex, paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex );
670 // Update paragraph info.
671 UpdateLayoutInfo( paragraphLayout, layoutParameters.mLineHeightOffset );
672 }// end delete text from same paragraph.
674 if( mergeParagraphs )
676 // Merges paragraphs pointed by textInfoMergeIndicesBegin.mParagraphIndex and textInfoMergeIndicesEnd.mParagraphIndex calculated previously.
678 ParagraphLayoutInfo& firstParagraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoMergeIndicesBegin.mParagraphIndex ) );
680 const ParagraphLayoutInfo& lastParagraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoMergeIndicesEnd.mParagraphIndex ) );
682 MergeParagraph( firstParagraphLayout,
683 lastParagraphLayout );
686 // Store text-actors before removing them.
687 const std::size_t endIndex = ( mergeParagraphs && ( textInfoIndicesEnd.mParagraphIndex > 0u ) ) ? textInfoIndicesEnd.mParagraphIndex - 1u : textInfoIndicesEnd.mParagraphIndex; // text-actors from the last paragraph may have been added in the merge above.
688 CollectTextActorsFromParagraphs( removedTextActorsFromMid,
689 relayoutData.mTextLayoutInfo,
690 textInfoIndicesBegin.mParagraphIndex,
693 // Remove unwanted paragraphs using previously calculated indices. (including the last part of the merged paragraph)
694 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.erase( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex,
695 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesEnd.mParagraphIndex );
698 UpdateLayoutInfo( relayoutData.mTextLayoutInfo );
700 // If the last character of the last paragraph is a new paragraph character, an empty paragraph need to be added.
701 if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() )
703 const WordLayoutInfo lastWordLayout = GetLastWordLayoutInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) );
705 if( ParagraphSeparator == lastWordLayout.mType )
707 ParagraphLayoutInfo lastParagraphLayout;
709 const CharacterLayoutInfo layoutInfo = GetLastCharacterLayoutInfo( lastWordLayout );
710 lastParagraphLayout.mSize.height = layoutInfo.mSize.height;
712 relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.push_back( lastParagraphLayout );
714 relayoutData.mTextLayoutInfo.mWholeTextSize.height += layoutInfo.mSize.height;
718 // Clear the text from the text-actors if required.
719 if( CLEAR_TEXT == clearText )
721 ClearText( removedTextActorsFromEnd );
722 ClearText( removedTextActorsFromMid );
723 ClearText( removedTextActorsFromBegin );
726 // Insert text-actors into the cache.
727 // Text-actors are inserted in reverse order to use first the first removed.
728 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromEnd );
729 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromMid );
730 relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin );
733 void UpdateTextInfo( const std::size_t position,
734 const std::size_t numberOfCharacters,
735 const MarkupProcessor::StyledTextArray& text,
736 const TextView::LayoutParameters& layoutParameters,
737 TextView::RelayoutData& relayoutData )
739 // Replaces 'numberOfCharacters' of text starting from 'position' with the given text.
741 // TODO: Temporary implementation with remove and insert.
744 UpdateTextInfo( position,
748 KEEP_TEXT ); // Do not clear the text from the text-actors.
751 UpdateTextInfo( position,
757 void UpdateTextInfo( float lineHeightOffset,
758 TextLayoutInfo& textLayoutInfo )
760 // Updates the space between lines with the new offset value.
762 float newTextHeight = 0.f;
764 for( ParagraphLayoutInfoContainer::iterator paragraphIt = textLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = textLayoutInfo.mParagraphsLayoutInfo.end();
765 paragraphIt != paragraphEndIt;
768 ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphIt );
770 paragraphLayoutInfo.mSize.height += ( lineHeightOffset - paragraphLayoutInfo.mLineHeightOffset );
771 newTextHeight += paragraphLayoutInfo.mSize.height;
773 paragraphLayoutInfo.mLineHeightOffset = lineHeightOffset;
776 textLayoutInfo.mWholeTextSize.height = newTextHeight;
779 void UpdateTextInfo( const TextStyle& style,
780 const TextStyle::Mask mask,
781 TextView::RelayoutData& relayoutData )
783 // Change text style for all text-actors.
785 for( ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end();
786 paragraphIt != paragraphEndIt;
789 ParagraphLayoutInfo& paragraph( *paragraphIt );
791 for( WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end();
795 WordLayoutInfo& word( *wordIt );
797 for( CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end();
798 characterIt != characterEndIt;
801 CharacterLayoutInfo& characterLayout( *characterIt );
803 characterLayout.mStyledText.mStyle.Copy( style, mask );
805 // Checks if the font family supports all glyphs. If not, chooses a most suitable one.
806 ChooseFontFamilyName( characterLayout.mStyledText );
808 // Mark the character to be set the new style into the text-actor.
809 characterLayout.mSetStyle = true;
815 } // namespace TextViewProcessor
817 } // namespace Internal
819 } // namespace Toolkit