X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=base%2Fdali-toolkit%2Finternal%2Fcontrols%2Ftext-view%2Ftext-view-line-processor.cpp;h=d82691f5bcc66033259b5611c5e3bb09cb6dca3c;hb=refs%2Fchanges%2F61%2F27361%2F4;hp=60ad206e93be4554390bd47e3436e66bcd0f7e8f;hpb=e58fa784d19a558e35f458ecf6d262a2344beb4f;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-line-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-line-processor.cpp index 60ad206..d82691f 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-line-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-line-processor.cpp @@ -1,25 +1,27 @@ -// -// Copyright (c) 2014 Samsung Electronics Co., Ltd. -// -// Licensed under the Flora License, Version 1.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://floralicense.org/license/ -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include // INTERNAL INCLUDES -#include "text-view-line-processor.h" -#include "text-view-word-group-processor.h" -#include "text-view-word-processor.h" -#include "text-view-processor-helper-functions.h" -#include "text-processor.h" +#include +#include +#include namespace Dali { @@ -41,8 +43,8 @@ LineLayoutInfo::LineLayoutInfo() : mSize(), mAscender( 0.f ), mLineHeightOffset( 0.f ), - mWordGroupsLayoutInfo(), - mNumberOfCharacters( 0 ) + mWordsLayoutInfo(), + mNumberOfCharacters( 0u ) { } @@ -50,7 +52,7 @@ LineLayoutInfo::LineLayoutInfo( const LineLayoutInfo& line ) : mSize( line.mSize ), mAscender( line.mAscender ), mLineHeightOffset( line.mLineHeightOffset ), - mWordGroupsLayoutInfo( line.mWordGroupsLayoutInfo ), + mWordsLayoutInfo( line.mWordsLayoutInfo ), mNumberOfCharacters( line.mNumberOfCharacters ) { } @@ -60,130 +62,327 @@ LineLayoutInfo& LineLayoutInfo::operator=( const LineLayoutInfo& line ) mSize = line.mSize; mAscender = line.mAscender; mLineHeightOffset = line.mLineHeightOffset; - mWordGroupsLayoutInfo = line.mWordGroupsLayoutInfo; + mWordsLayoutInfo = line.mWordsLayoutInfo; mNumberOfCharacters = line.mNumberOfCharacters; return *this; } -void UpdateLineLayoutInfo( TextViewProcessor::LineLayoutInfo& lineLayoutInfo, const float lineHeightOffset ) -{ - lineLayoutInfo.mSize = Size(); - - for( WordGroupLayoutInfoContainer::iterator it = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), endIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - it != endIt; - ++it ) - { - WordGroupLayoutInfo& layoutInfo( *it ); - - UpdateSize( lineLayoutInfo.mSize, layoutInfo.mSize ); - } - lineLayoutInfo.mSize.height += lineHeightOffset; -} - void CreateLineInfo( const MarkupProcessor::StyledTextArray& line, TextView::RelayoutData& relayoutData, - TextViewProcessor::LineLayoutInfo& lineLayoutInfo ) + LineLayoutInfo& lineLayoutInfo ) { - // TODO: Split the line in group of words. Each group of words has only left to right characters or right to left characters but not a mix of both. - // TODO: set the wordgroup direction (LTR or RTL) - std::vector wordGroups; + // Split the line in words. + // TODO: Proper RTL support. + MarkupProcessor::StyledTextArray convertedLine; if( TextProcessor::ContainsRightToLeftCharacter( line ) ) { // If the text is bidirectional, the characters will be converted and reordered // as specified by the Unicode Bidirectional Algorithm. // Reorders the line and converts arabic glyphs (if any). - // It also split words in different groups if there are a mix of left to right - // and right to left text. - // If the whole line is left to right or right to left all words are grouped in the same group. TextProcessor::ConvertBidirectionalText( line, - wordGroups, + convertedLine, relayoutData.mCharacterLogicalToVisualMap, relayoutData.mCharacterVisualToLogicalMap); } else { // No bidirectional text to process. + convertedLine = line; - if( !line.empty() ) + // Create trivial bidirectional map tables. + std::size_t index = 0u; + for( MarkupProcessor::StyledTextArray::const_iterator it = convertedLine.begin(), endIt = convertedLine.end(); it != endIt; ++it ) { - // Add all words in a group. - wordGroups.push_back( line ); + const MarkupProcessor::StyledText& styledText( *it ); - // Create trivial bidirectional map tables. - std::size_t index = 0; - for( MarkupProcessor::StyledTextArray::const_iterator it = line.begin(), endIt = line.end(); it != endIt; ++it ) + for( std::size_t i = 0u, length = styledText.mText.GetLength(); i < length; ++i ) { - const MarkupProcessor::StyledText& styledText( *it ); + relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); + relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); + ++index; + } + } + } + + // Split the line in words + std::vector words; + TextProcessor::SplitInWords( convertedLine, words ); - for( std::size_t i = 0, length = styledText.mText.GetLength(); i < length; ++i ) + // if last word has a new line separator, create a new word. + if( !words.empty() ) + { + MarkupProcessor::StyledTextArray& word( *( words.end() - 1u ) ); + if( word.size() > 1u ) + { + // do nothing if the word has only one character. + MarkupProcessor::StyledText& styledText( *( word.end() - 1u ) ); + if( !styledText.mText.IsEmpty() ) + { + const std::size_t length = styledText.mText.GetLength(); + if( styledText.mText[length-1u].IsNewLine() ) { - relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); - relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); - ++index; + // Last character of this word is a new line character. + + // Remove line separator character from current word. + styledText.mText.Remove( length - 1u, 1u ); + + // Create a new word with the line separator character. + MarkupProcessor::StyledText newLineText( Text( styledText.mText[length-1u] ), styledText.mStyle ); + + MarkupProcessor::StyledTextArray newLineWord; + newLineWord.push_back( newLineText ); + + words.push_back( newLineWord ); } } } } - // Traverse all group of words. - for( std::vector::const_iterator groupIt = wordGroups.begin(), groupEndIt = wordGroups.end(); groupIt != groupEndIt; ++groupIt ) + std::string lastCharacterFont; // Keeps the font used by the last character. It's used to set the font to a word separator. + + // Traverse all words. + for( std::vector::const_iterator wordIt = words.begin(), wordEndIt = words.end(); wordIt != wordEndIt; ++wordIt ) { - const MarkupProcessor::StyledTextArray& wordGroup( *groupIt ); + const MarkupProcessor::StyledTextArray& word( *wordIt ); + + // Data structures for the new word. + WordLayoutInfo wordLayoutInfo; + + CreateWordTextInfo( word, + wordLayoutInfo ); - // Data structures for the new group of words. - WordGroupLayoutInfo wordGroupLayoutInfo; + // White space's size could be different depending on the type of font. It's important to use the same font than the previous character to + // avoid 'jumps' of characters when there is a switch between one text-actor per character and one text-actor per line and/or style. + if( WordSeparator == wordLayoutInfo.mType ) + { + // If current word is a word separator (white space) then the font of the last character is set. + for( CharacterLayoutInfoContainer::iterator characterIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), characterEndIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + characterIt != characterEndIt; + ++characterIt ) + { + CharacterLayoutInfo& characterLayout( *characterIt ); + + characterLayout.mStyledText.mStyle.SetFontName( lastCharacterFont ); + } + } + else + { + // kepps the font of the last character. + if( !wordLayoutInfo.mCharactersLayoutInfo.empty() ) + { + lastCharacterFont = ( *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u ) ).mStyledText.mStyle.GetFontName(); + } + } - CreateWordGroupInfo( wordGroup, - relayoutData.mTextLayoutInfo, - wordGroupLayoutInfo ); + // Update the max word width figure. + relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width ); // Update layout info for the current line. - lineLayoutInfo.mAscender = std::max( lineLayoutInfo.mAscender, wordGroupLayoutInfo.mAscender ); - lineLayoutInfo.mNumberOfCharacters += wordGroupLayoutInfo.mNumberOfCharacters; - UpdateSize( lineLayoutInfo.mSize, wordGroupLayoutInfo.mSize ); + lineLayoutInfo.mAscender = std::max( lineLayoutInfo.mAscender, wordLayoutInfo.mAscender ); + lineLayoutInfo.mNumberOfCharacters += wordLayoutInfo.mCharactersLayoutInfo.size(); + UpdateSize( lineLayoutInfo.mSize, wordLayoutInfo.mSize ); - // Add the group of words to the current line. - lineLayoutInfo.mWordGroupsLayoutInfo.push_back( wordGroupLayoutInfo ); - } // end of group of words + // Add the word to the current line. + lineLayoutInfo.mWordsLayoutInfo.push_back( wordLayoutInfo ); + } // end of words } -void RemoveWordGroupsFromLine( const std::size_t groupIndex, - const std::size_t numberOfGroups, - const PointSize& lineHeightOffset, - LineLayoutInfo& lineLayout ) +void UpdateLayoutInfo( LineLayoutInfo& lineLayoutInfo, const float lineHeightOffset ) { - // Removes groups of words from a line. + // Update layout info. + lineLayoutInfo.mSize = Size::ZERO; + lineLayoutInfo.mAscender = 0.f; + lineLayoutInfo.mNumberOfCharacters = 0u; + for( WordLayoutInfoContainer::iterator it = lineLayoutInfo.mWordsLayoutInfo.begin(), endIt = lineLayoutInfo.mWordsLayoutInfo.end(); + it != endIt; + ++it ) + { + WordLayoutInfo& word( *it ); + + UpdateSize( lineLayoutInfo.mSize, word.mSize ); + lineLayoutInfo.mAscender = std::max( lineLayoutInfo.mAscender, word.mAscender ); + lineLayoutInfo.mNumberOfCharacters += word.mCharactersLayoutInfo.size(); + } + + lineLayoutInfo.mSize.height += lineHeightOffset; + lineLayoutInfo.mLineHeightOffset = lineHeightOffset; +} - // * Check if words or lines can be merged after removing a group of words or a line separator have to be done outside this method. +void RemoveWordsFromLine( std::size_t wordIndex, + std::size_t numberOfWords, + float lineHeightOffset, + LineLayoutInfo& lineLayout ) +{ + // Removes words from a line. - // * Note: Currently it's only used to remove a number of groups of words from the beginning, or - // from groupIndex index to the end. This function doesn't merge groups of words (if a whole group is removed) - // TODO: merge groups of words if required. + // * Check if words or lines can be merged after removing a number of words or a line separator needs to be done outside this method. - const std::size_t groupEndIndex = groupIndex + numberOfGroups; + // Remove words from layout info. + lineLayout.mWordsLayoutInfo.erase( lineLayout.mWordsLayoutInfo.begin() + wordIndex, + lineLayout.mWordsLayoutInfo.begin() + ( wordIndex + numberOfWords ) ); - // Remove word groups from layout info. - lineLayout.mWordGroupsLayoutInfo.erase( lineLayout.mWordGroupsLayoutInfo.begin() + groupIndex, - lineLayout.mWordGroupsLayoutInfo.begin() + groupEndIndex ); + UpdateLayoutInfo( lineLayout, lineHeightOffset ); +} - // Update layout info. - lineLayout.mSize = Size(); - lineLayout.mAscender = 0.f; - lineLayout.mNumberOfCharacters = 0; - for( WordGroupLayoutInfoContainer::const_iterator it = lineLayout.mWordGroupsLayoutInfo.begin(), endIt = lineLayout.mWordGroupsLayoutInfo.end(); - it != endIt; - ++it ) +void RemoveCharactersFromLineInfo( TextView::RelayoutData& relayoutData, + const std::size_t numberOfCharacters, + bool& mergeWords, + bool& mergeLines, + TextInfoIndices& textInfoIndicesBegin, + TextInfoIndices& textInfoIndicesEnd, + TextInfoIndices& textInfoMergeIndicesBegin, + TextInfoIndices& textInfoMergeIndicesEnd, + LineLayoutInfo& lineLayout, + std::vector& removedTextActorsFromFirstWord, + std::vector& removedTextActorsFromLastWord ) +{ + const TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo; + + if( textInfoIndicesBegin.mWordIndex < textInfoIndicesEnd.mWordIndex ) { - const WordGroupLayoutInfo& group( *it ); + // Deleted text is from different words. The two different words may be merged. + + // Get first word. + WordLayoutInfo& firstWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex ) ); + + // Get last word. + WordLayoutInfo& lastWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) ); + + // whether first or last word need to be split and merged. + bool mergeFromBegin = false; + bool mergeToEnd = false; + + if( textInfoIndicesBegin.mCharacterIndex > 0u ) + { + // First word is going to be split. It could be merged with the last word. + mergeFromBegin = true; + textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex; + } + else if( ( textInfoIndicesBegin.mCharacterIndex == 0u ) && ( textInfoIndicesBegin.mWordIndex > 0u ) ) + { + // First word is going to be removed completely. + // Check if previous word could be merged. - UpdateSize( lineLayout.mSize, group.mSize ); - lineLayout.mAscender = std::max( lineLayout.mAscender, group.mAscender ); - lineLayout.mNumberOfCharacters += group.mNumberOfCharacters; + // Get word before. + WordLayoutInfo& previousWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesBegin.mWordIndex - 1u ) ); + if( WordSeparator != previousWordLayout.mType ) + { + // Previous word is not a word separator, so could be merged. + mergeFromBegin = true; + textInfoMergeIndicesBegin.mWordIndex = textInfoIndicesBegin.mWordIndex - 1u; + } + } + + if( mergeFromBegin ) + { + // First word (or previous one) could be merged. Check if last one could be merged as well. + + if( textInfoIndicesEnd.mCharacterIndex + 1u < lastWordLayout.mCharactersLayoutInfo.size() ) + { + // Last word is going to be split. It could be merged with the first word. + mergeToEnd = true; + textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex; + } + else if( ( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1u < lineLayout.mWordsLayoutInfo.size() ) ) + { + // Last word is going to be removed completely. + // Check if the word after could be merged. + + // Get word after. + WordLayoutInfo& afterWordLayout( *( lineLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex + 1u ) ); + if( WordSeparator != afterWordLayout.mType ) + { + // The word after is not a word separator, so could be merged. + mergeToEnd = true; + textInfoMergeIndicesEnd.mWordIndex = textInfoIndicesEnd.mWordIndex + 1u; + } + } + + // Merge words only if both words could be merged. + mergeWords = mergeFromBegin && mergeToEnd; + } + + if( ( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() ) && ( textInfoIndicesEnd.mWordIndex + 1u == lineLayout.mWordsLayoutInfo.size() ) ) + { + // Last word of the line is going to be removed completely. + // Check if it's a line separator. + + if( LineSeparator == lastWordLayout.mType ) + { + // The line separator is going to be removed. + if( textInfoIndicesBegin.mLineIndex + 1u < textLayoutInfo.mLinesLayoutInfo.size() ) + { + // Line need to be merged. + textInfoMergeIndicesBegin.mLineIndex = textInfoIndicesBegin.mLineIndex; + textInfoMergeIndicesEnd.mLineIndex = textInfoIndicesBegin.mLineIndex + 1u; + mergeLines= true; + + ++textInfoIndicesBegin.mLineIndex; // increase both indices, + textInfoIndicesEnd.mLineIndex +=2u; // will delete last line. + } + } + } + + if( textInfoIndicesBegin.mCharacterIndex > 0u ) + { + // First word needs to be split. + + // Store text-actors before removing them. + CollectTextActors( removedTextActorsFromFirstWord, firstWordLayout, textInfoIndicesBegin.mCharacterIndex, firstWordLayout.mCharactersLayoutInfo.size() ); + + RemoveCharactersFromWord( textInfoIndicesBegin.mCharacterIndex, + firstWordLayout.mCharactersLayoutInfo.size() - textInfoIndicesBegin.mCharacterIndex, + firstWordLayout ); + + ++textInfoIndicesBegin.mWordIndex; // will delete from the word after. + } + + if( textInfoIndicesEnd.mCharacterIndex + 1u < lastWordLayout.mCharactersLayoutInfo.size() ) + { + // Last word needs to be split. + + // Store text-actors before removing them. + CollectTextActors( removedTextActorsFromLastWord, lastWordLayout, 0u, textInfoIndicesEnd.mCharacterIndex + 1u ); + + RemoveCharactersFromWord( 0u, + textInfoIndicesEnd.mCharacterIndex + 1u, + lastWordLayout ); + + if( mergeWords ) + { + // This word is going to be merged, so is not needed. + ++textInfoIndicesEnd.mWordIndex; // will delete the last word. + } + } + else if( textInfoIndicesEnd.mCharacterIndex + 1u == lastWordLayout.mCharactersLayoutInfo.size() ) + { + // The whole last word is going to be removed. + ++textInfoIndicesEnd.mWordIndex; // will delete the last word. + + if( ( WordSeparator == lastWordLayout.mType ) && mergeWords ) + { + // The last word is a word separator and the word after is going to be merged so is not needed. + ++textInfoIndicesEnd.mWordIndex; // will delete the word after the last one. + } + } } - lineLayout.mSize.height += lineHeightOffset; - lineLayout.mLineHeightOffset = lineHeightOffset; + else + { + // Chraracters to be removed are from the same word. + + RemoveCharactersFromWordInfo( relayoutData, + numberOfCharacters, + mergeWords, + mergeLines, + textInfoIndicesBegin, + textInfoIndicesEnd, + textInfoMergeIndicesBegin, + textInfoMergeIndicesEnd, + lineLayout, + removedTextActorsFromFirstWord ); + } // word indices } void SplitLine( const TextInfoIndices& indices, @@ -192,16 +391,16 @@ void SplitLine( const TextInfoIndices& indices, LineLayoutInfo& lastLineLayoutInfo ) { // Splits a line in two. - // A group of words and a word may be split in two as well. + // A word may be split in two as well. - // * Split the group of words within the line. - // * Add last part of the group of words to the new line. - // * Add groups of words from groupPosition + 1 to the end. + // * Split the word within the line. + // * Add last part of the word to the new line. + // * Add words from wordPosition + 1 to the end. // * Update layout info of the last line. - // * Remove groups of words added to the last part of the line from the first line. + // * Remove words added to the last part of the line from the first line. // early returns!! - if( ( 0 == indices.mGroupIndex ) && ( 0 == indices.mWordIndex ) && ( 0 == indices.mCharacterIndex ) ) + if( ( 0u == indices.mWordIndex ) && ( 0u == indices.mCharacterIndex ) ) { // the whole line goes to the last part. lastLineLayoutInfo = firstLineLayoutInfo; @@ -211,87 +410,68 @@ void SplitLine( const TextInfoIndices& indices, return; } - if( !firstLineLayoutInfo.mWordGroupsLayoutInfo.empty() ) + if( !firstLineLayoutInfo.mWordsLayoutInfo.empty() ) { - const std::size_t numberOfGroups = firstLineLayoutInfo.mWordGroupsLayoutInfo.size(); - if( indices.mGroupIndex == numberOfGroups - 1 ) + const std::size_t numberOfWords = firstLineLayoutInfo.mWordsLayoutInfo.size(); + if( indices.mWordIndex == numberOfWords - 1u ) { - const WordGroupLayoutInfo& group( *( firstLineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) ); - - const std::size_t numberOfWords = group.mWordsLayoutInfo.size(); - if( indices.mWordIndex == numberOfWords - 1 ) + const WordLayoutInfo& word( *( firstLineLayoutInfo.mWordsLayoutInfo.end() - 1u ) ); + if( indices.mCharacterIndex == word.mCharactersLayoutInfo.size() ) { - const WordLayoutInfo& word( *( group.mWordsLayoutInfo.end() - 1 ) ); - if( indices.mCharacterIndex == word.mCharactersLayoutInfo.size() ) - { - // the whole line goes to the first part. + // the whole line goes to the first part. - // Just delete whatever there is in the last part of the line. - lastLineLayoutInfo = LineLayoutInfo(); + // Just delete whatever there is in the last part of the line. + lastLineLayoutInfo = LineLayoutInfo(); - return; - } + return; } } } lastLineLayoutInfo = LineLayoutInfo(); - // 1) Split the group of words whitin the line. - WordGroupLayoutInfo& firstWordGroupLayoutInfo( *( firstLineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex ) ); - WordGroupLayoutInfo lastWordGroupLayoutInfo; + // 1) Split the word whitin the line. + WordLayoutInfo& firstWordLayoutInfo( *( firstLineLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex ) ); + WordLayoutInfo lastWordLayoutInfo; - SplitWordGroup( indices, - firstWordGroupLayoutInfo, - lastWordGroupLayoutInfo ); + SplitWord( indices.mCharacterIndex, + firstWordLayoutInfo, + lastWordLayoutInfo ); - // 2) Add last part of the group of words to the new line. - if( !lastWordGroupLayoutInfo.mWordsLayoutInfo.empty() ) + // 2) Add last part of the word to the new line. + if( !lastWordLayoutInfo.mCharactersLayoutInfo.empty() ) { - lastLineLayoutInfo.mWordGroupsLayoutInfo.push_back( lastWordGroupLayoutInfo ); + lastLineLayoutInfo.mWordsLayoutInfo.push_back( lastWordLayoutInfo ); } - // 3) Add groups from group-position + 1 to the end. - lastLineLayoutInfo.mWordGroupsLayoutInfo.insert( lastLineLayoutInfo.mWordGroupsLayoutInfo.end(), - firstLineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex + 1, firstLineLayoutInfo.mWordGroupsLayoutInfo.end() ); + // 3) Add words from word-position + 1 to the end. + lastLineLayoutInfo.mWordsLayoutInfo.insert( lastLineLayoutInfo.mWordsLayoutInfo.end(), + firstLineLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex + 1u, + firstLineLayoutInfo.mWordsLayoutInfo.end() ); // 4) update layout info of the last line. - for( WordGroupLayoutInfoContainer::iterator it = lastLineLayoutInfo.mWordGroupsLayoutInfo.begin(), endIt = lastLineLayoutInfo.mWordGroupsLayoutInfo.end(); + for( WordLayoutInfoContainer::iterator it = lastLineLayoutInfo.mWordsLayoutInfo.begin(), endIt = lastLineLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it ) { - WordGroupLayoutInfo& layoutInfo( *it ); + WordLayoutInfo& layoutInfo( *it ); - lastLineLayoutInfo.mNumberOfCharacters += layoutInfo.mNumberOfCharacters; UpdateSize( lastLineLayoutInfo.mSize, layoutInfo.mSize ); + lastLineLayoutInfo.mNumberOfCharacters += layoutInfo.mCharactersLayoutInfo.size(); lastLineLayoutInfo.mAscender = std::max( lastLineLayoutInfo.mAscender, layoutInfo.mAscender ); } lastLineLayoutInfo.mSize.height += lineHeightOffset; lastLineLayoutInfo.mLineHeightOffset = lineHeightOffset; - // 5) Remove groups of words added to the last part of the line from the first line. + // 5) Remove words added to the last part of the line from the first line. - // if the number of characters of the last group of words of the first line is zero, it should be removed. - const std::size_t index = ( 0 == firstWordGroupLayoutInfo.mNumberOfCharacters ? indices.mGroupIndex : indices.mGroupIndex + 1 ); + // if the number of characters of the last word of the first line is zero, it should be removed. + const std::size_t index = ( firstWordLayoutInfo.mCharactersLayoutInfo.empty() ? indices.mWordIndex : indices.mWordIndex + 1u ); - firstLineLayoutInfo.mWordGroupsLayoutInfo.erase( firstLineLayoutInfo.mWordGroupsLayoutInfo.begin() + index, firstLineLayoutInfo.mWordGroupsLayoutInfo.end() ); + firstLineLayoutInfo.mWordsLayoutInfo.erase( firstLineLayoutInfo.mWordsLayoutInfo.begin() + index, firstLineLayoutInfo.mWordsLayoutInfo.end() ); // 6) update layout info of the first line. - firstLineLayoutInfo.mNumberOfCharacters = 0; - firstLineLayoutInfo.mSize = Size(); - firstLineLayoutInfo.mAscender = 0.f; - for( WordGroupLayoutInfoContainer::iterator it = firstLineLayoutInfo.mWordGroupsLayoutInfo.begin(), endIt = firstLineLayoutInfo.mWordGroupsLayoutInfo.end(); - it != endIt; - ++it ) - { - WordGroupLayoutInfo& layoutInfo( *it ); - - firstLineLayoutInfo.mNumberOfCharacters += layoutInfo.mNumberOfCharacters; - UpdateSize( firstLineLayoutInfo.mSize, layoutInfo.mSize ); - firstLineLayoutInfo.mAscender = std::max( firstLineLayoutInfo.mAscender, layoutInfo.mAscender ); - } - firstLineLayoutInfo.mSize.height += lineHeightOffset; - firstLineLayoutInfo.mLineHeightOffset = lineHeightOffset; + UpdateLayoutInfo( firstLineLayoutInfo, lineHeightOffset ); } void MergeLine( LineLayoutInfo& firstLineLineLayoutInfo, @@ -303,78 +483,64 @@ void MergeLine( LineLayoutInfo& firstLineLineLayoutInfo, // Early returns. - if( lastLineLayoutInfo.mWordGroupsLayoutInfo.empty() ) + if( lastLineLayoutInfo.mWordsLayoutInfo.empty() ) { // Nothing to merge if last line is empty. return; } - if( firstLineLineLayoutInfo.mWordGroupsLayoutInfo.empty() ) + if( firstLineLineLayoutInfo.mWordsLayoutInfo.empty() ) { // If first line is empty, just copy the last line to the first one. firstLineLineLayoutInfo = lastLineLayoutInfo; - return; + return; } - if( 1 == firstLineLineLayoutInfo.mWordGroupsLayoutInfo.size() ) - { - WordGroupLayoutInfo& wordGroupLayout( *firstLineLineLayoutInfo.mWordGroupsLayoutInfo.begin() ); - - if( wordGroupLayout.mWordsLayoutInfo.empty() ) - { - // If first line is empty, just copy the last line to the first one. - firstLineLineLayoutInfo = lastLineLayoutInfo; - - return; - } - } - - // Check the last word of the last group of the first line doesn't finish with a new line character. - WordGroupLayoutInfo& lastWordGroupLayout( *( firstLineLineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) ); - WordLayoutInfo& lastWordLayout( *( lastWordGroupLayout.mWordsLayoutInfo.end() - 1 ) ); + // Check the last word of the first line doesn't finish with a new line character. + WordLayoutInfo& lastWordLayout( *( firstLineLineLayoutInfo.mWordsLayoutInfo.end() - 1u ) ); if( LineSeparator == lastWordLayout.mType ) { DALI_ASSERT_ALWAYS( !"TextViewProcessor::MergeLine(). ERROR: A line can't be merged to another line which finishes with a new line character." ); } - // If the last group of the first line has the same direction than the first group of the last line, both lines can be concatenated. - // Otherwise, both groups have to be merged first. - const WordGroupLayoutInfo& firstWordGroupLayout( *lastLineLayoutInfo.mWordGroupsLayoutInfo.begin() ); + // If the las word of the first line or the first word of the last line is a white space, both lines can be concatenated. + // Otherwise both words need to be merged first. + const WordLayoutInfo& firstWordLayout( *lastLineLayoutInfo.mWordsLayoutInfo.begin() ); - std::size_t index = 0; - if( lastWordGroupLayout.mDirection == firstWordGroupLayout.mDirection ) + std::size_t index = 0u; + if( ( WordSeparator != lastWordLayout.mType ) && ( WordSeparator != firstWordLayout.mType ) && ( LineSeparator != firstWordLayout.mType ) ) { - // Both groups of words have the same direction. They need to be merged. - MergeWordGroup( lastWordGroupLayout, - firstWordGroupLayout ); + // Last word of the first line is not a word separator and first word of the last line is not a word or line separator. + // Words need to be merged. + + MergeWord( lastWordLayout, + firstWordLayout ); - // After merging two groups of words, the rest of groups need to be added. - ++index; // By increasing this index the group of words already merged won't be added again. + // After merging two words, the rest of the words need to be added. + ++index; // By increasing this index the word already merged won't be added again. } // Merge layout info - firstLineLineLayoutInfo.mWordGroupsLayoutInfo.insert( firstLineLineLayoutInfo.mWordGroupsLayoutInfo.end(), - lastLineLayoutInfo.mWordGroupsLayoutInfo.begin() + index, lastLineLayoutInfo.mWordGroupsLayoutInfo.end() ); + + // Insert the layout of the words. + firstLineLineLayoutInfo.mWordsLayoutInfo.insert( firstLineLineLayoutInfo.mWordsLayoutInfo.end(), + lastLineLayoutInfo.mWordsLayoutInfo.begin() + index, lastLineLayoutInfo.mWordsLayoutInfo.end() ); + + // Update the size and other layout parameters. UpdateSize( firstLineLineLayoutInfo.mSize, lastLineLayoutInfo.mSize ); firstLineLineLayoutInfo.mAscender = std::max( firstLineLineLayoutInfo.mAscender, lastLineLayoutInfo.mAscender ); firstLineLineLayoutInfo.mLineHeightOffset = std::max( firstLineLineLayoutInfo.mLineHeightOffset, lastLineLayoutInfo.mLineHeightOffset ); firstLineLineLayoutInfo.mNumberOfCharacters += lastLineLayoutInfo.mNumberOfCharacters; - } WordLayoutInfo GetLastWordLayoutInfo( const LineLayoutInfo& lineLayoutInfo ) { WordLayoutInfo layoutInfo; - if( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() ) + if( !lineLayoutInfo.mWordsLayoutInfo.empty() ) { - const WordGroupLayoutInfo& groupInfo( *( lineLayoutInfo.mWordGroupsLayoutInfo.end() - 1 ) ); - - if( !groupInfo.mWordsLayoutInfo.empty() ) - { - layoutInfo = *( groupInfo.mWordsLayoutInfo.end() - 1 ); - } + layoutInfo = *( lineLayoutInfo.mWordsLayoutInfo.end() - 1u ); } return layoutInfo; @@ -384,16 +550,11 @@ CharacterLayoutInfo GetFirstCharacterLayoutInfo( const LineLayoutInfo& lineLayou { CharacterLayoutInfo layoutInfo; - if( !lineLayoutInfo.mWordGroupsLayoutInfo.empty() ) + if( !lineLayoutInfo.mWordsLayoutInfo.empty() ) { - const WordGroupLayoutInfo& groupInfo( *lineLayoutInfo.mWordGroupsLayoutInfo.begin() ); + const WordLayoutInfo& wordInfo( *lineLayoutInfo.mWordsLayoutInfo.begin() ); - if( !groupInfo.mWordsLayoutInfo.empty() ) - { - const WordLayoutInfo& wordInfo( *groupInfo.mWordsLayoutInfo.begin() ); - - layoutInfo = GetFirstCharacterLayoutInfo( wordInfo ); - } + layoutInfo = GetFirstCharacterLayoutInfo( wordInfo ); } return layoutInfo; @@ -414,7 +575,7 @@ void CollectTextActorsFromLines( std::vector& textActors, const TextL { const LineLayoutInfo& line( *lineIt ); - CollectTextActorsFromGroups( textActors, line, 0, line.mWordGroupsLayoutInfo.size() ); + CollectTextActorsFromWords( textActors, line, 0u, line.mWordsLayoutInfo.size() ); } }