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


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/3518

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/18/3518/1

Add support for using HarfBuzz instead of ICU LE

Change-Id: I07e698f7486379bae68329771695cd94d6e561b5
---
M vcl/generic/glyphs/gcach_layout.cxx
1 file changed, 178 insertions(+), 15 deletions(-)



diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx
index ddf6d7c..02392c2 100644
--- a/vcl/generic/glyphs/gcach_layout.cxx
+++ b/vcl/generic/glyphs/gcach_layout.cxx
@@ -17,6 +17,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <config_harfbuzz.h>
 #include <gcach_ftyp.hxx>
 #include <sallayout.hxx>
 #include <salgdi.hxx>
@@ -30,10 +31,15 @@
 #include <sal/alloca.h>
 #include <rtl/instance.hxx>
 
+#if ENABLE_HARFBUZZ
+#include <hb-ft.h>
+#include <hb-icu.h>
+#else
 #include <layout/LayoutEngine.h>
 #include <layout/LEFontInstance.h>
 #include <layout/LELanguages.h>
 #include <layout/LEScripts.h>
+#endif // ENABLE_HARFBUZZ
 
 #include <unicode/uscript.h>
 #include <unicode/ubidi.h>
@@ -86,6 +92,172 @@
     }
 }
 
+// =======================================================================
+
+static bool lcl_CharIsJoiner(sal_Unicode cChar)
+{
+    return ((cChar == 0x200C) || (cChar == 0x200D));
+}
+
+static bool needPreviousCode(sal_Unicode cChar)
+{
+    return lcl_CharIsJoiner(cChar) || U16_IS_LEAD(cChar);
+}
+
+static bool needNextCode(sal_Unicode cChar)
+{
+    return lcl_CharIsJoiner(cChar) || U16_IS_TRAIL(cChar);
+}
+
+#if ENABLE_HARFBUZZ
+class HbLayoutEngine : public ServerFontLayoutEngine
+{
+private:
+    UScriptCode             meScriptCode;
+
+public:
+                            HbLayoutEngine(ServerFont&);
+    virtual                 ~HbLayoutEngine(){};
+
+    virtual bool            layout(ServerFontLayout&, ImplLayoutArgs&);
+};
+
+HbLayoutEngine::HbLayoutEngine(ServerFont& /*rServerFont*/)
+:   meScriptCode(USCRIPT_INVALID_CODE)
+{}
+
+bool HbLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
+{
+    ServerFont& rFont = rLayout.GetServerFont();
+    FT_Face aFace = rFont.GetFtFace();
+
+    // allocate temporary arrays, note: round to even
+    int nGlyphCapacity = (3 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos) | 15) + 1;
+
+    rLayout.Reserve(nGlyphCapacity);
+
+    Point aNewPos(0, 0);
+    while (true)
+    {
+        int nMinRunPos, nEndRunPos;
+        bool bRightToLeft;
+        if (!rArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRightToLeft))
+            break;
+
+        int nRunLen = nEndRunPos - nMinRunPos;
+
+        // find matching script
+        // TODO: use ICU's UScriptRun API
+        UScriptCode eScriptCode = USCRIPT_INVALID_CODE;
+        for (int i = nMinRunPos; i < nEndRunPos; ++i)
+        {
+            UErrorCode rcI18n = U_ZERO_ERROR;
+            UScriptCode eNextScriptCode = uscript_getScript(rArgs.mpStr[i], &rcI18n);
+            if ((eNextScriptCode > USCRIPT_INHERITED))
+            {
+                eScriptCode = eNextScriptCode;
+                if (eNextScriptCode != USCRIPT_LATIN)
+                    break;
+            }
+        }
+        if (eScriptCode < 0)   // TODO: handle errors better
+            eScriptCode = USCRIPT_LATIN;
+
+        meScriptCode = eScriptCode;
+
+        hb_font_t *aHbFont = hb_ft_font_create(aFace, NULL);
+
+        LanguageTag aLangTag(rArgs.meLanguage);
+        OString sLanguage = OUStringToOString(aLangTag.getLanguage(), RTL_TEXTENCODING_UTF8);
+
+        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_icu_script_to_script(eScriptCode));
+        hb_buffer_set_language(aHbBuffer, hb_language_from_string(sLanguage.getStr(), -1));
+        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 *aHbGlyphInfos = hb_buffer_get_glyph_infos(aHbBuffer, NULL);
+        hb_glyph_position_t *aHbPositions = hb_buffer_get_glyph_positions(aHbBuffer, NULL);
+
+        int32_t nLastCluster = -1;
+        for (int i = 0; i < nRunGlyphCount; ++i) {
+            int32_t nGlyphIndex = aHbGlyphInfos[i].codepoint;
+            int32_t nCluster = aHbGlyphInfos[i].cluster;
+            int32_t nCharPos = nCluster;
+
+            // if needed request glyph fallback by updating LayoutArgs
+            if (!nGlyphIndex)
+            {
+                if (nCharPos >= 0)
+                {
+                    rArgs.NeedFallback(nCharPos, bRightToLeft);
+                    // XXX: do we need this in harfbuzz?
+                    if  ((nCharPos > 0) && needPreviousCode(rArgs.mpStr[nCharPos-1]))
+                        rArgs.NeedFallback(nCharPos-1, bRightToLeft);
+                    else if  ((nCharPos + 1 < nEndRunPos) && needNextCode(rArgs.mpStr[nCharPos+1]))
+                        rArgs.NeedFallback(nCharPos+1, bRightToLeft);
+                }
+
+                if (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)
+                    continue;
+            }
+
+            const GlyphMetric& rGM = rFont.GetGlyphMetric(nGlyphIndex);
+            int nGlyphWidth = rGM.GetCharWidth();
+
+            long nGlyphFlags = 0;
+            if (bRightToLeft)
+                nGlyphFlags |= GlyphItem::IS_RTL_GLYPH;
+
+            // what is this for?
+            // XXX: rtl clusters
+            bool bInCluster = false;
+            if (nCluster == nLastCluster)
+                bInCluster = true;
+            nLastCluster = nCluster;
+            if (bInCluster)
+                nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
+
+            // XXX: query GDEF glyph class? Do we even need this?
+            if (aHbPositions[i].x_advance == 0)
+                nGlyphFlags |= GlyphItem::IS_DIACRITIC;
+
+            aHbPositions[i].x_offset /= 64;
+            aHbPositions[i].y_offset /= 64;
+            aHbPositions[i].x_advance /= 64;
+            aHbPositions[i].y_advance /= 64;
+
+            aNewPos = Point(aNewPos.X() + aHbPositions[i].x_offset, aNewPos.Y() - 
aHbPositions[i].y_offset);
+
+            GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nGlyphWidth);
+
+            if (i + 1 < nRunGlyphCount)
+                aGI.mnNewWidth = nGlyphWidth + (aHbPositions[i + 1].x_offset / 64);
+
+            rLayout.AppendGlyph(aGI);
+
+            aNewPos.X() += aHbPositions[i].x_advance;
+            aNewPos.Y() += aHbPositions[i].y_advance;
+        }
+
+        hb_buffer_destroy(aHbBuffer);
+        hb_font_destroy(aHbFont);
+    }
+
+    // sort glyphs in visual order
+    // and then in logical order (e.g. diacritics after cluster start)
+    rLayout.SortGlyphItems();
+
+    // determine need for kashida justification
+    if((rArgs.mpDXArray || rArgs.mnLayoutWidth)
+    && ((meScriptCode == USCRIPT_ARABIC) || (meScriptCode == USCRIPT_SYRIAC)))
+        rArgs.mnFlags |= SAL_LAYOUT_KASHIDA_JUSTIFICATON;
+
+    return true;
+}
+#else
 // =======================================================================
 // bridge to ICU LayoutEngine
 // =======================================================================
@@ -301,21 +473,6 @@
 }
 
 // -----------------------------------------------------------------------
-
-static bool lcl_CharIsJoiner(sal_Unicode cChar)
-{
-    return ((cChar == 0x200C) || (cChar == 0x200D));
-}
-
-static bool needPreviousCode(sal_Unicode cChar)
-{
-    return lcl_CharIsJoiner(cChar) || U16_IS_LEAD(cChar);
-}
-
-static bool needNextCode(sal_Unicode cChar)
-{
-    return lcl_CharIsJoiner(cChar) || U16_IS_TRAIL(cChar);
-}
 
 namespace
 {
@@ -742,6 +899,7 @@
 #ifdef ARABIC_BANDAID
             aGI.mnNewWidth = nNewWidth;
 #endif
+
             rLayout.AppendGlyph( aGI );
             ++nFilteredRunGlyphCount;
             nLastCharPos = nCharPos;
@@ -762,6 +920,7 @@
 
     return true;
 }
+#endif // ENABLE_HARFBUZZ
 
 // =======================================================================
 
@@ -769,7 +928,11 @@
 {
     // find best layout engine for font, platform, script and language
     if (!mpLayoutEngine)
+#if ENABLE_HARFBUZZ
+        mpLayoutEngine = new HbLayoutEngine(*this);
+#else
         mpLayoutEngine = new IcuLayoutEngine(*this);
+#endif // ENABLE_HARFBUZZ
     return mpLayoutEngine;
 }
 

-- 
To view, visit https://gerrit.libreoffice.org/3518
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I07e698f7486379bae68329771695cd94d6e561b5
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: master
Gerrit-Owner: Khaled Hosny <khaledhosny@eglug.org>


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.