From: Victor Cebollada Date: Tue, 10 Feb 2015 08:52:30 +0000 (+0000) Subject: Shaper implementation X-Git-Tag: new_text_0.1~43 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=bee80770f7faa39a9d71c21e4d9ccf34a47fcc2e Shaper implementation Change-Id: Ia7e7062c12c08f5c8829037ea867282ee9ba77b8 Signed-off-by: Victor Cebollada --- diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp index 8e89473..2d1f5e6 100644 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -69,7 +69,7 @@ FontId GetFontId( Length index, fontId = fontRun.fontId; } - if( index == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) + if( index + 1u == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) { // All the characters of the current run have been traversed. Get the next one for the next iteration. ++fontRunIt; @@ -106,7 +106,7 @@ Script GetScript( Length index, script = scriptRun.script; } - if( index == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) + if( index + 1u == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) { // All the characters of the current run have been traversed. Get the next one for the next iteration. ++scriptRunIt; diff --git a/dali-toolkit/public-api/text/layouts/layout-engine.cpp b/dali-toolkit/public-api/text/layouts/layout-engine.cpp index 65cfc61..698832d 100644 --- a/dali-toolkit/public-api/text/layouts/layout-engine.cpp +++ b/dali-toolkit/public-api/text/layouts/layout-engine.cpp @@ -43,44 +43,20 @@ struct LayoutEngine::Impl mFontClient = TextAbstraction::FontClient::Get(); } - void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ) + void UpdateVisualModel( const Vector2& boundingBox, + const Vector& glyphs, + const Vector& characterIndices, + const Vector& charactersPerGlyph, + VisualModel& visualModel ) { // TODO Switch between different layouts - TextAbstraction::FontId fontId = mFontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 13*64 ); + visualModel.SetGlyphs( &glyphs[0], + &characterIndices[0], + &charactersPerGlyph[0], + glyphs.Count() ); - const Length characterCount = logicalModel.GetNumberOfCharacters(); - - Vector glyphs; - glyphs.Reserve( characterCount ); - - Vector characterIndices; - characterIndices.Reserve( characterCount ); - - std::vector charactersPerGlyph; - charactersPerGlyph.assign( characterCount, 1 ); - - for( unsigned int i=0; imLayout = layout; } -void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ) +void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox, + const Vector& glyphs, + const Vector& characterIndices, + const Vector& charactersPerGlyph, + VisualModel& visualModel ) { - mImpl->UpdateVisualModel( boundingBox, logicalModel, visualModel ); + mImpl->UpdateVisualModel( boundingBox, + glyphs, + characterIndices, + charactersPerGlyph, + visualModel ); } } // namespace Text diff --git a/dali-toolkit/public-api/text/layouts/layout-engine.h b/dali-toolkit/public-api/text/layouts/layout-engine.h index 55483de..87a8980 100644 --- a/dali-toolkit/public-api/text/layouts/layout-engine.h +++ b/dali-toolkit/public-api/text/layouts/layout-engine.h @@ -18,6 +18,12 @@ * */ +// INTERNAL INCLUDE +#include + +// EXTERNAL INCLUDE +#include + namespace Dali { @@ -66,10 +72,16 @@ public: * @brief Store the visual position of glyphs in the VisualModel. * * @param[in] boundingBox The size of the box containing the text. - * @param[in] logicalModel The logical model. + * @param[in] glyphs A vector with glyphs. + * @param[in] characterIndices Vector with indices pointing the first character of each glyph. + * @param[in] charactersPerGlyph Vector with the number of characters that forms each glyph. * @param[in] visualModel The visual model to update. */ - void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ); + void UpdateVisualModel( const Vector2& boundingBox, + const Vector& glyphs, + const Vector& characterIndices, + const Vector& charactersPerGlyph, + VisualModel& visualModel ); private: diff --git a/dali-toolkit/public-api/text/shaper.cpp b/dali-toolkit/public-api/text/shaper.cpp index 3be21ab..54444ac 100644 --- a/dali-toolkit/public-api/text/shaper.cpp +++ b/dali-toolkit/public-api/text/shaper.cpp @@ -18,6 +18,13 @@ // CLASS HEADER #include +// INTERNAL INCLUDES +#include +#include +#include +#include +#include + namespace Dali { @@ -27,6 +34,12 @@ namespace Toolkit namespace Text { +CharacterIndex min( CharacterIndex index0, + CharacterIndex index1 ) +{ + return ( index0 < index1 ) ? index0 : index1; +} + void ShapeText( const Vector& text, const Vector& lineBreakInfo, const Vector& scripts, @@ -35,6 +48,129 @@ void ShapeText( const Vector& text, Vector& characterIndices, Vector& charactersPerGlyph ) { + const Length numberOfCharacters = text.Count(); + + if( 0u == numberOfCharacters ) + { + // Nothing to do if there are no characters. + return; + } + + const Length numberOfFontRuns = fonts.Count(); + + DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) && + ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) && + "Toolkit::Text::ShapeText. All characters must have a font set." ); + + const Length numberOfScriptRuns = scripts.Count(); + + DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) && + ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) && + "Toolkit::Text::ShapeText. All characters must have a script set." ); + + // 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. + + TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get(); + + // To shape the text a font and an script is needed. + Vector::ConstIterator fontRunIt = fonts.Begin(); + Vector::ConstIterator scriptRunIt = scripts.Begin(); + + // The line must break token converted to LineBreakInfo to be compared and avoid a compile error. + const LineBreakInfo MUST_BREAK = static_cast( TextAbstraction::LINE_MUST_BREAK ); + + // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped. + CharacterIndex previousIndex = 0u; + + // The current font id and script used to shape the text. + FontId currentFontId = 0u; + Script currentScript = TextAbstraction::UNKNOWN; + + // Reserve some space to allocate the glyphs and the glyph to character map. + // There is no way to know the number of glyphs before shaping the text. + // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters. + + Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); + glyphs.Resize( numberOfGlyphsReserved ); + charactersPerGlyph.Resize( numberOfGlyphsReserved ); + + // The actual number of glyphs. + Length totalNumberOfGlyphs = 0u; + + // Traverse the characters and shape the text. + for( previousIndex = 0; previousIndex < numberOfCharacters; ) + { + // Get the font id and the script. + const FontRun& fontRun = *fontRunIt; + const ScriptRun& scriptRun = *scriptRunIt; + + currentFontId = fontRun.fontId; + currentScript = scriptRun.script; + + // Get the min index to the last character of both runs. + CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters, + scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ); + + // Check if there is a line must break. + for( CharacterIndex index = previousIndex; index < currentIndex; ++index ) + { + if( MUST_BREAK == lineBreakInfo.Begin() + index ) + { + currentIndex = index; + break; + } + } + + // Shape the text for the current chunk. + const Length numberOfGlyphs = shaping.Shape( text.Begin() + previousIndex, + currentIndex - previousIndex, + currentFontId, + currentScript ); + + const Length glyphIndex = totalNumberOfGlyphs; + totalNumberOfGlyphs += numberOfGlyphs; + + if( totalNumberOfGlyphs > numberOfGlyphsReserved ) + { + // Resize the vectors to get enough space. + numberOfGlyphsReserved = static_cast( totalNumberOfGlyphs * 1.3f ); + glyphs.Resize( numberOfGlyphsReserved ); + charactersPerGlyph.Resize( numberOfGlyphsReserved ); + } + + // Retrieve the glyphs and the glyph to character conversion map. + shaping.GetGlyphs( glyphs.Begin() + glyphIndex, + charactersPerGlyph.Begin() + glyphIndex ); + + // Update the iterators to get the next font or script run. + if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) + { + ++fontRunIt; + } + if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters ) + { + ++scriptRunIt; + } + + // Update the previous index. + previousIndex = currentIndex; + } + + characterIndices.Reserve( totalNumberOfGlyphs ); + CharacterIndex characterIndex = 0u; + characterIndices.PushBack( characterIndex ); + for( Length index = 0u, length = totalNumberOfGlyphs - 1u; index < length; ++index ) + { + characterIndex += *( charactersPerGlyph.Begin() + index ); + characterIndices.PushBack( characterIndex ); + } + + // Resize the vectors to set the right number of items. + glyphs.Resize( totalNumberOfGlyphs ); + // characterIndices.Resize( totalNumberOfGlyphs ); + charactersPerGlyph.Resize( totalNumberOfGlyphs ); } } // namespace Text diff --git a/dali-toolkit/public-api/text/text-controller.cpp b/dali-toolkit/public-api/text/text-controller.cpp index 6fe0f33..2592653 100644 --- a/dali-toolkit/public-api/text/text-controller.cpp +++ b/dali-toolkit/public-api/text/text-controller.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -106,13 +107,36 @@ bool Controller::Relayout( const Vector2& size ) scripts, fonts ); + Vector lineBreakInfo; + lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK ); + + Vector glyphs; + Vector characterIndices; + Vector charactersPerGlyph; + + ShapeText( utf32Characters, + lineBreakInfo, + scripts, + fonts, + glyphs, + characterIndices, + charactersPerGlyph ); + // Manipulate the logical model mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount ); + mImpl->mLogicalModel->SetLineBreakInfo( &lineBreakInfo[0], characterCount ); mImpl->mLogicalModel->SetScripts( &scripts[0], scripts.Count() ); mImpl->mLogicalModel->SetFonts( &fonts[0], fonts.Count() ); - // Update the visual model - mImpl->mLayoutEngine.UpdateVisualModel( size, *mImpl->mLogicalModel, *mImpl->mVisualModel ); + if( TextAbstraction::FontClient::Get().GetGlyphMetrics( &glyphs[0], glyphs.Size() ) ) + { + // Update the visual model + mImpl->mLayoutEngine.UpdateVisualModel( size, + glyphs, + characterIndices, + charactersPerGlyph, + *mImpl->mVisualModel ); + } // Discard temporary text mImpl->mNewTextArrived = false;