From: Victor Cebollada Date: Wed, 10 Sep 2014 14:58:06 +0000 (+0100) Subject: TextView - Right to Left implementation. X-Git-Tag: accepted/tizen/common/20140925.172059~10 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=c11191b4322a0687606b3e7f05db0a31f85403cc TextView - Right to Left implementation. * Text and style is stored in the paragraph instead inside the character. * If a paragraph has bidirectional text, it stores the minimum common data needed to reorder a line. * Before creating text-actors, text-view reorders the bidirectional text, keeping the logical order. Change-Id: Iff9c7e9223eb9c9a7d15b1e41cc6dc2f47096aa0 Signed-off-by: Victor Cebollada --- diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor-Types.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor-Types.cpp index 7cb03fe..44e25c0 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor-Types.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor-Types.cpp @@ -67,12 +67,11 @@ int UtcDaliTextViewDefaultConstructorDestructor_PT(void) DALI_TEST_EQUALS( characterLayoutInfo.mUnderlineThickness, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo.mUnderlinePosition, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_CHECK( !characterLayoutInfo.mGlyphActor ); - DALI_TEST_CHECK( characterLayoutInfo.mStyledText.mText.IsEmpty() ); DALI_TEST_EQUALS( characterLayoutInfo.mColorAlpha, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_CHECK( NULL == characterLayoutInfo.mGradientInfo ); DALI_TEST_CHECK( characterLayoutInfo.mIsVisible ); - DALI_TEST_CHECK( characterLayoutInfo.mSetText ); - DALI_TEST_CHECK( characterLayoutInfo.mSetStyle ); + DALI_TEST_CHECK( !characterLayoutInfo.mSetText ); + DALI_TEST_CHECK( !characterLayoutInfo.mSetStyle ); TextViewProcessor::WordLayoutInfo wordLayoutInfo; DALI_TEST_EQUALS( wordLayoutInfo.mSize, Vector2::ZERO, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); @@ -116,7 +115,6 @@ int UtcDaliTextViewCopyConstructorOperator(void) characterLayoutInfo.mUnderlinePosition = 1.f; characterLayoutInfo.mGlyphActor = TextActor::New( "Hello" ); - characterLayoutInfo.mStyledText.mText = Text( "Hello" ); TextViewProcessor::GradientInfo* info = new TextViewProcessor::GradientInfo(); info->mGradientColor = Vector4( 1.f, 1.f, 1.f, 1.f ); @@ -141,7 +139,6 @@ int UtcDaliTextViewCopyConstructorOperator(void) DALI_TEST_EQUALS( characterLayoutInfo1.mUnderlineThickness, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo1.mUnderlinePosition, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_CHECK( characterLayoutInfo1.mGlyphActor ); - DALI_TEST_EQUALS( characterLayoutInfo1.mStyledText.mText.GetLength(), 5u, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo1.mColorAlpha, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo1.mGradientInfo->mGradientColor, Vector4( 1.f, 1.f, 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo1.mGradientInfo->mStartPoint, Vector2( 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); @@ -159,7 +156,6 @@ int UtcDaliTextViewCopyConstructorOperator(void) DALI_TEST_EQUALS( characterLayoutInfo2.mUnderlineThickness, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo2.mUnderlinePosition, 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_CHECK( characterLayoutInfo2.mGlyphActor ); - DALI_TEST_EQUALS( characterLayoutInfo2.mStyledText.mText.GetLength(), 5u, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo2.mColorAlpha, 0.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo2.mGradientInfo->mGradientColor, Vector4( 1.f, 1.f, 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); DALI_TEST_EQUALS( characterLayoutInfo2.mGradientInfo->mStartPoint, Vector2( 1.f, 1.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION ); diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor.cpp index 2fb823f..8fef857 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Processor.cpp @@ -22,6 +22,7 @@ // Internal headers are allowed here #include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -53,11 +54,10 @@ struct BeginsRightToLeftCharacterTest bool TestBeginsRightToLeftCharacter( const std::string& description, const std::string& input, const bool result, const char* location ) { - // Creates a styled text with the markup or plain string. - MarkupProcessor::StyledTextArray styledText; - MarkupProcessor::GetStyledTextArray( input, styledText, true ); + // Creates a text with the string. + Text text( input ); - const bool ret = ( result == TextProcessor::BeginsRightToLeftCharacter( styledText ) ); + const bool ret = ( result == TextProcessor::BeginsRightToLeftCharacter( text ) ); if( !ret ) { @@ -79,11 +79,10 @@ struct ContainsRightToLeftCharacterTest bool TestContainsRightToLeftCharacter( const std::string& description, const std::string& input, const bool result, const char* location ) { - // Creates a styled text with the markup or plain string. - MarkupProcessor::StyledTextArray styledText; - MarkupProcessor::GetStyledTextArray( input, styledText, true ); + // Creates a text with the string. + Text text( input ); - const bool ret = ( result == TextProcessor::ContainsRightToLeftCharacter( styledText ) ); + const bool ret = ( result == TextProcessor::ContainsRightToLeftCharacter( text ) ); if( !ret ) { @@ -141,10 +140,12 @@ bool TestSplitInParagraphs( const SplitInParagraphsTest& test, const char* locat MarkupProcessor::StyledTextArray styledText; MarkupProcessor::GetStyledTextArray( test.inputText, styledText, true ); - std::vector paragraphs; + std::vector paragraphs; + std::vector< Vector > styles; TextProcessor::SplitInParagraphs( styledText, - paragraphs ); + paragraphs, + styles ); if( paragraphs.size() != test.resultNumberOfParagraphs ) { @@ -163,24 +164,23 @@ struct SplitInWordsTest { std::string inputText; - std::size_t resultNumberOfWords; + std::size_t resultNumberOfSeparators; }; bool TestSplitInWords( const SplitInWordsTest& test, const char* location ) { - // Creates a styled text with the markup or plain string. - MarkupProcessor::StyledTextArray styledText; - MarkupProcessor::GetStyledTextArray( test.inputText, styledText, true ); + // Creates a text with the string. + Text text( test.inputText ); - std::vector words; + Vector positions; - TextProcessor::SplitInWords( styledText, - words ); + TextProcessor::SplitInWords( text, + positions ); - if( words.size() != test.resultNumberOfWords ) + if( positions.Count() != test.resultNumberOfSeparators ) { tet_printf( "Fail. %s", location ); - tet_printf( "Different number of words, result %d, expected result %d", words.size(), test.resultNumberOfWords ); + tet_printf( "Different number of separators, result %d, expected result %d", positions.Count(), test.resultNumberOfSeparators ); return false; } @@ -236,10 +236,14 @@ int UtcDaliTextViewSplitInWords(void) { { std::string( "Hello world, hello word!" ), - 7 + 3u }, + { + std::string( "Hello world\n" ), + 2u + } }; - const std::size_t numberOfTests( 1 ); + const std::size_t numberOfTests( 2u ); for( std::size_t index = 0; index < numberOfTests; ++index ) { diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Relayout-Utilities.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Relayout-Utilities.cpp index 255c96a..c556e08 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Relayout-Utilities.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView-Relayout-Utilities.cpp @@ -88,6 +88,7 @@ bool TestCalculateLineLayout( const CalculateLineLayoutTest& test, const char* // Creaqte indices. TextViewProcessor::TextInfoIndices indices( 0u, test.wordIndex, test.characterIndex ); + indices.mCharacterParagraphIndex = test.characterParagraphIndex; // Get the input paragraph. TextViewProcessor::ParagraphLayoutInfo inputParagraphLayout; diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView.cpp index ee43cbd..dc2a363 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextView.cpp @@ -66,6 +66,7 @@ struct SplitParagraphTest std::string input; std::size_t wordIndex; std::size_t characterIndex; + std::size_t characterParagraphIndex; float lineHeightOffset; std::string firstResult; std::string lastResult; @@ -141,10 +142,6 @@ void Print( const TextViewProcessor::CharacterLayoutInfo& character ) { std::cout << "[" << textActor.GetText() << "]"; } - else - { - std::cout << "{" << character.mStyledText.mText.GetText() << "}"; - } } void Print( const TextViewProcessor::WordLayoutInfo& word ) @@ -186,21 +183,13 @@ void Print( const TextViewProcessor::TextLayoutInfo& text ) std::cout << "||" << std::endl; } -std::string GetText( const TextViewProcessor::CharacterLayoutInfo& character ) -{ - return character.mStyledText.mText.GetText(); -} - -std::string GetText( const TextViewProcessor::WordLayoutInfo& word ) +std::string GetText( const TextViewProcessor::WordLayoutInfo& word, const Text& paragraphText ) { - std::string text; + Text text; - for( TextViewProcessor::CharacterLayoutInfoContainer::const_iterator it = word.mCharactersLayoutInfo.begin(), endIt = word.mCharactersLayoutInfo.end(); it != endIt; ++it ) - { - text += GetText( *it ); - } + paragraphText.GetSubText( word.mFirstCharacter, word.mFirstCharacter + word.mCharactersLayoutInfo.size() - 1u, text ); - return text; + return text.GetText(); } std::string GetText( const TextViewProcessor::ParagraphLayoutInfo& paragraph ) @@ -209,7 +198,7 @@ std::string GetText( const TextViewProcessor::ParagraphLayoutInfo& paragraph ) for( TextViewProcessor::WordLayoutInfoContainer::const_iterator it = paragraph.mWordsLayoutInfo.begin(), endIt = paragraph.mWordsLayoutInfo.end(); it != endIt; ++it ) { - text += GetText( *it ); + text += GetText( *it, paragraph.mText ); } return text; @@ -288,27 +277,6 @@ bool TestEqual( const TextViewProcessor::CharacterLayoutInfo& character1, return false; } - text1 = character1.mStyledText.mText.GetText(); - style1 = character1.mStyledText.mStyle; - - text2 = character2.mStyledText.mText.GetText(); - style2 = character2.mStyledText.mStyle; - - if( text1 != text2 ) - { - return false; - } - - if( style1 != style2 ) - { - std::cout << " style1 : " << std::endl; - TextViewProcessor::dbgPrint( style1 ); - - std::cout << " style2 : " << std::endl; - TextViewProcessor::dbgPrint( style2 ); - return false; - } - return true; } @@ -557,6 +525,7 @@ bool TestSplitWord( const std::string& description, const std::string& input, co * @param input The input word. * @param wordIndex Index to the word within the paragraph where to split it. * @param characterIndex Where to split the word. + * @param characterIndex Character index within the paragraph. * @param lineHeightOffset Offset between lines. * @param firstResult First part of the split paragraph. * @param lastResult Last part of the split paragraph. @@ -568,6 +537,7 @@ bool TestSplitParagraph( const std::string& description, const std::string& input, size_t wordIndex, size_t characterIndex, + size_t characterParagraphIndex, float lineHeightOffset, const std::string& firstResult, const std::string& lastResult, @@ -589,7 +559,6 @@ bool TestSplitParagraph( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), relayoutData ); @@ -616,7 +585,6 @@ bool TestSplitParagraph( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), firstRelayoutData ); @@ -643,7 +611,6 @@ bool TestSplitParagraph( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..."), true ), lastRelayoutData ); @@ -660,6 +627,7 @@ bool TestSplitParagraph( const std::string& description, TextViewProcessor::ParagraphLayoutInfo lastParagraphLayoutInfo; TextViewProcessor::TextInfoIndices indices( 0, wordIndex, characterIndex ); + indices.mCharacterParagraphIndex = characterParagraphIndex; SplitParagraph( indices, PointSize( lineHeightOffset ), @@ -812,7 +780,6 @@ bool TestMergeParagraphs( const std::string& description, const std::string& inp static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), firstRelayoutData ); @@ -838,7 +805,6 @@ bool TestMergeParagraphs( const std::string& description, const std::string& inp static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), lastRelayoutData ); @@ -864,7 +830,6 @@ bool TestMergeParagraphs( const std::string& description, const std::string& inp static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), resultRelayoutData ); @@ -998,7 +963,6 @@ bool TestRemoveWordsFromParagraph( const std::string& description, const std::st static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), relayoutData ); @@ -1024,7 +988,6 @@ bool TestRemoveWordsFromParagraph( const std::string& description, const std::st static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), resultRelayoutData ); @@ -1099,7 +1062,6 @@ bool TestUpdateTextInfo( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), relayoutData ); @@ -1117,7 +1079,6 @@ bool TestUpdateTextInfo( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ), resultRelayoutData ); @@ -1128,7 +1089,6 @@ bool TestUpdateTextInfo( const std::string& description, static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Center, PointSize( lineHeightOffset ), - std::string( "..." ), true ); switch( operation ) @@ -1254,15 +1214,6 @@ int UtcDaliTextViewCreateTextInfo(void) layoutInfo12.mBearing = BEARING_12; layoutInfo12.mAscender = ASCENDER_12; - TextStyle style10; - style10.SetFontName( "" ); - style10.SetFontPointSize( PointSize( 10.f ) ); - TextStyle style12; - style12.SetFontName( "" ); - - layoutInfo12.mStyledText.mStyle = style12; - layoutInfo10.mStyledText.mStyle = style10; - // Words TextViewProcessor::WordLayoutInfo wordLayout1, wordLayout2, wordLayout3, wordLayout4; @@ -1272,46 +1223,33 @@ int UtcDaliTextViewCreateTextInfo(void) wordLayout1.mAscender = ASCENDER_12; wordLayout1.mType = TextViewProcessor::NoSeparator; - layoutInfo12.mStyledText.mText = Text( "H" ); wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // H - layoutInfo12.mStyledText.mText = Text( "e" ); wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // e - layoutInfo12.mStyledText.mText = Text( "l" ); wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo12 ); // l - layoutInfo10.mStyledText.mText = Text( "l" ); wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo10 ); // l - layoutInfo10.mStyledText.mText = Text( "o" ); wordLayout1.mCharactersLayoutInfo.push_back( layoutInfo10 ); // o // (white space) wordLayout2.mSize = Size( ADVANCE_10, HEIGHT_10 ); wordLayout2.mAscender = ASCENDER_10; wordLayout2.mType = TextViewProcessor::WordSeparator; - layoutInfo10.mStyledText.mText = Text( " " ); wordLayout2.mCharactersLayoutInfo.push_back( layoutInfo10 ); // (white space) // world! wordLayout3.mSize = Size( 2.f * ADVANCE_10 + 4.f * ADVANCE_12, HEIGHT_12 ); wordLayout3.mAscender = ASCENDER_12; wordLayout3.mType = TextViewProcessor::NoSeparator; - layoutInfo10.mStyledText.mText = Text( "w" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo10 ); // w - layoutInfo10.mStyledText.mText = Text( "o" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo10 ); // o - layoutInfo12.mStyledText.mText = Text( "r" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // r - layoutInfo12.mStyledText.mText = Text( "l" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // l - layoutInfo12.mStyledText.mText = Text( "d" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // d - layoutInfo12.mStyledText.mText = Text( "!" ); wordLayout3.mCharactersLayoutInfo.push_back( layoutInfo12 ); // ! // (new paragraph character) wordLayout4.mSize = Size( 0.f, HEIGHT_12 ); wordLayout4.mAscender = ASCENDER_12; wordLayout4.mType = TextViewProcessor::ParagraphSeparator; - layoutInfo12.mStyledText.mText = Text( "\n" ); layoutInfo12.mSize.width = 0.f; wordLayout4.mCharactersLayoutInfo.push_back( layoutInfo12 ); // (new paragraph char) @@ -1533,7 +1471,6 @@ int UtcDaliTextViewUpdateTextInfo(void) std::string( "Hello worldhello world" ) }, // * Remove RTL text within LTR - /* TODO check this when RTL text is working { std::string( "Remove within the same paragraph, RTL text within LTR." ), Remove, @@ -1544,7 +1481,6 @@ int UtcDaliTextViewUpdateTextInfo(void) 0.f, std::string( "Hello worlello world" ) }, - */ // * Remove whole paragraph { std::string( "Remove whole paragraph" ), @@ -1668,7 +1604,7 @@ int UtcDaliTextViewUpdateTextInfo(void) std::string( "Touch me\nhello\nworld" ) }, }; - const std::size_t numberOfTests( 21u ); + const std::size_t numberOfTests( 22u ); for( std::size_t index = 0u; index < numberOfTests; ++index ) { @@ -1697,6 +1633,7 @@ int UtcDaliTextViewSplitParagraph(void) std::string( "Helloooo wooorld שלום עולם text text" ), 0, 0, + 0, 3.f, std::string( "" ), std::string( "Helloooo wooorld שלום עולם text text" ), @@ -1706,6 +1643,7 @@ int UtcDaliTextViewSplitParagraph(void) std::string( "Helloooo wooorld שלום עולם text text" ), 10, 4, + 36, 0.f, std::string( "Helloooo wooorld שלום עולם text text" ), std::string( "" ), @@ -1715,16 +1653,17 @@ int UtcDaliTextViewSplitParagraph(void) std::string("Hello world, hello world"), 2, 4, + 10, 0.f, std::string("Hello worl"), std::string("d, hello world") - } - /* TODO RTL + }, { std::string( "Split paragraph, wordPosition 6, position 0." ), std::string( "Helloooo wooorld שלום עולם text text" ), 6, 0, + 21, 0.f, std::string( "Helloooo wooorld שלום " ), std::string( "עולם text text" ), @@ -1734,6 +1673,7 @@ int UtcDaliTextViewSplitParagraph(void) std::string( "Helloooo wooorld שלום עולם text text" ), 4, 0, + 17, 0.f, std::string( "Helloooo wooorld " ), std::string( "שלום עולם text text" ), @@ -1743,13 +1683,13 @@ int UtcDaliTextViewSplitParagraph(void) std::string( "Helloooo wooorld שלום עולם text text" ), 8, 0, + 27, 6.f, std::string( "Helloooo wooorld שלום עולם " ), std::string( "text text" ), }, - */ }; - const std::size_t numberOfTests( 3u ); + const std::size_t numberOfTests( 6u ); for( std::size_t index = 0u; index < numberOfTests; ++index ) { @@ -1759,6 +1699,7 @@ int UtcDaliTextViewSplitParagraph(void) test.input, test.wordIndex, test.characterIndex, + test.characterParagraphIndex, test.lineHeightOffset, test.firstResult, test.lastResult, @@ -1969,7 +1910,6 @@ int UtcDaliTextViewMergeParagraph01(void) 0.f, std::string( "Hello world, this is a whole paragraph" ) }, - /* TODO RTL { std::string( "Merge paragraphs: last starting with RTL text and first ending with RTL" ), std::string( "Hello world, שלום" ), @@ -1984,7 +1924,6 @@ int UtcDaliTextViewMergeParagraph01(void) 3.f, std::string( "Hello world, שלום עולם, hello world." ) }, - */ { std::string( "Merge paragraphs. Don't merge words" ), std::string( "Hello world," ), @@ -2000,7 +1939,7 @@ int UtcDaliTextViewMergeParagraph01(void) std::string( "Hello world, this is a whole paragraph" ) }, }; - const std::size_t numberOfTests( 4u ); + const std::size_t numberOfTests( 6u ); for( std::size_t index = 0u; index < numberOfTests; ++index ) { 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 fab32ca..d39300e 100644 --- a/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp +++ b/base/dali-toolkit/internal/controls/text-view/relayout-utilities.cpp @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -19,7 +19,11 @@ #include // INTERNAL INCLUDES +#include +#include +#include #include +#include // EXTERNAL INCLUDES #include @@ -213,7 +217,7 @@ struct CurrentTextActorInfo Vector3 position; Size size; Vector4 color; - TextViewProcessor::GradientInfo* gradientInfo; + TextViewProcessor::CharacterLayoutInfo* characterLayout; }; void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo, @@ -222,11 +226,12 @@ void SetVisualParameters( CurrentTextActorInfo& currentTextActorInfo, const float lineHeight ) { currentTextActorInfo.textActor.SetTextColor( currentTextActorInfo.color ); - if( NULL != currentTextActorInfo.gradientInfo ) + if( ( NULL != currentTextActorInfo.characterLayout ) && + ( NULL != currentTextActorInfo.characterLayout->mGradientInfo ) ) { - currentTextActorInfo.textActor.SetGradientColor( currentTextActorInfo.gradientInfo->mGradientColor ); - currentTextActorInfo.textActor.SetGradientStartPoint( currentTextActorInfo.gradientInfo->mStartPoint ); - currentTextActorInfo.textActor.SetGradientEndPoint( currentTextActorInfo.gradientInfo->mEndPoint ); + 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 @@ -343,6 +348,278 @@ void CalculateLineLayout( float parentWidth, subLineInfo.mMaxAscender *= shrinkFactor; } + +/** + * 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 ); @@ -513,8 +790,11 @@ 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 = 0u; // Index to the first position of the vector which stores all line justification info. - std::size_t infoTableCharacterIndex = 0u; + // 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.mParagraphIndex = 0u; @@ -527,10 +807,16 @@ void UpdateAlignment( const TextView::LayoutParameters& layoutParameters, float justificationOffset = 0.f; + 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; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); + 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 ) { @@ -541,19 +827,24 @@ void UpdateAlignment( const TextView::LayoutParameters& layoutParameters, for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex ) + ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++characterGlobalIndex ) { TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); - // Calculate line justification offset. - if( lineJustificationIndex < relayoutData.mLineJustificationInfo.size() ) + // Check if there is a new line. + const bool newLine = !lineLayoutEnd && ( characterGlobalIndex == relayoutData.mLines[lineLayoutInfoIndex].mCharacterGlobalIndex ); + + if( newLine ) { - const TextView::LineJustificationInfo lineJustificationInfo( *( relayoutData.mLineJustificationInfo.begin() + lineJustificationIndex ) ); + // Calculate line justification offset. + justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, relayoutData.mLines[lineLayoutInfoIndex].mSize.width ); - if( relayoutParameters.mIndices == lineJustificationInfo.mIndices ) + // Point to the next line. + ++lineLayoutInfoIndex; + if( lineLayoutInfoIndex >= lineLayoutInfoSize ) { - justificationOffset = CalculateJustificationOffset( layoutParameters.mLineJustification, relayoutData.mTextSizeForRelayoutOption.width, lineJustificationInfo.mLineLength ); - ++lineJustificationIndex; // increase the index to point the next position in the vector. + // Arrived at last line. + lineLayoutEnd = true; // Avoids access out of bounds in the relayoutData.mLines vector. } } @@ -565,7 +856,7 @@ void UpdateAlignment( const TextView::LayoutParameters& layoutParameters, // 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; + std::vector::iterator infoTableIt = relayoutData.mCharacterLayoutInfoTable.begin() + characterGlobalIndex; Toolkit::TextView::CharacterLayoutInfo& characterTableInfo( *infoTableIt ); characterTableInfo.mPosition.x = positionOffset.x + characterLayoutInfo.mOffset.x; @@ -646,7 +937,7 @@ void UpdateLayoutInfoTable( Vector4& minMaxXY, characterLayoutInfo.mSize.height * relayoutData.mShrinkFactor ), positionOffset, ( TextViewProcessor::ParagraphSeparator == wordLayoutInfo.mType ), - false, // VCC set the correct direction if needed. + false, true, descender ); @@ -657,6 +948,7 @@ void UpdateLayoutInfoTable( Vector4& minMaxXY, void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters, TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo, + const TextStyle& style, RelayoutParameters& relayoutParameters, FadeParameters& fadeParameters, TextView::RelayoutData& relayoutData ) @@ -813,35 +1105,40 @@ void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& lay Vector2 startPoint = Vector2::ZERO; Vector2 endPoint = Vector2::ZERO; - if( NULL == characterLayoutInfo.mGradientInfo ) - { - characterLayoutInfo.mGradientInfo = new TextViewProcessor::GradientInfo(); - } - if( !( rightFadeOut && leftFadeOut ) ) { // 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(); + } } } @@ -850,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.mGradientInfo->mGradientColor = gradientColor; - characterLayoutInfo.mGradientInfo->mStartPoint = startPoint; - characterLayoutInfo.mGradientInfo->mEndPoint = endPoint; + if( NULL != characterLayoutInfo.mGradientInfo ) + { + characterLayoutInfo.mGradientInfo->mGradientColor = gradientColor; + characterLayoutInfo.mGradientInfo->mStartPoint = startPoint; + characterLayoutInfo.mGradientInfo->mEndPoint = endPoint; + } } else { @@ -1034,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() ) @@ -1061,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; @@ -1071,7 +1383,7 @@ 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 ); } } @@ -1131,8 +1443,11 @@ void EllipsizeLine( const TextView::LayoutParameters& layoutParameters, std::size_t wordCount = 0u; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + firstIndices.mWordIndex, - endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin() + lastIndices.mWordIndex + 1u; + 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 ) { @@ -1193,9 +1508,13 @@ void SetTextVisible( TextView::RelayoutData& relayoutData ) ++paragraphLayoutIt ) { 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::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); wordLayoutIt != endWordLayoutIt; ++wordLayoutIt ) { @@ -1204,14 +1523,14 @@ void SetTextVisible( TextView::RelayoutData& relayoutData ) for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt ) + ++characterLayoutIt, ++characterIndex ) { TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); characterLayoutInfo.mIsVisible = true; delete characterLayoutInfo.mGradientInfo; characterLayoutInfo.mGradientInfo = NULL; - characterLayoutInfo.mColorAlpha = characterLayoutInfo.mStyledText.mStyle.GetTextColor().a; + characterLayoutInfo.mColorAlpha = ( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) )->GetTextColor().a; } // end characters } // end words } // end paragraphs @@ -1272,10 +1591,14 @@ void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters { TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); + std::size_t characterIndex = 0u; relayoutParameters.mIndices.mWordIndex = 0u; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); + 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 ) { @@ -1288,7 +1611,7 @@ void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); characterLayoutIt != endCharacterLayoutIt; - ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex ) + ++characterLayoutIt, ++relayoutParameters.mIndices.mCharacterIndex, ++infoTableCharacterIndex, ++characterIndex ) { TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo( *characterLayoutIt ); @@ -1298,6 +1621,7 @@ void UpdateVisibilityForFade( const TextView::LayoutParameters& layoutParameters // Calculates the visibility for the current character. CalculateVisibilityForFade( layoutParameters, characterLayoutInfo, + *( *( paragraphLayoutInfo.mTextStyles.Begin() + characterIndex ) ), relayoutParameters, fadeParameters, relayoutData ); @@ -1524,7 +1848,12 @@ void CreateTextActor( const TextView::VisualParameters& visualParameters, // Set the text-actor for the current traversed text. if( currentTextActorInfo.textActor ) { - currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); + 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 ); @@ -1534,8 +1863,18 @@ void CreateTextActor( const TextView::VisualParameters& visualParameters, paragraph.mSize.height ); } + float rightToLeftOffset = 0.f; + if( character.IsWhiteSpace() ) + { + // 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, + 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; @@ -1543,8 +1882,6 @@ void CreateTextActor( const TextView::VisualParameters& visualParameters, currentTextActorInfo.color = style.GetTextColor(); currentTextActorInfo.color.a = characterLayout.mColorAlpha; - currentTextActorInfo.gradientInfo = characterLayout.mGradientInfo; - TextActor textActor = TextActor::DownCast( characterLayout.mGlyphActor ); if( createGlyphActors ) @@ -1570,6 +1907,9 @@ void CreateTextActor( const TextView::VisualParameters& visualParameters, textActor.SetTextStyle( style ); } } + characterLayout.mSetText = true; + currentTextActorInfo.characterLayout = &characterLayout; + characterLayout.mGlyphActor = textActor; } @@ -1589,12 +1929,13 @@ void CreateTextActor( const TextView::VisualParameters& visualParameters, */ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualParameters, TextView::RelayoutData& relayoutData, - TextViewProcessor::ParagraphLayoutInfo& paragraph, + 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. @@ -1610,14 +1951,24 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa 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; + std::size_t characterParagraphIndex = 0u; // Index to the character (within the paragraph). - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end(); + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end(); wordIt != wordEndIt; ++wordIt ) { - TextViewProcessor::WordLayoutInfo& word( *wordIt ); + TextViewProcessor::WordLayoutInfo& wordLayout( *wordIt ); - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); + for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = wordLayout.mCharactersLayoutInfo.begin(), characterEndIt = wordLayout.mCharactersLayoutInfo.end(); characterIt != characterEndIt; ++characterIt ) { @@ -1639,14 +1990,14 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa } // Do not create a glyph-actor if there is no text. - const Character character = characterLayout.mStyledText.mText[0u]; // there are only one character per character layout. - const TextStyle& style = characterLayout.mStyledText.mStyle; + const Character character = text[characterParagraphIndex]; + const TextStyle& style = *( *( textStyles.Begin() + characterParagraphIndex ) ); bool appendCharacter = false; if( characterLayout.mIsColorGlyph || - !character.IsWhiteSpace() || // A new paragraph character is also a white space. - ( character.IsWhiteSpace() && style.IsUnderlineEnabled() ) ) + ( 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. @@ -1673,9 +2024,6 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa characterLayout.mSetText = false; characterLayout.mSetStyle = false; - // There is a new style or a new line. - glyphActorCreatedForLine = true; - if( characterLayout.mIsColorGlyph ) { CreateEmoticon( visualParameters, @@ -1686,14 +2034,17 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa { CreateTextActor( visualParameters, relayoutData, - paragraph, + paragraphLayout, characterLayout, character, style, currentTextActorInfo, - createGlyphActors ); + createGlyphActors || previousRightToLeftLayoutCleared ); } + // There is a new style or a new line. + glyphActorCreatedForLine = true; + // Update style to be checked with next characters. currentStyle = style; currentGradientInfo = characterLayout.mGradientInfo; @@ -1734,7 +2085,7 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa if( appendCharacter ) { // Add the character to the current text-actor and update the size. - if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != word.mType ) ) + if( characterLayout.mIsVisible && ( TextViewProcessor::ParagraphSeparator != wordLayout.mType ) ) { currentTextActorInfo.text.Append( character ); @@ -1753,14 +2104,19 @@ void UpdateTextActorInfoForParagraph( const TextView::VisualParameters& visualPa { if( currentTextActorInfo.textActor ) { - currentTextActorInfo.textActor.SetText( currentTextActorInfo.text ); + 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 ); + paragraphLayout.mSize.height ); } } @@ -1827,7 +2183,12 @@ void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelay { TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end(); + std::size_t characterIndex = 0u; + + 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 ) { @@ -1835,9 +2196,10 @@ void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelay for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); characterIt != characterEndIt; - ++characterIt ) + ++characterIt, ++characterIndex ) { TextViewProcessor::CharacterLayoutInfo& character( *characterIt ); + const TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) ); // Check if current character is the first of a new line const bool isNewLine = ( textUnderlineStatus.mLineGlobalIndex < relayoutData.mLines.size() ) && @@ -1847,7 +2209,7 @@ void CalculateUnderlineInfo( TextView::RelayoutData& relayoutData, TextViewRelay ++textUnderlineStatus.mLineGlobalIndex; // If it's a new line, point to the next one. } - if( character.mStyledText.mStyle.IsUnderlineEnabled() ) + 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. @@ -1927,8 +2289,12 @@ void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) ++paragraphIt ) { TextViewProcessor::ParagraphLayoutInfo& paragraph( *paragraphIt ); + std::size_t characterIndex = 0u; + + const bool isRightToLeftLayout = NULL != paragraph.mRightToLeftLayout; + TextViewProcessor::WordLayoutInfoContainer& wordsLayoutInfo = isRightToLeftLayout ? paragraph.mRightToLeftLayout->mWordsLayoutInfo : paragraph.mWordsLayoutInfo; - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end(); + for( TextViewProcessor::WordLayoutInfoContainer::iterator wordIt = wordsLayoutInfo.begin(), wordEndIt = wordsLayoutInfo.end(); wordIt != wordEndIt; ++wordIt ) { @@ -1936,9 +2302,10 @@ void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterIt = word.mCharactersLayoutInfo.begin(), characterEndIt = word.mCharactersLayoutInfo.end(); characterIt != characterEndIt; - ++characterIt ) + ++characterIt, ++characterIndex ) { TextViewProcessor::CharacterLayoutInfo& character( *characterIt ); + TextStyle& style = *( *( paragraph.mTextStyles.Begin() + characterIndex ) ); // Check if current character is the first of a new line @@ -1957,7 +2324,7 @@ void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) } } - if( character.mStyledText.mStyle.IsUnderlineEnabled() ) + if( style.IsUnderlineEnabled() ) { if( textUnderlineStatus.mCurrentUnderlineStatus ) { @@ -1982,7 +2349,7 @@ void SetUnderlineInfo( TextView::RelayoutData& relayoutData ) const float positionOffset = ( underlineInfo.mMaxHeight - character.mSize.height ) - bearingOffset; // Sets the underline's parameters. - character.mStyledText.mStyle.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset ); + style.SetUnderline( true, underlineInfo.mMaxThickness, underlineInfo.mPosition - positionOffset ); // Mark the character to be set the new style into the text-actor. character.mSetStyle = true; @@ -2038,8 +2405,12 @@ void InsertToTextView( Actor textView, { TextViewProcessor::ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphLayoutIt ); - for( TextViewProcessor::WordLayoutInfoContainer::iterator wordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.begin(), - endWordLayoutIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); + // 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::WordLayoutInfoContainer::iterator wordLayoutIt = wordsLayoutInfo.begin(), + endWordLayoutIt = wordsLayoutInfo.end(); wordLayoutIt != endWordLayoutIt; ++wordLayoutIt ) { diff --git a/base/dali-toolkit/internal/controls/text-view/relayout-utilities.h b/base/dali-toolkit/internal/controls/text-view/relayout-utilities.h index aff3ae3..5150186 100644 --- a/base/dali-toolkit/internal/controls/text-view/relayout-utilities.h +++ b/base/dali-toolkit/internal/controls/text-view/relayout-utilities.h @@ -19,8 +19,9 @@ */ // INTERNAL INCLUDES +#include +#include #include -#include namespace Dali { @@ -265,6 +266,13 @@ void CalculateLineLayout( float parentWidth, LineLayoutInfo& layoutInfo ); /** + * Reorders the text layout of each line of each paragraph of the text. + * + * @param[in,out] relayoutData The text-view's data structures. + */ +void ReorderRightToLeftLayout( TextView::RelayoutData& relayoutData ); + +/** * Calculates the \e x offset position for the whole text. * * @param[in] horizontalTextAlignment The horizontal alignment type. @@ -358,12 +366,14 @@ void UpdateLayoutInfoTable( Vector4& minMaxXY, * * @param[in] layoutParameters The layout parameters. * @param[in] characterLayoutInfo Character layout info. + * @param[in] style The style of the character. Used to get the color (and alpha) of the character. * @param[in,out] relayoutParameters Temporary layout parameters. * @param[in,out] fadeParameters Temporary fade parameters. * @param[in,out] relayoutData The text-view's data structures. */ void CalculateVisibilityForFade( const Internal::TextView::LayoutParameters& layoutParameters, TextViewProcessor::CharacterLayoutInfo& characterLayoutInfo, + const TextStyle& style, RelayoutParameters& relayoutParameters, FadeParameters& fadeParameters, TextView::RelayoutData& relayoutData ); @@ -391,7 +401,11 @@ void CreateEllipsizeTextActor( const EllipsizeParameters& ellipsizeParameters, TextView::RelayoutData& relayoutData ); /** + * Replace the text which exceeds the boundary by the ellipsis text. * + * @param[in] layoutParameters The layout parameters. + * @param[in,out] ellipsisParameters Temporary ellipsis parameters. + * @param[in,out] relayoutData The text-view's data structures. */ void EllipsizeLine( const TextView::LayoutParameters& layoutParameters, EllipsizeParameters& ellipsizeParameters, diff --git a/base/dali-toolkit/internal/controls/text-view/split-by-char-policies.cpp b/base/dali-toolkit/internal/controls/text-view/split-by-char-policies.cpp index 10933a7..613b0a6 100644 --- a/base/dali-toolkit/internal/controls/text-view/split-by-char-policies.cpp +++ b/base/dali-toolkit/internal/controls/text-view/split-by-char-policies.cpp @@ -72,14 +72,6 @@ Vector3 NoShrinkWhenExceedPosition( const TextViewRelayout::RelayoutParameters& 1.f, // Shrink factor subLineInfo ); - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - Toolkit::TextView::LineLayoutInfo lineInfo; lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line. lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. @@ -234,10 +226,11 @@ void Relayout( Actor textView, { if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION ) { - relayoutData.mLineJustificationInfo.clear(); CalculateSizeAndPosition( layoutParameters, relayoutData ); + TextViewRelayout::ReorderRightToLeftLayout( relayoutData ); + TextViewRelayout::SetUnderlineInfo( relayoutData ); } diff --git a/base/dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.cpp b/base/dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.cpp index 98ee6b8..f74966d 100644 --- a/base/dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.cpp +++ b/base/dali-toolkit/internal/controls/text-view/split-by-new-line-char-policies.cpp @@ -71,14 +71,6 @@ Vector3 SplitPosition( const TextViewRelayout::RelayoutParameters& relayoutParam 1.f, // Shrink factor subLineInfo ); - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - Toolkit::TextView::LineLayoutInfo lineInfo; lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line. lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. @@ -158,22 +150,6 @@ void CalculateSizeAndPosition( const TextView::LayoutParameters& layoutParameter relayoutParameters.mWordSize = wordLayoutInfo.mSize; relayoutParameters.mIndices.mCharacterIndex = 0u; - if( relayoutParameters.mIsNewLine ) - { - // Stores some info to calculate the line justification in a post-process. - const bool isSplitOriginal = layoutParameters.mExceedPolicy == TextView::SplitOriginal; - - if( !isSplitOriginal ) - { - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = relayoutParameters.mParagraphSize.width; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - } - } - for( TextViewProcessor::CharacterLayoutInfoContainer::iterator characterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), endCharacterLayoutIt = wordLayoutInfo.mCharactersLayoutInfo.end(); characterLayoutIt != endCharacterLayoutIt; @@ -290,10 +266,11 @@ void Relayout( Actor textView, { if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION ) { - relayoutData.mLineJustificationInfo.clear(); CalculateSizeAndPosition( layoutParameters, relayoutData ); + TextViewRelayout::ReorderRightToLeftLayout( relayoutData ); + TextViewRelayout::SetUnderlineInfo( relayoutData ); } diff --git a/base/dali-toolkit/internal/controls/text-view/split-by-word-policies.cpp b/base/dali-toolkit/internal/controls/text-view/split-by-word-policies.cpp index 4081150..b5bd9f6 100644 --- a/base/dali-toolkit/internal/controls/text-view/split-by-word-policies.cpp +++ b/base/dali-toolkit/internal/controls/text-view/split-by-word-policies.cpp @@ -83,14 +83,6 @@ Vector3 OriginalPosition( const TextViewRelayout::RelayoutParameters& relayoutPa } } - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - Toolkit::TextView::LineLayoutInfo lineInfo; lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line. lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. @@ -147,14 +139,6 @@ Vector3 SplitWhenExceedPosition( const TextViewRelayout::RelayoutParameters& rel 1.f, // Shrink factor. subLineInfo ); - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - Toolkit::TextView::LineLayoutInfo lineInfo; lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line. lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. @@ -211,14 +195,6 @@ Vector3 ShrinkWidthWhenExceedPosition( const TextViewRelayout::RelayoutParameter relayoutData.mShrinkFactor, subLineInfo ); - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = relayoutParameters.mIndices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); - Toolkit::TextView::LineLayoutInfo lineInfo; lineInfo.mCharacterGlobalIndex = relayoutParameters.mCharacterGlobalIndex; // Index to the first character of the next line. lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. @@ -242,8 +218,6 @@ void CalculatePositionsForShrinkWhenExceed( TextView::RelayoutData& relayoutData const float parentWidth = relayoutData.mTextViewSize.width; TextViewProcessor::TextLayoutInfo& textLayoutInfo = relayoutData.mTextLayoutInfo; - relayoutData.mLineJustificationInfo.clear(); - // Reset the text height. This value is returned in order to shrink further or not the text. newTextHeight = 0.f; @@ -332,14 +306,6 @@ void CalculatePositionsForShrinkWhenExceed( TextView::RelayoutData& relayoutData lineInfo.mSize = Size( subLineInfo.mLineLength, subLineInfo.mMaxCharHeight ); // Size of this piece of paragraph. lineInfo.mAscender = subLineInfo.mMaxAscender; // Ascender of this piece of paragraph. relayoutData.mLines.push_back( lineInfo ); - - // Stores some info to calculate the line justification in a post-process. - TextView::LineJustificationInfo justificationInfo; - - justificationInfo.mIndices = indices; - justificationInfo.mLineLength = subLineInfo.mLineLength; - - relayoutData.mLineJustificationInfo.push_back( justificationInfo ); } else { @@ -618,10 +584,11 @@ void Relayout( Actor textView, { if( relayoutOperationMask & TextView::RELAYOUT_SIZE_POSITION ) { - relayoutData.mLineJustificationInfo.clear(); CalculateSizeAndPosition( layoutParameters, relayoutData ); + TextViewRelayout::ReorderRightToLeftLayout( relayoutData ); + TextViewRelayout::SetUnderlineInfo( relayoutData ); } diff --git a/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.cpp b/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.cpp new file mode 100644 index 0000000..8131b47 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace TextProcessor +{ + +BidirectionalParagraphInfo::BidirectionalParagraphInfo() +: mDirection( FRIBIDI_TYPE_ON ), + mCharactersTypeBuffer(), + mLevelsBuffer(), + mLogicalUnicodeBuffer() +{ +} + +BidirectionalParagraphInfo::~BidirectionalParagraphInfo() +{ +} + +BidirectionalParagraphInfo::BidirectionalParagraphInfo( const BidirectionalParagraphInfo& info ) +: mDirection( info.mDirection ), + mCharactersTypeBuffer( info.mCharactersTypeBuffer ), + mLevelsBuffer( info.mLevelsBuffer ), + mLogicalUnicodeBuffer( info.mLogicalUnicodeBuffer ) +{ +} + +BidirectionalParagraphInfo& BidirectionalParagraphInfo::operator=( const BidirectionalParagraphInfo& info ) +{ + if( this != &info ) + { + mDirection = info.mDirection; + mCharactersTypeBuffer = info.mCharactersTypeBuffer; + mLevelsBuffer = info.mLevelsBuffer; + mLogicalUnicodeBuffer = info.mLogicalUnicodeBuffer; + } + + return *this; +} + +BidirectionalLineInfo::BidirectionalLineInfo() +: mCharacterParagraphIndex(), + mNumberOfCharacters(), + mText(), + mVisualToLogicalMap(), + mLogicalToVisualMap() +{ +} + +BidirectionalLineInfo::~BidirectionalLineInfo() +{ +} + +BidirectionalLineInfo::BidirectionalLineInfo( const BidirectionalLineInfo& info ) +: mCharacterParagraphIndex( info.mCharacterParagraphIndex ), + mNumberOfCharacters( info.mNumberOfCharacters ), + mText( info.mText ), + mVisualToLogicalMap( info.mVisualToLogicalMap ), + mLogicalToVisualMap( info.mLogicalToVisualMap ) +{ +} + +BidirectionalLineInfo& BidirectionalLineInfo::operator=( const BidirectionalLineInfo& info ) +{ + if( this != &info ) + { + mCharacterParagraphIndex = info.mCharacterParagraphIndex; + mNumberOfCharacters = info.mNumberOfCharacters; + mText = info.mText; + mVisualToLogicalMap = info.mVisualToLogicalMap; + mLogicalToVisualMap = info.mLogicalToVisualMap; + } + + return *this; +} + +bool BeginsRightToLeftCharacter( const Text& text ) +{ + for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) + { + Character::CharacterDirection direction = text[i].GetCharacterDirection(); + if( direction != Character::Neutral ) + { + return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak ); + } + } + + return false; +} + +bool ContainsRightToLeftCharacter( const Dali::Text& text ) +{ + for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) + { + Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection(); + if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) ) + { + return true; + } + } + + return false; +} + +void ProcessBidirectionalText( Text& paragraph, BidirectionalParagraphInfo* info ) +{ + if( paragraph.IsEmpty() ) + { + // nothing to do if the paragraph is empty. + return; + } + + const std::size_t stringSize = paragraph.GetText().size(); + + // Text buffer in logical order. Coded in unicode. + info->mLogicalUnicodeBuffer.resize( stringSize + 1u, 0u ); + FriBidiChar* logicalUnicodeBufferPointer = &info->mLogicalUnicodeBuffer[0u]; + + // Converts from utf8 to unicode. + const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, paragraph.GetText().c_str(), stringSize, logicalUnicodeBufferPointer ); + + // Character type buffer. + info->mCharactersTypeBuffer.resize( length, 0u ); + + // Levels buffer. + info->mLevelsBuffer.resize( length, 0u ); + + // Joining type buffer. + std::vector joiningTypeBuffer; + joiningTypeBuffer.resize( length, 0u ); + + // Pointers to the buffers. + FriBidiCharType* charactersTypeBufferPointer = &info->mCharactersTypeBuffer[0u]; + FriBidiLevel* levelsBufferPointer = &info->mLevelsBuffer[0u]; + FriBidiJoiningType* joiningTypeBufferPointer = &joiningTypeBuffer[0u]; + + // Retrieves the type of each character. + fribidi_get_bidi_types( logicalUnicodeBufferPointer, length, charactersTypeBufferPointer ); + + // Retrieves the paragraph direction. + info->mDirection = fribidi_get_par_direction( charactersTypeBufferPointer, length ); + + // Retrieve the embedding levels. + fribidi_get_par_embedding_levels( charactersTypeBufferPointer, length, &info->mDirection, levelsBufferPointer ); + + // Retrieve the joining types. + fribidi_get_joining_types( logicalUnicodeBufferPointer, length, joiningTypeBufferPointer ); + + fribidi_join_arabic( charactersTypeBufferPointer, length, levelsBufferPointer, joiningTypeBufferPointer ); + + const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC; + + fribidi_shape( flags, levelsBufferPointer, length, joiningTypeBufferPointer, logicalUnicodeBufferPointer ); + + std::vector bidiTextConverted; + + bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6. + // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character. + + fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, logicalUnicodeBufferPointer, length, &bidiTextConverted[0] ); + + paragraph = Text( &bidiTextConverted[0u] ); +} + +void ReorderLine( BidirectionalParagraphInfo* paragraphInfo, + BidirectionalLineInfo* lineInfo ) +{ + const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC; + + lineInfo->mVisualToLogicalMap.Resize( lineInfo->mNumberOfCharacters, 0u ); + lineInfo->mLogicalToVisualMap.Resize( lineInfo->mNumberOfCharacters, 0u ); + + std::vector visualUnicodeBuffer; + visualUnicodeBuffer.insert( visualUnicodeBuffer.end(), + paragraphInfo->mLogicalUnicodeBuffer.begin() + lineInfo->mCharacterParagraphIndex, + paragraphInfo->mLogicalUnicodeBuffer.begin() + ( lineInfo->mCharacterParagraphIndex + lineInfo->mNumberOfCharacters ) ); + + // Pointers to the buffers. + FriBidiCharType* charactersTypeBufferPointer = ¶graphInfo->mCharactersTypeBuffer[lineInfo->mCharacterParagraphIndex]; + FriBidiLevel* levelsBufferPointer = ¶graphInfo->mLevelsBuffer[lineInfo->mCharacterParagraphIndex]; + FriBidiChar* visualUnicodeBufferPointer = &visualUnicodeBuffer[0u]; + FriBidiStrIndex* visualToLogicalMapPointer = &lineInfo->mVisualToLogicalMap[0u]; + + // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table. + for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index ) + { + lineInfo->mVisualToLogicalMap[ index ] = index; + } + + fribidi_reorder_line( flags, + charactersTypeBufferPointer, + lineInfo->mNumberOfCharacters, + 0u, + paragraphInfo->mDirection, + levelsBufferPointer, + visualUnicodeBufferPointer, + visualToLogicalMapPointer ); + + // Fill the logical to visual mapping table. + for( std::size_t index = 0u; index < lineInfo->mNumberOfCharacters; ++index ) + { + lineInfo->mLogicalToVisualMap[ lineInfo->mVisualToLogicalMap[ index ] ] = index; + } + + std::vector bidiTextConverted; + + bidiTextConverted.resize( lineInfo->mNumberOfCharacters * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6. + // Currently Dali doesn't support this UTF-8 extension. + // Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character. + + fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualUnicodeBufferPointer, lineInfo->mNumberOfCharacters, &bidiTextConverted[0u] ); + + lineInfo->mText = Text( &bidiTextConverted[0u] ); +} + +} // namespace TextProcessor + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h b/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h new file mode 100644 index 0000000..77d6ee9 --- /dev/null +++ b/base/dali-toolkit/internal/controls/text-view/text-processor-bidirectional-info.h @@ -0,0 +1,157 @@ +#ifndef __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__ +#define __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__ + +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include +#include + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Internal +{ + +namespace TextProcessor +{ + +/** + * Stores the text containing right to left characters and info for each character needed by fribidi to reorder a line. + */ +struct BidirectionalParagraphInfo +{ + /** + * Default constructor. + * + * Initializes all members to their default values. + */ + BidirectionalParagraphInfo(); + + /** + * Default destructor. + */ + ~BidirectionalParagraphInfo(); + + /** + * Copy constructor. + */ + BidirectionalParagraphInfo( const BidirectionalParagraphInfo& info ); + + /** + * Assignment operator. + */ + BidirectionalParagraphInfo& operator=( const BidirectionalParagraphInfo& info ); + + FriBidiParType mDirection; ///< The paragraph direction. + std::vector mCharactersTypeBuffer; ///< Character type buffer. + std::vector mLevelsBuffer; ///< Levels buffer. + std::vector mLogicalUnicodeBuffer; ///< Text buffer in logical order. Coded in unicode. +}; + +/** + * Stores the reordered text, the conversion tables for a paragraph's line, + * the index to the first character of the line and the number of characters. + */ +struct BidirectionalLineInfo +{ + /** + * Default constructor. + * + * Initializes all members to their default values. + */ + BidirectionalLineInfo(); + + /** + * Default destructor. + */ + ~BidirectionalLineInfo(); + + /** + * Copy constructor. + */ + BidirectionalLineInfo( const BidirectionalLineInfo& info ); + + /** + * Assignment operator. + */ + BidirectionalLineInfo& operator=( const BidirectionalLineInfo& info ); + + std::size_t mCharacterParagraphIndex; ///< Index within the paragraph of the first character of the line. + std::size_t mNumberOfCharacters; ///< Number of characters of the line. + Text mText; ///< Text in visual order. + Vector mVisualToLogicalMap; ///< The character position map from the visual output text to the logical input text. + Vector mLogicalToVisualMap; ///< The character position map from the logical input text to the visual output text. +}; + +/** + * Whether the text begins with right-to-left (bidirectional) character. + * @param [in] text The given text. + * @return \e true if the text begins right-to-left character. + */ +bool BeginsRightToLeftCharacter( const Text& text ); + +/** + * Whether the text contains any right-to-left (bidirectional) character. + * @param [in] text The given text. + * @return \e true if the text contains right-to-left character. + */ +bool ContainsRightToLeftCharacter( const Text& text ); + +/** + * Processes a bidirectional paragraph's text. + * + * It stores the paragraph's direction (the direction of the first non neutral character), + * the direction of all characters, and the ligatures in case of arabic glyphs. + * + * It doesn't reorder the paragraph as this task must be done per line. + * The stored info is needed to reorder each line of the paragraph. + * + * @param[in] paragraph The paragraph to be processed. + * @param[out] info Struct containing the needed info to reorder each line of the paragraph. + */ +void ProcessBidirectionalText( Text& paragraph, + BidirectionalParagraphInfo* info ); + +/** + * Reorders one line of the paragraph according the Unicode Bidirectional Algorithm. + * + * The result is the text in the visual order and the conversion tables: logical <--> visual order + * + * @param[in] paragraphInfo Struct containing the needed info to reorder each line of the paragraph. + * @param[in,out] lineInfo Struct containing (in) A character index pointing the first character of the line and the number of characters, (out) the reordered line and the conversion tables. + */ +void ReorderLine( BidirectionalParagraphInfo* paragraphInfo, + BidirectionalLineInfo* lineInfo ); + +} // namespace TextProcessor + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_PROCESSOR_BIDIRECTIONAL_INFO_H__ + diff --git a/base/dali-toolkit/internal/controls/text-view/text-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-processor.cpp index 1f32dd9..b41b841 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-processor.cpp @@ -18,9 +18,6 @@ // FILE HEADER #include -// EXTERNAL INCLUDES -#include - namespace Dali { @@ -33,234 +30,78 @@ namespace Internal namespace TextProcessor { -void SplitInParagraphs( const MarkupProcessor::StyledTextArray& text, - std::vector& paragraphs ) +void SplitInParagraphs( const MarkupProcessor::StyledTextArray& styledTextArray, + std::vector& paragraphs, + std::vector< Vector >& styles ) { - MarkupProcessor::StyledTextArray paragraph; - for( MarkupProcessor::StyledTextArray::const_iterator it = text.begin(), endIt = text.end(); it != endIt; ++it ) + // Stores the text for a paragraph. + Text paragraph; + + // Stores the styles for each character of the paragraph. + Vector stylesForParagraph; + + // Traverses all styled texts of the array. + for( MarkupProcessor::StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it ) { const MarkupProcessor::StyledText& styledText( *it ); + // Traverses all the characters of the styled text (It may have more than one). for( size_t i = 0u, length = styledText.mText.GetLength(); i < length; ++i ) { const Dali::Character character = styledText.mText[i]; if( character.IsNewLine() ) // LF { - Text newText( character ); - MarkupProcessor::StyledText newStyledText( newText, styledText.mStyle ); - paragraph.push_back( newStyledText ); + // The character is a new paragraph character. - paragraphs.push_back( paragraph ); - paragraph.clear(); - } - else - { - Text newText( character ); - MarkupProcessor::StyledText newStyledText( newText, styledText.mStyle ); - paragraph.push_back( newStyledText ); - } - } - } + // Append the new paragraph character. + paragraph.Append( character ); - // This paragraph could be empty if the last character of the previous paragraph is a 'new paragraph' character - // and is the last of the text. - paragraphs.push_back( paragraph ); -} + // Creates a new text style for the character and insert it to the vector of styles for that paragraph. + TextStyle* style = new TextStyle( styledText.mStyle ); + stylesForParagraph.PushBack( style ); -void SplitInWords( const MarkupProcessor::StyledTextArray& paragraph, - std::vector& words ) -{ - MarkupProcessor::StyledTextArray word; - for( MarkupProcessor::StyledTextArray::const_iterator it = paragraph.begin(), endIt = paragraph.end(); it != endIt; ++it ) - { - const MarkupProcessor::StyledText& styledText( *it ); - const Dali::Character character = styledText.mText[0u]; + // Inserts the paragraph and the styles to the vector of paragraphs and the vector of styles. + paragraphs.push_back( paragraph ); + styles.push_back( stylesForParagraph ); - if( character.IsWhiteSpace() ) - { - // When a separator is found, the previous word is added to the list, - // then a new word is initialized and the separator is also added as a word. - if( !word.empty() ) - { - words.push_back( word ); - word.clear(); // initializes a new word. + // Clears the text and the vector of styles for the next paragraph. + paragraph = Text(); + stylesForParagraph.Clear(); } - - // Separator added as a word. - MarkupProcessor::StyledText separatorChar; - separatorChar.mText.Append( character ); - separatorChar.mStyle = styledText.mStyle; - - MarkupProcessor::StyledTextArray separatorWord; - separatorWord.push_back( separatorChar ); - - words.push_back( separatorWord ); - } - else - { - MarkupProcessor::StyledText styledChar; - styledChar.mStyle = styledText.mStyle; - styledChar.mText.Append( character ); - - // Add the character to the current word. - word.push_back( styledChar ); - } - } - - //Finally the last word need to be added. - if( !word.empty() ) - { - words.push_back( word ); - } -} - -bool BeginsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& styledText ) -{ - for( MarkupProcessor::StyledTextArray::const_iterator it = styledText.begin(), endIt = styledText.end(); it != endIt; ++it ) - { - const Text& text( (*it).mText ); - - for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) - { - Character::CharacterDirection direction = text[i].GetCharacterDirection(); - if( direction != Character::Neutral ) + else { - return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak ); - } - } - } + // The character is not a new paragraph character. - return false; -} + // Append it to the paragraph's text + paragraph.Append( character ); -bool BeginsRightToLeftCharacter( const Text& text ) -{ - for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) - { - Character::CharacterDirection direction = text[i].GetCharacterDirection(); - if( direction != Character::Neutral ) - { - return ( direction == Character::RightToLeft || direction == Character::RightToLeftWeak ); - } - } - - return false; -} - -bool ContainsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& styledText ) -{ - for( MarkupProcessor::StyledTextArray::const_iterator it = styledText.begin(), endIt = styledText.end(); it != endIt; ++it ) - { - const Text& text( (*it).mText ); - - for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) - { - Character::CharacterDirection direction = text[i].GetCharacterDirection(); - if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) ) - { - return true; + // Add the style to the vector of styles for that paragraph. + TextStyle* style = new TextStyle( styledText.mStyle ); + stylesForParagraph.PushBack( style ); } } } - return false; -} - -bool ContainsRightToLeftCharacter( const Dali::Text& text ) -{ - for( size_t i = 0u, length = text.GetLength(); i < length; ++i ) - { - Character::CharacterDirection direction = ( text[i] ).GetCharacterDirection(); - if( ( Character::RightToLeft == direction ) || ( Character::RightToLeftWeak == direction ) ) - { - return true; - } - } - - return false; + // This paragraph could be empty if the last character of the previous paragraph is a 'new paragraph' character + // and is the last of the text. + paragraphs.push_back( paragraph ); + styles.push_back( stylesForParagraph ); } -void ConvertBidirectionalText( const MarkupProcessor::StyledTextArray& line, - MarkupProcessor::StyledTextArray& convertedText, - std::vector& logicalToVisualMap, - std::vector& visualToLogicalMap ) +void SplitInWords( const Dali::Text& paragraph, + Vector& positions ) { - // Clean vectors first. This function doesn't use any previous value. - logicalToVisualMap.clear(); - visualToLogicalMap.clear(); - convertedText.clear(); - - if( line.empty() ) - { - // nothing to do if the line is empty. - return; - } - - // Get the plain text from the line to be reordered by the BiDirectional algorithm. - std::string textToBeConverted; - GetPlainString( line, textToBeConverted ); - - const std::size_t stringSize = textToBeConverted.size(); - - std::vector logicalStrBuffer; - std::vector visualStrBuffer; - // unicode length <= UTF-8 length in bytes (reserve one extra for terminator) - // pad these buffers with 0's, as it's unclear what fribidi_log2vis does w.r.t. - // the length of it's output content (appears the same as input content, and does - // not seem to generate bidi marks i.e. FRIBIDI_CHAR_LRM/FRIBIDI_CHAR_RLM) - logicalStrBuffer.resize( stringSize+1u, 0u ); - visualStrBuffer.resize( stringSize+1u, 0u ); - FriBidiChar *logicalStr( &logicalStrBuffer[0u] ); - FriBidiChar *visualStr( &visualStrBuffer[0u] ); - - // Convert UTF-8 string to unicode string - const std::size_t length = fribidi_charset_to_unicode( FRIBIDI_CHAR_SET_UTF8, textToBeConverted.c_str(), stringSize, logicalStr ); - - if( 0u == length ) - { - DALI_ASSERT_DEBUG( !"TextProcessor::ConvertBidirectionalText. Error when calling at fribidi_charset_to_unicode" ); - - return; - } - - logicalToVisualMap.resize( length ); - visualToLogicalMap.resize( length ); + const std::size_t length = paragraph.GetLength(); - // Convert and reorder the string as specified by the Unicode Bidirectional Algorithm - FriBidiCharType baseDirection = FRIBIDI_TYPE_ON; - fribidi_boolean log2vis = fribidi_log2vis( logicalStr, length, &baseDirection, visualStr, &logicalToVisualMap[0u], &visualToLogicalMap[0u], NULL ); + // Magic number: Let's soupose there is ~6 characters per word. Used to do less memory reallocation inside Vector. + const size_t magicNumberOfWords = ( length / 6u ) + 1u; - if(log2vis) - { - // Convert the unicode string back to the UTF-8 string - std::vector bidiTextConverted; - - bidiTextConverted.resize( length * 4u + 1u ); // Maximum bytes to represent one UTF-8 character is 6. - // Currently Dali doesn't support this UTF-8 extension. Dali only supports 'regular' UTF-8 which has a maximum of 4 bytes per character. - - fribidi_unicode_to_charset( FRIBIDI_CHAR_SET_UTF8, visualStr, length, &bidiTextConverted[0u] ); - - textToBeConverted = &bidiTextConverted[0u]; - - // After reorder the text, rebuild the text with the original styles is needed. - // To assign the original style is needed to use the characterLogicalToVisualMap table. - Text text( &bidiTextConverted[0u] ); - - // Split the line in words. - // Add the correct styles for the characters after they are reordered. + // Find the positions of the new paragraph characters. + positions.Reserve( magicNumberOfWords ); - for( size_t i = 0u; i < length; ++i ) - { - const Character character( text[i] ); - - MarkupProcessor::StyledText styledText; - styledText.mText.Append( character ); - styledText.mStyle = line[visualToLogicalMap[i]].mStyle; - - convertedText.push_back( styledText ); - } - } + // Find the position of all white spaces. A new paragraph character is also considered a white space but it doesn't matter at this point. + paragraph.Find( Text::WHITE_SPACE, 0u, length - 1u, positions ); } /** @@ -276,7 +117,7 @@ bool IsWhiteSpace( const MarkupProcessor::StyledTextArray& text, size_t offset ) DALI_ASSERT_DEBUG( offset < text.size() ); // assume 1 Character per StyledText - return text[offset].mText[0u].IsWhiteSpace(); + return ( *( text.begin() + offset ) ).mText[0u].IsWhiteSpace(); } void FindNearestWord( const MarkupProcessor::StyledTextArray& text, size_t offset, size_t& start, size_t& end) diff --git a/base/dali-toolkit/internal/controls/text-view/text-processor.h b/base/dali-toolkit/internal/controls/text-view/text-processor.h index 6324805..9814c09 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-processor.h +++ b/base/dali-toolkit/internal/controls/text-view/text-processor.h @@ -32,6 +32,8 @@ namespace Internal namespace TextProcessor { +// Forward declarations. +struct BidirectionalParagraphInfo; /** * Splits the given text in paragraphs. @@ -39,60 +41,22 @@ namespace TextProcessor * @note Assumes the StyledTextArray has 1 Character per Text element. (which is the case for text in TextInput, but * not necessarily the case for text in TextView) * - * @param [in] text The given text. + * @param [in] styledTextArray The given text. * @param [out] paragraphs The text split in paragraphs. + * @param [out] styles The styles of each character of each paragraph. */ -void SplitInParagraphs( const MarkupProcessor::StyledTextArray& text, - std::vector& paragraphs ); +void SplitInParagraphs( const MarkupProcessor::StyledTextArray& styledTextArray, + std::vector& paragraphs, + std::vector< Vector >& styles ); /** - * Splits the given paragraph in words. - * - * @note Assumes the StyledTextArray has 1 Character per Text element. (which is the case for text in TextInput, but - * not necessarily the case for text in TextView) + * Finds the position of all word separators (currently white spaces and new paragraph characters '\n') in the given text. * * @param [in] paragraph The given paragraph. - * @param [out] words The paragraph split in words. - */ -void SplitInWords( const MarkupProcessor::StyledTextArray& paragraph, - std::vector& words ); - -/** - * Whether the text begins with right-to-left (bidirectional) character. - * @param [in] text The given text. - * @return \e true if the text begins right-to-left character. - */ -bool BeginsRightToLeftCharacter( const Text& text ); - -/** - * @copydoc BeginsRightToLeftCharacter( const Text& text ) - */ -bool BeginsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& text ); - -/** - * Whether the text contains any right-to-left (bidirectional) character. - * @param [in] text The given text. - * @return \e true if the text contains right-to-left character. - */ -bool ContainsRightToLeftCharacter( const Text& text ); - -/** - * @copydoc ContainsRightToLeftCharacter( const Text& text ) - */ -bool ContainsRightToLeftCharacter( const MarkupProcessor::StyledTextArray& text ); - -/** - * Convert the text as specified by the Unicode Bidirectional Algorithm. - * The text is converted only if it is bidirectional. - * @param[in] line The line of text to be converted. - * @param[out] convertedText The text converted. - * @param[out] logicalToVisualMap The character position map from the logical input text to the visual output text. - * @param[out] visualToLogicalMap The character position map from the visual output text to the logical input text. + * @param [out] positions Positions within the paragraph of all word sepatators. */ - void ConvertBidirectionalText( const MarkupProcessor::StyledTextArray& line, - MarkupProcessor::StyledTextArray& convertedText, - std::vector& logicalToVisualMap, - std::vector& visualToLogicalMap ); +void SplitInWords( const Text& paragraph, + Vector& positions ); /** * Finds the nearest word in a string to a specified diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-character-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-character-processor.cpp index 3373ab7..ddcf00f 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-character-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-character-processor.cpp @@ -73,12 +73,11 @@ CharacterLayoutInfo::CharacterLayoutInfo() mPosition(), mOffset(), mGlyphActor(), - mStyledText(), mColorAlpha( 1.f ), mGradientInfo( NULL ), mIsVisible( true ), - mSetText( true ), - mSetStyle( true ), + mSetText( false ), + mSetStyle( false ), mIsColorGlyph( false ) { } @@ -98,7 +97,6 @@ CharacterLayoutInfo::CharacterLayoutInfo( const CharacterLayoutInfo& character ) mPosition( character.mPosition ), mOffset( character.mOffset ), mGlyphActor( character.mGlyphActor ), - mStyledText( character.mStyledText ), mColorAlpha( character.mColorAlpha ), mGradientInfo( ( NULL == character.mGradientInfo ) ? NULL : new GradientInfo( *character.mGradientInfo ) ), // Copies the gradient info. mIsVisible( character.mIsVisible ), @@ -120,7 +118,6 @@ CharacterLayoutInfo& CharacterLayoutInfo::operator=( const CharacterLayoutInfo& mOffset = character.mOffset; mGlyphActor = character.mGlyphActor; - mStyledText = character.mStyledText; mColorAlpha = character.mColorAlpha; diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-impl.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-impl.cpp index 0079170..be8f974 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-impl.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-impl.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -193,23 +194,38 @@ void TextView::InsertTextAt( std::size_t position, const std::string& text ) void TextView::InsertTextAt( std::size_t position, const MarkupProcessor::StyledTextArray& text ) { - // Creates metadata with the Insert operation. - TextViewProcessorMetadata metadata; - metadata.mType = TextView::TextInserted; - metadata.mPosition = position; - metadata.mText = text; + std::string textStr; + MarkupProcessor::GetPlainString( text, textStr ); - // Store metadata. - mTextViewProcessorOperations.push_back( metadata ); + if( TextProcessor::ContainsRightToLeftCharacter( Text( textStr ) ) || + TextProcessor::ContainsRightToLeftCharacter( Text( GetText() ) ) ) + { + // Temporary fix. Creates the whole layout if there is rtl text. - // Updates current styled text. - mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() ); + MarkupProcessor::StyledTextArray textToSet = mCurrentStyledText; + textToSet.insert( textToSet.begin() + position, text.begin(), text.end() ); + SetText( textToSet ); + } + else + { + // Creates metadata with the Insert operation. + TextViewProcessorMetadata metadata; + metadata.mType = TextView::TextInserted; + metadata.mPosition = position; + metadata.mText = text; - // Request to be relaid out - RelayoutRequest(); + // Store metadata. + mTextViewProcessorOperations.push_back( metadata ); - // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values. - mRelayoutOperations = RELAYOUT_ALL; + // Updates current styled text. + mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() ); + + // Request to be relaid out + RelayoutRequest(); + + // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values. + mRelayoutOperations = RELAYOUT_ALL; + } } void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const std::string& text ) @@ -377,14 +393,18 @@ void TextView::SetStyleToCurrentText( const TextStyle& style, TextStyle::Mask ma } // Sets the new style to the ellipsize text - if( !mLayoutParameters.mEllipsizeText.empty() ) + // TODO: fix this as a call to SetEllipsizeText will trigger the creation of new text actors. + if( 0u < mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Count() ) { - for( MarkupProcessor::StyledTextArray::iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it ) + for( Vector::Iterator it = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.Begin(), + endIt = mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles.End(); + it != endIt; + ++it ) { - (*it).mStyle.Copy( style, mask ); + (*it)->Copy( style, mask ); } - SetEllipsizeText( mLayoutParameters.mEllipsizeText ); + SetEllipsizeText( mRelayoutData.mTextLayoutInfo.mEllipsisText, mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles ); } } @@ -547,17 +567,35 @@ void TextView::SetEllipsizeText( const std::string& ellipsizeText ) MarkupProcessor::StyledTextArray styledText; MarkupProcessor::GetStyledTextArray( ellipsizeText, styledText, IsMarkupProcessingEnabled() ); + // Creates the ellipsis layout info and sets the text and styles. SetEllipsizeText( styledText ); } void TextView::SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText ) { - mLayoutParameters.mEllipsizeText = ellipsizeText; + // Converts the styled text array into a Text and a vector of TextStyles. + Text text; + Vector styles; + for( MarkupProcessor::StyledTextArray::const_iterator it = ellipsizeText.begin(), endIt = ellipsizeText.end(); it != endIt; ++it ) + { + const MarkupProcessor::StyledText& styledText( *it ); - mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo(); + text.Append( styledText.mText ); + styles.PushBack( new TextStyle( styledText.mStyle ) ); + } - TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText, - mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo ); + // Creates the ellipsis layout info and sets the text and styles. + SetEllipsizeText( text, styles ); +} + +void TextView::SetEllipsizeText( const Text& ellipsizeText, const Vector& ellipsizeStyles ) +{ + // Sets the text and styles for the ellipsis text. + mRelayoutData.mTextLayoutInfo.mEllipsisText = ellipsizeText; + mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles = ellipsizeStyles; + + // Creates the ellipsis layout info. + CreateEllipsizeLayout(); // Request to be relaid out RelayoutRequest(); @@ -567,13 +605,7 @@ void TextView::SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsi std::string TextView::GetEllipsizeText() const { - std::string text; - for( MarkupProcessor::StyledTextArray::const_iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it ) - { - text.append( (*it).mText.GetText() ); - } - - return text; + return mRelayoutData.mTextLayoutInfo.mEllipsisText.GetText(); } void TextView::GetTextLayoutInfo() @@ -632,7 +664,6 @@ void TextView::GetTextLayoutInfo() { mRelayoutOperations = static_cast( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW ); } - } } } @@ -861,12 +892,8 @@ TextView::LayoutParameters::LayoutParameters() mVerticalAlignment( Toolkit::Alignment::VerticalCenter ), mLineJustification( Toolkit::TextView::Left ), mLineHeightOffset( 0.f ), - mEllipsizeText(), mMarkUpEnabled( false ) { - // Sets ellipsize text - MarkupProcessor::StyledTextArray styledEllipsize; - MarkupProcessor::GetStyledTextArray( std::string( "..." ), mEllipsizeText, false ); } TextView::LayoutParameters::~LayoutParameters() @@ -879,7 +906,6 @@ TextView::LayoutParameters::LayoutParameters( Toolkit::TextView::MultilinePolicy Toolkit::Alignment::Type alignmentType, Toolkit::TextView::LineJustification lineJustification, float lineHeightOffset, - const std::string& ellipsizeText, bool markUpEnabled ) : mMultilinePolicy( multilinePolicy ), mWidthExceedPolicy( widthExceedPolicy ), @@ -888,7 +914,6 @@ TextView::LayoutParameters::LayoutParameters( Toolkit::TextView::MultilinePolicy mVerticalAlignment(), mLineJustification( lineJustification ), mLineHeightOffset( lineHeightOffset ), - mEllipsizeText(), mMarkUpEnabled( markUpEnabled ) { // Sets alignment @@ -901,10 +926,6 @@ TextView::LayoutParameters::LayoutParameters( Toolkit::TextView::MultilinePolicy mHorizontalAlignment = horizontalAlignment; mVerticalAlignment = verticalAlignment; - - // Sets ellipsize text - MarkupProcessor::StyledTextArray styledEllipsize; - MarkupProcessor::GetStyledTextArray( ellipsizeText, mEllipsizeText, mMarkUpEnabled ); } TextView::LayoutParameters::LayoutParameters( const TextView::LayoutParameters& layoutParameters ) @@ -915,7 +936,6 @@ TextView::LayoutParameters::LayoutParameters( const TextView::LayoutParameters& mVerticalAlignment( layoutParameters.mVerticalAlignment ), mLineJustification( layoutParameters.mLineJustification ), mLineHeightOffset( layoutParameters.mLineHeightOffset ), - mEllipsizeText( layoutParameters.mEllipsizeText ), mMarkUpEnabled( layoutParameters.mMarkUpEnabled ) { } @@ -929,7 +949,6 @@ TextView::LayoutParameters& TextView::LayoutParameters::operator=( const TextVie mVerticalAlignment = layoutParameters.mVerticalAlignment; mLineJustification = layoutParameters.mLineJustification; mLineHeightOffset = layoutParameters.mLineHeightOffset; - mEllipsizeText = layoutParameters.mEllipsizeText; mMarkUpEnabled = layoutParameters.mMarkUpEnabled; return *this; @@ -1018,7 +1037,6 @@ TextView::TextView() static_cast( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ), Toolkit::TextView::Left, PointSize( 0.f ), - std::string( "..." ), false ), mVisualParameters(), mRelayoutData(), @@ -1034,8 +1052,8 @@ TextView::TextView() mPreviousSnapshotModeEnabled( false ), mMarkUpEnabled( false ) { - TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText, - mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo ); + // Creates the ellipsis layout info. + CreateEllipsizeLayout(); } TextView::~TextView() @@ -1149,9 +1167,8 @@ void TextView::OnInitialize() void TextView::OnFontChange( bool defaultFontChange, bool defaultFontSizeChange ) { - mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo(); - TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText, - mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo ); + // Creates the ellipsis layout info. + CreateEllipsizeLayout(); SetText( mCurrentStyledText ); } @@ -1191,6 +1208,17 @@ void TextView::OnRelaidOut( Vector2 size, ActorSizeContainer& container ) } } + if( ( Toolkit::TextView::Fade == mLayoutParameters.mWidthExceedPolicy ) || + ( Toolkit::TextView::Fade == mLayoutParameters.mHeightExceedPolicy ) ) + { + if( mRelayoutOperations & RELAYOUT_ALIGNMENT ) + { + // If the text of the alignment changes and a fade exceed policy is set, + // some characters may need new TextActor. + mRelayoutOperations = RELAYOUT_ALL; + } + } + // Remove glyph-actors from text-view if( !mRelayoutData.mGlyphActors.empty() && ( mRelayoutOperations & RELAYOUT_REMOVE_TEXT_ACTORS ) ) { @@ -1880,6 +1908,16 @@ Actor TextView::GetRootActor() const return rootActor; } +void TextView::CreateEllipsizeLayout() +{ + // Creates the ellipsis layout info for the ellipsis text and styles. + mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo(); + mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo.mCharactersLayoutInfo.resize( mRelayoutData.mTextLayoutInfo.mEllipsisText.GetLength(), TextViewProcessor::CharacterLayoutInfo() ); + TextViewProcessor::CreateWordTextInfo( mRelayoutData.mTextLayoutInfo.mEllipsisText, + mRelayoutData.mTextLayoutInfo.mEllipsisTextStyles, + mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo ); +} + void TextView::OnMarkupEnabledPeopertySet( Property::Value propertyValue ) { bool newValue( propertyValue.Get() ); diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-impl.h b/base/dali-toolkit/internal/controls/text-view/text-view-impl.h index 220871b..70c149a 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-impl.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-impl.h @@ -90,7 +90,7 @@ public: TextViewProcessorMetadataType mType; ///< Stores the type of operation. std::size_t mPosition; ///< Character position within the text. - std::size_t mNumberOfCharacters; ///< Number of characters to be removed/ replaced. + std::size_t mNumberOfCharacters; ///< Number of characters to be removed/replaced. MarkupProcessor::StyledTextArray mText; ///< The new text. TextStyle::Mask mStyleMask; ///< The style mask. }; @@ -245,6 +245,11 @@ public: void SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText ); /** + * @copydoc SetEllipsizeText() + */ + void SetEllipsizeText( const Text& ellipsizeText, const Vector& ellipsizeStyles ); + + /** * @copydoc GetEllipsizeText() */ std::string GetEllipsizeText() const; @@ -524,6 +529,11 @@ private: Actor GetRootActor() const; /** + * Creates the ellipsize text layout. + */ + void CreateEllipsizeLayout(); + + /** * Handle SetProperty for markup processing. * @param[in] propertyValue The new property value. */ @@ -604,7 +614,6 @@ public: Toolkit::Alignment::Type alignment, Toolkit::TextView::LineJustification lineJustification, float lineHeightOffset, - const std::string& ellipsizeText, bool markUpEnabled ); /** @@ -618,15 +627,14 @@ public: LayoutParameters& operator=( const LayoutParameters& layoutParameters ); Toolkit::TextView::MultilinePolicy mMultilinePolicy; ///< Stores the multiline policy. - TextView::ExceedPolicy mExceedPolicy; ///< Stores a combination of both policies; + TextView::ExceedPolicy mExceedPolicy; ///< Stores a combination of both policies. Toolkit::TextView::ExceedPolicy mWidthExceedPolicy; ///< Stores the text width exceed policy. Toolkit::TextView::ExceedPolicy mHeightExceedPolicy; ///< Stores the text height exceed policy. Toolkit::Alignment::Type mHorizontalAlignment; ///< Stores the horizontal alignment for the whole text. Toolkit::Alignment::Type mVerticalAlignment; ///< Stores the vertical alignment for the whole text. Toolkit::TextView::LineJustification mLineJustification; ///< Stores the line justification. float mLineHeightOffset; ///< Line height offset to be addded to the font line height (measured in PointSize). - MarkupProcessor::StyledTextArray mEllipsizeText; ///< Stores the ellipsize text - bool mMarkUpEnabled:1; ///< Is markup string scanning enabled + bool mMarkUpEnabled:1; ///< Is markup string scanning enabled. }; /** @@ -658,15 +666,6 @@ public: }; /** - * Temporary data used to calculate line justification. - */ - struct LineJustificationInfo - { - TextViewProcessor::TextInfoIndices mIndices; ///< Indices to the first character of the new line. - float mLineLength; ///< Length of the line (or portion of line). - }; - - /** * The results of the relayout process. */ struct RelayoutData @@ -696,7 +695,6 @@ public: Toolkit::TextView::CharacterLayoutInfoContainer mCharacterLayoutInfoTable; ///< Stores layout info per character sorted by the character's visual index. Toolkit::TextView::LineLayoutInfoContainer mLines; ///< Stores an index to the first character of each line. Size mTextSizeForRelayoutOption; ///< Stores the text size after relayout. - std::vector mLineJustificationInfo; ///< Stores justification info per line. TextActorCache mTextActorCache; ///< Stores previously created text-actors to be reused. }; diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.cpp index be29790..70a0309 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace Dali { @@ -39,26 +40,74 @@ namespace TextViewProcessor // Layout info. ///////////////////// +void RightToLeftParagraphLayout::Clear() +{ + mWordsLayoutInfo.clear(); + mText = Text(); + mTextStyles.Clear(); +} + ParagraphLayoutInfo::ParagraphLayoutInfo() : mSize(), mAscender( 0.f ), mLineHeightOffset( 0.f ), + mFirstCharacter( 0u ), mNumberOfCharacters( 0u ), - mWordsLayoutInfo() + mWordsLayoutInfo(), + mText(), + mTextStyles(), + mRightToLeftLayout( NULL ), + mBidirectionalParagraphInfo( NULL ), + mBidirectionalLinesInfo() { } ParagraphLayoutInfo::~ParagraphLayoutInfo() { + if( NULL != mRightToLeftLayout ) + { + // TextStyle pointers are the same than the ones stored at ParagraphLayoutInfo::mTextStyles. + // Do not delete them, just clear the vector. + mRightToLeftLayout->mTextStyles.Clear(); + + delete mRightToLeftLayout; + } + + // Clears text styles. It destroys TextStyle objects. + ClearStyles(); + + // Deletes the bidirectional info for the whole paragraph. + delete mBidirectionalParagraphInfo; + + // Clears the bidirectional info for all lines. Destroys the BidirectionalLineInfo objects. + ClearBidirectionalInfo(); } ParagraphLayoutInfo::ParagraphLayoutInfo( const ParagraphLayoutInfo& paragraph ) : mSize( paragraph.mSize ), mAscender( paragraph.mAscender ), mLineHeightOffset( paragraph.mLineHeightOffset ), + mFirstCharacter( paragraph.mFirstCharacter ), mNumberOfCharacters( paragraph.mNumberOfCharacters ), - mWordsLayoutInfo( paragraph.mWordsLayoutInfo ) + mWordsLayoutInfo( paragraph.mWordsLayoutInfo ), + mText( paragraph.mText ), + mTextStyles(), + mRightToLeftLayout( NULL ), + // Copies bidirectional info for the whole paragraph. + mBidirectionalParagraphInfo( ( NULL == paragraph.mBidirectionalParagraphInfo ) ? NULL : new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo ) ), + mBidirectionalLinesInfo() { + // Copies styles. + for( Vector::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it ) + { + mTextStyles.PushBack( new TextStyle( *(*it) ) ); + } + + // Copies bidirectional info for each line. + for( Vector::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it ) + { + mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) ); + } } ParagraphLayoutInfo& ParagraphLayoutInfo::operator=( const ParagraphLayoutInfo& paragraph ) @@ -66,150 +115,207 @@ ParagraphLayoutInfo& ParagraphLayoutInfo::operator=( const ParagraphLayoutInfo& mSize = paragraph.mSize; mAscender = paragraph.mAscender; mLineHeightOffset = paragraph.mLineHeightOffset; + mFirstCharacter = paragraph.mFirstCharacter; mNumberOfCharacters = paragraph.mNumberOfCharacters; mWordsLayoutInfo = paragraph.mWordsLayoutInfo; + mText = paragraph.mText; - return *this; -} + // If it has styles, destroy them. + ClearStyles(); -void CreateParagraphInfo( const MarkupProcessor::StyledTextArray& paragraph, - TextView::RelayoutData& relayoutData, - ParagraphLayoutInfo& paragraphLayoutInfo ) -{ - // Split the paragraph in words. - // TODO: Proper RTL support. - MarkupProcessor::StyledTextArray convertedParagraph; - if( TextProcessor::ContainsRightToLeftCharacter( paragraph ) ) + // Copies styles. + for( Vector::ConstIterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it ) { - // If the text is bidirectional, the characters will be converted and reordered - // as specified by the Unicode Bidirectional Algorithm. + mTextStyles.PushBack( new TextStyle( *(*it) ) ); + } - // Reorders the paragraph and converts arabic glyphs (if any). - TextProcessor::ConvertBidirectionalText( paragraph, - convertedParagraph, - relayoutData.mCharacterLogicalToVisualMap, - relayoutData.mCharacterVisualToLogicalMap); + // Copies the paragraph's bidirectiona info. + if( NULL == paragraph.mBidirectionalParagraphInfo ) + { + // The source doesn't have bidirectiona info. Deletes the current one. + delete mBidirectionalParagraphInfo; + mBidirectionalParagraphInfo = NULL; } else { - // No bidirectional text to process. - convertedParagraph = paragraph; - - // Create trivial bidirectional map tables. - std::size_t index = 0u; - for( MarkupProcessor::StyledTextArray::const_iterator it = convertedParagraph.begin(), endIt = convertedParagraph.end(); it != endIt; ++it ) + // The source has bidirectional info. + if( NULL != mBidirectionalParagraphInfo ) { - const MarkupProcessor::StyledText& styledText( *it ); - - for( std::size_t i = 0u, length = styledText.mText.GetLength(); i < length; ++i ) - { - relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); - relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); - ++index; - } + // It it has, copy to it. + *mBidirectionalParagraphInfo = *paragraph.mBidirectionalParagraphInfo; + } + else + { + // If it doesn't have, create a new one. + mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo( *paragraph.mBidirectionalParagraphInfo ); } } - // Split the paragraph in words - std::vector words; - TextProcessor::SplitInWords( convertedParagraph, words ); + // If it has bidirectiona info per line, destroy them. + ClearBidirectionalInfo(); - // if last word has a new paragraph separator, create a new word. - if( !words.empty() ) + // Copies bidirectional info per line. + for( Vector::ConstIterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it ) { - MarkupProcessor::StyledTextArray& word( *( words.end() - 1u ) ); - if( word.size() > 1u ) - { - // do nothing if the word has only one character. - MarkupProcessor::StyledText& styledText( *( word.end() - 1u ) ); - if( !styledText.mText.IsEmpty() ) - { - const std::size_t length = styledText.mText.GetLength(); - if( styledText.mText[length-1u].IsNewLine() ) - { - // Last character of this word is a new paragraph character. + mBidirectionalLinesInfo.PushBack( new TextProcessor::BidirectionalLineInfo( *( *it ) ) ); + } - // Remove paragraph separator character from current word. - styledText.mText.Remove( length - 1u, 1u ); + return *this; +} - // Create a new word with the paragraph separator character. - MarkupProcessor::StyledText newParagraphText( Text( styledText.mText[length-1u] ), styledText.mStyle ); +void ParagraphLayoutInfo::ClearBidirectionalInfo() +{ + // Destroys the bidirectional infor per line. + for( Vector::Iterator it = mBidirectionalLinesInfo.Begin(), endIt = mBidirectionalLinesInfo.End(); it != endIt; ++it ) + { + delete *it; + } + mBidirectionalLinesInfo.Clear(); +} - MarkupProcessor::StyledTextArray newParagraphWord; - newParagraphWord.push_back( newParagraphText ); +void ParagraphLayoutInfo::ClearStyles() +{ + // Destroys the styles. + for( Vector::Iterator it = mTextStyles.Begin(), endIt = mTextStyles.End(); it != endIt; ++it ) + { + delete *it; + } + mTextStyles.Clear(); +} - words.push_back( newParagraphWord ); - } - } - } +void CreateParagraphInfo( TextView::RelayoutData& relayoutData, + ParagraphLayoutInfo& paragraphLayoutInfo ) +{ + if( TextProcessor::ContainsRightToLeftCharacter( paragraphLayoutInfo.mText ) ) + { + // If the text is bidirectional, the characters will be converted and reordered + // as specified by the Unicode Bidirectional Algorithm. + + paragraphLayoutInfo.mBidirectionalParagraphInfo = new TextProcessor::BidirectionalParagraphInfo(); + + TextProcessor::ProcessBidirectionalText( paragraphLayoutInfo.mText, paragraphLayoutInfo.mBidirectionalParagraphInfo ); } - std::string lastCharacterFont; // Keeps the font used by the last character. It's used to set the font to a word separator. + // Split the paragraph in words. It retrieves the positions of white spaces and the last '\n' if there is one. + Vector positions; + TextProcessor::SplitInWords( paragraphLayoutInfo.mText, positions ); - // Traverse all words. - for( std::vector::const_iterator wordIt = words.begin(), wordEndIt = words.end(); wordIt != wordEndIt; ++wordIt ) - { - const MarkupProcessor::StyledTextArray& word( *wordIt ); + const std::size_t lastCharacterIndex = paragraphLayoutInfo.mText.GetLength() - 1u; + const bool isLastCharacterParagraphSeparator = paragraphLayoutInfo.mText.IsNewLine( lastCharacterIndex ); - // Data structures for the new word. - WordLayoutInfo wordLayoutInfo; + // The number of words is ~the number of white spaces found + 1u. + // White spaces are also words. + // New line characters are also white spaces. If the last character is a white space the +1 is not needed. + const std::size_t numberOfWords = 2u * positions.Count() + ( isLastCharacterParagraphSeparator ? 0u : 1u ); - CreateWordTextInfo( word, - wordLayoutInfo ); + // Reserve space for all the words. + paragraphLayoutInfo.mWordsLayoutInfo.resize( numberOfWords, WordLayoutInfo() ); + + // Traverses all positions creating and setting all character layout info objects to every word. + std::size_t wordIndex = 0u; + Vector::ConstIterator positionIt = positions.Begin(); + Vector::ConstIterator positionEndIt = positions.End(); + std::size_t from = 0u; + for( std::size_t positionIndex = 0u, size = positions.Count() + 1u; positionIndex < size; ++positionIndex ) + { + const bool isEndPosition = positionIt == positionEndIt; + const std::size_t to = isEndPosition ? lastCharacterIndex + 1u : *positionIt; - // White space's size could be different depending on the type of font. It's important to use the same font than the previous character to - // avoid 'jumps' of characters when there is a switch between one text-actor per character and one text-actor per line and/or style. - if( WordSeparator == wordLayoutInfo.mType ) + if( from < to ) { - // If current word is a word separator (white space) then the font of the last character is set. - for( CharacterLayoutInfoContainer::iterator characterIt = wordLayoutInfo.mCharactersLayoutInfo.begin(), characterEndIt = wordLayoutInfo.mCharactersLayoutInfo.end(); - characterIt != characterEndIt; - ++characterIt ) - { - CharacterLayoutInfo& characterLayout( *characterIt ); + // The word is not a white space. + WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex ); + ++wordIndex; + // Sets the index within the paragraph to the first character of the word. + wordLayoutInfo.mFirstCharacter = from; + // Creates character layout info objects. + wordLayoutInfo.mCharactersLayoutInfo.resize( ( to - from ), CharacterLayoutInfo() ); + } - characterLayout.mStyledText.mStyle.SetFontName( lastCharacterFont ); - } + if( !isEndPosition ) + { + // Create a word for the white space. + WordLayoutInfo& wordLayoutInfo = *( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex ); + ++wordIndex; + // Sets the index within the paragraph to the white space. + wordLayoutInfo.mFirstCharacter = to; + wordLayoutInfo.mType = WordSeparator; + + CharacterLayoutInfo characterLayoutInfo; + wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo ); + } + + from = to + 1u; + + if( !isEndPosition ) + { + // next white space position. + ++positionIt; } else { - // kepps the font of the last character. - if( !wordLayoutInfo.mCharactersLayoutInfo.empty() ) + // All white space positiona have been traversed. + // It may be some extra words. i.e if the text is \n. + // Erase them. + paragraphLayoutInfo.mWordsLayoutInfo.erase( paragraphLayoutInfo.mWordsLayoutInfo.begin() + wordIndex, paragraphLayoutInfo.mWordsLayoutInfo.end() ); + + // Check if the last character is a new paragraph character. + if( isLastCharacterParagraphSeparator ) { - lastCharacterFont = ( *( wordLayoutInfo.mCharactersLayoutInfo.end() - 1u ) ).mStyledText.mStyle.GetFontName(); + ( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) ).mType = ParagraphSeparator; } } + } - // Update the max word width figure. - relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width ); + // Traverse all words and fill the layout info. + for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it ) + { + WordLayoutInfo& wordLayoutInfo( *it ); + + CreateWordTextInfo( paragraphLayoutInfo.mText, + paragraphLayoutInfo.mTextStyles, + wordLayoutInfo ); // Update layout info for the current paragraph. + UpdateSize( paragraphLayoutInfo.mSize, wordLayoutInfo.mSize ); paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, wordLayoutInfo.mAscender ); paragraphLayoutInfo.mNumberOfCharacters += wordLayoutInfo.mCharactersLayoutInfo.size(); - UpdateSize( paragraphLayoutInfo.mSize, wordLayoutInfo.mSize ); - // Add the word to the current paragraph. - paragraphLayoutInfo.mWordsLayoutInfo.push_back( wordLayoutInfo ); + // Update the max word width figure. + relayoutData.mTextLayoutInfo.mMaxWordWidth = std::max( relayoutData.mTextLayoutInfo.mMaxWordWidth, wordLayoutInfo.mSize.width ); } // end of words } void UpdateLayoutInfo( ParagraphLayoutInfo& paragraphLayoutInfo, float lineHeightOffset ) { // Update layout info. + + // Initialize members to be updated. paragraphLayoutInfo.mSize = Size::ZERO; paragraphLayoutInfo.mAscender = 0.f; paragraphLayoutInfo.mNumberOfCharacters = 0u; + + // Traverses all words. for( WordLayoutInfoContainer::iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it ) { WordLayoutInfo& word( *it ); + // Sets the index within the paragraph to the first character of the word. + word.mFirstCharacter = paragraphLayoutInfo.mNumberOfCharacters; + + // Updates the paragraph's size. UpdateSize( paragraphLayoutInfo.mSize, word.mSize ); + + // Updates the paragraph's max asender. paragraphLayoutInfo.mAscender = std::max( paragraphLayoutInfo.mAscender, word.mAscender ); + + // Updates the paragraph's number of characters. paragraphLayoutInfo.mNumberOfCharacters += word.mCharactersLayoutInfo.size(); } + // Sets the line height offset. paragraphLayoutInfo.mSize.height += lineHeightOffset; paragraphLayoutInfo.mLineHeightOffset = lineHeightOffset; } @@ -476,6 +582,26 @@ void SplitParagraph( const TextInfoIndices& indices, // 6) update layout info of the first paragraph. UpdateLayoutInfo( firstParagraphLayoutInfo, lineHeightOffset ); + + // 7) Split text and styles. + + // Copies the whole text to the last part of the paragraph. + lastParagraphLayoutInfo.mText = firstParagraphLayoutInfo.mText; + + // Removes from the first part of the paragraph the text that goes to the last part. + firstParagraphLayoutInfo.mText.Remove( indices.mCharacterParagraphIndex, firstParagraphLayoutInfo.mText.GetLength() - indices.mCharacterParagraphIndex ); + + // Removes from the last part of the paragraph the text that remains in the first part. + lastParagraphLayoutInfo.mText.Remove( 0u, indices.mCharacterParagraphIndex ); + + // Sets the character's styles for the last part of the paragraph. + lastParagraphLayoutInfo.mTextStyles.Insert( lastParagraphLayoutInfo.mTextStyles.End(), + firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex, + firstParagraphLayoutInfo.mTextStyles.End() ); + + // Removes the character's styles that go to the last part of the paragraph. + firstParagraphLayoutInfo.mTextStyles.Erase( firstParagraphLayoutInfo.mTextStyles.Begin() + indices.mCharacterParagraphIndex, + firstParagraphLayoutInfo.mTextStyles.End() ); } void MergeParagraph( ParagraphLayoutInfo& firstParagraphLayoutInfo, @@ -528,14 +654,29 @@ void MergeParagraph( ParagraphLayoutInfo& firstParagraphLayoutInfo, // Merge layout info // Insert the layout of the words. + const std::size_t numberOfWords = firstParagraphLayoutInfo.mWordsLayoutInfo.size(); firstParagraphLayoutInfo.mWordsLayoutInfo.insert( firstParagraphLayoutInfo.mWordsLayoutInfo.end(), lastParagraphLayoutInfo.mWordsLayoutInfo.begin() + index, lastParagraphLayoutInfo.mWordsLayoutInfo.end() ); + // Increase the index of the first character of each inserted word. + for( WordLayoutInfoContainer::iterator it = firstParagraphLayoutInfo.mWordsLayoutInfo.begin() + numberOfWords, endIt = firstParagraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it ) + { + WordLayoutInfo& word( *it ); + word.mFirstCharacter += firstParagraphLayoutInfo.mNumberOfCharacters; + } + // Update the size and other layout parameters. UpdateSize( firstParagraphLayoutInfo.mSize, lastParagraphLayoutInfo.mSize ); firstParagraphLayoutInfo.mAscender = std::max( firstParagraphLayoutInfo.mAscender, lastParagraphLayoutInfo.mAscender ); firstParagraphLayoutInfo.mLineHeightOffset = std::max( firstParagraphLayoutInfo.mLineHeightOffset, lastParagraphLayoutInfo.mLineHeightOffset ); firstParagraphLayoutInfo.mNumberOfCharacters += lastParagraphLayoutInfo.mNumberOfCharacters; + + // Merge text and styles. + firstParagraphLayoutInfo.mText.Append( lastParagraphLayoutInfo.mText ); + for( Vector::ConstIterator it = lastParagraphLayoutInfo.mTextStyles.Begin(), endIt = lastParagraphLayoutInfo.mTextStyles.End(); it != endIt; ++it ) + { + firstParagraphLayoutInfo.mTextStyles.PushBack( new TextStyle( *(*it) ) ); + } } WordLayoutInfo GetLastWordLayoutInfo( const ParagraphLayoutInfo& paragraphLayoutInfo ) diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h b/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h index b43489c..3e9b0f0 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-paragraph-processor.h @@ -36,12 +36,10 @@ namespace TextViewProcessor /** * Creates a data structure with info to layout the paragraph, and data structures with useful info to modify the layout data structure if characters are added or removed. * - * @param[in] paragraph The styled paragraph. * @param[in,out] relayoutData Natural size (metrics), layout, text-actor info and conversion from visual to logical order and vice versa (for RTL text). * @param[out] paragraphLayoutInfo Layout info for the whole paragraph. */ -void CreateParagraphInfo( const MarkupProcessor::StyledTextArray& line, - TextView::RelayoutData& relayoutData, +void CreateParagraphInfo( TextView::RelayoutData& relayoutData, ParagraphLayoutInfo& paragraphLayoutInfo ); /** diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.cpp index b3a59c7..713c681 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.cpp @@ -19,7 +19,7 @@ #include // INTERNAL INCLUDES -#include +#include namespace Dali { @@ -39,30 +39,9 @@ Debug::Filter* gTextViewProcessorLogFilter = Debug::Filter::New(Debug::NoLogging void dbgPrint( const WordLayoutInfo& word ) { - for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end(); - characterIt != endCharacterIt; - ++characterIt ) - { - const CharacterLayoutInfo& character( *characterIt ); - - std::cout << "[" << character.mSize << std::endl; - std::cout << " ascender " << character.mAscender << std::endl; - - TextActor textActor = TextActor::DownCast( character.mGlyphActor ); - if( textActor ) - { - std::cout << "[" << textActor.GetText() << "]"; - } - else - { - std::cout << "[ImageActor]" << std::endl; - } - std::cout << "{" << character.mStyledText.mText.GetText() << "}"; - } - std::cout << " size " << word.mSize << std::endl; - std::cout << " ascender " << word.mAscender << std::endl; - std::cout << " num char " << word.mCharactersLayoutInfo.size() << std::endl; - std::cout << " type "; + std::cout << " size " << word.mSize << std::endl; + std::cout << " ascender " << word.mAscender << std::endl; + std::cout << " type "; switch( word.mType ) { case NoSeparator: @@ -81,11 +60,24 @@ void dbgPrint( const WordLayoutInfo& word ) break; } } + std::cout << " first char " << word.mFirstCharacter << std::endl; + std::cout << " num char " << word.mCharactersLayoutInfo.size() << std::endl; + for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end(); + characterIt != endCharacterIt; + ++characterIt ) + { + const CharacterLayoutInfo& character( *characterIt ); + + std::cout << "[" << character.mSize << std::endl; + std::cout << " ascender " << character.mAscender << std::endl; + } } void dbgPrint( const ParagraphLayoutInfo& paragraph ) { std::cout << "< "; + std::cout << " text : [" << paragraph.mText.GetText() << "]" << std::endl; + std::cout << " number of styles : " << paragraph.mTextStyles.Count() << std::endl; std::cout << paragraph.mSize; for( WordLayoutInfoContainer::const_iterator wordIt = paragraph.mWordsLayoutInfo.begin(), endWordIt = paragraph.mWordsLayoutInfo.end(); wordIt != endWordIt; @@ -157,6 +149,7 @@ void dbgPrint( const TextInfoIndices& indices ) std::cout << " paragraph : " << indices.mParagraphIndex << std::endl; std::cout << " word : " << indices.mWordIndex << std::endl; std::cout << " char : " << indices.mCharacterIndex << std::endl; + std::cout << " char in paragraph : " << indices.mCharacterParagraphIndex << std::endl; } void dbgPrint( const MarkupProcessor::StyledTextArray& textArray ) @@ -169,18 +162,6 @@ void dbgPrint( const MarkupProcessor::StyledTextArray& textArray ) } } -void dbgPrintText( const WordLayoutInfo& word ) -{ - for( CharacterLayoutInfoContainer::const_iterator characterIt = word.mCharactersLayoutInfo.begin(), endCharacterIt = word.mCharactersLayoutInfo.end(); - characterIt != endCharacterIt; - ++characterIt ) - { - const CharacterLayoutInfo& character( *characterIt ); - - std::cout << character.mStyledText.mText.GetText(); - } -} - } // namespace TextViewProcessor } // namespace Internal diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h b/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h index b5131e4..2529bb8 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor-dbg.h @@ -19,13 +19,15 @@ */ // INTERNAL INCLUDES -#include #include -#include +#include namespace Dali { +//Forward declarations. +class TextStyle; + namespace Toolkit { @@ -35,6 +37,12 @@ namespace Internal namespace TextViewProcessor { +//Forward declarations. +struct WordLayoutInfo; +struct ParagraphLayoutInfo; +struct TextLayoutInfo; +struct TextInfoIndices; + #if defined(DEBUG_ENABLED) extern Debug::Filter* gTextViewProcessorLogFilter; #endif @@ -46,8 +54,6 @@ void dbgPrint( const TextStyle& style ); void dbgPrint( const TextInfoIndices& indices ); void dbgPrint( const MarkupProcessor::StyledTextArray& text ); -void dbgPrintText( const WordLayoutInfo& word ); - } // namespace TextViewProcessor } // namespace Internal diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.cpp index 1855b6e..43a5f4e 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.cpp @@ -58,20 +58,20 @@ TextSeparatorType GetTextSeparatorType( const Character& character ) return ( character.IsNewLine() ? ParagraphSeparator : ( character.IsWhiteSpace() ? WordSeparator : NoSeparator ) ); } -void ChooseFontFamilyName( MarkupProcessor::StyledText& text ) +void ChooseFontFamilyName( const Character& character, TextStyle& style ) { DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::ChooseFontFamilyName\n" ); - DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " input font name: [%s]\n", text.mStyle.GetFontName().c_str() ); + DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " input font name: [%s]\n", style.GetFontName().c_str() ); bool userDefinedFontFamilyName = false; // First check if there is a font defined in the style and it supports the given text. - if( !text.mStyle.GetFontName().empty() ) + if( !style.GetFontName().empty() ) { - const FontParameters fontParams( text.mStyle.GetFontName(), text.mStyle.GetFontStyle() , text.mStyle.GetFontPointSize() ); + const FontParameters fontParams( style.GetFontName(), style.GetFontStyle() , style.GetFontPointSize() ); const Font font = Font::New( fontParams ); - if( !font.IsDefaultSystemFont() && font.AllGlyphsSupported( text.mText ) ) + if( !font.IsDefaultSystemFont() && font.AllGlyphsSupported( character ) ) { userDefinedFontFamilyName = true; } @@ -82,20 +82,20 @@ void ChooseFontFamilyName( MarkupProcessor::StyledText& text ) const Font defaultSystemFont = Font::New(); // At this point no font is set or doesn't support the given text. - if( !defaultSystemFont.AllGlyphsSupported( text.mText ) ) + if( !defaultSystemFont.AllGlyphsSupported( character ) ) { // If the default system font doesn't support the given text, // an appropiate font is selected. - text.mStyle.SetFontName( Font::GetFamilyForText( text.mText ) ); + style.SetFontName( Font::GetFamilyForText( character ) ); // @TODO Font::GetFamilyForText() should return font family and font style. } else { // All characters are supported with default font, so use it - text.mStyle.SetFontName( "" ); + style.SetFontName( "" ); } } - DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " output font name: [%s]\n", text.mStyle.GetFontName().c_str() ); + DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " output font name: [%s]\n", style.GetFontName().c_str() ); DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::ChooseFontFamilyName\n" ); } @@ -123,6 +123,7 @@ void GetIndicesFromGlobalCharacterIndex( const std::size_t index, ++paragraphIt, ++indices.mParagraphIndex ) { const ParagraphLayoutInfo& paragraphLayoutInfo( *paragraphIt ); + std::size_t currentCharactersTraversed = currentIndex; // stores how many characters have been traversed until this paragraph. if( currentIndex + paragraphLayoutInfo.mNumberOfCharacters > index ) { @@ -138,6 +139,7 @@ void GetIndicesFromGlobalCharacterIndex( const std::size_t index, { // The character is in this word indices.mCharacterIndex = index - currentIndex; + indices.mCharacterParagraphIndex = index - currentCharactersTraversed; found = true; } else diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h b/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h index ef9fb2a..c543e32 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor-helper-functions.h @@ -71,13 +71,14 @@ void UpdateSize( Size& size1, const Size& size2, SizeGrowType type = GrowWidth ) TextSeparatorType GetTextSeparatorType( const Character& character ); /** - * Choose a suitable font family name for the given styled text. + * Choose a suitable font family name for the given character. * - * It may modify the text-style of the given text by setting a suitable font-family. + * It may modify the text-style of the given character by setting a suitable font-family. * - * @param[in,out] text Text with style. + * @param[in] character The character. + * @param[in,out] style The style of the character. */ -void ChooseFontFamilyName( MarkupProcessor::StyledText& text ); +void ChooseFontFamilyName( const Character& character, TextStyle& style ); /** * Retrieves the line, word and character indices for the given global character's index. diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor-types.h b/base/dali-toolkit/internal/controls/text-view/text-view-processor-types.h index a4d1873..15005cc 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor-types.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor-types.h @@ -20,17 +20,26 @@ // INTERNAL INCLUDES #include -#include +#include namespace Dali { +class TextStyle; + namespace Toolkit { namespace Internal { +namespace TextProcessor +{ +// Forward declarations. +struct BidirectionalParagraphInfo; +struct BidirectionalLineInfo; +} // namespace TextProcessor + namespace TextViewProcessor { @@ -84,6 +93,7 @@ struct TextInfoIndices std::size_t mParagraphIndex; ///< The paragraph index within the text. std::size_t mWordIndex; ///< The word index within the paragraph. std::size_t mCharacterIndex; ///< The character index within the word. + std::size_t mCharacterParagraphIndex; ///< The character index within the paragraph. }; /** @@ -161,10 +171,9 @@ struct CharacterLayoutInfo Vector3 mPosition; ///< Position within the text-view Vector2 mOffset; ///< Alignment and justification offset. - RenderableActor mGlyphActor; ///< Handle to a text-actor. - MarkupProcessor::StyledText mStyledText; ///< Stores the text and its style. - float mColorAlpha; ///< Alpha component for the initial text color when text is faded. - GradientInfo* mGradientInfo; ///< Stores gradient info. + RenderableActor mGlyphActor; ///< Handle to a text-actor. + float mColorAlpha; ///< Alpha component for the initial text color when text is faded. + GradientInfo* mGradientInfo; ///< Stores gradient info. bool mIsVisible:1; ///< Whether the text-actor is visible. bool mSetText:1; ///< Whether a new text needs to be set in the text-actor. @@ -205,11 +214,36 @@ struct WordLayoutInfo Size mSize; ///< Size of the word. float mAscender; ///< Max of all ascenders of all characters. TextSeparatorType mType; ///< Whether this word is a word separator, a line separator or is not a separator. + std::size_t mFirstCharacter; ///< Index to the first character of the word within the paragraph. CharacterLayoutInfoContainer mCharactersLayoutInfo; ///< Layout info for all characters. }; typedef std::vector WordLayoutInfoContainer; /** + * Stores the reordered layout for right to left text. + */ +struct RightToLeftParagraphLayout +{ + RightToLeftParagraphLayout() + : mWordsLayoutInfo(), + mText(), + mTextStyles(), + mPreviousLayoutCleared( false ) + { + } + + WordLayoutInfoContainer mWordsLayoutInfo; ///< Layout info for all words. + Text mText; ///< Stores the text. + Vector mTextStyles; ///< Stores the style per each character. + bool mPreviousLayoutCleared:1; ///< Whether the previous right to left layout has been cleared. + + /** + * Clears the word layout vector, the text and the vector of styles. + */ + void Clear(); +}; + +/** * Layout information for a paragraph. */ struct ParagraphLayoutInfo @@ -224,7 +258,7 @@ struct ParagraphLayoutInfo /** * Default destructor. * - * Clears all words. + * Clears all words, deletes all text styles, the paragraph bidirectional info and all bidirectional infor for each line. */ ~ParagraphLayoutInfo(); @@ -238,11 +272,30 @@ struct ParagraphLayoutInfo */ ParagraphLayoutInfo& operator=( const ParagraphLayoutInfo& paragraph ); + /** + * Deletes the bidirectional info for each line. + */ + void ClearBidirectionalInfo(); + +private: + + /** + * Deletes all text styles. + */ + void ClearStyles(); + +public: Size mSize; ///< Size of the paragraph. float mAscender; ///< Max of all ascenders of all words. float mLineHeightOffset; ///< Line height offset. + std::size_t mFirstCharacter; ///< Index to the first character of the paragraph. std::size_t mNumberOfCharacters; ///< Stores the number of characters. WordLayoutInfoContainer mWordsLayoutInfo; ///< Layout info for all words. + Text mText; ///< Stores the text. + Vector mTextStyles; ///< Stores the style per each character. + RightToLeftParagraphLayout* mRightToLeftLayout; ///< Stores the reordered layout for the paragraph. + TextProcessor::BidirectionalParagraphInfo* mBidirectionalParagraphInfo; ///< Contains bidirectional info for the whole paragraph. Set to NULL if the paragraph has left to right characters only. + Vector mBidirectionalLinesInfo; ///< Contains bidirectional info for each laid-out line. }; typedef std::vector ParagraphLayoutInfoContainer; @@ -259,6 +312,13 @@ struct TextLayoutInfo TextLayoutInfo(); /** + * Defualt destructor. + * + * Clears the paragraph vector, the ellipsis text and deletes all ellipsis styles. + */ + ~TextLayoutInfo(); + + /** * Copy constructor. */ TextLayoutInfo( const TextLayoutInfo& text ); @@ -268,12 +328,21 @@ struct TextLayoutInfo */ TextLayoutInfo& operator=( const TextLayoutInfo& text ); +private: + /** + * Deletes all the ellipsis text styles. + */ + void ClearStyles(); + +public: Size mWholeTextSize; ///< width and height of the whole text. float mMaxWordWidth; ///< maximum width between all words. float mMaxItalicsOffset; ///< When rendering text-view in offscreen an extra width offset is needed to prevent italic characters to be cut if they are in the right edge. std::size_t mNumberOfCharacters; ///< Stores the number of characters. ParagraphLayoutInfoContainer mParagraphsLayoutInfo; ///< Layout information for all paragraphs. WordLayoutInfo mEllipsizeLayoutInfo; ///< Layout information for the ellipsize text. + Dali::Text mEllipsisText; ///< The ellipsis text. + Vector mEllipsisTextStyles; ///< Stores the style per each character of the ellipsis text. }; } // namespace TextViewProcessor diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-processor.cpp index a485a6e..40f1fab 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-processor.cpp @@ -19,10 +19,12 @@ #include // INTERNAL INCLUDES +#include #include #include #include #include +#include namespace Dali { @@ -84,7 +86,8 @@ void UpdateLayoutInfo( TextLayoutInfo& textLayoutInfo ) TextInfoIndices::TextInfoIndices() : mParagraphIndex( 0u ), mWordIndex( 0u ), - mCharacterIndex( 0u ) + mCharacterIndex( 0u ), + mCharacterParagraphIndex( 0u ) { } @@ -93,7 +96,8 @@ TextInfoIndices::TextInfoIndices( const std::size_t paragraphIndex, const std::size_t characterIndex ) : mParagraphIndex( paragraphIndex ), mWordIndex( wordIndex ), - mCharacterIndex( characterIndex ) + mCharacterIndex( characterIndex ), + mCharacterParagraphIndex( 0u ) { } @@ -101,7 +105,8 @@ bool TextInfoIndices::operator==( const TextInfoIndices& indices ) const { return ( ( mParagraphIndex == indices.mParagraphIndex ) && ( mWordIndex == indices.mWordIndex ) && - ( mCharacterIndex == indices.mCharacterIndex ) ); + ( mCharacterIndex == indices.mCharacterIndex ) && + ( mCharacterParagraphIndex == indices.mCharacterParagraphIndex ) ); } ///////////////////// @@ -114,8 +119,19 @@ TextLayoutInfo::TextLayoutInfo() mMaxItalicsOffset( 0.f ), mNumberOfCharacters( 0u ), mParagraphsLayoutInfo(), - mEllipsizeLayoutInfo() + mEllipsizeLayoutInfo(), + mEllipsisText( "..." ), + mEllipsisTextStyles() { + // Sets default styles for the default ellipsis text. + mEllipsisTextStyles.PushBack( new TextStyle() ); + mEllipsisTextStyles.PushBack( new TextStyle() ); + mEllipsisTextStyles.PushBack( new TextStyle() ); +} + +TextLayoutInfo::~TextLayoutInfo() +{ + ClearStyles(); } TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text ) @@ -124,8 +140,14 @@ TextLayoutInfo::TextLayoutInfo( const TextLayoutInfo& text ) mMaxItalicsOffset( text.mMaxItalicsOffset ), mNumberOfCharacters( text.mNumberOfCharacters ), mParagraphsLayoutInfo( text.mParagraphsLayoutInfo ), - mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo ) + mEllipsizeLayoutInfo( text.mEllipsizeLayoutInfo ), + mEllipsisText( text.mEllipsisText ), + mEllipsisTextStyles() { + for( Vector::ConstIterator it = text.mEllipsisTextStyles.Begin(), endIt = text.mEllipsisTextStyles.End(); it != endIt; ++it ) + { + mEllipsisTextStyles.PushBack( new TextStyle( *(*it) ) ); + } } TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text ) @@ -138,11 +160,27 @@ TextLayoutInfo& TextLayoutInfo::operator=( const TextLayoutInfo& text ) mNumberOfCharacters = text.mNumberOfCharacters; mParagraphsLayoutInfo = text.mParagraphsLayoutInfo; mEllipsizeLayoutInfo = text.mEllipsizeLayoutInfo; - } + mEllipsisText = text.mEllipsisText; + ClearStyles(); + + for( Vector::ConstIterator it = text.mEllipsisTextStyles.Begin(), endIt = text.mEllipsisTextStyles.End(); it != endIt; ++it ) + { + mEllipsisTextStyles.PushBack( new TextStyle( *(*it) ) ); + } + } return *this; } +void TextLayoutInfo::ClearStyles() +{ + for( Vector::Iterator it = mEllipsisTextStyles.Begin(), endIt = mEllipsisTextStyles.End(); it != endIt; ++it ) + { + delete *it; + } + mEllipsisTextStyles.Clear(); +} + ///////////////////////////////////////////////////////////////////////////////////////////// void CreateTextInfo( const MarkupProcessor::StyledTextArray& text, @@ -152,9 +190,11 @@ void CreateTextInfo( const MarkupProcessor::StyledTextArray& text, // * Traverse the given text spliting it in paragraphs and each paragraph in words. // * White spaces and new paragraph characters are alone in one word. // * Bidirectional text is processed in each paragraph. + // It creates the conversion tables + // It does the ligatures if there is arabic glyphs. + // It doesn't reorder the text as it must be done for each line not for the paragraph. // * Generates a layout data structure to store layout information (size, position, ascender, text direction, etc) and metrics of all characters. - // * Generates a text-actor data structure to store text, style and text-actors. - // TODO: finish and test the bidirectional implementation. + // * Store text for each paragraph and the style for each character. // Collect previously created text-actors. std::vector textActors; @@ -168,49 +208,77 @@ void CreateTextInfo( const MarkupProcessor::StyledTextArray& text, } // Store the ellipsize layout info before clearing the previous created info. + // TODO: fix this. Don't clear the ellipsis layout, store it somewhere else ... const WordLayoutInfo ellipsizeInfo = relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo; + Dali::Text ellipsisText = relayoutData.mTextLayoutInfo.mEllipsisText; + Vector ellipsisTextStyles = relayoutData.mTextLayoutInfo.mEllipsisTextStyles; + relayoutData.mTextLayoutInfo.mEllipsisTextStyles.Clear(); - // clear previous created info. + // clear previously created info. relayoutData.mTextLayoutInfo = TextLayoutInfo(); relayoutData.mCharacterLogicalToVisualMap.clear(); relayoutData.mCharacterVisualToLogicalMap.clear(); // Sets the ellipsize layout info. relayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = ellipsizeInfo; + relayoutData.mTextLayoutInfo.mEllipsisText = ellipsisText; + relayoutData.mTextLayoutInfo.mEllipsisTextStyles = ellipsisTextStyles; // Split the whole text in paragraphs. - std::vector paragraphs; + // It returns a vector of Text with all the paragraphs. + // and for each paragraph a vector of styles per character. TODO: don't create a style per character. + std::vector paragraphs; + std::vector< Vector > styles; TextProcessor::SplitInParagraphs( text, - paragraphs ); + paragraphs, + styles ); + + // Reserve space for the current number of paragraphs. + relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.resize( paragraphs.size(), ParagraphLayoutInfo() ); // Traverse all paragraphs - for( std::vector::const_iterator paragraphIt = paragraphs.begin(), paragraphEndIt = paragraphs.end(); paragraphIt != paragraphEndIt; ++paragraphIt ) + std::size_t paragraphIndex = 0u; + std::vector::iterator paragraphIt, paragraphEndIt; + std::vector< Vector >::const_iterator styleIt, styleEndIt; + for( paragraphIt = paragraphs.begin(), paragraphEndIt = paragraphs.end(), + styleIt = styles.begin(), styleEndIt = styles.end(); + ( paragraphIt != paragraphEndIt ) && ( styleIt != styleEndIt ); + ++paragraphIndex, + ++paragraphIt, + ++styleIt ) { - const MarkupProcessor::StyledTextArray& paragraph( *paragraphIt ); + // Gets the paragraph and the styles for each character. + Text& paragraph( *paragraphIt ); + const Vector& textStyles( *styleIt ); + + // Retrieve the data structure for the current paragraph. + ParagraphLayoutInfo& paragraphLayoutInfo = *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndex ); - // Data structures for the new paragraph - ParagraphLayoutInfo paragraphLayoutInfo; + // Sets text and styles. + paragraphLayoutInfo.mText = paragraph; + paragraphLayoutInfo.mTextStyles = textStyles; - // Fills the paragraph data structures with the layout info. - CreateParagraphInfo( paragraph, - relayoutData, - paragraphLayoutInfo ); + // Fills the paragraph data structure with the layout info. - if( 0u < paragraphLayoutInfo.mNumberOfCharacters ) + if( !paragraph.IsEmpty() ) { + CreateParagraphInfo( relayoutData, + paragraphLayoutInfo ); + // do not add the line offset if the paragraph has no characters. paragraphLayoutInfo.mSize.height += layoutParameters.mLineHeightOffset; paragraphLayoutInfo.mLineHeightOffset = layoutParameters.mLineHeightOffset; } else { - // line height needs to be added for the last paragraph. + // This paragraph has no text. i.e. the previous paragraph ends with '\n'. + // Even though, line height needs to be set in order to align the whole text correctly. float lineHeight = 0.f; // Get the last character of the last paragraph. - if( !relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.empty() ) + if( 0u < paragraphIndex ) { - const ParagraphLayoutInfo& paragraphInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.end() - 1u ) ); + const ParagraphLayoutInfo& paragraphInfo( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + ( paragraphIndex - 1u ) ) ); const CharacterLayoutInfo characterInfo = GetLastCharacterLayoutInfo( paragraphInfo ); @@ -220,16 +288,21 @@ void CreateTextInfo( const MarkupProcessor::StyledTextArray& text, paragraphLayoutInfo.mSize.height = lineHeight; } + // Fills the conversion tables used to get the logical or visual position of a character is case there is right to left text. + // If there is right to left text, it needs to be updated every time the text is relaid-out. + for( std::size_t index = 0u; index < paragraphLayoutInfo.mNumberOfCharacters; ++index ) + { + relayoutData.mCharacterLogicalToVisualMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); + relayoutData.mCharacterVisualToLogicalMap.push_back( relayoutData.mTextLayoutInfo.mNumberOfCharacters + index ); + } + // Update layout info for the whole text. UpdateSize( relayoutData.mTextLayoutInfo.mWholeTextSize, paragraphLayoutInfo.mSize, GrowHeight ); relayoutData.mTextLayoutInfo.mNumberOfCharacters += paragraphLayoutInfo.mNumberOfCharacters; - - // Add the paragraph to the current text. - relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.push_back( paragraphLayoutInfo ); } // end of paragraphs } -void UpdateTextInfo( const std::size_t position, +void UpdateTextInfo( std::size_t position, const MarkupProcessor::StyledTextArray& text, const TextView::LayoutParameters& layoutParameters, TextView::RelayoutData& relayoutData ) @@ -242,7 +315,7 @@ void UpdateTextInfo( const std::size_t position, // * Merge the last paragraph of the new text to the last part or the split paragraph. // * Add paragraphs between first and last of the new text. // * Merge the first part of the split paragraph with the first paragraph of the new text. - // * Update layout info and create new text actors if needed. + // * Update the layout info for the whole text. // Early returns: @@ -269,6 +342,15 @@ void UpdateTextInfo( const std::size_t position, DALI_ASSERT_ALWAYS( !"TextViewProcessor::UpdateTextInfo (insert). Trying to insert text out of bounds." ); } + + // TODO + // If in the insertion is involved right to left text, + // check the neighbour characters is needed. + // i.e. Arabic characters may have four different glyphs (isolated, end, middle, begin). + // So check the neighbours on each side is needed in order to render + // the correct ligatures. + + TextView::RelayoutData relayoutDataForNewText; // Creates layout info for the given text. @@ -277,8 +359,8 @@ void UpdateTextInfo( const std::size_t position, layoutParameters, relayoutDataForNewText ); - // Update logical-to-visual and visual-to-logical tables. - // TODO: check that for mixed RTL/LTR text. + // Fills the conversion tables used to get the logical or visual position of a character is case there is right to left text. + // If there is right to left text, it needs to be updated every time the text is relaid-out. std::size_t index = 0u; for( std::size_t i = 0u; i < relayoutDataForNewText.mTextLayoutInfo.mNumberOfCharacters; ++i ) { @@ -335,6 +417,13 @@ void UpdateTextInfo( const std::size_t position, const WordLayoutInfo& wordLayoutInfo( *( paragraphLayoutInfo.mWordsLayoutInfo.end() - 1u ) ); textInfoIndices.mCharacterIndex = wordLayoutInfo.mCharactersLayoutInfo.size(); + + // Sets the character index within the paragraph. + textInfoIndices.mCharacterParagraphIndex = 0u; + for( WordLayoutInfoContainer::const_iterator it = paragraphLayoutInfo.mWordsLayoutInfo.begin(), endIt = paragraphLayoutInfo.mWordsLayoutInfo.end(); it != endIt; ++it ) + { + textInfoIndices.mCharacterParagraphIndex += wordLayoutInfo.mCharactersLayoutInfo.size(); + } } } } @@ -382,8 +471,8 @@ void UpdateTextInfo( const std::size_t position, UpdateLayoutInfo( relayoutData.mTextLayoutInfo ); } -void UpdateTextInfo( const std::size_t position, - const std::size_t numberOfCharacters, +void UpdateTextInfo( std::size_t position, + std::size_t numberOfCharacters, const TextView::LayoutParameters& layoutParameters, TextView::RelayoutData& relayoutData, const TextOperationOnRemove clearText ) @@ -414,7 +503,8 @@ void UpdateTextInfo( const std::size_t position, // Asserts if trying to delete text out of bounds. DALI_ASSERT_ALWAYS( position + numberOfCharacters <= relayoutData.mTextLayoutInfo.mNumberOfCharacters && "TextViewProcessor::UpdateTextInfo. ERROR: trying to delete characters out of boundary" ); - // Remove characters from character to visual map and vs //TODO: check this for RTL text!! + // Remove characters from character to visual map and vs. + // If there is right to left text, it needs to be updated every time the text is relaid-out. relayoutData.mCharacterLogicalToVisualMap.erase( relayoutData.mCharacterLogicalToVisualMap.end() - numberOfCharacters, relayoutData.mCharacterLogicalToVisualMap.end() ); relayoutData.mCharacterVisualToLogicalMap.erase( relayoutData.mCharacterVisualToLogicalMap.end() - numberOfCharacters, relayoutData.mCharacterVisualToLogicalMap.end() ); @@ -521,6 +611,19 @@ void UpdateTextInfo( const std::size_t position, // As paragraphIndexBegin has been increased just to not to remove the paragraph, decrease now is needed to access it. ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex - 1u ) ); + // Remove the characters from the text and the styles. + paragraphLayout.mText.Remove( textInfoIndicesBegin.mCharacterParagraphIndex, paragraphLayout.mNumberOfCharacters - textInfoIndicesBegin.mCharacterParagraphIndex ); + + for( Vector::Iterator it = paragraphLayout.mTextStyles.Begin() + textInfoIndicesBegin.mCharacterParagraphIndex, + endIt = paragraphLayout.mTextStyles.End(); + it != endIt; + ++it ) + { + delete *it; + } + paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin() + textInfoIndicesBegin.mCharacterParagraphIndex, + paragraphLayout.mTextStyles.End() ); + if( ( textInfoIndicesBegin.mWordIndex + 1u < paragraphLayout.mWordsLayoutInfo.size() ) || ( 0u == textInfoIndicesBegin.mCharacterIndex ) ) { // Remove extra words within current paragraph. (and current word if whole characters are removed) @@ -577,6 +680,21 @@ void UpdateTextInfo( const std::size_t position, // Get the last paragraph. ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + paragraphIndex ) ); + // Remove the characters from the text and the styles. + const std::size_t lastCharacterIndex = textInfoIndicesEnd.mCharacterParagraphIndex + 1u; + + paragraphLayout.mText.Remove( 0u, lastCharacterIndex ); + + for( Vector::Iterator it = paragraphLayout.mTextStyles.Begin(), + endIt = paragraphLayout.mTextStyles.Begin() + lastCharacterIndex; + it != endIt; + ++it ) + { + delete *it; + } + paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin(), + paragraphLayout.mTextStyles.Begin() + lastCharacterIndex ); + // Check if is needed remove the whole word. (If the character index is pointing just after the end of the word) const WordLayoutInfo& wordLayout( *( paragraphLayout.mWordsLayoutInfo.begin() + textInfoIndicesEnd.mWordIndex ) ); bool removeWholeWord = wordLayout.mCharactersLayoutInfo.size() == textInfoIndicesEnd.mCharacterIndex + 1u; @@ -634,6 +752,22 @@ void UpdateTextInfo( const std::size_t position, // Paragraph which contains the characters to be deleted. ParagraphLayoutInfo& paragraphLayout( *( relayoutData.mTextLayoutInfo.mParagraphsLayoutInfo.begin() + textInfoIndicesBegin.mParagraphIndex ) ); + // Remove the characters from the text and the styles. + const std::size_t firstCharacterIndex = textInfoIndicesBegin.mCharacterParagraphIndex; + const std::size_t lastCharacterIndex = textInfoIndicesEnd.mCharacterParagraphIndex + 1u; + + paragraphLayout.mText.Remove( firstCharacterIndex, lastCharacterIndex - firstCharacterIndex ); + + for( Vector::Iterator it = paragraphLayout.mTextStyles.Begin() + firstCharacterIndex, + endIt = paragraphLayout.mTextStyles.Begin() + lastCharacterIndex; + it != endIt; + ++it ) + { + delete *it; + } + paragraphLayout.mTextStyles.Erase( paragraphLayout.mTextStyles.Begin() + firstCharacterIndex, + paragraphLayout.mTextStyles.Begin() + lastCharacterIndex ); + // Remove the characters from the paragraph layout info. It returns whether the current paragraph can be merged with the next one. RemoveCharactersFromParagraphInfo( relayoutData, numberOfCharacters, @@ -730,8 +864,8 @@ void UpdateTextInfo( const std::size_t position, relayoutData.mTextActorCache.InsertTextActors( removedTextActorsFromBegin ); } -void UpdateTextInfo( const std::size_t position, - const std::size_t numberOfCharacters, +void UpdateTextInfo( std::size_t position, + std::size_t numberOfCharacters, const MarkupProcessor::StyledTextArray& text, const TextView::LayoutParameters& layoutParameters, TextView::RelayoutData& relayoutData ) @@ -788,6 +922,17 @@ void UpdateTextInfo( const TextStyle& style, { ParagraphLayoutInfo& paragraph( *paragraphIt ); + std::size_t index = 0u; + for( Vector::Iterator it = paragraph.mTextStyles.Begin(), endIt = paragraph.mTextStyles.End(); it != endIt; ++it ) + { + (*it)->Copy( style, mask ); + + // Checks if the font family supports all glyphs. If not, chooses a most suitable one. + ChooseFontFamilyName( paragraph.mText[index], *(*it) ); + + ++index; + } + for( WordLayoutInfoContainer::iterator wordIt = paragraph.mWordsLayoutInfo.begin(), wordEndIt = paragraph.mWordsLayoutInfo.end(); wordIt != wordEndIt; ++wordIt ) @@ -800,11 +945,6 @@ void UpdateTextInfo( const TextStyle& style, { CharacterLayoutInfo& characterLayout( *characterIt ); - characterLayout.mStyledText.mStyle.Copy( style, mask ); - - // Checks if the font family supports all glyphs. If not, chooses a most suitable one. - ChooseFontFamilyName( characterLayout.mStyledText ); - // Mark the character to be set the new style into the text-actor. characterLayout.mSetStyle = true; } // end characters diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.cpp b/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.cpp index b1426c9..800a96b 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.cpp +++ b/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.cpp @@ -39,33 +39,6 @@ namespace const std::string EMOJI_FONT_NAME( "SamsungEmoji" ); // Emoticons font family name. -/** - * Updates the word size and ascender. - * - * It's called after deleting some characters. - * - * @param[in] wordLayout The word layout info. - */ -void UpdateLayoutInfo( WordLayoutInfo& wordLayout ) -{ - // Initialize layout info for the whole word. - wordLayout.mSize = Size::ZERO; - wordLayout.mAscender = 0.f; - - // Traverse the character layout info to update the word layout. - for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end(); - layoutIt != layoutEndIt; - ++layoutIt ) - { - // Layout info for the current character. - CharacterLayoutInfo& layoutInfo( *layoutIt ); - - // Update layout info for the current word. - UpdateSize( wordLayout.mSize, layoutInfo.mSize ); - wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender ); - } -} - } // namespace ///////////////////// @@ -76,6 +49,7 @@ WordLayoutInfo::WordLayoutInfo() : mSize(), mAscender( 0.f ), mType( NoSeparator ), + mFirstCharacter( 0u ), mCharactersLayoutInfo() { } @@ -88,6 +62,7 @@ WordLayoutInfo::WordLayoutInfo( const WordLayoutInfo& word ) : mSize( word.mSize ), mAscender( word.mAscender ), mType( word.mType ), + mFirstCharacter( word.mFirstCharacter ), mCharactersLayoutInfo( word.mCharactersLayoutInfo ) { } @@ -97,87 +72,103 @@ WordLayoutInfo& WordLayoutInfo::operator=( const WordLayoutInfo& word ) mSize = word.mSize; mAscender = word.mAscender; mType = word.mType; + mFirstCharacter = word.mFirstCharacter; mCharactersLayoutInfo = word.mCharactersLayoutInfo; return *this; } -void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word, +void CreateWordTextInfo( const Text& paragraph, + Vector& textStyles, WordLayoutInfo& wordLayoutInfo ) { DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "-->TextViewProcessor::CreateWordTextInfo\n" ); // Split in characters. - for( MarkupProcessor::StyledTextArray::const_iterator charIt = word.begin(), charEndIt = word.end(); charIt != charEndIt; ++charIt ) + std::size_t characterIndex = wordLayoutInfo.mFirstCharacter; + for( CharacterLayoutInfoContainer::iterator it = wordLayoutInfo.mCharactersLayoutInfo.begin(), + endIt = wordLayoutInfo.mCharactersLayoutInfo.end(); + it != endIt; + ++it, ++characterIndex ) { - const MarkupProcessor::StyledText& styledText( *charIt ); + // Gets a reference of the character's layout info. + CharacterLayoutInfo& characterLayoutInfo( *it ); + + // Gets the character and the style for that character from the paragraph. + Character character = paragraph[characterIndex]; + TextStyle* textStyle = *( textStyles.Begin() + characterIndex ); - const std::size_t length = styledText.mText.GetLength(); + // Checks whether the character is an emoticon. + characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character ); + DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) ); - // It could be a group of characters. - for( std::size_t index = 0u; index < length; ++index ) + if( characterLayoutInfo.mIsColorGlyph ) { - MarkupProcessor::StyledText styledCharacter; - styledCharacter.mStyle = styledText.mStyle; - Character character = styledText.mText[index]; - styledCharacter.mText.Append( character ); + // If the character is an emoticon a predefined font is set. + textStyle->SetFontName( EMOJI_FONT_NAME ); + } + else + { + // Checks if the font family and the font style set in the text style supports the character. + // If not, it chooses the right font for the given character and style. + ChooseFontFamilyName( character, *textStyle ); + } - // Create layout character info. - CharacterLayoutInfo characterLayoutInfo; + // Gets the metrics of the font. + const Font font = Font::New( FontParameters( textStyle->GetFontName(), textStyle->GetFontStyle(), textStyle->GetFontPointSize() ) ); + const Font::Metrics metrics = font.GetMetrics( character ); + const float ascender = font.GetAscender(); - characterLayoutInfo.mIsColorGlyph = GlyphImage::IsColorGlyph( character ); - DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, " Is color glyph: %s\n", ( characterLayoutInfo.mIsColorGlyph ? "True" : "False" ) ); + // Fill Natural size info for current character. - if( characterLayoutInfo.mIsColorGlyph ) - { - styledCharacter.mStyle.SetFontName( EMOJI_FONT_NAME ); - } - else - { - //Choose the right font for the given character and style. - ChooseFontFamilyName( styledCharacter ); - } + // The font line's height is used as character's height. + characterLayoutInfo.mSize.height = font.GetLineHeight(); - // Gets the metrics of the font. - const Font font = Font::New( FontParameters( styledCharacter.mStyle.GetFontName(), styledCharacter.mStyle.GetFontStyle(), styledCharacter.mStyle.GetFontPointSize() ) ); - const Font::Metrics metrics = font.GetMetrics( character ); - const float ascender = font.GetAscender(); + // The character's advance is used as charcter's width. + characterLayoutInfo.mSize.width = metrics.GetAdvance(); - // The font line's height is used as character's height. - characterLayoutInfo.mSize.height = font.GetLineHeight(); + // The ascender and bearing are used to position correctly glyphs of different font sizes. + characterLayoutInfo.mAscender = ascender; + characterLayoutInfo.mBearing = metrics.GetBearing(); - // The character's advance is used as charcter's width. - characterLayoutInfo.mSize.width = metrics.GetAdvance(); + if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph ) + { + // A new paragraph character '\n' doesn't have any width. + characterLayoutInfo.mSize.width = 0.f; + } - // The ascender and bearing are used to position correctly glyphs of different font sizes. - characterLayoutInfo.mAscender = ascender; - characterLayoutInfo.mBearing = metrics.GetBearing(); + // Set's the underline thickness and position. + // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow. + if( textStyle->IsUnderlineEnabled() ) + { + characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); + characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); + } - if( character.IsNewLine() && !characterLayoutInfo.mIsColorGlyph ) - { - // A new paragraph character doesn't have any width. - characterLayoutInfo.mSize.width = 0.f; - } + // Updates the word size and ascender. + UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize ); + wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender ); + } // end of characters in the word. + DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" ); +} - // Set's the underline thickness and position. - // Both thickness and position includes the vertical pad adjust used in effects like glow or shadow. - if( styledCharacter.mStyle.IsUnderlineEnabled() ) - { - characterLayoutInfo.mUnderlineThickness = font.GetUnderlineThickness(); - characterLayoutInfo.mUnderlinePosition = font.GetUnderlinePosition(); - } +void UpdateLayoutInfo( WordLayoutInfo& wordLayout ) +{ + // Initialize layout info for the whole word. + wordLayout.mSize = Size::ZERO; + wordLayout.mAscender = 0.f; - // stores the styled text. - characterLayoutInfo.mStyledText.mText = styledCharacter.mText; - characterLayoutInfo.mStyledText.mStyle = styledCharacter.mStyle; + // Traverse the character layout info to update the word layout. + for( CharacterLayoutInfoContainer::iterator layoutIt = wordLayout.mCharactersLayoutInfo.begin(), layoutEndIt = wordLayout.mCharactersLayoutInfo.end(); + layoutIt != layoutEndIt; + ++layoutIt ) + { + // Layout info for the current character. + CharacterLayoutInfo& layoutInfo( *layoutIt ); - // Add character layout info to the word layout info and update it. - wordLayoutInfo.mCharactersLayoutInfo.push_back( characterLayoutInfo ); - UpdateSize( wordLayoutInfo.mSize, characterLayoutInfo.mSize ); - wordLayoutInfo.mAscender = std::max( wordLayoutInfo.mAscender, characterLayoutInfo.mAscender ); - wordLayoutInfo.mType = GetTextSeparatorType( character ); - } // end of each character in the group of characters. - } // end of characters in the word. - DALI_LOG_INFO( gTextViewProcessorLogFilter, Debug::General, "<--TextViewProcessor::CreateWordTextInfo\n" ); + // Update layout info for the current word. + UpdateSize( wordLayout.mSize, layoutInfo.mSize ); + wordLayout.mAscender = std::max( wordLayout.mAscender, layoutInfo.mAscender ); + } } void RemoveCharactersFromWordInfo( TextView::RelayoutData& relayoutData, diff --git a/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.h b/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.h index 7b2845c..82f36f0 100644 --- a/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.h +++ b/base/dali-toolkit/internal/controls/text-view/text-view-word-processor.h @@ -36,13 +36,25 @@ namespace TextViewProcessor /** * Creates a data structure with info to layout the word, and data structures with useful info to modify the layout data structure if characters are added or removed. * - * @param[in] word The styled word. + * @param[in] paragraphText The paragraph's text. + * @param[in] textStyles The styles for each character of the paragraph. * @param[out] wordLayoutInfo Layout info for all characters of the word. */ -void CreateWordTextInfo( const MarkupProcessor::StyledTextArray& word, +void CreateWordTextInfo( const Text& paragraphText, + Vector& textStyles, WordLayoutInfo& wordLayoutInfo ); /** + * Updates the word size and ascender. + * + * It's called after deleting some characters, split a word in two, + * or when a new word is created when right to left text is reordered. + * + * @param[in] wordLayout The word layout info. + */ +void UpdateLayoutInfo( WordLayoutInfo& wordLayout ); + +/** * Removes a given number of characters from the given word. * * It calls the RemoveCharactersFromWord() function to remove characters from the word. diff --git a/base/dali-toolkit/internal/file.list b/base/dali-toolkit/internal/file.list index 4fa6bf8..f2331cc 100644 --- a/base/dali-toolkit/internal/file.list +++ b/base/dali-toolkit/internal/file.list @@ -47,6 +47,7 @@ toolkit_base_src_files = \ $(toolkit_base_src_dir)/controls/text-view/split-by-char-policies.cpp \ $(toolkit_base_src_dir)/controls/text-view/text-actor-cache.cpp \ $(toolkit_base_src_dir)/controls/text-view/text-processor.cpp \ + $(toolkit_base_src_dir)/controls/text-view/text-processor-bidirectional-info.cpp \ $(toolkit_base_src_dir)/controls/text-view/text-view-impl.cpp \ $(toolkit_base_src_dir)/controls/text-view/text-view-character-processor.cpp \ $(toolkit_base_src_dir)/controls/text-view/text-view-paragraph-processor.cpp \