Text shaping implementation 33/35133/3
authorVictor Cebollada <v.cebollada@samsung.com>
Tue, 20 Jan 2015 18:15:11 +0000 (18:15 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Tue, 10 Feb 2015 08:44:14 +0000 (08:44 +0000)
Change-Id: Ia172056ccc02180c0674fa225bbf8128b4816210
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
text/dali/internal/text-abstraction/shaping-impl.cpp
text/dali/internal/text-abstraction/shaping-impl.h

index fed5d29..2a3001f 100644 (file)
 
 // INTERNAL INCLUDES
 #include <singleton-service-impl.h>
+#include <dali/public-api/text-abstraction/font-client.h>
+#include <dali/public-api/text-abstraction/glyph-info.h>
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <harfbuzz/hb.h>
+#include <harfbuzz/hb-ft.h>
+
+#include <ft2build.h>
 
 namespace Dali
 {
@@ -30,15 +39,161 @@ namespace TextAbstraction
 namespace Internal
 {
 
+const unsigned int HIGH_QUALITY_PIXEL_SIZE = 200u;  // Pixel size sent to FreeType2 FT_Set_Char_Size() for high quality glyphs.
+const char*        DEFAULT_LANGUAGE = "en";
+const unsigned int DEFAULT_LANGUAGE_LENGTH = 2u;
+const float        TO_PIXELS = 64.f;
+
+const hb_script_t SCRIPT_TO_HARFBUZZ[] =
+{
+  HB_SCRIPT_LATIN,
+  HB_SCRIPT_ARABIC,
+  HB_SCRIPT_DEVANAGARI,
+  HB_SCRIPT_BENGALI,
+  HB_SCRIPT_GURMUKHI,
+  HB_SCRIPT_GUJARATI,
+  HB_SCRIPT_ORIYA,
+  HB_SCRIPT_TAMIL,
+  HB_SCRIPT_TELUGU,
+  HB_SCRIPT_KANNADA,
+  HB_SCRIPT_MALAYALAM,
+  HB_SCRIPT_SINHALA,
+  HB_SCRIPT_HAN,
+  HB_SCRIPT_HANGUL,
+  HB_SCRIPT_KHMER,
+  HB_SCRIPT_LAO,
+  HB_SCRIPT_THAI,
+  HB_SCRIPT_MYANMAR,
+  HB_SCRIPT_UNKNOWN
+};
+
+struct Shaping::Plugin
+{
+  Plugin()
+  : mFreeTypeLibrary( NULL ),
+    mIndices(),
+    mAdvance(),
+    mCharacterMap()
+  {
+  }
+
+  ~Plugin()
+  {
+    FT_Done_FreeType( mFreeTypeLibrary );
+  }
+
+  void Initialize()
+  {
+    int error = FT_Init_FreeType( &mFreeTypeLibrary );
+    if( FT_Err_Ok != error )
+    {
+      DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
+    }
+  }
+
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script )
+  {
+    // Clear previoursly shaped texts.
+    mIndices.Clear();
+    mAdvance.Clear();
+    mCharacterMap.Clear();
+
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+    // Get the font's path file name from the font Id.
+    FontDescription fontDescription;
+    fontClient.GetDescription( fontId, fontDescription );
+
+    // Create a FreeType font's face.
+    FT_Face face;
+    FT_Error retVal = FT_New_Face( mFreeTypeLibrary, fontDescription.path.c_str(), 0u, &face );
+    if( FT_Err_Ok != retVal )
+    {
+      DALI_LOG_ERROR( "Failed to open face: %s\n", fontDescription.path.c_str() );
+      return 0u;
+    }
+
+    FT_Set_Pixel_Sizes( face, HIGH_QUALITY_PIXEL_SIZE, HIGH_QUALITY_PIXEL_SIZE );
+
+    /* Get our harfbuzz font struct */
+    hb_font_t* harfBuzzFont;
+    harfBuzzFont = hb_ft_font_create( face, NULL );
+
+    /* Create a buffer for harfbuzz to use */
+    hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
+
+    hb_buffer_set_direction( harfBuzzBuffer,
+                             ( ARABIC == script ) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR ); /* or LTR */
+
+    hb_buffer_set_script( harfBuzzBuffer,
+                          SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
+
+    hb_buffer_set_language( harfBuzzBuffer,
+                            hb_language_from_string( DEFAULT_LANGUAGE,
+                                                     DEFAULT_LANGUAGE_LENGTH ) );
+
+    /* Layout the text */
+    hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
+
+    hb_shape( harfBuzzFont, harfBuzzBuffer, NULL, 0u );
+
+    /* Get glyph data */
+    unsigned int glyphCount;
+    hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
+    hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
+
+    for( Length i = 0u; i < glyphCount; ++i )
+    {
+      mIndices.PushBack( glyphInfo[i].codepoint );
+      mAdvance.PushBack( glyphPositions[i].x_advance / TO_PIXELS );
+      mCharacterMap.PushBack( glyphInfo[i].cluster );
+    }
+
+    /* Cleanup */
+    hb_buffer_destroy( harfBuzzBuffer );
+    hb_font_destroy( harfBuzzFont );
+    FT_Done_Face( face );
+
+    return mIndices.Count();
+  }
+
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap )
+  {
+    Vector<CharacterIndex>::ConstIterator indicesIt = mIndices.Begin();
+    Vector<float>::ConstIterator advanceIt = mAdvance.Begin();
+    Vector<CharacterIndex>::ConstIterator characterMapIt = mCharacterMap.Begin();
+
+    for( Length index = 0u, size = mIndices.Count(); index < size; ++index )
+    {
+      GlyphInfo& glyph = *( glyphInfo + index );
+      CharacterIndex& glyphToCharacter = *( glyphToCharacterMap + index );
+
+      glyph.index = *( indicesIt + index );
+      glyph.advance = *( advanceIt + index );
+
+      glyphToCharacter = *( characterMapIt + index );
+    }
+  }
+
+  FT_Library             mFreeTypeLibrary;
+
+  Vector<CharacterIndex> mIndices;
+  Vector<float>          mAdvance;
+  Vector<CharacterIndex> mCharacterMap;
+};
+
 Shaping::Shaping()
 : mPlugin( NULL )
 {
-
 }
 
 Shaping::~Shaping()
 {
-
+  delete mPlugin;
 }
 
 TextAbstraction::Shaping Shaping::Get()
@@ -71,12 +226,30 @@ Length Shaping::Shape( const Character* const text,
                        FontId fontId,
                        Script script )
 {
-  return 0u;
+  CreatePlugin();
+
+  return mPlugin->Shape( text,
+                         numberOfCharacters,
+                         fontId,
+                         script );
 }
 
 void Shaping::GetGlyphs( GlyphInfo* glyphInfo,
                          CharacterIndex* glyphToCharacterMap )
 {
+  CreatePlugin();
+
+  mPlugin->GetGlyphs( glyphInfo,
+                      glyphToCharacterMap );
+}
+
+void Shaping::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+    mPlugin->Initialize();
+  }
 }
 
 } // namespace Internal
index 04c347b..3d20306 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/public-api/object/base-object.h>
 
 // INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/text-abstraction/shaping.h>
 
 namespace Dali
@@ -71,13 +72,21 @@ public:
 
 private:
 
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
   // Undefined copy constructor.
   Shaping( const Shaping& );
 
   // Undefined assignment constructor.
   Shaping& operator=( Shaping& );
 
-  void*   mPlugin;  ///< TODO replace this with shaping plugin
+  struct Plugin;
+  Plugin* mPlugin;
 
 }; // class Shaping