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;
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;
mFontClient = TextAbstraction::FontClient::Get();
}
- void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel )
+ void UpdateVisualModel( const Vector2& boundingBox,
+ const Vector<GlyphInfo>& glyphs,
+ const Vector<CharacterIndex>& characterIndices,
+ const Vector<Length>& 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<GlyphInfo> glyphs;
- glyphs.Reserve( characterCount );
-
- Vector<CharacterIndex> characterIndices;
- characterIndices.Reserve( characterCount );
-
- std::vector<Length> charactersPerGlyph;
- charactersPerGlyph.assign( characterCount, 1 );
-
- for( unsigned int i=0; i<characterCount; ++i )
- {
- Character charcode;
- logicalModel.GetText( i, &charcode, 1 );
-
- // TODO - Perform shaping to get correct glyph indices
- GlyphIndex glyphIndex = mFontClient.GetGlyphIndex( fontId, charcode );
-
- glyphs.PushBack( GlyphInfo(fontId, glyphIndex) );
- characterIndices.PushBack( 1 );
- }
-
- if( mFontClient.GetGlyphMetrics( &glyphs[0], glyphs.Size() ) )
- {
- visualModel.SetGlyphs( &glyphs[0],
- &characterIndices[0],
- &charactersPerGlyph[0],
- characterCount );
-
- UpdateGlyphPositions( boundingBox, visualModel );
- }
+ UpdateGlyphPositions( boundingBox, visualModel );
}
void UpdateGlyphPositions( const Vector2& boundingBox, VisualModel& visualModel )
mImpl->mLayout = layout;
}
-void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel )
+void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox,
+ const Vector<GlyphInfo>& glyphs,
+ const Vector<CharacterIndex>& characterIndices,
+ const Vector<Length>& charactersPerGlyph,
+ VisualModel& visualModel )
{
- mImpl->UpdateVisualModel( boundingBox, logicalModel, visualModel );
+ mImpl->UpdateVisualModel( boundingBox,
+ glyphs,
+ characterIndices,
+ charactersPerGlyph,
+ visualModel );
}
} // namespace Text
*
*/
+// INTERNAL INCLUDE
+#include <dali-toolkit/public-api/text/text-definitions.h>
+
+// EXTERNAL INCLUDE
+#include <dali/public-api/common/dali-vector.h>
+
namespace Dali
{
* @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<GlyphInfo>& glyphs,
+ const Vector<CharacterIndex>& characterIndices,
+ const Vector<Length>& charactersPerGlyph,
+ VisualModel& visualModel );
private:
// CLASS HEADER
#include <dali-toolkit/public-api/text/shaper.h>
+// INTERNAL INCLUDES
+#include <dali/public-api/text-abstraction/shaping.h>
+#include <dali-toolkit/public-api/text/font-run.h>
+#include <dali-toolkit/public-api/text/logical-model.h>
+#include <dali-toolkit/public-api/text/script-run.h>
+#include <dali-toolkit/public-api/text/visual-model.h>
+
namespace Dali
{
namespace Text
{
+CharacterIndex min( CharacterIndex index0,
+ CharacterIndex index1 )
+{
+ return ( index0 < index1 ) ? index0 : index1;
+}
+
void ShapeText( const Vector<Character>& text,
const Vector<LineBreakInfo>& lineBreakInfo,
const Vector<ScriptRun>& scripts,
Vector<CharacterIndex>& characterIndices,
Vector<Length>& 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<FontRun>::ConstIterator fontRunIt = fonts.Begin();
+ Vector<ScriptRun>::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<LineBreakInfo>( 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<Length>( 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<Length>( 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
#include <dali-toolkit/public-api/text/logical-model.h>
#include <dali-toolkit/public-api/text/multi-language-support.h>
#include <dali-toolkit/public-api/text/script-run.h>
+#include <dali-toolkit/public-api/text/shaper.h>
#include <dali-toolkit/public-api/text/text-view.h>
#include <dali-toolkit/public-api/text/visual-model.h>
scripts,
fonts );
+ Vector<LineBreakInfo> lineBreakInfo;
+ lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
+
+ Vector<GlyphInfo> glyphs;
+ Vector<CharacterIndex> characterIndices;
+ Vector<Length> 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;