X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=base%2Fdali-toolkit%2Finternal%2Fcontrols%2Ftext-view%2Frelayout-utilities.cpp;h=23c943c8a44427d78afbea842b58b9c4e7d30067;hp=3040654ffb83bcde44a5ee2eac2777451e56a4ca;hb=eec166d805a775a763db4fa4cb874e87fa640be5;hpb=0023f4d39b640af529ddcd0a07f271a877c473ef diff --git a/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp b/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp index 3040654..23c943c 100644 --- a/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp +++ b/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp @@ -1,33 +1,33 @@ -// -// 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/license/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 "relayout-utilities.h" +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include // EXTERNAL INCLUDES #include -// INTERNAL INCLUDES -#include -#include -#include "text-view-line-processor.h" -#include "text-view-word-processor.h" -#include "text-view-processor-helper-functions.h" -#include "text-view-processor-dbg.h" - namespace Dali { @@ -44,7 +44,7 @@ const float MINIMUM_FADE_BOUNDARY = 0.05f; // When the fade boundary is the same RelayoutParameters::RelayoutParameters() : mPositionOffset(), - mLineSize(), + mParagraphSize(), mWordSize(), mCharacterSize(), mIndices(), @@ -52,7 +52,7 @@ RelayoutParameters::RelayoutParameters() mIsFirstCharacter( false ), mIsFirstCharacterOfWord( false ), mIsNewLine( false ), - mIsNewLineCharacter( false ), + mIsNewParagraphCharacter( false ), mIsWhiteSpace( false ), mIsVisible( false ) { @@ -135,14 +135,14 @@ TextUnderlineStatus::~TextUnderlineStatus() { } -SubLineLayoutInfo::SubLineLayoutInfo() +LineLayoutInfo::LineLayoutInfo() : mLineLength( 0.f ), mMaxCharHeight( 0.f ), mMaxAscender( 0.f ) { } -SubLineLayoutInfo::~SubLineLayoutInfo() +LineLayoutInfo::~LineLayoutInfo() { } @@ -188,7 +188,7 @@ bool IsExceedingHeight( const Vector3& position, const Size& size, const Size& p * @param[out] lineLength The length of the portion of line which doesn't exceed the parant's width * @param[out] endWhiteSpaceLength The length of white spaces which are at the end of the line. */ -void CalculateLineLength( const bool isWhiteSpace, const float width, const float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength ) +void CalculateLineLength( bool isWhiteSpace, float width, float parentWidth, bool& found, float& lineLength, float& endWhiteSpaceLength ) { if( lineLength + width > parentWidth ) { @@ -217,9 +217,7 @@ struct CurrentTextActorInfo Vector3 position; Size size; Vector4 color; - Vector4 gradientColor; - Vector2 startPoint; - Vector2 endPoint; + TextViewProcessor::CharacterLayoutInfo* characterLayout; }; void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo, @@ -228,9 +226,13 @@ void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo, const float lineHeight ) { currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color ); - currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientColor ); - currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.startPoint ); - currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.endPoint ); + if( ( NULL != currentTextActorInfo.characterLayout ) && + ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) ) + { + currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.characterLayout->mGradientInfo->mGradientColor ); + currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.characterLayout->mGradientInfo->mStartPoint ); + currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.characterLayout->mGradientInfo->mEndPoint ); + } // The italics offset is used in the offscreen rendering. When text is in italics, it may exceed the text-view's boundary // due to the trick used to implement it. @@ -245,12 +247,12 @@ void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo, currentTextActorInfo.textActor.SetBlendMode( !visualParameters.mSnapshotModeEnabled ? BlendingMode::ON : BlendingMode::OFF ); } -void CalculateSubLineLayout( const float parentWidth, - const TextViewProcessor::TextInfoIndices& indices, - const TextViewProcessor::LineLayoutInfo& lineLayoutInfo, - const HorizontalWrapType splitPolicy, - const float shrinkFactor, - SubLineLayoutInfo& subLineInfo ) +void CalculateLineLayout( float parentWidth, + const TextViewProcessor::TextInfoIndices& indices, + const TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo, + HorizontalWrapType splitPolicy, + float shrinkFactor, + LineLayoutInfo& subLineInfo ) { subLineInfo.mLineLength = 0.f; subLineInfo.mMaxCharHeight = 0.f; @@ -258,108 +260,367 @@ void CalculateSubLineLayout( const float parentWidth, float endWhiteSpaceLength = 0.f; - std::size_t wordIndex = indices.mWordIndex; std::size_t characterIndex = indices.mCharacterIndex; float lineOffset = 0.f; bool found = false; bool isFirstCharacter = true; - for( TextViewProcessor::WordGroupLayoutInfoContainer::const_iterator wordGroupIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + indices.mGroupIndex, - wordGroupEndIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - ( wordGroupIt != wordGroupEndIt ) && !found; - ++wordGroupIt ) + for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + indices.mWordIndex, + wordEndIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); + ( wordIt != wordEndIt ) && !found; + ++wordIt ) { - const TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *wordGroupIt ); + const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt ); - for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + wordIndex, - wordEndIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - ( wordIt != wordEndIt ) && !found; - ++wordIt ) - { - const TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordIt ); + const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor; + const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType; - const float shrunkWordWidth = wordLayoutInfo.mSize.width * shrinkFactor; - const bool isWhiteSpace = TextViewProcessor::WordSeparator == wordLayoutInfo.mType; + bool splitByCharacter = false; - bool splitByCharacter = false; - - switch( splitPolicy ) + switch( splitPolicy ) + { + case WrapByCharacter: + { + splitByCharacter = true; + break; + } + case WrapByWord: + case WrapByParagraphCharacter: // Fall through + { + splitByCharacter = false; + break; + } + case WrapByWordAndSplit: + { + splitByCharacter = ( shrunkWordWidth > parentWidth ); + break; + } + case WrapByParagraphCharacterAndSplit: { - case WrapByCharacter: + if( ( 0u != characterIndex ) || + ( ( 0u == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) ) { splitByCharacter = true; - break; } - case WrapByWord: - case WrapByLine: // Fall through + else { + lineOffset += shrunkWordWidth; splitByCharacter = false; - break; - } - case WrapByWordAndSplit: - { - splitByCharacter = ( shrunkWordWidth > parentWidth ); - break; - } - case WrapByLineAndSplit: - { - if( ( 0 != characterIndex ) || - ( ( 0 == characterIndex ) && ( lineOffset + shrunkWordWidth > parentWidth ) ) ) - { - splitByCharacter = true; - } - else - { - lineOffset += shrunkWordWidth; - splitByCharacter = false; - } } } + } - if( splitByCharacter ) + if( splitByCharacter ) + { + for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex, + charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + ( charIt != charEndIt ) && !found; + ++charIt ) { - for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator charIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + characterIndex, - charEndIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - ( charIt != charEndIt ) && !found; - ++charIt ) + const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt ); + CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength ); + if( !found || isFirstCharacter ) { - const TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *charIt ); - CalculateLineLength( isWhiteSpace, characterLayoutInfo.mSize.width * shrinkFactor, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength ); - if( !found || isFirstCharacter ) - { - subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height ); - subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender ); - } - - // All characters for word 'wordIndex' have been processed. - // Next word need to process all characters, so the characterIndex is reset to 0. - characterIndex = 0; - isFirstCharacter = false; + subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, characterLayoutInfo.mSize.height ); + subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, characterLayoutInfo.mAscender ); } - lineOffset += subLineInfo.mLineLength; + // All characters for word 'wordIndex' have been processed. + // Next word need to process all characters, so the characterIndex is reset to 0. + characterIndex = 0u; + isFirstCharacter = false; } - else + + lineOffset += subLineInfo.mLineLength; + } + else + { + CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength ); + if( !found || isFirstCharacter ) { - CalculateLineLength( isWhiteSpace, shrunkWordWidth, parentWidth, found, subLineInfo.mLineLength, endWhiteSpaceLength ); - if( !found || isFirstCharacter ) - { - subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height ); - subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender ); - } - isFirstCharacter = false; + subLineInfo.mMaxCharHeight = std::max( subLineInfo.mMaxCharHeight, wordLayoutInfo.mSize.height ); + subLineInfo.mMaxAscender = std::max( subLineInfo.mMaxAscender, wordLayoutInfo.mAscender ); } + isFirstCharacter = false; } - - // All words for group 'groupIndex' have been processed. - // Next group need to process all words, so the wordIndex is reset to 0. - wordIndex = 0; } subLineInfo.mMaxCharHeight *= shrinkFactor; subLineInfo.mMaxAscender *= shrinkFactor; } -float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, const float parentWidth, const float wholeTextWidth ) + +/** + * Sets a character of a line of a bidirectional paragraph in the new position. + * + * @param[in] wordsLayoutInfo Layout info of all the words of the paragraph. + * @param[in] index Index within the paragraph to the character to be set in the new position. + * @param[in,out] character Reference to the character in the new position. + */ +void SetCharacter( const TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo, + std::size_t index, + TextViewProcessor::CharacterLayoutInfo& character ) +{ + // Traverse all the characters of the paragraph till the one pointed by index is found. + std::size_t traversedCharacters = 0u; + for( TextViewProcessor::WordLayoutInfoContainer::const_iterator wordIt = wordsLayoutInfo.begin(), + wordEndIt = wordsLayoutInfo.end(); + wordIt != wordEndIt; + ++wordIt ) + { + const TextViewProcessor::WordLayoutInfo& word( *wordIt ); + + const std::size_t numberOfCharacters = word.mCharactersLayoutInfo.size(); + if( index < traversedCharacters + numberOfCharacters ) + { + character = *( word.mCharactersLayoutInfo.begin() + ( index - traversedCharacters ) ); + return; + } + traversedCharacters += numberOfCharacters; + } +} + +/** + * Reorders the layout info of each line of the paragraph. + * + * Uses the visual to logical conversion table to order the text, styles and character's layout (metrics). + * + * @param[in,out] rtlParagraph Layout info for the paragraph with rtl text. + */ +void ReorderLayout( TextViewProcessor::ParagraphLayoutInfo& paragraph ) +{ + // Clear any previous right to left layout. + if( NULL != paragraph.mRightToLeftLayout ) + { + paragraph.mRightToLeftLayout->Clear(); + paragraph.mRightToLeftLayout->mPreviousLayoutCleared = true; + } + else + { + // Create a new right to left layout if there isn't any. + paragraph.mRightToLeftLayout = new TextViewProcessor::RightToLeftParagraphLayout(); + } + + // Reorder Text and Styles. + + // Reserve space for the styles. + paragraph.mRightToLeftLayout->mTextStyles.Reserve( paragraph.mTextStyles.Count() ); + + // Traverses all the bidirectional info per line. + for( Vector::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it ) + { + TextProcessor::BidirectionalLineInfo* info( *it ); + + const std::size_t characterParagraphIndex = info->mCharacterParagraphIndex; + const Vector& visualToLogicalMap = info->mVisualToLogicalMap; + + // The text can be appended as it's already reordered. + paragraph.mRightToLeftLayout->mText.Append( info->mText ); + + // The visual to logical map needs to be used to reorder the styles. + for( std::size_t index = 0u, size = visualToLogicalMap.Count(); index < size; ++index ) + { + paragraph.mRightToLeftLayout->mTextStyles.PushBack( *( paragraph.mTextStyles.Begin() + ( characterParagraphIndex + *( visualToLogicalMap.Begin() + index ) ) ) ); + } + } + + // Reorder Layout Info. + + // Reserve space for the new word layout. + paragraph.mRightToLeftLayout->mWordsLayoutInfo.reserve( paragraph.mWordsLayoutInfo.size() ); + + // Traverses all the bidirectional info per line. + for( Vector::ConstIterator it = paragraph.mBidirectionalLinesInfo.Begin(), endIt = paragraph.mBidirectionalLinesInfo.End(); it != endIt; ++it ) + { + TextProcessor::BidirectionalLineInfo* info( *it ); + + // Reserve space for all characters. + TextViewProcessor::CharacterLayoutInfoContainer characters; + characters.resize( info->mNumberOfCharacters ); + + // Uses the visual to logical map to set every character in its new position. + for( std::size_t index = 0u; index < info->mNumberOfCharacters; ++index ) + { + SetCharacter( paragraph.mWordsLayoutInfo, + info->mCharacterParagraphIndex + info->mVisualToLogicalMap[index], + *( characters.begin() + index ) ); + } + + // Sets the new 'x' position for each character. + float xPosition = 0.f; + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator it = characters.begin(), endIt = characters.end(); it != endIt; ++it ) + { + TextViewProcessor::CharacterLayoutInfo& character( *it ); + + character.mPosition.x = xPosition; + xPosition += character.mSize.width; + } + + // Split the reordered text in words. + std::size_t previousPosition = 0u; + Vector positions; + TextProcessor::SplitInWords( info->mText, positions ); + + // Sets the characters into the words they belong to. + for( Vector::ConstIterator it = positions.Begin(), endIt = positions.End(); it != endIt; ++it ) + { + const std::size_t position = *it; + + TextViewProcessor::WordLayoutInfo word; + word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(), + characters.begin() + previousPosition, + characters.begin() + position ); + + if( !word.mCharactersLayoutInfo.empty() ) + { + // Updates the layout of the word. + TextViewProcessor::UpdateLayoutInfo( word ); + + paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word ); + } + + // white space or new paragraph. + TextViewProcessor::WordLayoutInfo space; + space.mCharactersLayoutInfo.insert( space.mCharactersLayoutInfo.end(), + characters.begin() + position, + characters.begin() + position + 1u ); + + TextViewProcessor::UpdateLayoutInfo( space ); + + paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( space ); + + previousPosition = position + 1u; + } + + // The last word. + if( previousPosition < paragraph.mRightToLeftLayout->mText.GetLength() ) + { + TextViewProcessor::WordLayoutInfo word; + word.mCharactersLayoutInfo.insert( word.mCharactersLayoutInfo.end(), + characters.begin() + previousPosition, + characters.end() ); + + TextViewProcessor::UpdateLayoutInfo( word ); + + paragraph.mRightToLeftLayout->mWordsLayoutInfo.push_back( word ); + } + } +} + +/** + * Creates the bidirectional info needed to reorder each line of the paragraph. + * + * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info. + * @param[in,out] paragraph Layout info for the paragraph. + * @param[in] characterGlobalIndex Index to the character within the whole text. + * @param[in] lineLayoutInfoIndex Index to the table of lines. + */ +void CreateBidirectionalInfoForLines( TextView::RelayoutData& relayoutData, + TextViewProcessor::ParagraphLayoutInfo& paragraph, + std::size_t& characterGlobalIndex, + std::size_t& lineLayoutInfoIndex ) +{ + const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number or laid out lines. + bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last laid out line. + + // Clear previously created bidirectional info. + paragraph.ClearBidirectionalInfo(); + + std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph). + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end(); + wordIt != wordEndIt; + ++wordIt ) + { + TextViewProcessor::WordLayoutInfo& word( *wordIt ); + + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); + characterIt != characterEndIt; + ++characterIt ) + { + TextProcessor::BidirectionalLineInfo* bidirectionalLineInfo = NULL; + + // Check if there is a new line. + const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ); + + if( newLine ) + { + // Point to the next line. + ++lineLayoutInfoIndex; + if( lineLayoutInfoIndex >= lineLayoutInfoSize ) + { + // Arrived at last line. + lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector. + } + + // Number of characters of the line. + const size_t numberOfCharacters = ( lineLayoutEnd ? relayoutData.mTextLayoutInfo.mNumberOfCharacters : relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ) - characterGlobalIndex; + + // There is right to left characters in this line. It needs to be reordered. + bidirectionalLineInfo = new TextProcessor::BidirectionalLineInfo(); + bidirectionalLineInfo->mCharacterParagraphIndex = characterParagraphIndex; + bidirectionalLineInfo->mNumberOfCharacters = numberOfCharacters; + + // Set all the Text's characters in the visual order and creates the mapping tables. + TextProcessor::ReorderLine( paragraph.mBidirectionalParagraphInfo, + bidirectionalLineInfo ); + + paragraph.mBidirectionalLinesInfo.PushBack( bidirectionalLineInfo ); + + for( std::size_t index = 0u; index < numberOfCharacters; ++index ) + { + relayoutData.mCharacterLogicalToVisualMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mLogicalToVisualMap[index] ); + relayoutData.mCharacterVisualToLogicalMap.push_back( characterGlobalIndex + bidirectionalLineInfo->mVisualToLogicalMap[index] ); + } + } + + ++characterGlobalIndex; + ++characterParagraphIndex; + } // characters + } // words +} + +void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData ) +{ + // Reset conversion tables shared through public-api + relayoutData.mCharacterLogicalToVisualMap.clear(); + relayoutData.mCharacterVisualToLogicalMap.clear(); + + std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text). + std::size_t lineLayoutInfoIndex = 0u; // Index to the line info. + + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphIt != paragraphEndIt; + ++paragraphIt ) + { + TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); + + if( NULL != paragraph.mBidirectionalParagraphInfo ) + { + // There is right to left text in this paragraph. + + // Creates the bidirectional info needed to reorder each line of the paragraph. + CreateBidirectionalInfoForLines( relayoutData, + paragraph, + characterGlobalIndex, + lineLayoutInfoIndex ); + + // Reorder each line of the paragraph + ReorderLayout( paragraph ); + } + else + { + // Identity in case the paragraph has no right to left text. + for( std::size_t index = 0u; index < paragraph.mNumberOfCharacters; ++index ) + { + const std::size_t globalIndex = characterGlobalIndex + index; + relayoutData.mCharacterLogicalToVisualMap.push_back( globalIndex ); + relayoutData.mCharacterVisualToLogicalMap.push_back( globalIndex ); + } + characterGlobalIndex += paragraph.mNumberOfCharacters; + } + } // paragraphs +} + +float CalculateXoffset( Toolkit::Alignment::Type horizontalTextAlignment, float parentWidth, float wholeTextWidth ) { float xOffset( 0.f ); switch( horizontalTextAlignment ) @@ -388,7 +649,7 @@ float CalculateXoffset( const Toolkit::Alignment::Type horizontalTextAlignment, return xOffset; } -float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, const float parentHeight, const float wholeTextHeight ) +float CalculateYoffset( Toolkit::Alignment::Type verticalTextAlignment, float parentHeight, float wholeTextHeight ) { float yOffset( 0.f ); switch( verticalTextAlignment ) @@ -417,7 +678,7 @@ float CalculateYoffset( const Toolkit::Alignment::Type verticalTextAlignment, co return yOffset; } -float CalculateJustificationOffset( const Toolkit::TextView::LineJustification justification, const float wholeTextWidth, const float lineLength ) +float CalculateJustificationOffset( Toolkit::TextView::LineJustification justification, float wholeTextWidth, float lineLength ) { float offset = 0.f; switch( justification ) @@ -447,7 +708,7 @@ float CalculateJustificationOffset( const Toolkit::TextView::LineJustification j return offset; } -bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, const VisibilityTestType type ) +bool IsVisible( const Vector3& position, const Size& size, const Size& parentSize, VisibilityTestType type ) { bool visible = false; @@ -529,77 +790,82 @@ void UpdateAlignment( const TextView::LayoutParameters& layoutParameters, const float textHorizontalOffset = CalculateXoffset( layoutParameters.mHorizontalAlignment, relayoutData.mTextViewSize.width, relayoutData.mTextSizeForRelayoutOption.width ); const float textVerticalOffset = CalculateYoffset( layoutParameters.mVerticalAlignment, relayoutData.mTextViewSize.height, relayoutData.mTextSizeForRelayoutOption.height ); - std::size_t lineJustificationIndex = 0; // Index to the first position of the vector which stores all line justification info. - std::size_t infoTableCharacterIndex = 0; + // Index to the global character (within the whole text). + std::size_t characterGlobalIndex = 0u; + + // Index to the line info. + std::size_t lineLayoutInfoIndex = 0u; - relayoutParameters.mIndices.mLineIndex = 0; + relayoutParameters.mIndices.mParagraphIndex = 0u; - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), + endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphLayoutIt != endParagraphLayoutIt; + ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); - relayoutParameters.mIndices.mGroupIndex = 0; float justificationOffset = 0.f; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex ) + const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines. + bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line. + + relayoutParameters.mIndices.mWordIndex = 0u; + + const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo; + + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); + wordLayoutIt != endWordLayoutIt; + ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - relayoutParameters.mIndices.mWordIndex = 0; + relayoutParameters.mIndices.mCharacterIndex = 0u; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), + endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + characterLayoutIt != endCharacterLayoutIt; + ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex ) { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); + TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - relayoutParameters.mIndices.mCharacterIndex = 0; + // Check if there is a new line. + const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex ) + if( newLine ) { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - // Calculate line justification offset. - if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() ) - { - const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) ); + justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width ); - if( relayoutParameters.mIndices == lineJustificationInfo.mIndices ) - { - justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength ); - ++lineJustificationIndex; // increase the index to point the next position in the vector. - } + // Point to the next line. + ++lineLayoutInfoIndex; + if( lineLayoutInfoIndex >= lineLayoutInfoSize ) + { + // Arrived at last line. + lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector. } + } - // Deletes the offsets if the exceed policies are EllipsizeEnd. - const float horizontalOffset = textHorizontalOffset + justificationOffset; - characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset; - characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset; + // Deletes the offsets if the exceed policies are EllipsizeEnd. + const float horizontalOffset = textHorizontalOffset + justificationOffset; + characterLayoutInfo.mOffset.x = ( ellipsizeAlignToLeft && ( horizontalOffset < 0.f ) ) ? 0.f : horizontalOffset; + characterLayoutInfo.mOffset.y = ( ellipsizeAlignToTop && ( textVerticalOffset < 0.f ) ) ? 0.f : textVerticalOffset; - // Updates the size and position table for text-input with the alignment offset. - Vector3 positionOffset( characterLayoutInfo.mPosition ); + // Updates the size and position table for text-input with the alignment offset. + Vector3 positionOffset( characterLayoutInfo.mPosition ); - std::vector::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex; - Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt ); + std::vector::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + characterGlobalIndex; + Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt ); - characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x; - characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y; + characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x; + characterTableInfo.mPosition.y = positionOffset.y + characterLayoutInfo.mOffset.y; - positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor; - } // end characters - } // end words - } // end group of words - } // end lines + positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor; + } // end characters + } // end words + } // end paragraphs } void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo, @@ -643,14 +909,13 @@ void CalculateBearing( TextViewProcessor::CharacterLayoutInfo& characterLayoutIn // gggggggggg // gggggggggg - const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1 ) ); + const Toolkit::TextView::LineLayoutInfo& lineInfo( *( relayoutData.mLines.end() - 1u ) ); const float bearingOffset = ( lineInfo.mSize.height - lineInfo.mAscender ) - ( characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender ); characterLayoutInfo.mPosition.y -= bearingOffset * relayoutData.mShrinkFactor; } void UpdateLayoutInfoTable( Vector4& minMaxXY, - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo, TextViewProcessor::WordLayoutInfo& wordLayoutInfo, TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo, RelayoutParameters& relayoutParameters, @@ -668,21 +933,22 @@ void UpdateLayoutInfoTable( Vector4& minMaxXY, const float descender = characterLayoutInfo.mSize.height - characterLayoutInfo.mAscender; - const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor, - characterLayoutInfo.mHeight * relayoutData.mShrinkFactor ), + const Toolkit::TextView::CharacterLayoutInfo characterLayoutTableInfo( Size( characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor, + characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ), positionOffset, - ( TextViewProcessor::LineSeparator == wordLayoutInfo.mType ), - ( TextViewProcessor::RTL == wordGroupLayoutInfo.mDirection ), - true, + ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ), + characterLayoutInfo.mIsRightToLeft, // whether the character is right to left. + true, // whether the character is visible. descender ); relayoutData.mCharacterLayoutInfoTable.push_back( characterLayoutTableInfo ); - positionOffset.x += characterLayoutInfo.mAdvance * relayoutData.mShrinkFactor; + positionOffset.x += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor; } void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters, TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo, + const TextStyle& style, RelayoutParameters& relayoutParameters, FadeParameters& fadeParameters, TextView::RelayoutData& relayoutData ) @@ -844,25 +1110,35 @@ void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& lay // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the left and the right boundaries. if( rightFadeOut ) { - gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor(); + gradientColor = style.GetTextColor(); // Calculates gradient coeficients. characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mRightAlphaCoeficients.x * position.x + fadeParameters.mRightAlphaCoeficients.y ); gradientColor.a *= std::max( 0.f, fadeParameters.mRightAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mRightAlphaCoeficients.y ); - startPoint = Vector2( std::max( 0.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ), 0.5f ); - endPoint = Vector2( std::min( 1.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ), 0.5f ); + startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mRightFadeThresholdOffset - position.x ) / size.width ) ), 0.5f ); + endPoint = Vector2( std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.width - position.x ) / size.width ) ), 0.5f ); + + if( NULL == characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo(); + } } else if( leftFadeOut ) { - gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor(); + gradientColor = style.GetTextColor(); // Calculates gradient coeficients. characterLayoutInfo.mColorAlpha = std::min( 1.f, fadeParameters.mLeftAlphaCoeficients.x * characterPositionPlusWidth + fadeParameters.mLeftAlphaCoeficients.y ); gradientColor.a *= gradientColor.a * std::max( 0.f, fadeParameters.mLeftAlphaCoeficients.x * position.x + fadeParameters.mLeftAlphaCoeficients.y ); - startPoint = Vector2( std::max( 0.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ), 0.5f ); - endPoint = Vector2( std::min( 1.f, -position.x / size.width ), 0.5f ); + startPoint = Vector2( std::max( 0.f, std::min( 1.f, ( fadeParameters.mLeftFadeThresholdOffset - position.x ) / size.width ) ), 0.5f ); + endPoint = Vector2( std::min( 1.f, std::max( 0.f, -position.x / size.width ) ), 0.5f ); + + if( NULL == characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo(); + } } } @@ -871,31 +1147,44 @@ void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& lay // Current implementation can't set gradient parameters for a text-actor exceeding at the same time the top and the bottom boundaries. if( bottomFadeOut ) { - gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor(); + gradientColor = style.GetTextColor(); // Calculates gradient coeficients. characterLayoutInfo.mColorAlpha = gradientColor.a * std::min( 1.f, fadeParameters.mBottomAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mBottomAlphaCoeficients.y ); gradientColor.a *= std::max( 0.f, fadeParameters.mBottomAlphaCoeficients.x * position.y + fadeParameters.mBottomAlphaCoeficients.y ); - startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ); - endPoint = Vector2( 0.5f, std::min( 1.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ); + startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mBottomFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) ); + endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, ( relayoutData.mTextViewSize.height - characterPositionMinusHeight ) / size.height ) ) ); + + if( NULL == characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo(); + } } else if( topFadeOut ) { - gradientColor = characterLayoutInfo.mStyledText.mStyle.GetTextColor(); + gradientColor = style.GetTextColor(); // Calculates gradient coeficients. characterLayoutInfo.mColorAlpha *= gradientColor.a * std::min( 1.f, fadeParameters.mTopAlphaCoeficients.x * position.y + fadeParameters.mTopAlphaCoeficients.y ); gradientColor.a *= std::max( 0.f, fadeParameters.mTopAlphaCoeficients.x * characterPositionMinusHeight + fadeParameters.mTopAlphaCoeficients.y ); - startPoint = Vector2( 0.5f, std::max( 0.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ); - endPoint = Vector2( 0.5f, std::min( 1.f, -characterPositionMinusHeight / size.height ) ); + startPoint = Vector2( 0.5f, std::max( 0.f, std::min( 1.f, ( fadeParameters.mTopFadeThresholdOffset - characterPositionMinusHeight ) / size.height ) ) ); + endPoint = Vector2( 0.5f, std::min( 1.f, std::max( 0.f, -characterPositionMinusHeight / size.height ) ) ); + + if( NULL == characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo(); + } } } - characterLayoutInfo.mGradientColor = gradientColor; - characterLayoutInfo.mStartPoint = startPoint; - characterLayoutInfo.mEndPoint = endPoint; + if( NULL != characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor; + characterLayoutInfo.mGradientInfo->mStartPoint = startPoint; + characterLayoutInfo.mGradientInfo->mEndPoint = endPoint; + } } else { @@ -1055,16 +1344,18 @@ void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters, float bearingOffset = 0.f; // Create ellipsize text-actor. + std::size_t characterIndex = 0u; for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator ellipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.begin(), endEllipsizeCharacterLayoutIt = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.end(); ellipsizeCharacterLayoutIt != endEllipsizeCharacterLayoutIt; - ++ellipsizeCharacterLayoutIt ) + ++ellipsizeCharacterLayoutIt, ++characterIndex ) { const TextViewProcessor::CharacterLayoutInfo& ellipsizeCharacterLayoutInfo( *ellipsizeCharacterLayoutIt ); + const TextStyle& style = *( *( relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin() + characterIndex ) ); if( isColorGlyph || ( isColorGlyph != ellipsizeCharacterLayoutInfo.mIsColorGlyph ) || - ( ellipsizeStyle != ellipsizeCharacterLayoutInfo.mStyledText.mStyle ) ) + ( ellipsizeStyle != style ) ) { // The style is different, so a new text-actor is needed. if( !ellipsizeText.IsEmpty() ) @@ -1082,8 +1373,8 @@ void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters, } // Resets the current ellipsize info. - ellipsizeText = ellipsizeCharacterLayoutInfo.mStyledText.mText; - ellipsizeStyle = ellipsizeCharacterLayoutInfo.mStyledText.mStyle; + ellipsizeText = Text( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] ); + ellipsizeStyle = style; ellipsizeSize = ellipsizeCharacterLayoutInfo.mSize; isColorGlyph = ellipsizeCharacterLayoutInfo.mIsColorGlyph; @@ -1092,10 +1383,9 @@ void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters, else { // Updates text and size with the new character. - ellipsizeText.Append( ellipsizeCharacterLayoutInfo.mStyledText.mText ); + ellipsizeText.Append( relayoutData.mTextLayoutInfo.mEllipsisText[characterIndex] ); TextViewProcessor::UpdateSize( ellipsizeSize, ellipsizeCharacterLayoutInfo.mSize ); } - } if( !ellipsizeText.IsEmpty() ) @@ -1114,16 +1404,16 @@ void EllipsizeLine( const TextView::LayoutParameters& layoutParameters, EllipsizeParameters& ellipsizeParameters, TextView::RelayoutData& relayoutData ) { - // Traverses the text layout info from the first character of the laid out line + // Traverses the text layout info from the first character of the line // to the last one setting to each character its visibility. If needed, it adds the ellipsize text (...). - // Indices to the first character of the laid out line. + // Indices to the first character of the line. TextViewProcessor::TextInfoIndices firstIndices; TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mFirstIndex, relayoutData.mTextLayoutInfo, firstIndices ); - // Indices to the last character of the laid out line. + // Indices to the last character of the line. TextViewProcessor::TextInfoIndices lastIndices; TextViewProcessor::GetIndicesFromGlobalCharacterIndex( ellipsizeParameters.mLastIndex, relayoutData.mTextLayoutInfo, @@ -1134,12 +1424,12 @@ void EllipsizeLine( const TextView::LayoutParameters& layoutParameters, ellipsizeParameters.mEllipsizeBoundary = relayoutData.mTextViewSize; ellipsizeParameters.mEllipsizeBoundary.width -= relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mSize.width; - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + firstIndices.mLineIndex, - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin() + lastIndices.mLineIndex + 1; - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + firstIndices.mParagraphIndex, + endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + lastIndices.mParagraphIndex + 1u; + paragraphLayoutIt != endParagraphLayoutIt; + ++paragraphLayoutIt ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); ellipsizeParameters.mLineFits = ellipsizeParameters.mIsLineWidthFullyVisible && ellipsizeParameters.mIsLineHeightFullyVisible && ellipsizeParameters.mIsNextLineFullyVisibleHeight; @@ -1148,124 +1438,102 @@ void EllipsizeLine( const TextView::LayoutParameters& layoutParameters, ellipsizeParameters.mEllipsizeBoundary.width = ellipsizeParameters.mLineWidth; } - bool firstGroup = true; - bool lastGroup = false; - std::size_t groupCount = 0; - bool firstWord = true; bool lastWord = false; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + firstIndices.mGroupIndex, - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin() + lastIndices.mGroupIndex + 1; - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt, ++groupCount ) + std::size_t wordCount = 0u; + + const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo; + + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin() + firstIndices.mWordIndex, + endWordLayoutIt = wordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u; + wordLayoutIt != endWordLayoutIt; + ++wordLayoutIt, ++wordCount ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - if( groupCount == lastIndices.mGroupIndex - firstIndices.mGroupIndex ) + if( wordCount == lastIndices.mWordIndex - firstIndices.mWordIndex ) { - lastGroup = true; + lastWord = true; } - std::size_t wordCount = 0; - const std::size_t firstWordIndex = firstGroup ? firstIndices.mWordIndex : 0u; - const std::size_t lastWordIndex = lastGroup ? lastIndices.mWordIndex : wordGroupLayoutInfo.mWordsLayoutInfo.size() - 1; - - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + firstWordIndex, - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin() + lastWordIndex + 1; - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt, ++wordCount ) + const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u; + const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1u; + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex, + endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1u; + characterLayoutIt != endCharacterLayoutIt; + ++characterLayoutIt ) { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - - if( lastGroup && ( wordCount == lastIndices.mWordIndex - firstWordIndex ) ) - { - lastWord = true; - } + TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - const std::size_t firstCharacterIndex = firstWord ? firstIndices.mCharacterIndex : 0u; - const std::size_t lastCharacterIndex = lastWord ? lastIndices.mCharacterIndex : wordLayoutInfo.mCharactersLayoutInfo.size() - 1; - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + firstCharacterIndex, - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin() + lastCharacterIndex + 1; - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt ) + if( ellipsizeParameters.mEllipsizeLine ) { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); + // Calculates the character visibility and whether it needs to be replace by ellipsized text. + CalculateVisibilityForEllipsize( layoutParameters, + characterLayoutInfo, + ellipsizeParameters, + relayoutData ); - if( ellipsizeParameters.mEllipsizeLine ) + if( ellipsizeParameters.mCreateEllipsizedTextActors ) { - // Calculates the character visibility and whether it needs to be replace by ellipsized text. - CalculateVisibilityForEllipsize( layoutParameters, - characterLayoutInfo, - ellipsizeParameters, - relayoutData ); - - if( ellipsizeParameters.mCreateEllipsizedTextActors ) - { - // Create ellipsize text-actors if the character needs to be replaced. - CreateEllipsizeTextActor( ellipsizeParameters, - relayoutData ); - } + // Create ellipsize text-actors if the character needs to be replaced. + CreateEllipsizeTextActor( ellipsizeParameters, + relayoutData ); } - else + } + else + { + if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) || + ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy )) { - if( ( TextView::EllipsizeEnd == layoutParameters.mExceedPolicy ) || - ( TextView::SplitEllipsizeEnd == layoutParameters.mExceedPolicy )) + if( !ellipsizeParameters.mIsLineHeightFullyVisible ) { - if( !ellipsizeParameters.mIsLineHeightFullyVisible ) - { - // Make characters invisible. - characterLayoutInfo.mIsVisible = false; - } + // Make characters invisible. + characterLayoutInfo.mIsVisible = false; } } - } // end characters - firstWord = false; - } // end words - firstGroup = false; - } // end groups - } // end lines + } + } // end characters + firstWord = false; + } // end words + } // end paragraphs } void SetTextVisible( TextView::RelayoutData& relayoutData ) { - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), + endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphLayoutIt != endParagraphLayoutIt; + ++paragraphLayoutIt ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); + std::size_t characterIndex = 0u; + + const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt ) + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); + wordLayoutIt != endWordLayoutIt; + ++wordLayoutIt ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), + endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + characterLayoutIt != endCharacterLayoutIt; + ++characterLayoutIt, ++characterIndex ) { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); + TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt ) - { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - - characterLayoutInfo.mIsVisible = true; - characterLayoutInfo.mGradientColor = Vector4::ZERO; - characterLayoutInfo.mStartPoint = Vector2::ZERO; - characterLayoutInfo.mEndPoint = Vector2::ZERO; - characterLayoutInfo.mColorAlpha = characterLayoutInfo.mStyledText.mStyle.GetTextColor().a; - } // end characters - } // end words - } // end group of words - } // end lines + characterLayoutInfo.mIsVisible = true; + delete characterLayoutInfo.mGradientInfo; + characterLayoutInfo.mGradientInfo = NULL; + characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a; + } // end characters + } // end words + } // end paragraphs // Updates the visibility for text-input.. for( std::vector::iterator it = relayoutData.mCharacterLayoutInfoTable.begin(), @@ -1288,19 +1556,19 @@ void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters // Calculates the fade thresholds (from where the text starts to fade out). If any of the fade boundaries is zero, it sets a very small value just to avoid a zero division. fadeParameters.mRightFadeBoundary = static_cast( visualParameters.mFadeBoundary.mRight ); - fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0 ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY ); + fadeParameters.mRightFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mRight > 0u ? fadeParameters.mRightFadeBoundary : MINIMUM_FADE_BOUNDARY ); fadeParameters.mRightFadeThreshold = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundary; fadeParameters.mRightFadeThresholdOffset = relayoutData.mTextViewSize.width - fadeParameters.mRightFadeBoundaryOffset; fadeParameters.mLeftFadeBoundary = static_cast( visualParameters.mFadeBoundary.mLeft ); - fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0 ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY ); + fadeParameters.mLeftFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mLeft > 0u ? fadeParameters.mLeftFadeBoundary : MINIMUM_FADE_BOUNDARY ); fadeParameters.mLeftFadeThreshold = fadeParameters.mLeftFadeBoundary; fadeParameters.mLeftFadeThresholdOffset = fadeParameters.mLeftFadeBoundaryOffset; fadeParameters.mTopFadeBoundary = static_cast( visualParameters.mFadeBoundary.mTop ); - fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0 ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY ); + fadeParameters.mTopFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mTop > 0u ? fadeParameters.mTopFadeBoundary : MINIMUM_FADE_BOUNDARY ); fadeParameters.mTopFadeThreshold = fadeParameters.mTopFadeBoundary; fadeParameters.mTopFadeThresholdOffset = fadeParameters.mTopFadeBoundaryOffset; fadeParameters.mBottomFadeBoundary = static_cast( visualParameters.mFadeBoundary.mBottom ); - fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0 ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY ); + fadeParameters.mBottomFadeBoundaryOffset = ( visualParameters.mFadeBoundary.mBottom > 0u ? fadeParameters.mBottomFadeBoundary : MINIMUM_FADE_BOUNDARY ); fadeParameters.mBottomFadeThreshold = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundary; fadeParameters.mBottomFadeThresholdOffset = relayoutData.mTextViewSize.height - fadeParameters.mBottomFadeBoundaryOffset; @@ -1310,86 +1578,81 @@ void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters fadeParameters.mTopAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mTopFadeThresholdOffset, 1.f ), Vector2( 0.f, 0.f ) ); fadeParameters.mBottomAlphaCoeficients = CalculateRectParameters( Vector2( fadeParameters.mBottomFadeThresholdOffset, 1.f ), Vector2( relayoutData.mTextViewSize.height, 0.f ) ); - // Traverses all groups of characters and calculates the visibility. + // Traverses all characters and calculates the visibility. - std::size_t infoTableCharacterIndex = 0; + std::size_t infoTableCharacterIndex = 0u; - relayoutParameters.mIndices.mLineIndex = 0; + relayoutParameters.mIndices.mParagraphIndex = 0u; - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt, ++relayoutParameters.mIndices.mLineIndex ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), + endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphLayoutIt != endParagraphLayoutIt; + ++paragraphLayoutIt, ++relayoutParameters.mIndices.mParagraphIndex ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); - relayoutParameters.mIndices.mGroupIndex = 0; + std::size_t characterIndex = 0u; + relayoutParameters.mIndices.mWordIndex = 0u; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt, ++relayoutParameters.mIndices.mGroupIndex ) + const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo; + + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); + wordLayoutIt != endWordLayoutIt; + ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - relayoutParameters.mIndices.mWordIndex = 0; + relayoutParameters.mIsFirstCharacterOfWord = true; + relayoutParameters.mWordSize = wordLayoutInfo.mSize; + relayoutParameters.mIndices.mCharacterIndex = 0u; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt, ++relayoutParameters.mIndices.mWordIndex ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), + endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + characterLayoutIt != endCharacterLayoutIt; + ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex ) { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - - relayoutParameters.mIsFirstCharacterOfWord = true; - relayoutParameters.mWordSize = wordLayoutInfo.mSize; - relayoutParameters.mIndices.mCharacterIndex = 0; - - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex ) - { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); + TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - relayoutParameters.mIsVisible = true; - fadeParameters.mIsPartiallyVisible = false; + relayoutParameters.mIsVisible = true; + fadeParameters.mIsPartiallyVisible = false; - // Calculates the visibility for the current group of characters. - CalculateVisibilityForFade( layoutParameters, - characterLayoutInfo, - relayoutParameters, - fadeParameters, - relayoutData ); + // Calculates the visibility for the current character. + CalculateVisibilityForFade( layoutParameters, + characterLayoutInfo, + *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ), + relayoutParameters, + fadeParameters, + relayoutData ); - // Updates the visibility for text-input.. - std::vector::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex; + // Updates the visibility for text-input.. + std::vector::iterator it = relayoutData.mCharacterLayoutInfoTable.begin() + infoTableCharacterIndex; - Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it ); + Toolkit::TextView::CharacterLayoutInfo& characterLayoutTableInfo( *it ); - characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible; + characterLayoutTableInfo.mIsVisible = relayoutParameters.mIsVisible; - relayoutParameters.mIsFirstCharacterOfWord = false; - } // end group of character - } // end words - } // end group of words - } // end lines + relayoutParameters.mIsFirstCharacterOfWord = false; + } // end character + } // end words + } // end paragraphs } void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParameters, const TextView::VisualParameters& visualParameters, TextView::RelayoutData& relayoutData ) { - // Traverses the laid-out lines and checks which ones doesn't fit in the text-view's boundary. + // Traverses the lines and checks which ones doesn't fit in the text-view's boundary. for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineInfoIt = relayoutData.mLines.begin(), endLineInfoIt = relayoutData.mLines.end(); lineInfoIt != endLineInfoIt; ++lineInfoIt ) { const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineInfoIt ); - // To check if a laid-out line fits in the text-view's boundary, + // To check if a line fits in the text-view's boundary, // get the position of the first character is needed and do the test - // with the laid-out line size. + // with the line size. // An bearing offset may have been applied to the first character so it's needed to // get the start position of the line. @@ -1399,15 +1662,15 @@ void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParam // Retrieves the first index and the last index of the line. ellipsizeParameters.mFirstIndex = lineInfo.mCharacterGlobalIndex; - ellipsizeParameters.mLastIndex = 0; - if( ( lineInfoIt + 1 ) != endLineInfoIt ) + ellipsizeParameters.mLastIndex = 0u; + if( ( lineInfoIt + 1u ) != endLineInfoIt ) { - const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1 ) ); - ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1; + const Toolkit::TextView::LineLayoutInfo& nextLineInfo( *( lineInfoIt + 1u ) ); + ellipsizeParameters.mLastIndex = nextLineInfo.mCharacterGlobalIndex - 1u; } else { - ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1; + ellipsizeParameters.mLastIndex = relayoutData.mCharacterLayoutInfoTable.size() - 1u; } // Retrieves the first character of the line and build the position of the line with the bearing. @@ -1451,7 +1714,7 @@ void UpdateVisibilityForEllipsize( const TextView::LayoutParameters& layoutParam { // Current line is not ellipsized. // Need to check if there is a next line and if it's not visible. If there is, current line needs to be ellipsized. - Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1; + Toolkit::TextView::LineLayoutInfoContainer::const_iterator nextLineInfoIt = lineInfoIt + 1u; if( nextLineInfoIt != endLineInfoIt ) { // Retrives the position of the first character of the line and remove @@ -1525,131 +1788,370 @@ void UpdateVisibility( const TextView::LayoutParameters& layoutParameters, } } -void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters, - TextView::RelayoutData& relayoutData ) +/** + * Creates an image actor for the emoticon. + * + * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending). + * @param[in,out] characterLayout Layout info for the character. + * @param[in] character The character. + */ +void CreateEmoticon( const TextView::VisualParameters& visualParameters, + TextViewProcessor::CharacterLayoutInfo& characterLayout, + const Character& character ) { - CurrentTextActorInfo currentTextActorInfo; + // The character is an emoticon. + ImageActor imageActor = ImageActor::DownCast( characterLayout.mGlyphActor ); + if( !imageActor ) + { + imageActor = ImageActor::New(); + + GlyphImage image = GlyphImage::New( character ); + + if( image ) + { + imageActor.SetImage( image ); + } + } + + imageActor.SetPosition( Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x, + characterLayout.mPosition.y + characterLayout.mOffset.y, + characterLayout.mPosition.z ) ); + imageActor.SetSize( characterLayout.mSize ); + + // Sets the sort modifier value. + imageActor.SetSortModifier( visualParameters.mSortModifier ); + + characterLayout.mGlyphActor = imageActor; +} + +/** + * Creates text-actors for the given text. + * + * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending). + * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info. + * @param[in,out] paragraph Layout info for the paragraph. + * @param[in,out] characterLayout Layout info for the character. + * @param[in] character The character. + * @param[in] style The character's style. + * @param[in,out] currentTextActorInfo Temporary stores the text-actor's info to be set. + * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles. + */ +void CreateTextActor( const TextView::VisualParameters& visualParameters, + TextView::RelayoutData& relayoutData, + const TextViewProcessor::ParagraphLayoutInfo& paragraph, + TextViewProcessor::CharacterLayoutInfo& characterLayout, + const Character& character, + const TextStyle& style, + CurrentTextActorInfo& currentTextActorInfo, + bool createGlyphActors ) +{ + // Set the text-actor for the current traversed text. + if( currentTextActorInfo.textActor ) + { + if( ( NULL != currentTextActorInfo.characterLayout ) && + currentTextActorInfo.characterLayout->mSetText ) + { + currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); + currentTextActorInfo.characterLayout->mSetText = false; + } + currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position ); + currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size ); + + SetVisualParameters( currentTextActorInfo, + visualParameters, + relayoutData, + paragraph.mSize.height ); + } - // Traverses the text-actor and layout info data structures. - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt ) + float rightToLeftOffset = 0.f; + if( character.IsWhiteSpace() ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + // In left to right text, a word never starts with a white space but + // it may happen in right to left text as the text is reversed. + // The text alignment and justification offset is calculated without this white space. + // It causes a missalignment which can be corrected by removing the size of the white space. + rightToLeftOffset = characterLayout.mSize.width * relayoutData.mShrinkFactor; + } + + currentTextActorInfo.text = Text( character ); + currentTextActorInfo.position = Vector3( characterLayout.mPosition.x + characterLayout.mOffset.x - rightToLeftOffset, + characterLayout.mPosition.y + characterLayout.mOffset.y, + characterLayout.mPosition.z ); + currentTextActorInfo.size = characterLayout.mSize * relayoutData.mShrinkFactor; + + currentTextActorInfo.color = style.GetTextColor(); + currentTextActorInfo.color.a = characterLayout.mColorAlpha; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt ) + TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor ); + + if( createGlyphActors ) + { + if( textActor ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + // Try to reuse first the text-actor of this character. + textActor.SetTextStyle( style ); + } + else + { + // If there is no text-actor, try to retrieve one from the cache. + textActor = relayoutData.mTextActorCache.RetrieveTextActor(); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt ) + // If still there is no text-actor, create one. + if( !textActor ) + { + TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF ); + textActor = TextActor::New( Text(), parameters ); + } + else { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); + textActor.SetTextStyle( style ); + } + } + characterLayout.mSetText = true; + currentTextActorInfo.characterLayout = &characterLayout; + + characterLayout.mGlyphActor = textActor; + } + + // Update the current text-actor. + currentTextActorInfo.textActor = textActor; +} + +/** + * Traverses the whole paragraph initializating renderable-actor handles and updating them with the new size and position. + * + * @param[in] visualParameters Some visual parameters (fade, sort modifier and blending). + * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info. + * @param[in,out] paragraph Layout info for the paragraph. + * @param[in,out] characterGlobalIndex Index to the character within the whole text. + * @param[in,out] lineLayoutInfoIndex Index to the table of lines. + * @param[in,out] createGlyphActors Whether to initialize renderable-actor handles. + */ +void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters, + TextView::RelayoutData& relayoutData, + TextViewProcessor::ParagraphLayoutInfo& paragraphLayout, + std::size_t& characterGlobalIndex, + std::size_t& lineLayoutInfoIndex, + bool createGlyphActors ) +{ + CurrentTextActorInfo currentTextActorInfo; + currentTextActorInfo.characterLayout = NULL; + + const std::size_t lineLayoutInfoSize = relayoutData.mLines.size(); // Number of lines. + bool lineLayoutEnd = false; // Whether lineLayoutInfoIndex points at the last line. + bool glyphActorCreatedForLine = false; // Whether a renderable actor has been created for this line. + + TextStyle currentStyle; // style for the current text-actor. + + TextViewProcessor::GradientInfo* currentGradientInfo = NULL; // gradient color for the current text-actor. + // start point for the current text-actor. + // end point for the current text-actor. + + bool currentIsColorGlyph = false; // Whether current glyph is an emoticon. + + std::vector textActorsToRemove; // Keep a vector of text-actors to be included into the cache. + + // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout. + const bool isRightToLeftLayout = NULL != paragraphLayout.mRightToLeftLayout; + + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayout.mWordsLayoutInfo; + Text& text = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mText : paragraphLayout.mText; + Vector& textStyles = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mTextStyles : paragraphLayout.mTextStyles; + + // In case the previous right to left layout has been cleared, all text-actors have been removed as well. If this bool is set to true, text-actors will be created again. + const bool previousRightToLeftLayoutCleared = isRightToLeftLayout ? paragraphLayout.mRightToLeftLayout->mPreviousLayoutCleared : false; - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt ) + std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph). + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end(); + wordIt != wordEndIt; + ++wordIt ) + { + TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt ); + + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end(); + characterIt != characterEndIt; + ++characterIt ) + { + TextViewProcessor::CharacterLayoutInfo& characterLayout( *characterIt ); + + // Check if there is a new line. + const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ); + + if( newLine ) + { + // Point to the next line. + ++lineLayoutInfoIndex; + if( lineLayoutInfoIndex >= lineLayoutInfoSize ) { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); + // Arrived at last line. + lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector. + } + glyphActorCreatedForLine = false; + } - if( characterLayoutInfo.mIsColorGlyph ) - { - ImageActor imageActor = ImageActor::DownCast( characterLayoutInfo.mGlyphActor ); + // Do not create a glyph-actor if there is no text. + const Character character = text[characterParagraphIndex]; + const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) ); - if( characterLayoutInfo.mSetText ) - { - GlyphImage image = GlyphImage::New( characterLayoutInfo.mStyledText.mText[0] ); + bool appendCharacter = false; - if( image ) - { - imageActor.SetImage( image ); - } - characterLayoutInfo.mSetText = false; - } + if( characterLayout.mIsColorGlyph || + ( TextViewProcessor::NoSeparator == wordLayout.mType ) || + ( ( TextViewProcessor::WordSeparator == wordLayout.mType ) && style.IsUnderlineEnabled() ) ) + { + // Do not create a glyph-actor if it's a white space (without underline) or a new paragraph character. - imageActor.SetPosition( Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x, - characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y, - characterLayoutInfo.mPosition.z ) ); - imageActor.SetSize( characterLayoutInfo.mSize ); + // Check if the character has the same gradient info than the current one. + bool differentGradientInfo = false; + if( characterLayout.mGradientInfo && currentGradientInfo ) + { + differentGradientInfo = ( characterLayout.mGradientInfo->mGradientColor != currentGradientInfo->mGradientColor ) || + ( characterLayout.mGradientInfo->mStartPoint != currentGradientInfo->mStartPoint ) || + ( characterLayout.mGradientInfo->mEndPoint != currentGradientInfo->mEndPoint ); + } + else if( ( NULL != currentGradientInfo ) || ( NULL != characterLayout.mGradientInfo ) ) + { + differentGradientInfo = true; + } - // Sets the sort modifier value. - imageActor.SetSortModifier( visualParameters.mSortModifier ); + // Creates one glyph-actor for each counsecutive group of characters, with the same style, per line, or if it's an emoticon. + if( !glyphActorCreatedForLine || + characterLayout.mIsColorGlyph || + differentGradientInfo || + ( characterLayout.mIsColorGlyph != currentIsColorGlyph ) || + ( style != currentStyle ) ) + { + characterLayout.mSetText = false; + characterLayout.mSetStyle = false; + + if( characterLayout.mIsColorGlyph ) + { + CreateEmoticon( visualParameters, + characterLayout, + character ); } else { - TextActor textActor = TextActor::DownCast( characterLayoutInfo.mGlyphActor ); - if( textActor ) - { - // There is a new text-actor. Set text and everything to the previous one. - if( currentTextActorInfo.textActor ) - { - currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); - currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position ); - currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size ); + CreateTextActor( visualParameters, + relayoutData, + paragraphLayout, + characterLayout, + character, + style, + currentTextActorInfo, + createGlyphActors || previousRightToLeftLayoutCleared ); + } - SetVisualParameters( currentTextActorInfo, - visualParameters, - relayoutData, - lineLayoutInfo.mSize.height ); - } + // There is a new style or a new line. + glyphActorCreatedForLine = true; - currentTextActorInfo.text = characterLayoutInfo.mStyledText.mText; - currentTextActorInfo.position = Vector3( characterLayoutInfo.mPosition.x + characterLayoutInfo.mOffset.x, - characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y, - characterLayoutInfo.mPosition.z ); - currentTextActorInfo.size = characterLayoutInfo.mSize * relayoutData.mShrinkFactor; + // Update style to be checked with next characters. + currentStyle = style; + currentGradientInfo = characterLayout.mGradientInfo; + currentIsColorGlyph = characterLayout.mIsColorGlyph; - currentTextActorInfo.color = characterLayoutInfo.mStyledText.mStyle.GetTextColor(); - currentTextActorInfo.color.a = characterLayoutInfo.mColorAlpha; + characterLayout.mGlyphActor.SetParentOrigin( ParentOrigin::TOP_LEFT ); + characterLayout.mGlyphActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT ); + } + else + { + DALI_ASSERT_DEBUG( !characterLayout.mIsColorGlyph && "TextViewProcessor::InitializeTextActorInfo. An image-actor doesn't store more than one emoticon." ); - currentTextActorInfo.gradientColor = characterLayoutInfo.mGradientColor; - currentTextActorInfo.startPoint = characterLayoutInfo.mStartPoint; - currentTextActorInfo.endPoint = characterLayoutInfo.mEndPoint; + // Same style than previous one. - // Update the current text-actor. - currentTextActorInfo.textActor = textActor; - } - else - { - // If this character layout has no text-actor is because this character has the same style than previous one. - // Add the character to the current text-actor and update the size. - if( characterLayoutInfo.mIsVisible && ( TextViewProcessor::LineSeparator != wordLayoutInfo.mType ) ) - { - currentTextActorInfo.text.Append( characterLayoutInfo.mStyledText.mText ); + // Add the character to the current text-actor and update the size. + appendCharacter = true; - currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayoutInfo.mPosition.y + characterLayoutInfo.mOffset.y ) ); - currentTextActorInfo.size.width += characterLayoutInfo.mSize.width * relayoutData.mShrinkFactor; - currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ); - } - } + TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor ); + if( textActor ) + { + // There is a previously created text-actor for this character. + // If this character has another one put it into the cache. + textActor.SetText( "" ); + textActorsToRemove.push_back( textActor ); } - } // end characters - } // end words - if( !currentTextActorInfo.text.IsEmpty() ) + if( characterLayout.mGlyphActor ) + { + characterLayout.mGlyphActor.Reset(); + } + } + } // no white space / new paragraph char + else + { + appendCharacter = true; + } + + if( appendCharacter ) { - if( currentTextActorInfo.textActor ) + // Add the character to the current text-actor and update the size. + if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) ) { - currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); - currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position ); - currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size ); + currentTextActorInfo.text.Append( character ); - SetVisualParameters( currentTextActorInfo, - visualParameters, - relayoutData, - lineLayoutInfo.mSize.height ); + currentTextActorInfo.position.y = std::min( currentTextActorInfo.position.y, ( characterLayout.mPosition.y + characterLayout.mOffset.y ) ); + currentTextActorInfo.size.width += characterLayout.mSize.width * relayoutData.mShrinkFactor; + currentTextActorInfo.size.height = std::max( currentTextActorInfo.size.height, characterLayout.mSize.height * relayoutData.mShrinkFactor ); } } - } //end groups of words - } // end lines + ++characterGlobalIndex; + ++characterParagraphIndex; + } // characters + } // words + + if( !currentTextActorInfo.text.IsEmpty() ) + { + if( currentTextActorInfo.textActor ) + { + if( ( NULL != currentTextActorInfo.characterLayout ) && + currentTextActorInfo.characterLayout->mSetText ) + { + currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); + currentTextActorInfo.characterLayout->mSetText = false; + } + currentTextActorInfo.textActor.SetPosition( currentTextActorInfo.position ); + currentTextActorInfo.textActor.SetSize( currentTextActorInfo.size ); + + SetVisualParameters( currentTextActorInfo, + visualParameters, + relayoutData, + paragraphLayout.mSize.height ); + } + } + + // Insert the spare text-actors into the cache. + relayoutData.mTextActorCache.InsertTextActors( textActorsToRemove ); +} + +void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters, + TextView::RelayoutData& relayoutData, + bool createGlyphActors ) +{ + if( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() ) + { + // nothing to do if there is no paragraphs. + return; + } + + std::size_t characterGlobalIndex = 0u; // Index to the global character (within the whole text). + std::size_t lineLayoutInfoIndex = 0u; // Index to the line info. + + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphIt != paragraphEndIt; + ++paragraphIt ) + { + TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); + + UpdateTextActorInfoForParagraph( visualParameters, + relayoutData, + paragraph, + characterGlobalIndex, + lineLayoutInfoIndex, + createGlyphActors ); + } // paragraphs + + // Set visual parameters for ellipsis renderable actors. for( std::vector::iterator it = relayoutData.mEllipsizedGlyphActors.begin(), endIt = relayoutData.mEllipsizedGlyphActors.end(); it != endIt; @@ -1670,90 +2172,89 @@ void UpdateTextActorInfo( const TextView::VisualParameters& visualParameters, void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelayout::TextUnderlineStatus& textUnderlineStatus ) { - // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line. + // Traverse the whole text to find all groups of consecutive underlined characters in the same line. // - // Note that relayoutData.mTextLayoutInfo contains layout info per line but these lines are the result of split the whole text every time a '\n' is found. - // According with the layout option, one of this lines could be laid-out in more than one. + // Note that relayoutData.mTextLayoutInfo contains layout info per paragraph but these paragraphs are the result of split the whole text every time a '\n' is found. + // According with the layout option, one of this paragraphs could be laid-out in more than one line. - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineIt != lineEndIt; - ++lineIt ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphIt != paragraphEndIt; + ++paragraphIt ) { - TextViewProcessor::LineLayoutInfo& line( *lineIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); + + std::size_t characterIndex = 0u; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end(); - groupIt != groupEndIt; - ++groupIt ) + const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo; + + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end(); + wordIt != wordEndIt; + ++wordIt ) { - TextViewProcessor::WordGroupLayoutInfo& group( *groupIt ); + TextViewProcessor::WordLayoutInfo& word( *wordIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end(); - wordIt != wordEndIt; - ++wordIt ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); + characterIt != characterEndIt; + ++characterIt, ++characterIndex ) { - TextViewProcessor::WordLayoutInfo& word( *wordIt ); + TextViewProcessor::CharacterLayoutInfo& character( *characterIt ); + const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); - characterIt != characterEndIt; - ++characterIt ) + // Check if current character is the first of a new line + const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) && + ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex ); + if( isNewLine ) { - TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt ); + ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one. + } - // Check if current character is the first of a new laid-out line - const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) && - ( textUnderlineStatus.mCharacterGlobalIndex == ( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ).mCharacterGlobalIndex ); - if( isNewLine ) + if( style.IsUnderlineEnabled() ) + { + if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't. + isNewLine ) // Current character is underlined and is the first of current line. { - ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one. - } + // Create a new underline info for the current underlined characters. + UnderlineInfo underlineInfo; + underlineInfo.mMaxHeight = character.mSize.height; + underlineInfo.mMaxThickness = character.mUnderlineThickness; + underlineInfo.mPosition = character.mUnderlinePosition; + + textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo ); - if( characterGroup.mStyledText.mStyle.GetUnderline() ) + textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined. + } + else { - if( !textUnderlineStatus.mCurrentUnderlineStatus || // Current character is underlined but previous one it wasn't. - isNewLine ) // Current character is underlined and is the first of current laid-out line. - { - // Create a new underline info for the current underlined characters. - UnderlineInfo underlineInfo; - underlineInfo.mMaxHeight = characterGroup.mSize.height; - underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness; - underlineInfo.mPosition = characterGroup.mUnderlinePosition; + // Retrieve last underline info and update it if current underline thickness is bigger. + UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1u ) ); - textUnderlineStatus.mUnderlineInfo.push_back( underlineInfo ); + underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, character.mSize.height ); - textUnderlineStatus.mCurrentUnderlineStatus = true; // Set the current text is underlined. - } - else + if( character.mUnderlineThickness > underlineInfo.mMaxThickness ) { - // Retrieve last underline info and update it if current underline thickness is bigger. - UnderlineInfo& underlineInfo( *( textUnderlineStatus.mUnderlineInfo.end() - 1 ) ); - - underlineInfo.mMaxHeight = std::max( underlineInfo.mMaxHeight, characterGroup.mSize.height ); - - if( characterGroup.mUnderlineThickness > underlineInfo.mMaxThickness ) - { - underlineInfo.mMaxThickness = characterGroup.mUnderlineThickness; - underlineInfo.mPosition = characterGroup.mUnderlinePosition; - } + underlineInfo.mMaxThickness = character.mUnderlineThickness; + underlineInfo.mPosition = character.mUnderlinePosition; } } - else - { - textUnderlineStatus.mCurrentUnderlineStatus = false; - } + } + else + { + textUnderlineStatus.mCurrentUnderlineStatus = false; + } - ++textUnderlineStatus.mCharacterGlobalIndex; - } // end group of characters. - } // end words. - } // end group of words. - } // end lines. + ++textUnderlineStatus.mCharacterGlobalIndex; + } // end characters. + } // end words. + } // end paragraphs. } void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) { - // Stores for each group of consecutive underlined text in each laid-out line its maximum thicknes, its position of that thickness and the maximum character's height. + // Stores for each group of consecutive underlined characters in each line its maximum thicknes, its position of that thickness and the maximum character's height. TextViewRelayout::TextUnderlineStatus textUnderlineStatus; - // Traverse the whole text to find all groups of consecutive underlined characters in the same laid-out line. + // Traverse the whole text to find all groups of consecutive underlined characters in the same line. CalculateUnderlineInfo( relayoutData, textUnderlineStatus ); if( textUnderlineStatus.mUnderlineInfo.empty() ) @@ -1777,109 +2278,104 @@ void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) // Whether current text is underlined. textUnderlineStatus.mCurrentUnderlineStatus = false; - textUnderlineStatus.mCharacterGlobalIndex = 0; - textUnderlineStatus.mLineGlobalIndex = 0; + textUnderlineStatus.mCharacterGlobalIndex = 0u; + textUnderlineStatus.mLineGlobalIndex = 0u; float currentLineHeight = 0.f; float currentLineAscender = 0.f; - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), lineEndIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineIt != lineEndIt; - ++lineIt ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), paragraphEndIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphIt != paragraphEndIt; + ++paragraphIt ) { - TextViewProcessor::LineLayoutInfo& line( *lineIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); + std::size_t characterIndex = 0u; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupIt = line.mWordGroupsLayoutInfo.begin(), groupEndIt = line.mWordGroupsLayoutInfo.end(); - groupIt != groupEndIt; - ++groupIt ) + const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo; + + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end(); + wordIt != wordEndIt; + ++wordIt ) { - TextViewProcessor::WordGroupLayoutInfo& group( *groupIt ); + TextViewProcessor::WordLayoutInfo& word( *wordIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = group.mWordsLayoutInfo.begin(), wordEndIt = group.mWordsLayoutInfo.end(); - wordIt != wordEndIt; - ++wordIt ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); + characterIt != characterEndIt; + ++characterIt, ++characterIndex ) { - TextViewProcessor::WordLayoutInfo& word( *wordIt ); + TextViewProcessor::CharacterLayoutInfo& character( *characterIt ); + TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); - characterIt != characterEndIt; - ++characterIt ) - { - TextViewProcessor::CharacterLayoutInfo& characterGroup( *characterIt ); + // Check if current character is the first of a new line - // Check if current character is the first of a new laid-out line + bool isNewLine = false; - bool isNewLine = false; + if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) + { + const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ); + isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex ); - if( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) + if( isNewLine ) { - const Toolkit::TextView::LineLayoutInfo& lineLayoutInfo( *( relayoutData.mLines.begin() + textUnderlineStatus.mLineGlobalIndex ) ); - isNewLine = ( textUnderlineStatus.mCharacterGlobalIndex == lineLayoutInfo.mCharacterGlobalIndex ); - - if( isNewLine ) - { - currentLineHeight = lineLayoutInfo.mSize.height; - currentLineAscender = lineLayoutInfo.mAscender; - ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one. - } + currentLineHeight = lineLayoutInfo.mSize.height; + currentLineAscender = lineLayoutInfo.mAscender; + ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one. } + } - if( characterGroup.mStyledText.mStyle.GetUnderline() ) + if( style.IsUnderlineEnabled() ) + { + if( textUnderlineStatus.mCurrentUnderlineStatus ) { - if( textUnderlineStatus.mCurrentUnderlineStatus ) + if( isNewLine ) { - if( isNewLine ) + // Retrieves the thickness and position for the next piece of underlined text. + if( underlineInfoIt < underlineInfoEndIt ) { - // Retrieves the thickness and position for the next piece of underlined text. + ++underlineInfoIt; if( underlineInfoIt < underlineInfoEndIt ) { - ++underlineInfoIt; - if( underlineInfoIt < underlineInfoEndIt ) - { - underlineInfo = *underlineInfoIt; - } + underlineInfo = *underlineInfoIt; } } } + } - textUnderlineStatus.mCurrentUnderlineStatus = true; - - // Sets the underline's thickness. - characterGroup.mStyledText.mStyle.SetUnderlineThickness( underlineInfo.mMaxThickness ); + textUnderlineStatus.mCurrentUnderlineStatus = true; - // Before setting the position it needs to be adjusted to match the base line. - const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( characterGroup.mSize.height - characterGroup.mAscender ); - const float positionOffset = ( underlineInfo.mMaxHeight - characterGroup.mSize.height ) - bearingOffset; + // Before setting the position it needs to be adjusted to match the base line. + const float bearingOffset = ( currentLineHeight - currentLineAscender ) - ( character.mSize.height - character.mAscender ); + const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset; - // Sets the underline's position. - characterGroup.mStyledText.mStyle.SetUnderlinePosition( underlineInfo.mPosition - positionOffset ); + // Sets the underline's parameters. + style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset ); - // Mark the group of characters to be set the new style into the text-actor. - characterGroup.mSetStyle = true; - } - else + // Mark the character to be set the new style into the text-actor. + character.mSetStyle = true; + } + else + { + if( textUnderlineStatus.mCurrentUnderlineStatus ) { - if( textUnderlineStatus.mCurrentUnderlineStatus ) - { - textUnderlineStatus.mCurrentUnderlineStatus = false; + textUnderlineStatus.mCurrentUnderlineStatus = false; - // Retrieves the thickness and position for the next piece of underlined text. + // Retrieves the thickness and position for the next piece of underlined text. + if( underlineInfoIt < underlineInfoEndIt ) + { + ++underlineInfoIt; if( underlineInfoIt < underlineInfoEndIt ) { - ++underlineInfoIt; - if( underlineInfoIt < underlineInfoEndIt ) - { - underlineInfo = *underlineInfoIt; - } + underlineInfo = *underlineInfoIt; } } } + } - ++textUnderlineStatus.mCharacterGlobalIndex; - } // end of group of characters. - } // end of word. - } // end of group of words. - } // end of lines. + ++textUnderlineStatus.mCharacterGlobalIndex; + } // end of characters. + } // end of word. + } // end of paragraphs. } void RemoveGlyphActors( Actor textView, @@ -1897,59 +2393,45 @@ void RemoveGlyphActors( Actor textView, } } -void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMask, - Actor textView, +void InsertToTextView( Actor textView, TextView::RelayoutData& relayoutData ) { - const bool insertToTextView = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_VIEW; - const bool insertToTextActorList = relayoutOperationMask & TextView::RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST; - // Add text-actors to the text-view. - for( TextViewProcessor::LineLayoutInfoContainer::iterator lineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.begin(), - endLineLayoutIt = relayoutData.mTextLayoutInfo.mLinesLayoutInfo.end(); - lineLayoutIt != endLineLayoutIt; - ++lineLayoutIt ) + for( TextViewProcessor::ParagraphLayoutInfoContainer::iterator paragraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin(), + endParagraphLayoutIt = relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end(); + paragraphLayoutIt != endParagraphLayoutIt; + ++paragraphLayoutIt ) { - TextViewProcessor::LineLayoutInfo& lineLayoutInfo( *lineLayoutIt ); + TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); + + // Retrieve the layout info to traverse. If there is right to left text it retrieves the right to left layout. + const bool isRightToLeftLayout = NULL != paragraphLayoutInfo.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraphLayoutInfo.mRightToLeftLayout->mWordsLayoutInfo : paragraphLayoutInfo.mWordsLayoutInfo; - for( TextViewProcessor::WordGroupLayoutInfoContainer::iterator groupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.begin(), - endGroupLayoutIt = lineLayoutInfo.mWordGroupsLayoutInfo.end(); - groupLayoutIt != endGroupLayoutIt; - ++groupLayoutIt ) + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); + wordLayoutIt != endWordLayoutIt; + ++wordLayoutIt ) { - TextViewProcessor::WordGroupLayoutInfo& wordGroupLayoutInfo( *groupLayoutIt ); + TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = wordGroupLayoutInfo.mWordsLayoutInfo.end(); - wordLayoutIt != endWordLayoutIt; - ++wordLayoutIt ) + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), + endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + characterLayoutIt != endCharacterLayoutIt; + ++characterLayoutIt ) { - TextViewProcessor::WordLayoutInfo& wordLayoutInfo( *wordLayoutIt ); + TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), - endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt ) + if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor. { - TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - - if( characterLayoutInfo.mIsVisible && characterLayoutInfo.mGlyphActor ) // White spaces and '\n' characters doesn't have a text-actor. - { - //Add to the text-view. - if( insertToTextView ) - { - textView.Add( characterLayoutInfo.mGlyphActor ); - } - if( insertToTextActorList ) - { - relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor ); - } - } - } // end group of character - } // end words - } // end group of words - } // end lines + //Add to the text-view. + textView.Add( characterLayoutInfo.mGlyphActor ); + relayoutData.mGlyphActors.push_back( characterLayoutInfo.mGlyphActor ); + } + } // end character + } // end words + } // end paragraphs for( std::vector::iterator it = relayoutData.mEllipsizedGlyphActors.begin(), endIt = relayoutData.mEllipsizedGlyphActors.end(); @@ -1959,14 +2441,8 @@ void InsertToTextView( const TextView::RelayoutOperationMask relayoutOperationMa RenderableActor glyphActor = ( *it ); //Add to the text-view. - if( insertToTextView ) - { - textView.Add( glyphActor ); - } - if( insertToTextActorList ) - { - relayoutData.mGlyphActors.push_back( glyphActor ); - } + textView.Add( glyphActor ); + relayoutData.mGlyphActors.push_back( glyphActor ); } relayoutData.mEllipsizedGlyphActors.clear(); } @@ -1984,7 +2460,8 @@ RenderableActor CreateGlyphActor( const Text& text, const TextStyle& style, Text else { // The text-actor cache is empty. Create a new one. - textActor = TextActor::New( text, style, false, true ); + TextActorParameters parameters( style, TextActorParameters::FONT_DETECTION_OFF ); + textActor = TextActor::New( text, parameters ); } return textActor;