Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


On Sat, Jul 21, 2012 at 03:08:20AM +0200, Khaled Hosny wrote:
On Fri, Mar 30, 2012 at 03:27:39PM +0100, Caolán McNamara wrote:
On Fri, 2012-03-30 at 16:13 +0200, Khaled Hosny wrote:
If there is interest in this, I can try implementing optional HarfBuzz
support next to ICU so we can experiment more with this (though I'm not
the best person to do this, but I can try).

Can't hurt to give it a go anyway. Even epic failure can point the next
person in the right way to go. Yeah lacking Indic shaping would be a
problem for right now.

Indic scripts are supported now (git master, not released yet), and
given HarfBuzz track record, it should even be better than ICU layout
engine which is essentially put on ventilator (pun intended), so now is
a good time to experiment, but I didn't manage to try doing it yet.

Here is a very crude, WIP patch. It adds --enable-harfbuzz configure
option, plus some (very broken) harfbuzz layout code, but I can't get
the ENABLE_HARFBUZZ to propagate in and thus can't do any testing
because the code is never compiled. I appreciate any insights on how to
get this to work.

Regards,
 Khaled
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 26676a7..4e0fc20 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1110,6 +1110,29 @@ endef
 endif # ENABLE_TELEPATHY
 
 
+ifeq ($(ENABLE_HARFBUZZ),TRUE)
+
+define gb_LinkTarget__use_harfbuzz
+$(call gb_LinkTarget_set_include,$(1),\
+       $$(INCLUDE) \
+       $(HARFBUZZ_CFLAGS) \
+)
+
+$(call gb_LinkTarget_add_libs,$(1),\
+       $(HARFBUZZ_LIBS) \
+)
+
+endef
+
+else # !ENABLE_HARFBUZZ
+
+define gb_LinkTarget__use_harfbuzz
+
+endef
+
+endif # ENABLE_HARFBUZZ
+
+
 ifeq ($(SYSTEM_DB),YES)
 
 define gb_LinkTarget__use_berkeleydb
diff --git a/config_host.mk.in b/config_host.mk.in
index 5e24730..3f3bf1f 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -116,6 +116,7 @@ export ENABLE_GSTREAMER=@ENABLE_GSTREAMER@
 export ENABLE_GTK3=@ENABLE_GTK3@
 export ENABLE_GTK=@ENABLE_GTK@
 export ENABLE_GTK_PRINT=@ENABLE_GTK_PRINT@
+export ENABLE_HARFBUZZ=@ENABLE_HARFBUZZ@
 export ENABLE_HEADLESS=@ENABLE_HEADLESS@
 export ENABLE_TDEAB=@ENABLE_TDEAB@
 export ENABLE_TDE=@ENABLE_TDE@
@@ -199,6 +200,8 @@ export GUIBASE=@GUIBASE@
 export GUIBASE_FOR_BUILD=@GUIBASE_FOR_BUILD@
 export GUI_FOR_BUILD=@GUI_FOR_BUILD@
 export GXX_INCLUDE_PATH=@GXX_INCLUDE_PATH@
+export HARFBUZZ_FLAGS=@HARFBUZZ_CFLAGS@
+export HARFBUZZ_LIBS=@HARFBUZZ_LIBS@
 export HAVE_CXX0X=@HAVE_CXX0X@
 export HAVE_GCC_AVX=@HAVE_GCC_AVX@
 export HAVE_GCC_GGDB2=@HAVE_GCC_GGDB2@
diff --git a/configure.in b/configure.in
index 980a2fb..86334ce 100644
--- a/configure.in
+++ b/configure.in
@@ -796,6 +796,11 @@ AC_ARG_ENABLE(gio,
         [Determines whether to use the GIO support.]),
 ,enable_gio=no)
 
+AC_ARG_ENABLE(harfbuzz,
+    AS_HELP_STRING([--enable-harfbuzz],
+        [Determines whether to use HarfBuzz text layout engine.]),
+,enable_harfbuzz=no)
+
 AC_ARG_ENABLE(telepathy,
     AS_HELP_STRING([--enable-telepathy],
         [Determines whether to enable Telepathy for collaboration.]),
@@ -8969,6 +8974,28 @@ AC_SUBST([GTK_PRINT_LIBS])
 
 
 dnl ===================================================================
+dnl Check whether the HarfBuzz libraries are available.
+dnl ===================================================================
+
+ENABLE_HARFBUZZ=""
+HARFBUZZ_CFLAGS=""
+HARFBUZZ_LIBS=""
+
+AC_MSG_CHECKING([whether to enable HarfBuzz support])
+if test "$_os" != "WINNT" -a "$_os" != "Darwin" -a "$enable_harfbuzz" = "yes"; then
+    ENABLE_HARFBUZZ="TRUE"
+    AC_MSG_RESULT([yes])
+    PKG_CHECK_MODULES( HARFBUZZ, harfbuzz >= 0.9.0 )
+else
+    AC_MSG_RESULT([no])
+fi
+
+AC_SUBST(ENABLE_HARFBUZZ)
+AC_SUBST(HARFBUZZ_CFLAGS)
+AC_SUBST(HARFBUZZ_LIBS)
+
+
+dnl ===================================================================
 dnl Check whether the Telepathy libraries are available.
 dnl ===================================================================
 
diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx
index cd6b96c..be327e2 100644
--- a/vcl/generic/glyphs/gcach_layout.cxx
+++ b/vcl/generic/glyphs/gcach_layout.cxx
@@ -35,9 +35,14 @@
 #include <sal/alloca.h>
 #include <rtl/instance.hxx>
 
+#ifdef ENABLE_HARFBUZZ
+#include <hb-ft.h>
+#include <hb-icu.h>
+#else
 #include <layout/LayoutEngine.h>
 #include <layout/LEFontInstance.h>
 #include <layout/LEScripts.h>
+#endif // ENABLE_HARFBUZZ
 
 #include <unicode/uscript.h>
 #include <unicode/ubidi.h>
@@ -156,6 +161,99 @@ bool ServerFontLayoutEngine::operator()( ServerFontLayout& rLayout, 
ImplLayoutAr
     return true;
 }
 
+#ifdef ENABLE_HARFBUZZ
+class HbLayoutEngine : public ServerFontLayoutEngine
+{
+private:
+
+public:
+                            HbLayoutEngine( ServerFont& );
+    virtual                 ~HbLayoutEngine();
+
+    virtual bool            operator()( ServerFontLayout&, ImplLayoutArgs& );
+};
+
+HbLayoutEngine::HbLayoutEngine( ServerFont& rServerFont )
+:   mrServerFont( rFont )
+{}
+
+HbLayoutEngine::~HbLayoutEngine()
+{}
+
+bool HbLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& rArgs )
+{
+    ServerFont& rFont = rLayout.GetServerFont();
+    FT_Face aFace = rFont.GetFtFace();
+    Point aNewPos( 0, 0 );
+
+    // allocate temporary arrays, note: round to even
+    int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos ) | 15) + 1;
+
+    rLayout.Reserve(nGlyphCapacity);
+
+    hb_font_t *aHbFont = hb_ft_font_create (aFace, NULL);
+
+    int x = 0, y = 0;
+    for( int nGlyphCount = 0;; )
+    {
+        int nMinRunPos, nEndRunPos;
+        bool bRightToLeft;
+        if( !rArgs.GetNextRun( &nMinRunPos, &nEndRunPos, &bRightToLeft ) )
+            break;
+
+        int nRunLen = nEndRunPos - nMinRunPos;
+
+        hb_buffer_t *aHbBuffer = hb_buffer_create ();
+        hb_buffer_set_direction (aHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
+        //hb_buffer_set_script (aHbBuffer, hb_script_from_string ("arab"));
+        //hb_buffer_set_language (aHbBuffer, hb_language_from_string ("ar"));
+        hb_buffer_add_utf16 (aHbBuffer, rArgs.mpStr, nRunLen, nMinRunPos, nRunLen);
+        hb_shape (aHbFont, aHbBuffer, NULL, 0);
+
+        int nRunGlyphCount = hb_buffer_get_length (aHbBuffer);
+        hb_glyph_info_t *aHbGlyph = hb_buffer_get_glyph_infos (aHbBuffer, NULL);
+        hb_glyph_position_t *aHbPosition = hb_buffer_get_glyph_positions (aHbBuffer, NULL);
+
+        uint32_t nLastCluster = -1;
+        bool bInCluster = false
+        for ( int i = 0; i < nRunGlyphCount; i++, aHbGlyph++, aHbPosition++ ) {
+            int nCharPos = 0; // XXX
+
+            hb_codepoint_t nGlyphIndex = aHbGlyph->codepoint;
+
+            // XXX
+            uint32_t nCluster = aHbGlyph->cluster;
+            if ( nCluster == nLastCluster )
+                bInCluster = true;
+
+            const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyphIndex );
+            int nGlyphWidth = rGM.GetCharWidth();
+            int nNewWidth = (aHbPosition->x_advance/64);
+
+            long nGlyphFlags = 0;
+            if( bRightToLeft )
+                nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
+            if( bInCluster )
+                nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
+
+            Point aNewPos = Point( x + (aHbPosition->x_offset/64), y - (aHbPosition->y_offset/64) 
);
+            x += (aHbPosition->x_advance/64);
+
+            GlyphItem aGI( nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth );
+            aGI.mnNewWidth = nNewWidth;
+
+            rLayout.AppendGlyph( aGI );
+        }
+
+        nGlyphCount += nRunGlyphCount;
+
+        hb_buffer_destroy (aHbBuffer);
+        hb_font_destroy (aHbFont);
+    }
+
+    return true;
+}
+#else
 // =======================================================================
 // bridge to ICU LayoutEngine
 // =======================================================================
@@ -638,13 +736,20 @@ bool IcuLayoutEngine::operator()( ServerFontLayout& rLayout, ImplLayoutArgs& 
rAr
     return true;
 }
 
+#endif // ENABLE_HARFBUZZ
+
 // =======================================================================
 
 ServerFontLayoutEngine* ServerFont::GetLayoutEngine()
 {
     // find best layout engine for font, platform, script and language
+#ifdef ENABLE_HARFBUZZ
+    if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
+        mpLayoutEngine = new HbLayoutEngine( *this );
+#else
     if( !mpLayoutEngine && FT_IS_SFNT( maFaceFT ) )
         mpLayoutEngine = new IcuLayoutEngine( *this );
+#endif // ENABLE_HARFBUZZ
     return mpLayoutEngine;
 }
 

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.