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-paragraph-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-processor-helper-functions.h>
24 #include <dali-toolkit/internal/controls/text-view/text-processor.h>
25 #include <dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h>
36 namespace TextViewProcessor
43 void RightToLeftParagraphLayout::Clear()
45 mWordsLayoutInfo.clear();
50 ParagraphLayoutInfo::ParagraphLayoutInfo()
53 mLineHeightOffset( 0.f ),
54 mFirstCharacter( 0u ),
55 mNumberOfCharacters( 0u ),
59 mRightToLeftLayout( NULL ),
60 mBidirectionalParagraphInfo( NULL ),
61 mBidirectionalLinesInfo()
65 ParagraphLayoutInfo::~ParagraphLayoutInfo()
67 if( NULL != mRightToLeftLayout )
69 // TextStyle pointers are the same than the ones stored at ParagraphLayoutInfo::mTextStyles.
70 // Do not delete them, just clear the vector.
71 mRightToLeftLayout->mTextStyles.Clear();
73 delete mRightToLeftLayout;
76 // Clears text styles. It destroys TextStyle objects.
79 // Deletes the bidirectional info for the whole paragraph.
80 delete mBidirectionalParagraphInfo;
82 // Clears the bidirectional info for all lines. Destroys the BidirectionalLineInfo objects.
83 ClearBidirectionalInfo();
86 ParagraphLayoutInfo::ParagraphLayoutInfo( const ParagraphLayoutInfo& paragraph )
87 : mSize( paragraph.mSize ),
88 mAscender( paragraph.mAscender ),
89 mLineHeightOffset( paragraph.mLineHeightOffset ),
90 mFirstCharacter( paragraph.mFirstCharacter ),
91 mNumberOfCharacters( paragraph.mNumberOfCharacters ),
92 mWordsLayoutInfo( paragraph.mWordsLayoutInfo ),
93 mText( paragraph.mText ),
95 mRightToLeftLayout( NULL ),
96 // Copies bidirectional info for the whole paragraph.
97 mBidirectionalParagraphInfo( ( NULL == paragraph.mBidirectionalParagraphInfo ) ? NULL : new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo ) ),
98 mBidirectionalLinesInfo()
101 for( Vector<TextStyle*>::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it )
103 mTextStyles.PushBack( new TextStyle( *(*it) ) );
106 // Copies bidirectional info for each line.
107 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
109 mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) );
113 ParagraphLayoutInfo& ParagraphLayoutInfo::operator=( const ParagraphLayoutInfo& paragraph )
115 mSize = paragraph.mSize;
116 mAscender = paragraph.mAscender;
117 mLineHeightOffset = paragraph.mLineHeightOffset;
118 mFirstCharacter = paragraph.mFirstCharacter;
119 mNumberOfCharacters = paragraph.mNumberOfCharacters;
120 mWordsLayoutInfo = paragraph.mWordsLayoutInfo;
121 mText = paragraph.mText;
123 // If it has styles, destroy them.
127 for( Vector<TextStyle*>::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it )
129 mTextStyles.PushBack( new TextStyle( *(*it) ) );
132 // Copies the paragraph's bidirectiona info.
133 if( NULL == paragraph.mBidirectionalParagraphInfo )
135 // The source doesn't have bidirectiona info. Deletes the current one.
136 delete mBidirectionalParagraphInfo;
137 mBidirectionalParagraphInfo = NULL;
141 // The source has bidirectional info.
142 if( NULL != mBidirectionalParagraphInfo )
144 // It it has, copy to it.
145 *mBidirectionalParagraphInfo = *paragraph.mBidirectionalParagraphInfo;
149 // If it doesn't have, create a new one.
150 mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo );
154 // If it has bidirectiona info per line, destroy them.
155 ClearBidirectionalInfo();
157 // Copies bidirectional info per line.
158 for( Vector<TextProcessor::BidirectionalLineInfo*>::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
160 mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) );
166 void ParagraphLayoutInfo::ClearBidirectionalInfo()
168 // Destroys the bidirectional infor per line.
169 for( Vector<TextProcessor::BidirectionalLineInfo*>::Iterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it )
173 mBidirectionalLinesInfo.Clear();
176 void ParagraphLayoutInfo::ClearStyles()
178 // Destroys the styles.
179 for( Vector<TextStyle*>::Iterator it = mTextStyles.Begin(), endIt = mTextStyles.End(); it != endIt; ++it )
186 void CreateParagraphInfo( TextView::RelayoutData& relayoutData,
187 ParagraphLayoutInfo& paragraphLayoutInfo )
189 if( TextProcessor::ContainsRightToLeftCharacter( paragraphLayoutInfo.mText ) )
191 // If the text is bidirectional, the characters will be converted and reordered
192 // as specified by the Unicode Bidirectional Algorithm.
194 paragraphLayoutInfo.mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo();
196 TextProcessor::ProcessBidirectionalText( paragraphLayoutInfo.mText, paragraphLayoutInfo.mBidirectionalParagraphInfo );
199 // Split the paragraph in words. It retrieves the positions of white spaces and the last '\n' if there is one.
200 Vector<std::size_t> positions;
201 TextProcessor::SplitInWords( paragraphLayoutInfo.mText, positions );
203 const std::size_t lastCharacterIndex = paragraphLayoutInfo.mText.GetLength() - 1u;
204 const bool isLastCharacterParagraphSeparator = paragraphLayoutInfo.mText.IsNewLine( lastCharacterIndex );
206 // The number of words is ~the number of white spaces found + 1u.
207 // White spaces are also words.
208 // New line characters are also white spaces. If the last character is a white space the +1 is not needed.
209 const std::size_t numberOfWords = 2u * positions.Count() + ( isLastCharacterParagraphSeparator ? 0u : 1u );
211 // Reserve space for all the words.
212 paragraphLayoutInfo.mWordsLayoutInfo.resize( numberOfWords, WordLayoutInfo() );
214 // Traverses all positions creating and setting all character layout info objects to every word.
215 std::size_t wordIndex = 0u;
216 Vector<std::size_t>::ConstIterator positionIt = positions.Begin();
217 Vector<std::size_t>::ConstIterator positionEndIt = positions.End();
218 std::size_t from = 0u;
219 for( std::size_t positionIndex = 0u, size = positions.Count() + 1u; positionIndex < size; ++positionIndex )
221 const bool isEndPosition = positionIt == positionEndIt;
222 const std::size_t to = isEndPosition ? lastCharacterIndex + 1u : *positionIt;
226 // The word is not a white space.
227 WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex );
229 // Sets the index within the paragraph to the first character of the word.
230 wordLayoutInfo.mFirstCharacter = from;
231 // Creates character layout info objects.
232 wordLayoutInfo.mCharactersLayoutInfo.resize( ( to - from ), CharacterLayoutInfo() );
237 // Create a word for the white space.
238 WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex );
240 // Sets the index within the paragraph to the white space.
241 wordLayoutInfo.mFirstCharacter = to;
242 wordLayoutInfo.mType = WordSeparator;
244 CharacterLayoutInfo characterLayoutInfo;
245 wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo );
252 // next white space position.
257 // All white space positiona have been traversed.
258 // It may be some extra words. i.e if the text is \n.
260 paragraphLayoutInfo.mWordsLayoutInfo.erase( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex, paragraphLayoutInfo.mWordsLayoutInfo.end() );
262 // Check if the last character is a new paragraph character.
263 if( isLastCharacterParagraphSeparator )
265 ( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) ).mType = ParagraphSeparator;
270 // Traverse all words and fill the layout info.
271 for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it )
273 WordLayoutInfo& wordLayoutInfo( *it );
275 CreateWordTextInfo( paragraphLayoutInfo.mText,
276 paragraphLayoutInfo.mTextStyles,
279 // Update layout info for the current paragraph.
280 UpdateSize( paragraphLayoutInfo.mSize, wordLayoutInfo.mSize );
281 paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, wordLayoutInfo.mAscender );
282 paragraphLayoutInfo.mNumberOfCharacters += wordLayoutInfo.mCharactersLayoutInfo.size();
284 // Update the max word width figure.
285 relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width );
289 void UpdateLayoutInfo( ParagraphLayoutInfo& paragraphLayoutInfo, float lineHeightOffset )
291 // Update layout info.
293 // Initialize members to be updated.
294 paragraphLayoutInfo.mSize = Size::ZERO;
295 paragraphLayoutInfo.mAscender = 0.f;
296 paragraphLayoutInfo.mNumberOfCharacters = 0u;
298 // Traverses all words.
299 for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end();
303 WordLayoutInfo& word( *it );
305 // Sets the index within the paragraph to the first character of the word.
306 word.mFirstCharacter = paragraphLayoutInfo.mNumberOfCharacters;
308 // Updates the paragraph's size.
309 UpdateSize( paragraphLayoutInfo.mSize, word.mSize );
311 // Updates the paragraph's max asender.
312 paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, word.mAscender );
314 // Updates the paragraph's number of characters.
315 paragraphLayoutInfo.mNumberOfCharacters += word.mCharactersLayoutInfo.size();
318 // Sets the line height offset.
319 paragraphLayoutInfo.mSize.height += lineHeightOffset;
320 paragraphLayoutInfo.mLineHeightOffset = lineHeightOffset;
323 void RemoveWordsFromParagraph( std::size_t wordIndex,
324 std::size_t numberOfWords,
325 float lineHeightOffset,
326 ParagraphLayoutInfo& paragraphLayout )
328 // Removes words from a paragraph.
330 // * Check if words or paragraphs can be merged after removing a number of words or a paragraph separator needs to be done outside this method.
332 // Remove words from layout info.
333 paragraphLayout.mWordsLayoutInfo.erase( paragraphLayout.mWordsLayoutInfo.begin() + wordIndex,
334 paragraphLayout.mWordsLayoutInfo.begin() + ( wordIndex + numberOfWords ) );
336 UpdateLayoutInfo( paragraphLayout, lineHeightOffset );
339 void RemoveCharactersFromParagraphInfo( TextView::RelayoutData& relayoutData,
340 const std::size_t numberOfCharacters,
342 bool& mergeParagraphs,
343 TextInfoIndices& textInfoIndicesBegin,
344 TextInfoIndices& textInfoIndicesEnd,
345 TextInfoIndices& textInfoMergeIndicesBegin,
346 TextInfoIndices& textInfoMergeIndicesEnd,
347 ParagraphLayoutInfo& paragraphLayout,
348 std::vector<TextActor>& removedTextActorsFromFirstWord,
349 std::vector<TextActor>& removedTextActorsFromLastWord )
351 const TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo;
353 if( textInfoIndicesBegin.mWordIndex < textInfoIndicesEnd.mWordIndex )
355 // Deleted text is from different words. The two different words may be merged.
358 WordLayoutInfo& firstWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) );
361 WordLayoutInfo& lastWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) );
363 // whether first or last word need to be split and merged.
364 bool mergeFromBegin = false;
365 bool mergeToEnd = false;
367 if( textInfoIndicesBegin.mCharacterIndex > 0u )
369 // First word is going to be split. It could be merged with the last word.
370 mergeFromBegin = true;
371 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex;
373 else if( ( textInfoIndicesBegin.mCharacterIndex == 0u ) && ( textInfoIndicesBegin.mWordIndex > 0u ) )
375 // First word is going to be removed completely.
376 // Check if previous word could be merged.
379 WordLayoutInfo& previousWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1u ) );
380 if( WordSeparator != previousWordLayout.mType )
382 // Previous word is not a word separator, so could be merged.
383 mergeFromBegin = true;
384 textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1u;
390 // First word (or previous one) could be merged. Check if last one could be merged as well.
392 if( textInfoIndicesEnd.mCharacterIndex + 1u < lastWordLayout.mCharactersLayoutInfo.size() )
394 // Last word is going to be split. It could be merged with the first word.
396 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex;
398 else if( ( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1u < paragraphLayout.mWordsLayoutInfo.size() ) )
400 // Last word is going to be removed completely.
401 // Check if the word after could be merged.
404 WordLayoutInfo& afterWordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex + 1u ) );
405 if( WordSeparator != afterWordLayout.mType )
407 // The word after is not a word separator, so could be merged.
409 textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex + 1u;
413 // Merge words only if both words could be merged.
414 mergeWords = mergeFromBegin && mergeToEnd;
417 if( ( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1u == paragraphLayout.mWordsLayoutInfo.size() ) )
419 // Last word of the paragraph is going to be removed completely.
420 // Check if it's a paragraph separator.
422 if( ParagraphSeparator == lastWordLayout.mType )
424 // The paragraph separator is going to be removed.
425 if( textInfoIndicesBegin.mParagraphIndex + 1u < textLayoutInfo.mParagraphsLayoutInfo.size() )
427 // Paragraph need to be merged.
428 textInfoMergeIndicesBegin.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex;
429 textInfoMergeIndicesEnd.mParagraphIndex = textInfoIndicesBegin.mParagraphIndex + 1u;
430 mergeParagraphs= true;
432 ++textInfoIndicesBegin.mParagraphIndex; // increase both indices,
433 textInfoIndicesEnd.mParagraphIndex +=2u; // will delete last paragraph.
438 if( textInfoIndicesBegin.mCharacterIndex > 0u )
440 // First word needs to be split.
442 // Store text-actors before removing them.
443 CollectTextActors( removedTextActorsFromFirstWord, firstWordLayout, textInfoIndicesBegin.mCharacterIndex, firstWordLayout.mCharactersLayoutInfo.size() );
445 RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex,
446 firstWordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex,
449 ++textInfoIndicesBegin.mWordIndex; // will delete from the word after.
452 if( textInfoIndicesEnd.mCharacterIndex + 1u < lastWordLayout.mCharactersLayoutInfo.size() )
454 // Last word needs to be split.
456 // Store text-actors before removing them.
457 CollectTextActors( removedTextActorsFromLastWord, lastWordLayout, 0u, textInfoIndicesEnd.mCharacterIndex + 1u );
459 RemoveCharactersFromWord( 0u,
460 textInfoIndicesEnd.mCharacterIndex + 1u,
465 // This word is going to be merged, so is not needed.
466 ++textInfoIndicesEnd.mWordIndex; // will delete the last word.
469 else if( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() )
471 // The whole last word is going to be removed.
472 ++textInfoIndicesEnd.mWordIndex; // will delete the last word.
474 if( ( WordSeparator == lastWordLayout.mType ) && mergeWords )
476 // The last word is a word separator and the word after is going to be merged so is not needed.
477 ++textInfoIndicesEnd.mWordIndex; // will delete the word after the last one.
483 // Chraracters to be removed are from the same word.
485 RemoveCharactersFromWordInfo( relayoutData,
489 textInfoIndicesBegin,
491 textInfoMergeIndicesBegin,
492 textInfoMergeIndicesEnd,
494 removedTextActorsFromFirstWord );
498 void SplitParagraph( const TextInfoIndices& indices,
499 float lineHeightOffset,
500 ParagraphLayoutInfo& firstParagraphLayoutInfo,
501 ParagraphLayoutInfo& lastParagraphLayoutInfo )
503 // Splits a paragraph in two.
504 // A word may be split in two as well.
506 // * Split the word within the paragraph.
507 // * Add last part of the word to the new paragraph.
508 // * Add words from wordPosition + 1 to the end.
509 // * Update layout info of the last paragraph.
510 // * Remove words added to the last part of the paragraph from the first paragraph.
513 if( ( 0u == indices.mWordIndex ) && ( 0u == indices.mCharacterIndex ) )
515 // the whole paragraph goes to the last part.
516 lastParagraphLayoutInfo = firstParagraphLayoutInfo;
518 firstParagraphLayoutInfo = ParagraphLayoutInfo();
523 if( !firstParagraphLayoutInfo.mWordsLayoutInfo.empty() )
525 const std::size_t numberOfWords = firstParagraphLayoutInfo.mWordsLayoutInfo.size();
526 if( indices.mWordIndex == numberOfWords - 1u )
528 const WordLayoutInfo& word( *( firstParagraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) );
529 if( indices.mCharacterIndex == word.mCharactersLayoutInfo.size() )
531 // the whole paragraph goes to the first part.
533 // Just delete whatever there is in the last part of the paragraph.
534 lastParagraphLayoutInfo = ParagraphLayoutInfo();
541 lastParagraphLayoutInfo = ParagraphLayoutInfo();
543 // 1) Split the word whitin the paragraph.
544 WordLayoutInfo& firstWordLayoutInfo( *( firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex ) );
545 WordLayoutInfo lastWordLayoutInfo;
547 SplitWord( indices.mCharacterIndex,
549 lastWordLayoutInfo );
551 // 2) Add last part of the word to the new paragraph.
552 if( !lastWordLayoutInfo.mCharactersLayoutInfo.empty() )
554 lastParagraphLayoutInfo.mWordsLayoutInfo.push_back( lastWordLayoutInfo );
557 // 3) Add words from word-position + 1 to the end.
558 lastParagraphLayoutInfo.mWordsLayoutInfo.insert( lastParagraphLayoutInfo.mWordsLayoutInfo.end(),
559 firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex + 1u,
560 firstParagraphLayoutInfo.mWordsLayoutInfo.end() );
562 // 4) update layout info of the last paragraph.
563 for( WordLayoutInfoContainer::iterator it = lastParagraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = lastParagraphLayoutInfo.mWordsLayoutInfo.end();
567 WordLayoutInfo& layoutInfo( *it );
569 UpdateSize( lastParagraphLayoutInfo.mSize, layoutInfo.mSize );
570 lastParagraphLayoutInfo.mNumberOfCharacters += layoutInfo.mCharactersLayoutInfo.size();
571 lastParagraphLayoutInfo.mAscender = std::max( lastParagraphLayoutInfo.mAscender, layoutInfo.mAscender );
573 lastParagraphLayoutInfo.mSize.height += lineHeightOffset;
574 lastParagraphLayoutInfo.mLineHeightOffset = lineHeightOffset;
576 // 5) Remove words added to the last part of the paragraph from the first paragraph.
578 // if the number of characters of the last word of the first paragraph is zero, it should be removed.
579 const std::size_t index = ( firstWordLayoutInfo.mCharactersLayoutInfo.empty() ? indices.mWordIndex : indices.mWordIndex + 1u );
581 firstParagraphLayoutInfo.mWordsLayoutInfo.erase( firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + index, firstParagraphLayoutInfo.mWordsLayoutInfo.end() );
583 // 6) update layout info of the first paragraph.
584 UpdateLayoutInfo( firstParagraphLayoutInfo, lineHeightOffset );
586 // 7) Split text and styles.
588 // Copies the whole text to the last part of the paragraph.
589 lastParagraphLayoutInfo.mText = firstParagraphLayoutInfo.mText;
591 // Removes from the first part of the paragraph the text that goes to the last part.
592 firstParagraphLayoutInfo.mText.Remove( indices.mCharacterParagraphIndex, firstParagraphLayoutInfo.mText.GetLength() - indices.mCharacterParagraphIndex );
594 // Removes from the last part of the paragraph the text that remains in the first part.
595 lastParagraphLayoutInfo.mText.Remove( 0u, indices.mCharacterParagraphIndex );
597 // Sets the character's styles for the last part of the paragraph.
598 lastParagraphLayoutInfo.mTextStyles.Insert( lastParagraphLayoutInfo.mTextStyles.End(),
599 firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex,
600 firstParagraphLayoutInfo.mTextStyles.End() );
602 // Removes the character's styles that go to the last part of the paragraph.
603 firstParagraphLayoutInfo.mTextStyles.Erase( firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex,
604 firstParagraphLayoutInfo.mTextStyles.End() );
607 void MergeParagraph( ParagraphLayoutInfo& firstParagraphLayoutInfo,
608 const ParagraphLayoutInfo& lastParagraphLayoutInfo )
610 // Merges two given paragraphs.
612 // Can't merge two paragraphs if the last word of the first one is a paragraph separator (new paragraph character)
616 if( lastParagraphLayoutInfo.mWordsLayoutInfo.empty() )
618 // Nothing to merge if last paragraph is empty.
622 if( firstParagraphLayoutInfo.mWordsLayoutInfo.empty() )
624 // If first paragraph is empty, just copy the last paragraph to the first one.
625 firstParagraphLayoutInfo = lastParagraphLayoutInfo;
630 // Check the last word of the first paragraph doesn't finish with a new paragraph character.
631 WordLayoutInfo& lastWordLayout( *( firstParagraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) );
632 if( ParagraphSeparator == lastWordLayout.mType )
634 DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeParagraph(). ERROR: A paragraph can't be merged to another paragraph which finishes with a new paragraph character." );
637 // If the las word of the first paragraph or the first word of the last paragraph is a white space, both paragraphs can be concatenated.
638 // Otherwise both words need to be merged first.
639 const WordLayoutInfo& firstWordLayout( *lastParagraphLayoutInfo.mWordsLayoutInfo.begin() );
641 std::size_t index = 0u;
642 if( ( WordSeparator != lastWordLayout.mType ) && ( WordSeparator != firstWordLayout.mType ) && ( ParagraphSeparator != firstWordLayout.mType ) )
644 // Last word of the first paragraph is not a word separator and first word of the last paragraph is not a word or paragraph separator.
645 // Words need to be merged.
647 MergeWord( lastWordLayout,
650 // After merging two words, the rest of the words need to be added.
651 ++index; // By increasing this index the word already merged won't be added again.
656 // Insert the layout of the words.
657 const std::size_t numberOfWords = firstParagraphLayoutInfo.mWordsLayoutInfo.size();
658 firstParagraphLayoutInfo.mWordsLayoutInfo.insert( firstParagraphLayoutInfo.mWordsLayoutInfo.end(),
659 lastParagraphLayoutInfo.mWordsLayoutInfo.begin() + index, lastParagraphLayoutInfo.mWordsLayoutInfo.end() );
661 // Increase the index of the first character of each inserted word.
662 for( WordLayoutInfoContainer::iterator it = firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + numberOfWords, endIt = firstParagraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it )
664 WordLayoutInfo& word( *it );
665 word.mFirstCharacter += firstParagraphLayoutInfo.mNumberOfCharacters;
668 // Update the size and other layout parameters.
669 UpdateSize( firstParagraphLayoutInfo.mSize, lastParagraphLayoutInfo.mSize );
670 firstParagraphLayoutInfo.mAscender = std::max( firstParagraphLayoutInfo.mAscender, lastParagraphLayoutInfo.mAscender );
671 firstParagraphLayoutInfo.mLineHeightOffset = std::max( firstParagraphLayoutInfo.mLineHeightOffset, lastParagraphLayoutInfo.mLineHeightOffset );
672 firstParagraphLayoutInfo.mNumberOfCharacters += lastParagraphLayoutInfo.mNumberOfCharacters;
674 // Merge text and styles.
675 firstParagraphLayoutInfo.mText.Append( lastParagraphLayoutInfo.mText );
676 for( Vector<TextStyle*>::ConstIterator it = lastParagraphLayoutInfo.mTextStyles.Begin(), endIt = lastParagraphLayoutInfo.mTextStyles.End(); it != endIt; ++it )
678 firstParagraphLayoutInfo.mTextStyles.PushBack( new TextStyle( *(*it) ) );
682 WordLayoutInfo GetLastWordLayoutInfo( const ParagraphLayoutInfo& paragraphLayoutInfo )
684 WordLayoutInfo layoutInfo;
686 if( !paragraphLayoutInfo.mWordsLayoutInfo.empty() )
688 layoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u );
694 CharacterLayoutInfo GetFirstCharacterLayoutInfo( const ParagraphLayoutInfo& paragraphLayoutInfo )
696 CharacterLayoutInfo layoutInfo;
698 if( !paragraphLayoutInfo.mWordsLayoutInfo.empty() )
700 const WordLayoutInfo& wordInfo( *paragraphLayoutInfo.mWordsLayoutInfo.begin() );
702 layoutInfo = GetFirstCharacterLayoutInfo( wordInfo );
708 CharacterLayoutInfo GetLastCharacterLayoutInfo( const ParagraphLayoutInfo& paragraphLayoutInfo )
710 const WordLayoutInfo wordInfo = GetLastWordLayoutInfo( paragraphLayoutInfo );
712 return GetLastCharacterLayoutInfo( wordInfo );
715 void CollectTextActorsFromParagraphs( std::vector<TextActor>& textActors, const TextLayoutInfo& textLayoutInfo, const std::size_t paragraphIndexBegin, const std::size_t paragraphIndexEnd )
717 for( ParagraphLayoutInfoContainer::const_iterator paragraphIt = textLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndexBegin, paragraphEndIt = textLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndexEnd;
718 paragraphIt != paragraphEndIt;
721 const ParagraphLayoutInfo& paragraph( *paragraphIt );
723 CollectTextActorsFromWords( textActors, paragraph, 0u, paragraph.mWordsLayoutInfo.size() );
727 } //namespace TextViewProcessor
729 } //namespace Internal
731 } //namespace Toolkit