From: Kimmo Hoikka Date: Wed, 22 Jul 2015 12:59:07 +0000 (-0700) Subject: Merge "Multi-line layout." into devel/master X-Git-Tag: dali_1.0.50~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=06e563f8a982e25a0efe2d91c794657dc8e4bc4a;hp=8269fc656ce5c08314e340932c2af762e7234628 Merge "Multi-line layout." into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp index 4b89f25..410c34f 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp @@ -68,23 +68,17 @@ bool ScriptsTest( const ScriptsData& data ) &utf32[0u] ); utf32.Resize( numberOfCharacters ); - // 2) Set the line break info. - Vector lineBreakInfo; - lineBreakInfo.Resize( numberOfCharacters ); - - SetLineBreakInfo( utf32, lineBreakInfo ); - - // 3) Set the script info. + // 2) Set the script info. Vector scripts; multilanguageSupport.SetScripts( utf32, - lineBreakInfo, scripts ); - // 4) Compare the results. + // 3) Compare the results. + tet_printf( "Testing %s\n", data.description.c_str() ); if( scripts.Count() != data.scriptRuns.Count() ) { - tet_infoline("ScriptsTest: different number of scripts."); + tet_printf("ScriptsTest FAIL: different number of scripts. %d, should be %d\n", scripts.Count(), data.scriptRuns.Count() ); return false; } @@ -95,19 +89,19 @@ bool ScriptsTest( const ScriptsData& data ) if( scriptRun1.characterRun.characterIndex != scriptRun2.characterRun.characterIndex ) { - tet_infoline("ScriptsTest: different character index."); + tet_printf("ScriptsTest FAIL: different character index. %d, should be %d\n", scriptRun1.characterRun.characterIndex, scriptRun2.characterRun.characterIndex ); return false; } if( scriptRun1.characterRun.numberOfCharacters != scriptRun2.characterRun.numberOfCharacters ) { - tet_infoline("ScriptsTest: different number of characters."); + tet_printf("ScriptsTest FAIL: different number of characters. %d, should be %d\n", scriptRun1.characterRun.numberOfCharacters, scriptRun2.characterRun.numberOfCharacters ); return false; } if( scriptRun1.script != scriptRun2.script ) { - tet_infoline("ScriptsTest: different script."); + tet_printf("ScriptsTest FAIL: different script. %s, should be %s\n", TextAbstraction::ScriptName[scriptRun1.script], TextAbstraction::ScriptName[scriptRun2.script] ); return false; } } @@ -128,20 +122,13 @@ bool ValidateFontTest( const ValidateFontsData& data ) &utf32[0u] ); utf32.Resize( numberOfCharacters ); - // 2) Set the line break info. - Vector lineBreakInfo; - lineBreakInfo.Resize( numberOfCharacters ); - - SetLineBreakInfo( utf32, lineBreakInfo ); - - // 3) Set the script info. + // 2) Set the script info. Vector scripts; multilanguageSupport.SetScripts( utf32, - lineBreakInfo, scripts ); Vector fonts; - // 4) Validate the fonts + // 3) Validate the fonts multilanguageSupport.ValidateFonts( utf32, scripts, fonts ); @@ -190,6 +177,249 @@ int UtcDaliTextMultiLanguageSetScripts(void) }; scriptRuns01.PushBack( scriptRun0100 ); + // Mix of LTR '\n'and RTL + Vector scriptRuns02; + ScriptRun scriptRun0200 = + { + 0u, + 12u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun0201 = + { + 12u, + 13u, + TextAbstraction::ARABIC + }; + scriptRuns02.PushBack( scriptRun0200 ); + scriptRuns02.PushBack( scriptRun0201 ); + + // Mix of RTL '\n'and LTR + Vector scriptRuns03; + ScriptRun scriptRun0300 = + { + 0u, + 14u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun0301 = + { + 14u, + 11u, + TextAbstraction::LATIN + }; + scriptRuns03.PushBack( scriptRun0300 ); + scriptRuns03.PushBack( scriptRun0301 ); + + // White spaces. At the beginning of the text. + Vector scriptRuns04; + ScriptRun scriptRun0400 = + { + 0u, + 16u, + TextAbstraction::LATIN + }; + scriptRuns04.PushBack( scriptRun0400 ); + + // White spaces. At the end of the text. + Vector scriptRuns05; + ScriptRun scriptRun0500 = + { + 0u, + 16u, + TextAbstraction::LATIN + }; + scriptRuns05.PushBack( scriptRun0500 ); + + // White spaces. At the middle of the text. + Vector scriptRuns06; + ScriptRun scriptRun0600 = + { + 0u, + 16u, + TextAbstraction::LATIN + }; + scriptRuns06.PushBack( scriptRun0600 ); + + // White spaces between different scripts. + Vector scriptRuns07; + ScriptRun scriptRun0700 = + { + 0u, + 8u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun0701 = + { + 8u, + 5u, + TextAbstraction::HANGUL + }; + scriptRuns07.PushBack( scriptRun0700 ); + scriptRuns07.PushBack( scriptRun0701 ); + + // White spaces between different scripts and differetn directions. Starting LTR. + Vector scriptRuns08; + ScriptRun scriptRun0800 = + { + 0u, + 18u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun0801 = + { + 18u, + 14u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun0802 = + { + 32u, + 18u, + TextAbstraction::HANGUL + }; + scriptRuns08.PushBack( scriptRun0800 ); + scriptRuns08.PushBack( scriptRun0801 ); + scriptRuns08.PushBack( scriptRun0802 ); + + // White spaces between different scripts and differetn directions. Starting RTL. + Vector scriptRuns09; + ScriptRun scriptRun0900 = + { + 0u, + 21u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun0901 = + { + 21u, + 16u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun0902 = + { + 37u, + 10u, + TextAbstraction::HANGUL + }; + ScriptRun scriptRun0903 = + { + 47u, + 20u, + TextAbstraction::ARABIC + }; + scriptRuns09.PushBack( scriptRun0900 ); + scriptRuns09.PushBack( scriptRun0901 ); + scriptRuns09.PushBack( scriptRun0902 ); + scriptRuns09.PushBack( scriptRun0903 ); + + // Paragraphs with different directions. + Vector scriptRuns10; + ScriptRun scriptRun1000 = + { + 0u, + 20u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun1001 = + { + 20u, + 12u, + TextAbstraction::HEBREW + }; + ScriptRun scriptRun1002 = + { + 32u, + 17u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun1003 = + { + 49u, + 18u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun1004 = + { + 67u, + 14u, + TextAbstraction::HANGUL + }; + ScriptRun scriptRun1005 = + { + 81u, + 19u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun1006 = + { + 100u, + 13u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun1007 = + { + 113u, + 16u, + TextAbstraction::HEBREW + }; + ScriptRun scriptRun1008 = + { + 129u, + 20u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun1009 = + { + 149u, + 14u, + TextAbstraction::ARABIC + }; + ScriptRun scriptRun1010 = + { + 163u, + 35u, + TextAbstraction::HANGUL + }; + scriptRuns10.PushBack( scriptRun1000 ); + scriptRuns10.PushBack( scriptRun1001 ); + scriptRuns10.PushBack( scriptRun1002 ); + scriptRuns10.PushBack( scriptRun1003 ); + scriptRuns10.PushBack( scriptRun1004 ); + scriptRuns10.PushBack( scriptRun1005 ); + scriptRuns10.PushBack( scriptRun1006 ); + scriptRuns10.PushBack( scriptRun1007 ); + scriptRuns10.PushBack( scriptRun1008 ); + scriptRuns10.PushBack( scriptRun1009 ); + scriptRuns10.PushBack( scriptRun1010 ); + + // Paragraphs with no scripts mixed with paragraphs with scripts. + Vector scriptRuns11; + ScriptRun scriptRun1100 = + { + 0u, + 31u, + TextAbstraction::LATIN + }; + ScriptRun scriptRun1101 = + { + 31u, + 21u, + TextAbstraction::HEBREW + }; + scriptRuns11.PushBack( scriptRun1100 ); + scriptRuns11.PushBack( scriptRun1101 ); + + // Paragraphs with no scripts. + Vector scriptRuns12; + ScriptRun scriptRun1200 = + { + 0u, + 11u, + TextAbstraction::LATIN + }; + scriptRuns12.PushBack( scriptRun1200 ); + const ScriptsData data[] = { { @@ -202,8 +432,67 @@ int UtcDaliTextMultiLanguageSetScripts(void) "Hello world", scriptRuns01, }, + { + "Mix of LTR '\\n'and RTL", + "Hello world\nمرحبا بالعالم", + scriptRuns02, + }, + { + "Mix of RTL '\\n'and LTR", + "مرحبا بالعالم\nHello world", + scriptRuns03, + }, + { + "White spaces. At the beginning of the text.", + " Hello world.", + scriptRuns04, + }, + { + "White spaces. At the end of the text.", + "Hello world. ", + scriptRuns05, + }, + { + "White spaces. At the middle of the text.", + "Hello world.", + scriptRuns06, + }, + { + "White spaces between different scripts.", + " Hel 세계 ", + scriptRuns07, + }, + { + "White spaces between different scripts and differetn directions. Starting LTR.", + " Hello world مرحبا بالعالم 안녕하세요 세계 ", + scriptRuns08, + }, + { + "White spaces between different scripts and differetn directions. Starting RTL.", + " مرحبا بالعالم Hello world 안녕하세요 세계 مرحبا بالعالم ", + scriptRuns09 + }, + { + "Paragraphs with different directions.", + " مرحبا بالعالم שלום עולם مرحبا بالعالم \n " + " Hello world 안녕하세요 세계 \n " + " مرحبا بالعالم Hello world שלום עולם \n " + " Hello world مرحبا بالعالم 안녕하세요 세계 \n " + " 안녕하세요 세계 ", + scriptRuns10 + }, + { + "Paragraphs with no scripts mixed with paragraphs with scripts.", + " \n \n Hello world \n \n \n שלום עולם \n \n \n ", + scriptRuns11 + }, + { + "Paragraphs with no scripts.", + " \n \n \n ", + scriptRuns12 + } }; - const unsigned int numberOfTests = 2u; + const unsigned int numberOfTests = 13u; for( unsigned int index = 0u; index < numberOfTests; ++index ) { diff --git a/dali-toolkit/internal/text/bidirectional-support.cpp b/dali-toolkit/internal/text/bidirectional-support.cpp index aff18be..fd85439 100644 --- a/dali-toolkit/internal/text/bidirectional-support.cpp +++ b/dali-toolkit/internal/text/bidirectional-support.cpp @@ -231,15 +231,33 @@ void ReorderLines( const Vector& bidirectionalInf } bool GetMirroredText( const Vector& text, - Vector& mirroredText ) + Vector& mirroredText, + const Vector& bidirectionalInfo ) { + bool hasTextMirrored = false; + // Handle to the bidirectional info module in text-abstraction. TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get(); mirroredText = text; - return bidirectionalSupport.GetMirroredText( mirroredText.Begin(), - mirroredText.Count() ); + Character* mirroredTextBuffer = mirroredText.Begin(); + + // Traverse the paragraphs and mirror the right to left ones. + for( Vector::ConstIterator it = bidirectionalInfo.Begin(), + endIt = bidirectionalInfo.End(); + it != endIt; + ++it ) + { + const BidirectionalParagraphInfoRun& run = *it; + + const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + run.characterRun.characterIndex, + run.characterRun.numberOfCharacters ); + + hasTextMirrored = hasTextMirrored || tmpMirrored; + } + + return hasTextMirrored; } void GetCharactersDirection( const Vector& bidirectionalInfo, diff --git a/dali-toolkit/internal/text/bidirectional-support.h b/dali-toolkit/internal/text/bidirectional-support.h index 2f3b251..72b147a 100644 --- a/dali-toolkit/internal/text/bidirectional-support.h +++ b/dali-toolkit/internal/text/bidirectional-support.h @@ -71,15 +71,17 @@ void ReorderLines( const Vector& bidirectionalInf Vector& lineInfoRuns ); /** - * @brief Replaces any character which could be mirrored. + * @brief Replaces any character in the right to left paragraphs which could be mirrored. * * @param[in] text The text. * @param[in] mirroredText The mirroredText. + * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph. * * @return @e true if a character has been replaced. */ bool GetMirroredText( const Vector& text, - Vector& mirroredText ); + Vector& mirroredText, + const Vector& bidirectionalInfo ); /** * @brief Retrieves the character's directions. diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index 01a5786..442b631 100644 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -580,7 +580,7 @@ struct LayoutEngine::Impl lineRun.numberOfGlyphs = layout.numberOfGlyphs; lineRun.characterRun.characterIndex = layout.characterIndex; lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters; - if( isLastLine ) + if( isLastLine && !layoutParameters.isLastNewParagraph ) { const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine; if( MULTI_LINE_BOX == mLayout ) @@ -623,8 +623,36 @@ struct LayoutEngine::Impl // Increase the glyph index. index += layout.numberOfGlyphs; + + if( isLastLine && + layoutParameters.isLastNewParagraph && + ( mLayout == MULTI_LINE_BOX ) ) + { + // Need to add a new line with no characters but with height to increase the actualSize.height + const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u ); + + Text::FontMetrics fontMetrics; + mFontClient.GetFontMetrics( glyphInfo.fontId, fontMetrics ); + + LineRun lineRun; + lineRun.glyphIndex = 0u; + lineRun.numberOfGlyphs = 0u; + lineRun.characterRun.characterIndex = 0u; + lineRun.characterRun.numberOfCharacters = 0u; + lineRun.width = 0.f; + lineRun.ascender = fontMetrics.ascender; + lineRun.descender = fontMetrics.descender; + lineRun.extraLength = 0.f; + lineRun.alignmentOffset = 0.f; + lineRun.direction = !RTL; + lineRun.ellipsis = false; + + actualSize.height += ( lineRun.ascender + -lineRun.descender ); + + lines.PushBack( lineRun ); + } } - } + } // end for() traversing glyphs. DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" ); diff --git a/dali-toolkit/internal/text/layouts/layout-parameters.h b/dali-toolkit/internal/text/layouts/layout-parameters.h index 8a49a91..78746ff 100644 --- a/dali-toolkit/internal/text/layouts/layout-parameters.h +++ b/dali-toolkit/internal/text/layouts/layout-parameters.h @@ -73,7 +73,8 @@ struct LayoutParameters charactersToGlyphsBuffer( NULL ), glyphsPerCharacterBuffer( NULL ), lineBidirectionalInfoRunsBuffer( NULL ), - numberOfBidirectionalInfoRuns( 0u ) + numberOfBidirectionalInfoRuns( 0u ), + isLastNewParagraph( false ) {} Vector2 boundingBox; @@ -89,6 +90,7 @@ struct LayoutParameters Length* glyphsPerCharacterBuffer; ///< The number of glyphs per character. BidirectionalLineInfoRun* lineBidirectionalInfoRunsBuffer; ///< Bidirectional conversion tables per line. Length numberOfBidirectionalInfoRuns; ///< The number of lines with bidirectional info. + bool isLastNewParagraph; ///< Whether the last character is a new paragraph character. }; } // namespace Text diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp index 3fa8f6f..5284a3b 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -194,7 +194,6 @@ Text::MultilanguageSupport MultilanguageSupport::Get() } void MultilanguageSupport::SetScripts( const Vector& text, - const Vector& lineBreakInfo, Vector& scripts ) { const Length numberOfCharacters = text.Count(); @@ -214,8 +213,8 @@ void MultilanguageSupport::SetScripts( const Vector& text, // Reserve some space to reduce the number of reallocations. scripts.Reserve( numberOfCharacters << 2u ); - // Whether the first valid script need to be set. - bool firstValidScript = true; + // Whether the first valid script needs to be set. + bool isFirstScriptToBeSet = true; // Whether the first valid script is a right to left script. bool isParagraphRTL = false; @@ -224,14 +223,15 @@ void MultilanguageSupport::SetScripts( const Vector& text, Length numberOfAllScriptCharacters = 0u; // Pointers to the text and break info buffers. - const Character* textBuffer = text.Begin(); - const LineBreakInfo* breakInfoBuffer = lineBreakInfo.Begin(); + const Character* const textBuffer = text.Begin(); // Traverse all characters and set the scripts. for( Length index = 0u; index < numberOfCharacters; ++index ) { Character character = *( textBuffer + index ); - LineBreakInfo breakInfo = *( breakInfoBuffer + index ); + + // Get the script of the character. + Script script = TextAbstraction::GetCharacterScript( character ); // Some characters (like white spaces) are valid for many scripts. The rules to set a script // for them are: @@ -244,19 +244,25 @@ void MultilanguageSupport::SetScripts( const Vector& text, // Skip those characters valid for many scripts like white spaces or '\n'. bool endOfText = index == numberOfCharacters; while( !endOfText && - TextAbstraction::IsCommonScript( character ) ) + ( TextAbstraction::COMMON == script ) ) { // Count all these characters to be added into a script. ++numberOfAllScriptCharacters; - if( TextAbstraction::LINE_MUST_BREAK == breakInfo ) + if( TextAbstraction::IsNewParagraph( character ) ) { - // The next character is a new paragraph. - // Know when there is a new paragraph is needed because if there is a white space + // The character is a new paragraph. + // To know when there is a new paragraph is needed because if there is a white space // between two scripts with different directions, it is added to the script with // the same direction than the first script of the paragraph. - firstValidScript = true; - isParagraphRTL = false; + isFirstScriptToBeSet = true; + + // Characters common to all scripts at the end of the paragraph are added to the last script (if the last one is not unknown). + if( TextAbstraction::UNKNOWN != currentScriptRun.script ) + { + currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; + numberOfAllScriptCharacters = 0u; + } } // Get the next character. @@ -265,7 +271,7 @@ void MultilanguageSupport::SetScripts( const Vector& text, if( !endOfText ) { character = *( textBuffer + index ); - breakInfo = *( breakInfoBuffer + index ); + script = TextAbstraction::GetCharacterScript( character ); } } @@ -276,25 +282,33 @@ void MultilanguageSupport::SetScripts( const Vector& text, break; } - // Get the script of the character. - Script script = TextAbstraction::GetCharacterScript( character ); - // Check if it is the first character of a paragraph. - if( firstValidScript && - ( TextAbstraction::UNKNOWN != script ) ) + if( isFirstScriptToBeSet && + ( TextAbstraction::UNKNOWN != script ) && + ( TextAbstraction::COMMON != script ) ) { // Sets the direction of the first valid script. isParagraphRTL = TextAbstraction::IsRightToLeftScript( script ); - firstValidScript = false; + isFirstScriptToBeSet = false; } - if( script != currentScriptRun.script ) + if( ( script != currentScriptRun.script ) && + ( TextAbstraction::COMMON != script ) ) { // Current run needs to be stored and a new one initialized. - if( isParagraphRTL != TextAbstraction::IsRightToLeftScript( script ) ) + if( ( isParagraphRTL == TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) ) && + ( TextAbstraction::UNKNOWN != currentScriptRun.script ) ) { - // Current script has different direction than the first script of the paragraph. + // Previous script has the same direction than the first script of the paragraph. + // All the previously skipped characters need to be added to the previous script before it's stored. + currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; + numberOfAllScriptCharacters = 0u; + } + else if( ( TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) == TextAbstraction::IsRightToLeftScript( script ) ) && + ( TextAbstraction::UNKNOWN != currentScriptRun.script ) ) + { + // Current script and previous one have the same direction. // All the previously skipped characters need to be added to the previous script before it's stored. currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; numberOfAllScriptCharacters = 0u; @@ -308,26 +322,22 @@ void MultilanguageSupport::SetScripts( const Vector& text, // Initialize the new one. currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters; - currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters; // Adds the white spaces which are at the begining of the script. + currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters + 1u; // Adds the white spaces which are at the begining of the script. currentScriptRun.script = script; numberOfAllScriptCharacters = 0u; } else { - // Adds white spaces between characters. - currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; - numberOfAllScriptCharacters = 0u; - } + if( TextAbstraction::UNKNOWN != currentScriptRun.script ) + { + // Adds white spaces between characters. + currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters; + numberOfAllScriptCharacters = 0u; - if( TextAbstraction::LINE_MUST_BREAK == breakInfo ) - { - // The next character is a new paragraph. - firstValidScript = true; - isParagraphRTL = false; + // Add one more character to the run. + ++currentScriptRun.characterRun.numberOfCharacters; + } } - - // Add one more character to the run. - ++currentScriptRun.characterRun.numberOfCharacters; } // Add remaining characters into the last script. diff --git a/dali-toolkit/internal/text/multi-language-support-impl.h b/dali-toolkit/internal/text/multi-language-support-impl.h index ee91aae..4dfc85c 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.h +++ b/dali-toolkit/internal/text/multi-language-support-impl.h @@ -94,7 +94,6 @@ public: * @copydoc Dali::MultilanguageSupport::SetScripts() */ void SetScripts( const Vector& text, - const Vector& lineBreakInfo, Vector& scripts ); /** diff --git a/dali-toolkit/internal/text/multi-language-support.cpp b/dali-toolkit/internal/text/multi-language-support.cpp index 8c28dd5..46d2cb5 100644 --- a/dali-toolkit/internal/text/multi-language-support.cpp +++ b/dali-toolkit/internal/text/multi-language-support.cpp @@ -49,11 +49,9 @@ MultilanguageSupport MultilanguageSupport::Get() } void MultilanguageSupport::SetScripts( const Vector& text, - const Vector& lineBreakInfo, Vector& scripts ) { GetImplementation( *this ).SetScripts( text, - lineBreakInfo, scripts ); } diff --git a/dali-toolkit/internal/text/multi-language-support.h b/dali-toolkit/internal/text/multi-language-support.h index a22676c..5c8ea1d 100644 --- a/dali-toolkit/internal/text/multi-language-support.h +++ b/dali-toolkit/internal/text/multi-language-support.h @@ -91,11 +91,9 @@ public: * script of the first character of the paragraph with a defined script. * * @param[in] text Vector of UTF-32 characters. - * @param[in] lineBreakInfo Vector with the line break info. * @param[out] scripts Vector containing the script runs for the whole text. */ void SetScripts( const Vector& text, - const Vector& lineBreakInfo, Vector& scripts ); /** diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp index 9ca8e9f..0f4a114 100644 --- a/dali-toolkit/internal/text/shaper.cpp +++ b/dali-toolkit/internal/text/shaper.cpp @@ -49,7 +49,8 @@ void ShapeText( const Vector& text, const Vector& fonts, Vector& glyphs, Vector& glyphToCharacterMap, - Vector& charactersPerGlyph ) + Vector& charactersPerGlyph, + Vector& newParagraphGlyphs ) { const Length numberOfCharacters = text.Count(); @@ -74,7 +75,7 @@ void ShapeText( const Vector& text, // The text needs to be split in chunks of consecutive characters. // Each chunk must contain characters with the same font id and script set. - // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk have to be created. + // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk has to be created. TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get(); @@ -100,8 +101,8 @@ void ShapeText( const Vector& text, // The actual number of glyphs. Length totalNumberOfGlyphs = 0u; - const Character* textBuffer = text.Begin(); - const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin(); + const Character* const textBuffer = text.Begin(); + const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin(); GlyphInfo* glyphsBuffer = glyphs.Begin(); CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); @@ -121,33 +122,26 @@ void ShapeText( const Vector& text, // Check if there is a line must break. bool mustBreak = false; + + // Check if the current index is a new paragraph character. + // A new paragraph character is going to be shaped in order to not to mess the conversion tables. + // However, the metrics need to be changed in order to not to draw a square. + bool isNewParagraph = false; + for( CharacterIndex index = previousIndex; index < currentIndex; ++index ) { mustBreak = TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ); if( mustBreak ) { - currentIndex = index; + isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + index ) ); + currentIndex = index + 1u; break; } } - // Check if the current index is a new paragraph character. - // A \n is going to be shaped in order to not to mess the conversion tables. - // After the \n character is shaped, the glyph is going to be reset to its - // default in order to not to get any metric or font index for it. - const bool isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + currentIndex ) ); - - // The last character is always a must-break even if it's not a \n. - Length numberOfCharactersToShape = currentIndex - previousIndex; - if( mustBreak ) - { - // Add one more character to shape. - ++numberOfCharactersToShape; - } - // Shape the text for the current chunk. const Length numberOfGlyphs = shaping.Shape( textBuffer + previousIndex, - numberOfCharactersToShape, + ( currentIndex - previousIndex ), // The number of characters to shape. currentFontId, currentScript ); @@ -172,14 +166,9 @@ void ShapeText( const Vector& text, if( isNewParagraph ) { - // TODO : This is a work around to avoid drawing a square in the - // place of a new line character. - - // If the last character is a \n, it resets the glyph to the default - // to avoid getting any metric for it. - GlyphInfo& glyph = *( glyphsBuffer + glyphIndex + ( numberOfGlyphs - 1u ) ); - - glyph = GlyphInfo(); + // Add the index of the new paragraph glyph to a vector. + // Their metrics will be updated in a following step. + newParagraphGlyphs.PushBack( totalNumberOfGlyphs - 1u ); } // Update indices. @@ -202,8 +191,8 @@ void ShapeText( const Vector& text, ++scriptRunIt; } - // Update the previous index. Jumps the \n if needed. - previousIndex = mustBreak ? currentIndex + 1u : currentIndex; + // Update the previous index. + previousIndex = currentIndex; } // Add the number of characters per glyph. diff --git a/dali-toolkit/internal/text/shaper.h b/dali-toolkit/internal/text/shaper.h index f07cf49..70e2e58 100644 --- a/dali-toolkit/internal/text/shaper.h +++ b/dali-toolkit/internal/text/shaper.h @@ -47,6 +47,7 @@ class VisualModel; * @param[out] glyphs Vector of glyphs in the visual order. * @param[out] glyphToCharacterMap Vector containing the first character in the logical model that each glyph relates to. * @param[out] charactersPerGlyph Vector containing the number of characters per glyph. + * @param[out] newParagraphGlyphs Vector containing the indices to the new paragraph glyphs. */ void ShapeText( const Vector& text, const Vector& lineBreakInfo, @@ -54,7 +55,8 @@ void ShapeText( const Vector& text, const Vector& fonts, Vector& glyphs, Vector& glyphToCharacterMap, - Vector& charactersPerGlyph ); + Vector& charactersPerGlyph, + Vector& newParagraphGlyphs ); } // namespace Text diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index c36b1d8..76e42ca 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -329,7 +329,6 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) { // Retrieves the scripts used in the text. multilanguageSupport.SetScripts( utf32Characters, - lineBreakInfo, scripts ); } @@ -352,13 +351,12 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) Vector mirroredUtf32Characters; bool textMirrored = false; + Length numberOfParagraphs = 0u; if( BIDI_INFO & operations ) { // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's // bidirectional info. - Length numberOfParagraphs = 0u; - const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin(); for( Length index = 0u; index < numberOfCharacters; ++index ) { @@ -382,7 +380,9 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) // This paragraph has right to left text. Some characters may need to be mirrored. // TODO: consider if the mirrored string can be stored as well. - textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters ); + textMirrored = GetMirroredText( utf32Characters, + mirroredUtf32Characters, + bidirectionalInfo ); // Only set the character directions if there is right to left characters. Vector& directions = mLogicalModel->mCharacterDirections; @@ -401,6 +401,9 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) Vector& glyphs = mVisualModel->mGlyphs; Vector& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters; Vector& charactersPerGlyph = mVisualModel->mCharactersPerGlyph; + Vector newParagraphGlyphs; + newParagraphGlyphs.Reserve( numberOfParagraphs ); + if( SHAPE_TEXT & operations ) { const Vector& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters; @@ -411,7 +414,8 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) validFonts, glyphs, glyphsToCharactersMap, - charactersPerGlyph ); + charactersPerGlyph, + newParagraphGlyphs ); // Create the 'number of glyphs' per character and the glyph to character conversion tables. mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters ); @@ -422,7 +426,19 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) if( GET_GLYPH_METRICS & operations ) { - mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs ); + GlyphInfo* glyphsBuffer = glyphs.Begin(); + mFontClient.GetGlyphMetrics( glyphsBuffer, numberOfGlyphs ); + + // Update the width and advance of all new paragraph characters. + for( Vector::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it ) + { + const GlyphIndex index = *it; + GlyphInfo& glyph = *( glyphsBuffer + index ); + + glyph.xBearing = 0.f; + glyph.width = 0.f; + glyph.advance = 0.f; + } } } diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 8b2b476..ef8b746 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -811,7 +811,7 @@ bool Controller::DoRelayout( const Size& size, // after the first time the text has been laid out. // Fill the vectors again. - Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count(); + const Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count(); if( 0u == numberOfGlyphs ) { @@ -820,16 +820,17 @@ bool Controller::DoRelayout( const Size& size, return true; } - Vector& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo; - Vector& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo; - Vector& characterDirection = mImpl->mLogicalModel->mCharacterDirections; - Vector& glyphs = mImpl->mVisualModel->mGlyphs; - Vector& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters; - Vector& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph; + const Vector& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo; + const Vector& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo; + const Vector& characterDirection = mImpl->mLogicalModel->mCharacterDirections; + const Vector& glyphs = mImpl->mVisualModel->mGlyphs; + const Vector& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters; + const Vector& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph; + const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin(); // Set the layout parameters. LayoutParameters layoutParameters( size, - mImpl->mLogicalModel->mText.Begin(), + textBuffer, lineBreakInfo.Begin(), wordBreakInfo.Begin(), ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL, @@ -854,6 +855,9 @@ bool Controller::DoRelayout( const Size& size, Vector& glyphPositions = mImpl->mVisualModel->mGlyphPositions; glyphPositions.Resize( numberOfGlyphs ); + // Whether the last character is a new paragraph character. + layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) ); + // Update the visual model. viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters, glyphPositions, @@ -991,16 +995,7 @@ void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment // Set the alignment. mImpl->mLayoutEngine.SetVerticalAlignment( alignment ); - // Set the flag to redo the alignment operation. - // TODO : Is not needed re-layout and reorder again but with the current implementation it is. - // Im working on a different patch to fix an issue with the alignment. When that patch - // is in, this issue can be fixed. - const OperationsMask layoutOperations = static_cast( LAYOUT | - UPDATE_ACTUAL_SIZE | - ALIGN | - REORDER ); - - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | layoutOperations ); + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | ALIGN ); mImpl->RequestRelayout(); }