Shaper implementation 14/35214/6
authorVictor Cebollada <v.cebollada@samsung.com>
Tue, 10 Feb 2015 08:52:30 +0000 (08:52 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Wed, 18 Feb 2015 16:26:00 +0000 (16:26 +0000)
Change-Id: Ia7e7062c12c08f5c8829037ea867282ee9ba77b8
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
dali-toolkit/internal/text/multi-language-support-impl.cpp
dali-toolkit/public-api/text/layouts/layout-engine.cpp
dali-toolkit/public-api/text/layouts/layout-engine.h
dali-toolkit/public-api/text/shaper.cpp
dali-toolkit/public-api/text/text-controller.cpp

index 8e89473..2d1f5e6 100644 (file)
@@ -69,7 +69,7 @@ FontId GetFontId( Length index,
       fontId = fontRun.fontId;
     }
 
       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;
     {
       // 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;
     }
 
       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;
     {
       // All the characters of the current run have been traversed. Get the next one for the next iteration.
       ++scriptRunIt;
index 65cfc61..698832d 100644 (file)
@@ -43,44 +43,20 @@ struct LayoutEngine::Impl
     mFontClient = TextAbstraction::FontClient::Get();
   }
 
     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
 
   {
     // 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 )
   }
 
   void UpdateGlyphPositions( const Vector2& boundingBox, VisualModel& visualModel )
@@ -240,9 +216,17 @@ void LayoutEngine::SetLayout( Layout layout )
   mImpl->mLayout = layout;
 }
 
   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
 }
 
 } // namespace Text
index 55483de..87a8980 100644 (file)
  *
  */
 
  *
  */
 
+// INTERNAL INCLUDE
+#include <dali-toolkit/public-api/text/text-definitions.h>
+
+// EXTERNAL INCLUDE
+#include <dali/public-api/common/dali-vector.h>
+
 namespace Dali
 {
 
 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.
    * @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.
    */
    * @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:
 
 
 private:
 
index 3be21ab..54444ac 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/public-api/text/shaper.h>
 
 // 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 Dali
 {
 
@@ -27,6 +34,12 @@ namespace Toolkit
 namespace Text
 {
 
 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,
 void ShapeText( const Vector<Character>& text,
                 const Vector<LineBreakInfo>& lineBreakInfo,
                 const Vector<ScriptRun>& scripts,
@@ -35,6 +48,129 @@ void ShapeText( const Vector<Character>& text,
                 Vector<CharacterIndex>& characterIndices,
                 Vector<Length>& charactersPerGlyph )
 {
                 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
 }
 
 } // namespace Text
index 6fe0f33..2592653 100644 (file)
@@ -27,6 +27,7 @@
 #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/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>
 
 #include <dali-toolkit/public-api/text/text-view.h>
 #include <dali-toolkit/public-api/text/visual-model.h>
 
@@ -106,13 +107,36 @@ bool Controller::Relayout( const Vector2& size )
                                         scripts,
                                         fonts );
 
                                         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 );
     // 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() );
 
     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;
 
     // Discard temporary text
     mImpl->mNewTextArrived = false;