[Libreoffice-commits] core.git: Branch 'feature/commonsallayout' - 392 commits - accessibility/inc accessibility/source apple_remote/source avmedia/inc avmedia/source basctl/source basegfx/source basegfx/test basic/qa basic/source bin/dump-poolitems-values.py bin/test-hid-vs-ui.py canvas/source chart2/inc chart2/source comphelper/source compilerplugins/clang config_host.mk.in configure.ac connectivity/qa connectivity/source cppcanvas/source cui/source cui/uiconfig dbaccess/source desktop/Executable_unopkg_com.mk desktop/inc desktop/source dictionaries drawinglayer/source editeng/source embeddedobj/test extensions/source extensions/test external/clucene external/firebird external/harfbuzz external/poppler extras/source filter/source forms/source formula/source fpicker/source fpicker/test framework/inc framework/qa framework/source helpcontent2 i18nlangtag/qa i18npool/qa icon-themes/breeze icon-themes/breeze_dark icon-themes/galaxy icon-themes/sifr idlc/inc idlc/source include/basic include/comphel per include/dbaccess include/editeng include/formula include/framework include/oox include/osl include/postwin.h include/rtl include/sal include/salhelper include/sfx2 include/svl include/svtools include/svx include/systools include/test include/toolkit include/tools include/ucbhelper include/unotools include/vcl include/xmloff include/xmlreader ios/experimental libreofficekit/source linguistic/source lotuswordpro/source odk/examples offapi/com officecfg/registry officecfg/util oox/source opencl/inc postprocess/CustomTarget_images.mk pyuno/GeneratedPackage_python-core.mk pyuno/README qadevOOo/runner registry/Library_reg.mk reportdesign/source RepositoryExternal.mk rsc/inc rsc/source sal/Library_sal.mk sal/Library_sal_textenc.mk sal/Library_uwinapi.mk sal/osl sal/qa sal/rtl sal/StaticLibrary_salcpprt.mk sal/systools sal/util scaddins/source sc/CppunitTest_sc_anchor_test.mk sc/inc sc/Library_sc.mk sc/Module_sc.mk sc/qa sc/res scripting/examples scripting/java scripting/source sc/sdi s c/source sc/uiconfig sc/UIConfig_scalc.mk sc/workben sdext/source sd/inc sd/Library_sd.mk sd/source setup_native/source sfx2/inc sfx2/source slideshow/source slideshow/test solenv/bin solenv/gbuild starmath/inc starmath/source stoc/test store/Library_store.mk svl/source svl/unx svtools/inc svtools/Library_svt.mk svtools/qa svtools/source svx/inc svx/Library_svxcore.mk svx/Library_svx.mk svx/qa svx/source svx/uiconfig svx/UIConfig_svx.mk svx/util svx/workben sw/inc sw/qa sw/source sw/uiconfig test/source toolkit/source tools/inc tools/source translations tubes/source ucbhelper/source ucb/qa ucb/source uitest/impress_tests UnoControls/source unoidl/source unoxml/source uui/source uui/uiconfig vbahelper/source vcl/android vcl/backendtest vcl/CppunitTest_vcl_wmf_test.mk vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/opengl vcl/osx vcl/qa vcl/quartz vcl/README.GDIMetaFile vcl/README.vars vcl/source vcl/unx vcl/win vcl/workben winaccessibility/source wizards/com wizards/source writer filter/source writerperfect/inc writerperfect/source xmloff/CppunitTest_xmloff_tokenmap.mk xmloff/CppunitTest_xmloff_uxmloff.mk xmloff/Module_xmloff.mk xmloff/qa xmloff/source xmlsecurity/inc xmlsecurity/source xmlsecurity/test_docs xmlsecurity/workben

Khaled Hosny khaledhosny at eglug.org
Mon Oct 10 03:02:50 UTC 2016


Rebased ref, commits from common ancestor:
commit c81fb933b89bbba18a1197f67b9325bbfb44648d
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Oct 10 01:36:45 2016 +0200

    Just call ICU directly and cut the middle layers
    
    Change-Id: I7603d03fef8ca227c3e6fe25239281d18801522a

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 0bbab99..7de1a80 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -25,6 +25,7 @@
 #include <i18nlangtag/mslangid.hxx>
 #include <limits>
 #include <salgdi.hxx>
+#include <unicode/uchar.h>
 
 #if defined(_WIN32)
 struct WinSalGraphicsWithIDFace
@@ -116,14 +117,14 @@ static void scaleHbFont(hb_font_t* pHbFont, const FontSelectPattern& aFontSelDat
     hb_font_set_scale(pHbFont, nXScale, nYScale);
 }
 
+#if !HB_VERSION_ATLEAST(1, 1, 0)
 static hb_unicode_funcs_t* getUnicodeFuncs()
 {
     static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
-#if !HB_VERSION_ATLEAST(1, 1, 0)
     hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, unicodeDecomposeCompatibility, nullptr, nullptr);
-#endif
     return ufuncs;
 }
+#endif
 
 #if defined(_WIN32)
 CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace)
@@ -389,8 +390,8 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                 nHbFlags |= HB_BUFFER_FLAG_EOT; /* End-of-text */
 
             hb_buffer_t *pHbBuffer = hb_buffer_create();
-            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
 #if !HB_VERSION_ATLEAST(1, 1, 0)
+            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
             hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
 #endif
             if (SAL_UNLIKELY(bVertical))
@@ -449,7 +450,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                 else
                 {
 #if HB_VERSION_ATLEAST(0, 9, 42)
-                    if(hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+                    if (u_getIntPropertyValue(aChar, UCHAR_GENERAL_CATEGORY) == U_NON_SPACING_MARK)
                         bDiacritic = true;
 #else
                     // the font lacks GDEF table
@@ -585,8 +586,7 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
 
             sal_Int32 indexUtf16 = pGlyphIter->mnCharPos;
             sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0);
-            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
-            if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)
+            if (u_isUWhiteSpace(aChar))
                 continue;
 
             DeviceCoordinate nGapWidth = pKashida.second;
commit 9773148d02c9c4f816ea21eabf292c4cf9cdad5f
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Oct 10 00:54:00 2016 +0200

    Validate Kashida positions in CommonSalLayout
    
    Currently checks only for ligatures, but that is a big improvement over
    al code that didn’t do any validation except on Windows.
    
    Change-Id: I035248f4ccc23134ea27b40c2dd6197130749f14

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index e9116ba..8ee1255 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -68,4 +68,6 @@ public:
 
     virtual bool            GetCharWidths(DeviceCoordinate* pCharWidths) const override;
     virtual void            ApplyDXArray(ImplLayoutArgs&) override;
+
+    virtual bool            IsKashidaPosValid(int nCharPos) const override;
 };
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index e338261..0bbab99 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -612,3 +612,30 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
         }
     }
 }
+
+bool CommonSalLayout::IsKashidaPosValid(int nCharPos) const
+{
+    for (auto pIter = m_GlyphItems.begin(); pIter != m_GlyphItems.end(); ++pIter)
+    {
+        if (pIter->mnCharPos == nCharPos)
+        {
+            // Search backwards for previous glyph belonging to a different
+            // character. We are looking backwards because we are dealing with
+            // RTL glyphs, which will be in visual order.
+            for (auto pPrev = pIter - 1; pPrev != m_GlyphItems.begin(); --pPrev)
+            {
+                if (pPrev->mnCharPos != nCharPos)
+                {
+                    // Check if the found glyph belongs to the next character,
+                    // otherwise the current glyph will be a ligature which is
+                    // invalid kashida position.
+                    if (pPrev->mnCharPos == (nCharPos + 1))
+                        return true;
+                    break;
+                }
+            }
+        }
+    }
+
+    return false;
+}
commit 6046b7630785d87f240dce92e1d2901de86a6629
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Oct 9 23:23:45 2016 +0200

    Re-enable Kashida insertion in CommonSalLayout
    
    We now do Kashida insertion in ApplyDXArray(), no need for a separate
    step. This simplifies the code greatly (old code is in
    GenericSalLayout::KashidaJustify()).
    
    Change-Id: Ie31c8969e26f1f293820f1e90f963a5ba1fc9eb1

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 433fbee..e338261 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -283,27 +283,18 @@ void CommonSalLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos,
 
 void CommonSalLayout::AdjustLayout(ImplLayoutArgs& rArgs)
 {
-    GenericSalLayout::AdjustLayout(rArgs);
+    SalLayout::AdjustLayout(rArgs);
+
+    if (rArgs.mpDXArray)
+        ApplyDXArray(rArgs);
+    else if (rArgs.mnLayoutWidth)
+        Justify(rArgs.mnLayoutWidth);
 
     // apply asian kerning if the glyphs are not already formatted
     if( (rArgs.mnFlags & SalLayoutFlags::KerningAsian)
     && !(rArgs.mnFlags & SalLayoutFlags::Vertical) )
         if( (rArgs.mpDXArray != nullptr) || (rArgs.mnLayoutWidth != 0) )
             ApplyAsianKerning(rArgs.mrStr);
-
-    if((rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray)
-    {
-        hb_codepoint_t nKashidaCodePoint = 0x0640;
-        hb_codepoint_t nKashidaGlyphIndex;
-
-        if(hb_font_get_glyph(mpHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex))
-        {
-            if(nKashidaGlyphIndex)
-            {
-                KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(mpHbFont, nKashidaGlyphIndex) >> 6);
-            }
-        }
-    }
 }
 
 void CommonSalLayout::DrawText( SalGraphics& rSalGraphics ) const
@@ -546,6 +537,16 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
             pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1];
     }
 
+    DeviceCoordinate nKashidaWidth = 0;
+    hb_codepoint_t nKashidaIndex;
+    if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification)
+    {
+        if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex))
+            nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, nKashidaIndex) / 64;
+    }
+
+    std::map<size_t, DeviceCoordinate> pKashidas;
+
     DeviceCoordinate nDelta = 0;
     size_t i = 0;
     while (i < m_GlyphItems.size())
@@ -553,16 +554,61 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
         int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos;
         DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos];
 
-        m_GlyphItems[i].maLinearPos.X() += nDelta;
+        if (nKashidaWidth && nDiff)
+            pKashidas[i] = nDiff;
+
         size_t j = i;
-        while (++j < m_GlyphItems.size())
+        while (j < m_GlyphItems.size())
         {
             if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos)
                 break;
             m_GlyphItems[j].maLinearPos.X() += nDelta;
+            // For RTL, put all justification space to the left of the glyph.
+            if (m_GlyphItems[i].IsRTLGlyph())
+                m_GlyphItems[j].maLinearPos.X() += nDiff;
+            ++j;
         }
 
         nDelta += nDiff;
         i = j;
     }
+
+    if (!pKashidas.empty())
+    {
+        size_t nInserted = 0;
+        for (auto const& pKashida : pKashidas)
+        {
+            auto pGlyphIter = m_GlyphItems.begin() + nInserted + pKashida.first;
+
+            if (!pGlyphIter->IsRTLGlyph())
+                continue;
+
+            sal_Int32 indexUtf16 = pGlyphIter->mnCharPos;
+            sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0);
+            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
+            if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)
+                continue;
+
+            DeviceCoordinate nGapWidth = pKashida.second;
+            int nKashidaCount = ceil(nGapWidth / nKashidaWidth);
+            DeviceCoordinate nInsertedKashidaWidth;
+            if (nGapWidth < nKashidaWidth)
+                nInsertedKashidaWidth = nGapWidth;
+            else
+                nInsertedKashidaWidth = nGapWidth / nKashidaCount;
+
+            Point aPos(pGlyphIter->maLinearPos.X() - nGapWidth, 0);
+            int nCharPos = pGlyphIter->mnCharPos;
+            int nFlags = GlyphItem::IS_IN_CLUSTER | GlyphItem::IS_RTL_GLYPH;
+            while (nKashidaCount)
+            {
+                GlyphItem aKashida(nCharPos, nKashidaIndex, aPos, nFlags, nInsertedKashidaWidth);
+                pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida);
+                aPos.X() += nInsertedKashidaWidth;
+                ++pGlyphIter;
+                ++nInserted;
+                --nKashidaCount;
+            }
+        }
+    }
 }
commit 5790af8f832c62d7cfcc9502d10e15710603532d
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Oct 9 19:08:18 2016 +0200

    Revert "Use HarfBuzz shape plan for a bit more control"
    
    This reverts commit 8b32ead0b988b142cd9878f126d985d946fd4ccc.

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index bd1b029..433fbee 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -314,7 +314,6 @@ void CommonSalLayout::DrawText( SalGraphics& rSalGraphics ) const
 
 bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 {
-    hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
     hb_script_t aHbScript = HB_SCRIPT_INVALID;
 
     int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos);
@@ -416,13 +415,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 #if HB_VERSION_ATLEAST(0, 9, 42)
             hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 #endif
-            const char *pHbShapers[5] = { "coretext_aat", "graphite2", "ot", "fallback", nullptr };
-            hb_segment_properties_t aHbProps;
-            hb_buffer_get_segment_properties(pHbBuffer, &aHbProps);
-            hb_shape_plan_t *pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, nullptr, 0, pHbShapers);
-            assert(hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, nullptr, 0));
-            hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
-            SAL_INFO("vcl.harfbuzz", hb_shape_plan_get_shaper(pHbPlan) << " shaper used for " << rArgs);
+            hb_shape(mpHbFont, pHbBuffer, nullptr, 0);
 
             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
             hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr);
@@ -455,6 +448,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                     nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
 
                 bool bDiacritic = false;
+                hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
                 if (hb_ot_layout_has_glyph_classes(pHbFace))
                 {
                     // the font has GDEF table
commit b16da3602a3239f05deb0983e8f97e81b73f7e3d
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Oct 6 04:15:41 2016 +0200

    Use HarfBuzz shape plan for a bit more control
    
    This way we control exactly what shapers we use in what order, and as an
    extra we can now tell which shaper HarfBuzz ends up using.
    
    Change-Id: Idd303b2a557e16ac86ada0c2006d3e2a052ac489

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 433fbee..bd1b029 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -314,6 +314,7 @@ void CommonSalLayout::DrawText( SalGraphics& rSalGraphics ) const
 
 bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 {
+    hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
     hb_script_t aHbScript = HB_SCRIPT_INVALID;
 
     int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos);
@@ -415,7 +416,13 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 #if HB_VERSION_ATLEAST(0, 9, 42)
             hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 #endif
-            hb_shape(mpHbFont, pHbBuffer, nullptr, 0);
+            const char *pHbShapers[5] = { "coretext_aat", "graphite2", "ot", "fallback", nullptr };
+            hb_segment_properties_t aHbProps;
+            hb_buffer_get_segment_properties(pHbBuffer, &aHbProps);
+            hb_shape_plan_t *pHbPlan = hb_shape_plan_create_cached(pHbFace, &aHbProps, nullptr, 0, pHbShapers);
+            assert(hb_shape_plan_execute(pHbPlan, mpHbFont, pHbBuffer, nullptr, 0));
+            hb_buffer_set_content_type(pHbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
+            SAL_INFO("vcl.harfbuzz", hb_shape_plan_get_shaper(pHbPlan) << " shaper used for " << rArgs);
 
             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
             hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr);
@@ -448,7 +455,6 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                     nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
 
                 bool bDiacritic = false;
-                hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
                 if (hb_ot_layout_has_glyph_classes(pHbFace))
                 {
                     // the font has GDEF table
commit 9271281614cd20d1f0256d88d8d01c1e5a0290a7
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Sep 26 19:09:52 2016 +0200

    First try on vertical text in CommonSalLayout
    
    Does not work quite right yet.
    
    Change-Id: I52a71c9c21ad75c7cb9c8574e5e7e3b7c1c0c0c3

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 20310b6..433fbee 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -381,6 +381,16 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
             LanguageTag &rTag = rArgs.maLanguageTag;
             OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US);
 
+            bool bVertical = false;
+            if ((rArgs.mnFlags & SalLayoutFlags::Vertical) &&
+                (aHbScript == HB_SCRIPT_HAN ||
+                 aHbScript == HB_SCRIPT_HANGUL ||
+                 aHbScript == HB_SCRIPT_HIRAGANA ||
+                 aHbScript == HB_SCRIPT_KATAKANA))
+            {
+                bVertical = true;
+            }
+
             int nHbFlags = HB_BUFFER_FLAGS_DEFAULT;
             if (nMinRunPos == 0)
                 nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */
@@ -392,7 +402,10 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 #if !HB_VERSION_ATLEAST(1, 1, 0)
             hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
 #endif
-            hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
+            if (SAL_UNLIKELY(bVertical))
+              hb_buffer_set_direction(pHbBuffer, HB_DIRECTION_TTB);
+            else
+              hb_buffer_set_direction(pHbBuffer, bRightToLeft ? HB_DIRECTION_RTL: HB_DIRECTION_LTR);
             hb_buffer_set_script(pHbBuffer, aHbScript);
             hb_buffer_set_language(pHbBuffer, hb_language_from_string(sLanguage.getStr(), -1));
             hb_buffer_set_flags(pHbBuffer, (hb_buffer_flags_t) nHbFlags);
@@ -457,17 +470,31 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                 if (bDiacritic)
                     nGlyphFlags |= GlyphItem::IS_DIACRITIC;
 
-                int32_t nXOffset =  pHbPositions[i].x_offset >> 6;
-                int32_t nYOffset =  pHbPositions[i].y_offset >> 6;
-                int32_t nXAdvance = pHbPositions[i].x_advance >> 6;
-                int32_t nYAdvance = pHbPositions[i].y_advance >> 6;
+                int32_t nXOffset;
+                int32_t nYOffset;
+                int32_t nXAdvance;
+                Point aNewPos;
+
+                if (SAL_UNLIKELY(bVertical))
+                {
+                    nXOffset =  pHbPositions[i].y_offset >> 6;
+                    nYOffset =  pHbPositions[i].x_offset >> 6;
+                    nXAdvance = pHbPositions[i].y_advance >> 6;
+                    nGlyphIndex |= GF_ROTL;
+                    aNewPos = Point(-(aCurrPos.X() + nXOffset), aCurrPos.Y() + nYOffset);
+                }
+                else
+                {
+                    nXOffset =  pHbPositions[i].x_offset >> 6;
+                    nYOffset =  pHbPositions[i].y_offset >> 6;
+                    nXAdvance = pHbPositions[i].x_advance >> 6;
+                    aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
+                }
 
-                Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() + nYOffset));
                 const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, nGlyphFlags, nXAdvance, nXOffset);
                 AppendGlyph(aGI);
 
                 aCurrPos.X() += nXAdvance;
-                aCurrPos.Y() += nYAdvance;
             }
 
             hb_buffer_destroy(pHbBuffer);
commit 90ee133d3f72b55da1c4788a1210b0bfd605376a
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sat Sep 24 23:13:47 2016 +0200

    Use range loop
    
    Change-Id: I5ce49e57ed57378b4b9e16c8bb020048644252a9

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 05b136d..20310b6 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -371,12 +371,12 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
         if (bRightToLeft)
             std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end());
 
-        for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it)
+        for (const auto& aScriptRun : aScriptSubRuns)
         {
-            int nMinRunPos = it->mnMin;
-            int nEndRunPos = it->mnEnd;
+            int nMinRunPos = aScriptRun.mnMin;
+            int nEndRunPos = aScriptRun.mnEnd;
             int nRunLen = nEndRunPos - nMinRunPos;
-            aHbScript = it->maScript;
+            aHbScript = aScriptRun.maScript;
             // hb_language_from_string() accept ISO639-3 language tag except for Chinese.
             LanguageTag &rTag = rArgs.maLanguageTag;
             OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US);
commit b1de1e9e143d34df51508c886fae9f87d3546fae
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sat Sep 24 23:04:39 2016 +0200

    Use const reference
    
    Change-Id: I0f632f3a8b480f785608aa081add1b1d2fefd312

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 89214d4..e9116ba 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -36,7 +36,7 @@
 class CommonSalLayout : public GenericSalLayout
 {
     hb_font_t* mpHbFont;
-    FontSelectPattern maFontSelData;
+    const FontSelectPattern& mrFontSelData;
     css::uno::Reference<css::i18n::XBreakIterator> mxBreak;
 #ifdef _WIN32
     HDC   mhDC;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 7698bab..05b136d 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -129,7 +129,7 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace)
 :   mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)),
     mhDC(WSL->getHDC()),
-    maFontSelData(rWinFontInstance.maFontSelData),
+    mrFontSelData(rWinFontInstance.maFontSelData),
     mpD2DRenderer(nullptr)
 {
     mpHbFont = rWinFontFace.GetHbFont();
@@ -153,7 +153,7 @@ CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontI
         hb_face_destroy(pHbFace);
     }
 
-    scaleHbFont(mpHbFont, maFontSelData);
+    scaleHbFont(mpHbFont, mrFontSelData);
 }
 
 void CommonSalLayout::InitFont() const
@@ -163,7 +163,7 @@ void CommonSalLayout::InitFont() const
 
 #elif defined(MACOSX) || defined(IOS)
 CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
-:   maFontSelData(rCoreTextStyle.maFontSelData),
+:   mrFontSelData(rCoreTextStyle.maFontSelData),
     mrCoreTextStyle(rCoreTextStyle)
 {
     mpHbFont = rCoreTextStyle.GetHbFont();
@@ -184,12 +184,12 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
         hb_face_destroy(pHbFace);
     }
 
-    scaleHbFont(mpHbFont, maFontSelData);
+    scaleHbFont(mpHbFont, mrFontSelData);
 }
 
 #else
 CommonSalLayout::CommonSalLayout(ServerFont& rServerFont)
-:   maFontSelData(rServerFont.GetFontSelData()),
+:   mrFontSelData(rServerFont.GetFontSelData()),
     mrServerFont(rServerFont)
 {
     mpHbFont = rServerFont.GetHbFont();
@@ -203,7 +203,7 @@ CommonSalLayout::CommonSalLayout(ServerFont& rServerFont)
         hb_face_destroy(pHbFace);
     }
 
-    scaleHbFont(mpHbFont, maFontSelData);
+    scaleHbFont(mpHbFont, mrFontSelData);
 }
 #endif
 
commit 90ce24477bc90325efcfce9a1e8f842e74eb7e0f
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Fri Sep 23 18:34:09 2016 +0200

    Make sure HarfBuzz module depends on Graphite
    
    Change-Id: I9c1cc9c679ceebeb4e5cd898876aaa7b61c18f17

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 64eeacf..c818136 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1368,6 +1368,8 @@ $(call gb_LinkTarget_add_libs,$(1),$(GRAPHITE_LIBS))
 
 endef
 
+gb_ExternalProject__use_graphite:=
+
 else # !SYSTEM_GRAPHITE
 
 define gb_LinkTarget__use_graphite
@@ -1382,6 +1384,10 @@ $(call gb_LinkTarget_use_static_libraries,$(1),\
 
 endef
 
+define gb_ExternalProject__use_graphite
+$(call gb_ExternalProject_use_external_project,$(1),graphite)
+
+endef
 endif # SYSTEM_GRAPHITE
 
 ifneq ($(SYSTEM_ICU),)
diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk
index 1be5c6f..57cfc44 100644
--- a/external/harfbuzz/ExternalProject_harfbuzz.mk
+++ b/external/harfbuzz/ExternalProject_harfbuzz.mk
@@ -17,6 +17,7 @@ $(eval $(call gb_ExternalProject_register_targets,harfbuzz,\
 
 $(eval $(call gb_ExternalProject_use_externals,harfbuzz,\
 	icu \
+	graphite \
 ))
 
 $(call gb_ExternalProject_get_state_target,harfbuzz,build) :
commit f3a6fcca5318680f912ebcec5932d132a7101fe5
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 07:57:04 2016 -0700

    Build HarfBuzz with Core Text on Mac
    
    To enable support for AAT fonts.
    
    Change-Id: Ifcc7d1672e98f8c067482400b7e45226bed4dbf1

diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk
index 4412815..1be5c6f 100644
--- a/external/harfbuzz/ExternalProject_harfbuzz.mk
+++ b/external/harfbuzz/ExternalProject_harfbuzz.mk
@@ -36,6 +36,7 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) :
 			--with-cairo=no \
 			--with-glib=no \
 			--with-graphite2=yes \
+			$(if $(filter MACOSX,$(OS)),--with-coretext=yes) \
 			$(if $(verbose),--disable-silent-rules,--enable-silent-rules) \
 			$(if $(CROSS_COMPILING),--build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM)) \
 			$(if $(filter LINUX,$(OS)),CXXFLAGS="$(CXXFLAGS) -fvisibility=hidden") \
commit a145b0f6e923456f6e38954bc362636964d9d64d
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 19:48:10 2016 +0200

    Always pass BCP 47 tags to HarfBuzz
    
    This is what it is expecting anyway, no need to special case it for
    Chinese.
    
    Change-Id: I6732412375d19816b599005d78abd796f67599ee

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index a5e3bf6..7698bab 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -379,7 +379,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
             aHbScript = it->maScript;
             // hb_language_from_string() accept ISO639-3 language tag except for Chinese.
             LanguageTag &rTag = rArgs.maLanguageTag;
-            OString sLanguage = OUStringToOString( MsLangId::isChinese(rTag.getLanguageType()) ? rTag.getBcp47():rTag.getLanguage() , RTL_TEXTENCODING_UTF8 );
+            OString sLanguage = OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US);
 
             int nHbFlags = HB_BUFFER_FLAGS_DEFAULT;
             if (nMinRunPos == 0)
commit c0c5f36ea78d057be28a00cf8a2513812bb2b0d1
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 19:45:23 2016 +0200

    Always build Graphite everywhere
    
    It is no longer an optional feature on any platform. The
    --enable-graphite stuff is kept as it controls the old Graphite
    integration code and it should be removed without.
    
    Change-Id: Ib4d76bba782a1439f02f93411b22d237a1987ea5

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index e0f1337..64eeacf 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1357,8 +1357,6 @@ endef
 
 endif # SYSTEM_FONTCONFIG
 
-ifeq ($(ENABLE_GRAPHITE),TRUE)
-
 ifneq ($(SYSTEM_GRAPHITE),)
 
 define gb_LinkTarget__use_graphite
@@ -1386,12 +1384,6 @@ endef
 
 endif # SYSTEM_GRAPHITE
 
-else # !ENABLE_GRAPHITE
-
-gb_LinkTarget__use_graphite :=
-
-endif # ENABLE_GRAPHITE
-
 ifneq ($(SYSTEM_ICU),)
 
 gb_LinkTarget__use_icu_headers:=
diff --git a/configure.ac b/configure.ac
index 43cc369..4124f5c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9240,19 +9240,20 @@ AC_SUBST(ICU_LIBS)
 dnl ===================================================================
 dnl Graphite
 dnl ===================================================================
+libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"])
+if test "$with_system_graphite" = "yes"; then
+    libo_MINGW_CHECK_DLL([libgraphite2])
+fi
+if test "$COM" = "MSC"; then # override the above
+    GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib"
+fi
 
+# This is the old Graphite support that will eventually be removed
 AC_MSG_CHECKING([whether to enable graphite support])
 if test $_os != Darwin -a $_os != Android -a $_os != iOS -a \( -z "$enable_graphite" -o "$enable_graphite" != no \); then
     AC_MSG_RESULT([yes])
     ENABLE_GRAPHITE="TRUE"
     AC_DEFINE(ENABLE_GRAPHITE)
-    libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"])
-    if test "$with_system_graphite" = "yes"; then
-        libo_MINGW_CHECK_DLL([libgraphite2])
-    fi
-    if test "$COM" = "MSC"; then # override the above
-        GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib"
-    fi
 
 else
     AC_MSG_RESULT([no])
@@ -9339,6 +9340,9 @@ if test "$COM" = "MSC"; then # override the above
     HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib"
 fi
 if test "$with_system_harfbuzz" = "yes"; then
+    if test "$with_system_graphite" = "no"; then
+        AC_MSG_ERROR([--with-system-graphite must be used when --with-system-harfbuzz is used])
+    fi
     AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support])
     _save_libs="$LIBS"
     _save_cflags="$CFLAGS"
@@ -9347,6 +9351,10 @@ if test "$with_system_harfbuzz" = "yes"; then
     AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])])
     LIBS="$_save_libs"
     CFLAGS="$_save_cflags"
+else
+    if test "$with_system_graphite" = "yes"; then
+        AC_MSG_ERROR([--without-system-graphite must be used when --without-system-harfbuzz is used])
+    fi
 fi
 
 AC_MSG_CHECKING([whether to use X11])
diff --git a/vcl/CppunitTest_vcl_wmf_test.mk b/vcl/CppunitTest_vcl_wmf_test.mk
index 51e9126..1de86d8 100644
--- a/vcl/CppunitTest_vcl_wmf_test.mk
+++ b/vcl/CppunitTest_vcl_wmf_test.mk
@@ -80,6 +80,7 @@ endif
 
 $(eval $(call gb_CppunitTest_use_externals,vcl_wmf_test,\
     gio \
+    graphite \
     harfbuzz \
     icuuc \
     lcms2 \
@@ -90,10 +91,6 @@ $(eval $(call gb_CppunitTest_use_externals,vcl_wmf_test,\
  ))
 endif
 
-ifeq ($(ENABLE_GRAPHITE),TRUE)
-$(eval $(call gb_CppunitTest_use_external,vcl_wmf_test,graphite))
-endif
-
 ifeq ($(OS),MACOSX)
 $(eval $(call gb_CppunitTest_use_system_darwin_frameworks,vcl_wmf_test,\
     ApplicationServices \
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 67bcbe5..2b0874a 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -116,6 +116,7 @@ $(eval $(call gb_Library_use_externals,vcl,\
 	boost_headers \
 	gio \
 	glm_headers \
+	graphite \
 	harfbuzz \
 	icu_headers \
 	icuuc \
@@ -434,8 +435,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
 ))
 endif
 
-$(eval $(call gb_Library_use_external,vcl,graphite))
-
 endif
 
 vcl_quartz_code= \
commit c20c1982491112b7e49888f9c587b9bebc4bc23c
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 19:29:04 2016 +0200

    Always build HarfBuzz everywhere
    
    It is no longer an optional feature on any platform.
    
    Change-Id: I70cdcd2c0df69d961ecc5f36b4e8d035d251ef16

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 95241ab..e0f1337 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1490,7 +1490,6 @@ endef
 
 endif # SYSTEM_ICU
 
-ifeq ($(ENABLE_HARFBUZZ),TRUE)
 ifneq ($(SYSTEM_HARFBUZZ),)
 
 define gb_LinkTarget__use_harfbuzz
@@ -1515,11 +1514,6 @@ $(call gb_LinkTarget_use_external_project,$(1),harfbuzz)
 endef
 
 endif # SYSTEM_HARFBUZZ
-else # ENABLE_HARFBUZZ != YES
-
-gb_LinkTarget__use_harfbuzz :=
-
-endif # ENABLE_HARFBUZZ
 
 ifeq ($(DISABLE_OPENSSL),TRUE)
 
diff --git a/config_host.mk.in b/config_host.mk.in
index 2e6d007..90c25a6 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -133,7 +133,6 @@ export ENABLE_FIREBIRD_SDBC=@ENABLE_FIREBIRD_SDBC@
 export ENABLE_GIO=@ENABLE_GIO@
 export ENABLE_GRAPHITE=@ENABLE_GRAPHITE@
 export ENABLE_ORCUS=@ENABLE_ORCUS@
-export ENABLE_HARFBUZZ=@ENABLE_HARFBUZZ@
 export ENABLE_GLTF=@ENABLE_GLTF@
 export SYSTEM_LIBGLTF=@SYSTEM_LIBGLTF@
 export LIBGLTF_CFLAGS=@LIBGLTF_CFLAGS@
diff --git a/configure.ac b/configure.ac
index 5559e8b..43cc369 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2135,12 +2135,6 @@ AC_ARG_WITH(iwyu,
          Use only if you are hacking on it.]),
 ,)
 
-AC_ARG_WITH(harfbuzz,
-    AS_HELP_STRING([--with-harfbuzz],
-        [Enable HarfBuzz support regardless of the platform.
-         Experimental only. Use only if working on it.]),
-,)
-
 dnl ===================================================================
 dnl Branding
 dnl ===================================================================
@@ -9340,32 +9334,20 @@ AC_SUBST(ENABLE_ORCUS)
 dnl ===================================================================
 dnl HarfBuzz
 dnl ===================================================================
-AC_MSG_CHECKING([whether to enable HarfBuzz support])
-if test "$with_harfbuzz" = "yes" -o \( $_os != WINNT -a $_os != Darwin -a $_os != iOS \); then
-    AC_MSG_RESULT([yes])
-    ENABLE_HARFBUZZ="TRUE"
-    if $PKG_CONFIG --atleast-version 0.9.18 harfbuzz; then
-        libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 0.9.18],["-I${WORKDIR}/UnpackedTarball/harfbuzz/src"],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"])
-    else
-        libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz >= 0.9.10],[-I${WORKDIR}/UnpackedTarball/harfbuzz/src],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"])
-    fi
-    if test "$COM" = "MSC"; then # override the above
-        HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib"
-    fi
-    if test "$with_system_harfbuzz" = "yes"; then
-        AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support])
-        _save_libs="$LIBS"
-        _save_cflags="$CFLAGS"
-        LIBS="$LIBS $HARFBUZZ_LIBS"
-        CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS"
-        AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])])
-        LIBS="$_save_libs"
-        CFLAGS="$_save_cflags"
-    fi
-else
-    AC_MSG_RESULT([no])
+libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 0.9.18],["-I${WORKDIR}/UnpackedTarball/harfbuzz/src"],["-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"])
+if test "$COM" = "MSC"; then # override the above
+    HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib"
+fi
+if test "$with_system_harfbuzz" = "yes"; then
+    AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support])
+    _save_libs="$LIBS"
+    _save_cflags="$CFLAGS"
+    LIBS="$LIBS $HARFBUZZ_LIBS"
+    CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS"
+    AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])])
+    LIBS="$_save_libs"
+    CFLAGS="$_save_cflags"
 fi
-AC_SUBST(ENABLE_HARFBUZZ)
 
 AC_MSG_CHECKING([whether to use X11])
 dnl ***************************************
commit dc85f88ad596bd754297b0a039978921cd63dbd5
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Sep 11 10:25:46 2016 +0200

    Override GetCharWidths and ApplyDXArray in CSL
    
    A much simpler and saner implementation. This also unbreaks Awami
    Nastaliq.
    
    Break kashida justification, will need to rewrite that one as well.
    
    Change-Id: I843679e937f2881e77df61f5cbd9516b6df1b3b6

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 83de5c1..89214d4 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -65,4 +65,7 @@ public:
     virtual bool            LayoutText(ImplLayoutArgs&) override;
     virtual void            DrawText( SalGraphics& ) const override;
     std::shared_ptr<vcl::TextLayoutCache> CreateTextLayoutCache(OUString const&) const override;
+
+    virtual bool            GetCharWidths(DeviceCoordinate* pCharWidths) const override;
+    virtual void            ApplyDXArray(ImplLayoutArgs&) override;
 };
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index cfb2930..1050943 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -326,7 +326,7 @@ public:
     void            AppendGlyph( const GlyphItem& );
     void            Reserve(int size) { m_GlyphItems.reserve(size + 1); }
     virtual void    AdjustLayout( ImplLayoutArgs& ) override;
-    void    ApplyDXArray( ImplLayoutArgs& );
+    virtual void    ApplyDXArray( ImplLayoutArgs& );
     void    Justify( DeviceCoordinate nNewWidth );
     void            KashidaJustify( long nIndex, int nWidth );
     void            ApplyAsianKerning(const OUString& rStr);
@@ -352,7 +352,7 @@ protected:
     virtual void    DropGlyph( int nStart ) override;
     virtual void    Simplify( bool bIsBase ) override;
 
-    bool            GetCharWidths( DeviceCoordinate* pCharWidths ) const;
+    virtual bool    GetCharWidths( DeviceCoordinate* pCharWidths ) const;
 
     std::vector<GlyphItem>     m_GlyphItems;
 
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 9c68bdb..a5e3bf6 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -486,3 +486,56 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 
     return true;
 }
+
+bool CommonSalLayout::GetCharWidths(DeviceCoordinate* pCharWidths) const
+{
+    int nCharCount = mnEndCharPos - mnMinCharPos;
+
+    for (int i = 0; i < nCharCount; ++i)
+        pCharWidths[i] = 0;
+
+    for (auto const& aGlyphItem : m_GlyphItems)
+        pCharWidths[aGlyphItem.mnCharPos - mnMinCharPos] += aGlyphItem.mnNewWidth;
+
+    return true;
+}
+
+void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
+{
+    if (rArgs.mpDXArray == nullptr)
+        return;
+
+    int nCharCount = mnEndCharPos - mnMinCharPos;
+    std::unique_ptr<DeviceCoordinate[]> const pOldCharWidths(new DeviceCoordinate[nCharCount]);
+    std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new DeviceCoordinate[nCharCount]);
+
+    GetCharWidths(pOldCharWidths.get());
+
+    for (int i = 0; i < nCharCount; ++i)
+    {
+        if (i == 0)
+            pNewCharWidths[i] = rArgs.mpDXArray[i];
+        else
+            pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1];
+    }
+
+    DeviceCoordinate nDelta = 0;
+    size_t i = 0;
+    while (i < m_GlyphItems.size())
+    {
+        int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos;
+        DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos];
+
+        m_GlyphItems[i].maLinearPos.X() += nDelta;
+        size_t j = i;
+        while (++j < m_GlyphItems.size())
+        {
+            if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos)
+                break;
+            m_GlyphItems[j].maLinearPos.X() += nDelta;
+        }
+
+        nDelta += nDiff;
+        i = j;
+    }
+}
commit 01a5fd925dbfff4c18bd15ca36418e65fad6a8ae
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Wed Sep 7 23:26:14 2016 +0200

    Don’t check glyph class unnecessarily
    
    Don’t call hb_ot_layout_get_glyph_class() unless the glyph advance width
    is zero, as we really do not use its result otherwise.
    
    Change-Id: Id02238abef91b9343931f1886d54d966d7157f25

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index fd7d59c..9c68bdb 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -439,9 +439,8 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                 if (hb_ot_layout_has_glyph_classes(pHbFace))
                 {
                     // the font has GDEF table
-                    bool bMark = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
-                    if (bMark && pHbPositions[i].x_advance == 0)
-                        bDiacritic = true;
+                    if (pHbPositions[i].x_advance == 0)
+                        bDiacritic = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
                 }
                 else
                 {
commit 0c50fde8c2d121ffcf41ab9d287dd2ba3c1f7536
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Wed Sep 7 19:40:11 2016 +0200

    Cache HarfBuzz font
    
    We now create it only once per physical font, saves us few percents from
    the all over time spent on layout.
    
    Change-Id: I8de582cb20a168c93d72921e539c2477fa97fb54

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index da75f0f..83de5c1 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -35,7 +35,7 @@
 
 class CommonSalLayout : public GenericSalLayout
 {
-    hb_face_t* mpHbFace;
+    hb_font_t* mpHbFont;
     FontSelectPattern maFontSelData;
     css::uno::Reference<css::i18n::XBreakIterator> mxBreak;
 #ifdef _WIN32
@@ -48,7 +48,6 @@ class CommonSalLayout : public GenericSalLayout
     ServerFont& mrServerFont;
 #endif
 
-    hb_font_t*              GetHbFont();
 public:
 #if defined(_WIN32)
     explicit                CommonSalLayout(WinSalGraphics*, WinFontInstance&, const WinFontFace&);
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 00b2d8e..f7e5156 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -99,8 +99,8 @@ public:
     void       GetFontMetric( ImplFontMetricDataRef& ) const;
     bool       GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const;
     bool       GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const;
-    hb_face_t* GetHbFace() const { return mpHbFace; }
-    void       SetHbFace(hb_face_t* pHbFace) const { mpHbFace = pHbFace; }
+    hb_font_t* GetHbFont() const { return mpHbFont; }
+    void       SetHbFont(hb_font_t* pHbFont) const { mpHbFont = pHbFont; }
 
     const CoreTextFontFace*  mpFontData;
     /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
@@ -112,7 +112,7 @@ public:
 private:
     /// CoreText text style object
     CFMutableDictionaryRef  mpStyleDict;
-    mutable hb_face_t*      mpHbFace;
+    mutable hb_font_t*      mpHbFont;
 
     friend class CTLayout;
     friend class AquaSalGraphics;
diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index 38967bf..7cb2a84 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -182,8 +182,8 @@ public:
     sal_GlyphId             FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const;
     bool                    GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const;
     bool                    GetAntialiasAdvice() const;
-    hb_face_t*              GetHbFace() { return mpHbFace; }
-    void                    SetHbFace( hb_face_t* pHbFace ) { mpHbFace=pHbFace; }
+    hb_font_t*              GetHbFont() { return mpHbFont; }
+    void                    SetHbFont( hb_font_t* pHbFont ) { mpHbFont = pHbFont; }
 
 private:
     friend class GlyphCache;
@@ -243,7 +243,7 @@ private:
     GlyphSubstitution       maGlyphSubstitution;
 
     ServerFontLayoutEngine* mpLayoutEngine;
-    hb_face_t*              mpHbFace;
+    hb_font_t*              mpHbFont;
 };
 
 // a class for cache entries for physical font instances that are based on serverfonts
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 5301390..3509f5a 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -142,12 +142,12 @@ private:
 
     mutable std::unordered_set<sal_UCS4>      maGsubTable;
     mutable bool            mbGsubRead;
-    mutable hb_face_t*      mpHbFace;
+    mutable hb_font_t*      mpHbFont;
 public:
     bool                    HasGSUBstitutions( HDC ) const;
     bool                    IsGSUBstituted( sal_UCS4 ) const;
-    hb_face_t*              GetHbFace() const { return mpHbFace; }
-    void                    SetHbFace( hb_face_t* pHbFace ) const { mpHbFace = pHbFace; }
+    hb_font_t*              GetHbFont() const { return mpHbFont; }
+    void                    SetHbFont( hb_font_t* pHbFont ) const { mpHbFont = pHbFont; }
 };
 
 /** Class that creates (and destroys) a compatible Device Context.
diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx
index f183c10..ac17abc 100644
--- a/vcl/quartz/ctfonts.cxx
+++ b/vcl/quartz/ctfonts.cxx
@@ -50,7 +50,7 @@ CoreTextStyle::CoreTextStyle( const FontSelectPattern& rFSD )
     , mfFontRotation( 0.0 )
     , maFontSelData( rFSD )
     , mpStyleDict( nullptr )
-    , mpHbFace( nullptr )
+    , mpHbFont( nullptr )
 {
     const FontSelectPattern* const pReqFont = &rFSD;
 
@@ -117,8 +117,8 @@ CoreTextStyle::~CoreTextStyle()
 {
     if( mpStyleDict )
         CFRelease( mpStyleDict );
-    if( mpHbFace )
-        hb_face_destroy( mpHbFace );
+    if( mpHbFont )
+        hb_font_destroy( mpHbFont );
 }
 
 void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef& rxFontMetric ) const
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index afdbdf8..fd7d59c 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -90,6 +90,32 @@ static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
     return pBlob;
 }
 
+static hb_font_t* createHbFont(hb_face_t* pHbFace)
+{
+    hb_font_t* pHbFont = hb_font_create(pHbFace);
+    hb_ot_font_set_funcs(pHbFont);
+
+    return pHbFont;
+}
+
+static void scaleHbFont(hb_font_t* pHbFont, const FontSelectPattern& aFontSelData)
+{
+    uint64_t nXScale = aFontSelData.mnWidth << 6;
+    uint64_t nYScale = aFontSelData.mnHeight << 6;
+
+#if defined(_WIN32)
+    // HACK to get stretched/shrunken text. TODO: Get rid of HACK
+    if (nXScale)
+        nXScale = double(nXScale) * 1.812;
+#endif
+
+    if (!nXScale)
+      nXScale = nYScale;
+
+    hb_font_set_ppem(pHbFont, nXScale, nYScale);
+    hb_font_set_scale(pHbFont, nXScale, nYScale);
+}
+
 static hb_unicode_funcs_t* getUnicodeFuncs()
 {
     static hb_unicode_funcs_t* ufuncs = hb_unicode_funcs_create(hb_icu_get_unicode_funcs());
@@ -103,16 +129,15 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace)
 :   mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)),
     mhDC(WSL->getHDC()),
-    mpHbFace(nullptr),
     maFontSelData(rWinFontInstance.maFontSelData),
     mpD2DRenderer(nullptr)
 {
-    mpHbFace = rWinFontFace.GetHbFace();
-    if(!mpHbFace)
+    mpHbFont = rWinFontFace.GetHbFont();
+    if (!mpHbFont)
     {
         mpD2DRenderer = dynamic_cast<D2DWriteTextOutRenderer*>(&TextOutRenderer::get());
         WinSalGraphicsWithIDFace* pWSLWithIDFace = new WinSalGraphicsWithIDFace(WSL, mpD2DRenderer->GetDWriteFontFace(mhDC));
-        mpHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace,
+        hb_face_t* pHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace,
                   [](void* pUserData)
                   {
                       WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>( pUserData );
@@ -121,8 +146,14 @@ CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontI
                       delete pUData;
                   }
                  );
-        rWinFontFace.SetHbFace(mpHbFace);
+
+        mpHbFont = createHbFont(pHbFace);
+        rWinFontFace.SetHbFont(mpHbFont);
+
+        hb_face_destroy(pHbFace);
     }
+
+    scaleHbFont(mpHbFont, maFontSelData);
 }
 
 void CommonSalLayout::InitFont() const
@@ -132,54 +163,49 @@ void CommonSalLayout::InitFont() const
 
 #elif defined(MACOSX) || defined(IOS)
 CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
-:   mpHbFace(nullptr),
-    maFontSelData(rCoreTextStyle.maFontSelData),
+:   maFontSelData(rCoreTextStyle.maFontSelData),
     mrCoreTextStyle(rCoreTextStyle)
 {
-    mpHbFace = rCoreTextStyle.GetHbFace();
-    if(!mpHbFace)
+    mpHbFont = rCoreTextStyle.GetHbFont();
+    if (!mpHbFont)
     {
+        hb_face_t* pHbFace;
         CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName));
         CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL);
         if (pCGFont)
-            mpHbFace = hb_coretext_face_create(pCGFont);
+            pHbFace = hb_coretext_face_create(pCGFont);
         else
-            mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
+            pHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
         CGFontRelease(pCGFont);
-        rCoreTextStyle.SetHbFace(mpHbFace);
+
+        mpHbFont = createHbFont(pHbFace);
+        rCoreTextStyle.SetHbFont(mpHbFont);
+
+        hb_face_destroy(pHbFace);
     }
+
+    scaleHbFont(mpHbFont, maFontSelData);
 }
 
 #else
 CommonSalLayout::CommonSalLayout(ServerFont& rServerFont)
-:   mpHbFace(nullptr),
-    maFontSelData(rServerFont.GetFontSelData()),
+:   maFontSelData(rServerFont.GetFontSelData()),
     mrServerFont(rServerFont)
 {
-    mpHbFace = rServerFont.GetHbFace();
-    if(!mpHbFace)
+    mpHbFont = rServerFont.GetHbFont();
+    if (!mpHbFont)
     {
-        mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr);
-        mrServerFont.SetHbFace(mpHbFace);
-    }
-}
-#endif
+        hb_face_t* pHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr);
 
-hb_font_t* CommonSalLayout::GetHbFont()
-{
-    // HACK. TODO: Get rid of HACK
-#if defined(_WIN32)
-    if(maFontSelData.mnWidth)
-        maFontSelData.mnWidth = (double)maFontSelData.mnWidth*1.812;
-#endif
+        mpHbFont = createHbFont(pHbFace);
+        mrServerFont.SetHbFont(mpHbFont);
 
-    hb_font_t* pHbFont = hb_font_create(mpHbFace);
-    hb_font_set_ppem(pHbFont, maFontSelData.mnWidth? maFontSelData.mnWidth:maFontSelData.mnHeight , maFontSelData.mnHeight);
-    hb_font_set_scale(pHbFont, (uint64_t)(maFontSelData.mnWidth? maFontSelData.mnWidth:maFontSelData.mnHeight) << 6
-                             , (uint64_t)maFontSelData.mnHeight << 6);
-    hb_ot_font_set_funcs(pHbFont);
-    return pHbFont;
+        hb_face_destroy(pHbFace);
+    }
+
+    scaleHbFont(mpHbFont, maFontSelData);
 }
+#endif
 
 struct HbScriptRun
 {
@@ -267,18 +293,16 @@ void CommonSalLayout::AdjustLayout(ImplLayoutArgs& rArgs)
 
     if((rArgs.mnFlags & SalLayoutFlags::KashidaJustification) && rArgs.mpDXArray)
     {
-        hb_font_t* pHbFont = GetHbFont();
         hb_codepoint_t nKashidaCodePoint = 0x0640;
         hb_codepoint_t nKashidaGlyphIndex;
 
-        if(hb_font_get_glyph(pHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex))
+        if(hb_font_get_glyph(mpHbFont, nKashidaCodePoint, 0, &nKashidaGlyphIndex))
         {
             if(nKashidaGlyphIndex)
             {
-                KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(pHbFont, nKashidaGlyphIndex) >> 6);
+                KashidaJustify(nKashidaGlyphIndex, hb_font_get_glyph_h_advance(mpHbFont, nKashidaGlyphIndex) >> 6);
             }
         }
-        hb_font_destroy(pHbFont);
     }
 }
 
@@ -290,7 +314,6 @@ void CommonSalLayout::DrawText( SalGraphics& rSalGraphics ) const
 
 bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 {
-    hb_font_t* pHbFont = GetHbFont();
     hb_script_t aHbScript = HB_SCRIPT_INVALID;
 
     int nGlyphCapacity = 2 * (rArgs.mnEndCharPos - rArgs.mnMinCharPos);
@@ -379,7 +402,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 #if HB_VERSION_ATLEAST(0, 9, 42)
             hb_buffer_set_cluster_level(pHbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 #endif
-            hb_shape(pHbFont, pHbBuffer, nullptr, 0);
+            hb_shape(mpHbFont, pHbBuffer, nullptr, 0);
 
             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
             hb_glyph_info_t *pHbGlyphInfos = hb_buffer_get_glyph_infos(pHbBuffer, nullptr);
@@ -412,10 +435,11 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
                     nGlyphFlags |= GlyphItem::IS_IN_CLUSTER;
 
                 bool bDiacritic = false;
-                if (hb_ot_layout_has_glyph_classes(mpHbFace))
+                hb_face_t* pHbFace = hb_font_get_face(mpHbFont);
+                if (hb_ot_layout_has_glyph_classes(pHbFace))
                 {
                     // the font has GDEF table
-                    bool bMark = hb_ot_layout_get_glyph_class(mpHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
+                    bool bMark = hb_ot_layout_get_glyph_class(pHbFace, nGlyphIndex) == HB_OT_LAYOUT_GLYPH_CLASS_MARK;
                     if (bMark && pHbPositions[i].x_advance == 0)
                         bDiacritic = true;
                 }
@@ -451,8 +475,6 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
         }
     }
 
-    hb_font_destroy(pHbFont);
-
     // sort glyphs in visual order
     // and then in logical order (e.g. diacritics after cluster start)
     // XXX: why?
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index 8cf7198..fbeb95e 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -462,7 +462,7 @@ ServerFont::ServerFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI )
     mbArtBold( false ),
     mbUseGamma( false ),
     mpLayoutEngine( nullptr ),
-    mpHbFace( nullptr )
+    mpHbFont( nullptr )
 {
     // TODO: move update of mpFontInstance into FontEntry class when
     // it becomes responsible for the ServerFont instantiation
@@ -611,8 +611,8 @@ ServerFont::~ServerFont()
 
     mpFontInfo->ReleaseFaceFT();
 
-    if( mpHbFace )
-        hb_face_destroy( mpHbFace );
+    if( mpHbFont )
+        hb_font_destroy( mpHbFont );
 
     ReleaseFromGarbageCollect();
 }
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 3977cee..379b8cc 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -869,7 +869,7 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
     mbAliasSymbolsHigh( false ),
     mbAliasSymbolsLow( false ),
     mbGsubRead( false ),
-    mpHbFace( nullptr )
+    mpHbFont( nullptr )
 {
     SetBitmapSize( 0, nHeight );
 
@@ -911,8 +911,8 @@ WinFontFace::~WinFontFace()
 #endif // ENABLE_GRAPHITE
     delete mpEncodingVector;
 
-    if( mpHbFace )
-        hb_face_destroy( mpHbFace );
+    if( mpHbFont )
+        hb_font_destroy( mpHbFont );
 }
 
 sal_IntPtr WinFontFace::GetFontId() const
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 4aafa44..9ab4dbe 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -4065,8 +4065,8 @@ PhysicalFontFace* WinFontFace::Clone() const
     if ( mpGraphiteData )
         mpGraphiteData->AddReference();
 #endif
-    if( mpHbFace )
-        hb_face_reference( mpHbFace );
+    if( mpHbFont )
+        hb_font_reference( mpHbFont );
 
     PhysicalFontFace* pClone = new WinFontFace( *this );
     return pClone;
commit dff8716b5baef329f4dbe4d7e423c560be70b614
Author: Akash Jain <akash96j at gmail.com>
Date:   Wed Aug 17 21:31:22 2016 +0530

    GSoC: Speed up CommonSalLayout by caching hb_face
    
    Cache hb_face so it is not created again and again.
    Switch from GDI to DirectWrite on Windows to obtain SFNT table data.
    
    Change-Id: I9c532cd72e1f6b57313f3b7d42a6b9b0633eb0ef

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index ba93855..da75f0f 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -41,6 +41,7 @@ class CommonSalLayout : public GenericSalLayout
 #ifdef _WIN32
     HDC   mhDC;
     HFONT mhFont;
+    D2DWriteTextOutRenderer* mpD2DRenderer;
 #elif defined(MACOSX) || defined(IOS)
     const CoreTextStyle& mrCoreTextStyle;
 #else
@@ -50,7 +51,7 @@ class CommonSalLayout : public GenericSalLayout
     hb_font_t*              GetHbFont();
 public:
 #if defined(_WIN32)
-    explicit                CommonSalLayout(HDC, WinFontInstance&);
+    explicit                CommonSalLayout(WinSalGraphics*, WinFontInstance&, const WinFontFace&);
     virtual void            InitFont() const override;
 #elif defined(MACOSX) || defined(IOS)
     explicit                CommonSalLayout(const CoreTextStyle&);
@@ -60,7 +61,6 @@ public:
     const ServerFont&       getFontData() const { return mrServerFont; };
 #endif
 
-    virtual                 ~CommonSalLayout();
     void                    SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool);
     void                    AdjustLayout(ImplLayoutArgs&) override;
     virtual bool            LayoutText(ImplLayoutArgs&) override;
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index 104699b..00b2d8e 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -45,6 +45,7 @@
 
 #include "quartz/salgdicommon.hxx"
 #include <unordered_map>
+#include <hb-ot.h>
 
 class AquaSalFrame;
 class FontAttributes;
@@ -98,6 +99,8 @@ public:
     void       GetFontMetric( ImplFontMetricDataRef& ) const;
     bool       GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const;
     bool       GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const;
+    hb_face_t* GetHbFace() const { return mpHbFace; }
+    void       SetHbFace(hb_face_t* pHbFace) const { mpHbFace = pHbFace; }
 
     const CoreTextFontFace*  mpFontData;
     /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
@@ -109,6 +112,7 @@ public:
 private:
     /// CoreText text style object
     CFMutableDictionaryRef  mpStyleDict;
+    mutable hb_face_t*      mpHbFace;
 
     friend class CTLayout;
     friend class AquaSalGraphics;
diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index 944ffff..38967bf 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -35,6 +35,7 @@
 #include <sallayout.hxx>
 #include "fontattributes.hxx"
 #include "impfontmetricdata.hxx"
+#include "hb-ot.h"
 
 #include <unordered_map>
 
@@ -181,6 +182,8 @@ public:
     sal_GlyphId             FixupGlyphIndex( sal_GlyphId aGlyphId, sal_UCS4 ) const;
     bool                    GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& ) const;
     bool                    GetAntialiasAdvice() const;
+    hb_face_t*              GetHbFace() { return mpHbFace; }
+    void                    SetHbFace( hb_face_t* pHbFace ) { mpHbFace=pHbFace; }
 
 private:
     friend class GlyphCache;
@@ -240,6 +243,7 @@ private:
     GlyphSubstitution       maGlyphSubstitution;
 
     ServerFontLayoutEngine* mpLayoutEngine;
+    hb_face_t*              mpHbFace;
 };
 
 // a class for cache entries for physical font instances that are based on serverfonts
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index dba23bb..5301390 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -44,6 +44,9 @@
 #  include "postwin.h"
 #endif
 
+#include <hb-ot.h>
+#include <dwrite.h>
+
 class FontSelectPattern;
 class WinFontInstance;
 class ImplFontAttrCache;
@@ -139,10 +142,12 @@ private:
 
     mutable std::unordered_set<sal_UCS4>      maGsubTable;
     mutable bool            mbGsubRead;
+    mutable hb_face_t*      mpHbFace;
 public:
     bool                    HasGSUBstitutions( HDC ) const;
     bool                    IsGSUBstituted( sal_UCS4 ) const;
-    static int              GetTable( const char pTagName[5], const unsigned char*&, HDC );
+    hb_face_t*              GetHbFace() const { return mpHbFace; }
+    void                    SetHbFace( hb_face_t* pHbFace ) const { mpHbFace = pHbFace; }
 };
 
 /** Class that creates (and destroys) a compatible Device Context.
@@ -353,6 +358,7 @@ private:
     sal_uLong               GetKernPairs();
 
 public:
+    sal_uLong               GetTable( const char pTagName[5], const unsigned char*&, void*&, IDWriteFontFace*& );
     // public SalGraphics methods, the interface to the independent vcl part
 
     // get device resolution
diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx
index 28be80b..f183c10 100644
--- a/vcl/quartz/ctfonts.cxx
+++ b/vcl/quartz/ctfonts.cxx
@@ -50,6 +50,7 @@ CoreTextStyle::CoreTextStyle( const FontSelectPattern& rFSD )
     , mfFontRotation( 0.0 )
     , maFontSelData( rFSD )
     , mpStyleDict( nullptr )
+    , mpHbFace( nullptr )
 {
     const FontSelectPattern* const pReqFont = &rFSD;
 
@@ -116,6 +117,8 @@ CoreTextStyle::~CoreTextStyle()
 {
     if( mpStyleDict )
         CFRelease( mpStyleDict );
+    if( mpHbFace )
+        hb_face_destroy( mpHbFace );
 }
 
 void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef& rxFontMetric ) const
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index eb5b6a2..afdbdf8 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -26,6 +26,21 @@
 #include <limits>
 #include <salgdi.hxx>
 
+#if defined(_WIN32)
+struct WinSalGraphicsWithIDFace
+{
+    WinSalGraphics*     mpWSL;
+    IDWriteFontFace*    mpIDFace;
+    void*               mpTableContext;
+
+    WinSalGraphicsWithIDFace( WinSalGraphics* pWSL, IDWriteFontFace* pIDFace )
+    : mpWSL( pWSL ),
+      mpIDFace( pIDFace ),
+      mpTableContext( nullptr )
+    {}
+};
+#endif
+
 static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData)
 {
     char pTagName[5];
@@ -38,8 +53,8 @@ static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
     sal_uLong nLength=0;
 #if defined(_WIN32)
     const unsigned char* pBuffer = nullptr;
-    HDC* phDC = static_cast<HDC*>(pUserData);
-    nLength = WinFontFace::GetTable(pTagName, pBuffer, *phDC);
+    WinSalGraphicsWithIDFace* pWSLWithIDFace = static_cast<WinSalGraphicsWithIDFace*>(pUserData);
+    nLength = (pWSLWithIDFace->mpWSL)->GetTable(pTagName, pBuffer, pWSLWithIDFace->mpTableContext, pWSLWithIDFace->mpIDFace);
 #elif defined(MACOSX) || defined(IOS)
     unsigned char* pBuffer = nullptr;
     CoreTextFontFace* pFont = static_cast<CoreTextFontFace*>(pUserData);
@@ -57,7 +72,15 @@ static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
 
     hb_blob_t* pBlob = nullptr;
     if (pBuffer != nullptr)
-#if defined(_WIN32) || defined(MACOSX) || defined(IOS)
+#if defined(_WIN32)
+        pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, pWSLWithIDFace,
+                               [](void* pUserData)
+                               {
+                                   WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>(pUserData);
+                                   pUData->mpIDFace->ReleaseFontTable(pUData->mpTableContext);
+                               }
+                              );
+#elif defined(MACOSX) || defined(IOS)
         pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY,
                                const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); } );
 #else
@@ -77,13 +100,29 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 }
 
 #if defined(_WIN32)
-CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance)
-:   mhDC(hDC),
-    mhFont((HFONT)GetCurrentObject(hDC, OBJ_FONT)),
+CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& rWinFontInstance, const WinFontFace& rWinFontFace)
+:   mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)),
+    mhDC(WSL->getHDC()),
     mpHbFace(nullptr),
-    maFontSelData(rWinFontInstance.maFontSelData)
+    maFontSelData(rWinFontInstance.maFontSelData),
+    mpD2DRenderer(nullptr)
 {
-    mpHbFace = hb_face_create_for_tables(getFontTable, &hDC, nullptr);
+    mpHbFace = rWinFontFace.GetHbFace();
+    if(!mpHbFace)
+    {
+        mpD2DRenderer = dynamic_cast<D2DWriteTextOutRenderer*>(&TextOutRenderer::get());
+        WinSalGraphicsWithIDFace* pWSLWithIDFace = new WinSalGraphicsWithIDFace(WSL, mpD2DRenderer->GetDWriteFontFace(mhDC));
+        mpHbFace= hb_face_create_for_tables( getFontTable, pWSLWithIDFace,
+                  [](void* pUserData)
+                  {
+                      WinSalGraphicsWithIDFace* pUData = static_cast<WinSalGraphicsWithIDFace*>( pUserData );
+                      if(pUData->mpIDFace)
+                          pUData->mpIDFace->Release();
+                      delete pUData;
+                  }
+                 );
+        rWinFontFace.SetHbFace(mpHbFace);
+    }
 }
 
 void CommonSalLayout::InitFont() const
@@ -97,13 +136,18 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
     maFontSelData(rCoreTextStyle.maFontSelData),
     mrCoreTextStyle(rCoreTextStyle)
 {
-    CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName));
-    CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL);
-    if (pCGFont)
-        mpHbFace = hb_coretext_face_create(pCGFont);
-    else
-        mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
-    CGFontRelease(pCGFont);
+    mpHbFace = rCoreTextStyle.GetHbFace();
+    if(!mpHbFace)
+    {
+        CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName));
+        CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL);
+        if (pCGFont)
+            mpHbFace = hb_coretext_face_create(pCGFont);
+        else
+            mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
+        CGFontRelease(pCGFont);
+        rCoreTextStyle.SetHbFace(mpHbFace);
+    }
 }
 
 #else
@@ -112,15 +156,15 @@ CommonSalLayout::CommonSalLayout(ServerFont& rServerFont)
     maFontSelData(rServerFont.GetFontSelData()),
     mrServerFont(rServerFont)
 {
-    mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr);
+    mpHbFace = rServerFont.GetHbFace();
+    if(!mpHbFace)
+    {
+        mpHbFace = hb_face_create_for_tables(getFontTable, &rServerFont, nullptr);
+        mrServerFont.SetHbFace(mpHbFace);
+    }
 }
 #endif
 
-CommonSalLayout::~CommonSalLayout()
-{
-    hb_face_destroy(mpHbFace);
-}
-
 hb_font_t* CommonSalLayout::GetHbFont()
 {
     // HACK. TODO: Get rid of HACK
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index 55df59e..8cf7198 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -461,7 +461,8 @@ ServerFont::ServerFont( const FontSelectPattern& rFSD, FreetypeFontInfo* pFI )
     mbArtItalic( false ),
     mbArtBold( false ),
     mbUseGamma( false ),
-    mpLayoutEngine( nullptr )
+    mpLayoutEngine( nullptr ),
+    mpHbFace( nullptr )
 {
     // TODO: move update of mpFontInstance into FontEntry class when
     // it becomes responsible for the ServerFont instantiation
@@ -610,6 +611,9 @@ ServerFont::~ServerFont()
 
     mpFontInfo->ReleaseFaceFT();
 
+    if( mpHbFace )
+        hb_face_destroy( mpHbFace );
+
     ReleaseFromGarbageCollect();
 }
 
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index d86d881..3977cee 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -868,7 +868,8 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
     mnPitchAndFamily( nPitchAndFamily ),
     mbAliasSymbolsHigh( false ),
     mbAliasSymbolsLow( false ),
-    mbGsubRead( false )
+    mbGsubRead( false ),
+    mpHbFace( nullptr )
 {
     SetBitmapSize( 0, nHeight );
 
@@ -909,6 +910,9 @@ WinFontFace::~WinFontFace()
 #endif
 #endif // ENABLE_GRAPHITE
     delete mpEncodingVector;
+
+    if( mpHbFace )
+        hb_face_destroy( mpHbFace );
 }
 
 sal_IntPtr WinFontFace::GetFontId() const
@@ -1061,16 +1065,22 @@ void WinFontFace::ReadCmapTable( HDC hDC ) const
     }
 }
 
-int WinFontFace::GetTable(const char pTagName[5], const unsigned char*& pResBuffer, HDC hDC)
+sal_uLong WinSalGraphics::GetTable( const char pTagName[5], const unsigned char*& pResBuffer, void*& pTableContext, IDWriteFontFace*& pIDFace )
 {
-    const DWORD nTableTag = CalcTag( pTagName );
-    RawFontData aRawFontData( hDC, nTableTag );
-
-    if( !aRawFontData.get() )
+    if( !pIDFace )
         return 0;
-
-    pResBuffer = aRawFontData.steal();
-    return aRawFontData.size();
+    const void* pResBuf;
+    UINT32 nSize;
+    BOOL bExists;
+    HRESULT hr = S_OK;
+    const DWORD nTableTag = DWRITE_MAKE_OPENTYPE_TAG( pTagName[0], pTagName[1], pTagName[2], pTagName[3] );
+    hr = pIDFace->TryGetFontTable( nTableTag, &pResBuf, &nSize, &pTableContext, &bExists );
+    if( SUCCEEDED( hr ) && ( bExists ) )
+    {
+        pResBuffer = static_cast<const unsigned char*>(pResBuf);
+        return static_cast<sal_uLong>(nSize);
+    }
+    return 0;
 }
 
 void WinFontFace::GetFontCapabilities( HDC hDC ) const
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 538f46a..4aafa44 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -3518,6 +3518,24 @@ bool D2DWriteTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC,
     return (succeeded && nGlyphs >= 1 && pRectToErase);
 }
 
+IDWriteFontFace* D2DWriteTextOutRenderer::GetDWriteFontFace(HDC hDC) const
+{
+    IDWriteFontFace* pFontFace;
+    bool succeeded = false;
+    try
+    {
+        succeeded = SUCCEEDED(mpGdiInterop->CreateFontFaceFromHdc(hDC, &pFontFace));
+    }
+    catch (const std::exception& e)
+    {
+        SAL_WARN("vcl.gdi.opengl", "Error in dwrite while creating font face: " << e.what());
+        return nullptr;
+    }
+    if(succeeded)
+    return pFontFace;
+    else return nullptr;
+}
+
 bool D2DWriteTextOutRenderer::BindFont(HDC hDC)
 {
     // A TextOutRender can only be bound to one font at a time, so the
@@ -3884,7 +3902,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
 
     if( getenv("SAL_USE_COMMON_LAYOUT") )
     {
-        return new CommonSalLayout( getHDC(), rFontInstance );
+        return new CommonSalLayout( this, rFontInstance, rFontFace );
     }
     else
     {
@@ -4047,6 +4065,9 @@ PhysicalFontFace* WinFontFace::Clone() const
     if ( mpGraphiteData )
         mpGraphiteData->AddReference();
 #endif
+    if( mpHbFace )
+        hb_face_reference( mpHbFace );
+
     PhysicalFontFace* pClone = new WinFontFace( *this );
     return pClone;
 }
commit b083e958c2fb49b5e8c0bdf62b9856a2a9d8f0e2
Author: Akash Jain <akash96j at gmail.com>
Date:   Thu Aug 18 20:51:25 2016 +0530

    GSoC: Move TextOutRenderer definition to winlayout.hxx
    
    Change-Id: I705f92d5ad55d7612c6413436c801de13f5352a6

diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index 7905513..4c6874f 100755
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -417,4 +417,105 @@ public:
 
 #endif
 
+class TextOutRenderer
+{
+protected:
+    explicit TextOutRenderer() = default;
+    TextOutRenderer(const TextOutRenderer &) = delete;
+    TextOutRenderer & operator = (const TextOutRenderer &) = delete;
+
+public:
+    static TextOutRenderer & get();
+
+    virtual ~TextOutRenderer() = default;
+
+    virtual bool operator ()(SalLayout const &rLayout, HDC hDC,
+        const Rectangle* pRectToErase,
+        Point* pPos, int* pGetNextGlypInfo) = 0;
+};
+
+class ExTextOutRenderer : public TextOutRenderer
+{
+    ExTextOutRenderer(const ExTextOutRenderer &) = delete;
+    ExTextOutRenderer & operator = (const ExTextOutRenderer &) = delete;
+
+public:
+    explicit ExTextOutRenderer() = default;
+    virtual ~ExTextOutRenderer() override = default;
+
+    bool operator ()(SalLayout const &rLayout, HDC hDC,
+        const Rectangle* pRectToErase,
+        Point* pPos, int* pGetNextGlypInfo) override;
+};
+
+#if ENABLE_GRAPHITE_DWRITE
+
+class D2DWriteTextOutRenderer : public TextOutRenderer
+{
+    typedef HRESULT(WINAPI *pD2D1CreateFactory_t)(D2D1_FACTORY_TYPE,
+        REFIID, const D2D1_FACTORY_OPTIONS *, void **);
+    typedef HRESULT(WINAPI *pDWriteCreateFactory_t)(DWRITE_FACTORY_TYPE,
+        REFIID, IUnknown **);
+
+    static HINSTANCE mmD2d1, mmDWrite;
+    static pD2D1CreateFactory_t     D2D1CreateFactory;
+    static pDWriteCreateFactory_t   DWriteCreateFactory;
+
+public:
+    static bool InitModules();
+
+    explicit D2DWriteTextOutRenderer();
+    virtual ~D2DWriteTextOutRenderer() override;
+
+    bool operator ()(SalLayout const &rLayout, HDC hDC,
+        const Rectangle* pRectToErase,
+        Point* pPos, int* pGetNextGlypInfo) override;
+
+    inline bool BindDC(HDC hDC, Rectangle const & rRect = Rectangle(0, 0, 0, 0)) {
+        RECT const rc = { rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() };
+        HRESULT ok= mpRT->BindDC(hDC, &rc);
+        return SUCCEEDED(ok);
+    }
+
+    bool BindFont(HDC hDC) /*override*/;
+    bool ReleaseFont() /*override*/;
+
+    std::vector<Rectangle>  GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const /*override*/;
+    ID2D1RenderTarget * GetRenderTarget() const { return mpRT; }
+    IDWriteFontFace*    GetDWriteFontFace(HDC) const;
+    IDWriteFontFace   * GetFontFace() const { return mpFontFace; }
+    float               GetEmHeight() const { return mlfEmHeight; }
+
+    inline HRESULT CreateRenderTarget() {
+        if (mpRT) mpRT->Release(); mpRT = nullptr;
+        return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT);
+    }
+
+    inline bool Ready() const { return mpGdiInterop && mpRT; }
+
+private:
+    static void CleanupModules();
+
+    // This is a singleton object disable copy ctor and assignemnt operator
+    D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete;
+    D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete;
+
+    bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const;
+    bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const;
+    bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd,
+        float * pAdvances, Point * pOffsets) /*override*/;
+
+    ID2D1Factory        * mpD2DFactory;
+    IDWriteFactory      * mpDWriteFactory;
+    IDWriteGdiInterop   * mpGdiInterop;
+    ID2D1DCRenderTarget * mpRT;
+    const D2D1_RENDER_TARGET_PROPERTIES mRTProps;
+
+    IDWriteFontFace * mpFontFace;
+    float             mlfEmHeight;
+    HDC               mhDC;
+};
+
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 48c40af..538f46a 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -17,8 +17,6 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
-#include "win/winlayout.hxx"
-
 #include "osl/module.h"
 #include "osl/file.h"
 
@@ -56,104 +54,8 @@
 std::unique_ptr<GlobalGlyphCache> GlyphCache::gGlobalGlyphCache(new GlobalGlyphCache);
 GLuint WinFontInstance::mnGLyphyProgram = 0;
 
-class TextOutRenderer
-{
-protected:
-    explicit TextOutRenderer() = default;
-    TextOutRenderer(const TextOutRenderer &) = delete;
-    TextOutRenderer & operator = (const TextOutRenderer &) = delete;
-
-public:
-    static TextOutRenderer & get();
-
-    virtual ~TextOutRenderer() = default;
-
-    virtual bool operator ()(SalLayout const &rLayout, HDC hDC,
-        const Rectangle* pRectToErase,
-        Point* pPos, int* pGetNextGlypInfo) = 0;
-};
-
-class ExTextOutRenderer : public TextOutRenderer
-{
-    ExTextOutRenderer(const ExTextOutRenderer &) = delete;
-    ExTextOutRenderer & operator = (const ExTextOutRenderer &) = delete;
-
-public:
-    explicit ExTextOutRenderer() = default;
-    virtual ~ExTextOutRenderer() override = default;
-
-    bool operator ()(SalLayout const &rLayout, HDC hDC,
-        const Rectangle* pRectToErase,
-        Point* pPos, int* pGetNextGlypInfo) override;
-};
-
 #if ENABLE_GRAPHITE_DWRITE
 
-class D2DWriteTextOutRenderer : public TextOutRenderer
-{
-    typedef HRESULT(WINAPI *pD2D1CreateFactory_t)(D2D1_FACTORY_TYPE,
-        REFIID, const D2D1_FACTORY_OPTIONS *, void **);
-
-    typedef HRESULT(WINAPI *pDWriteCreateFactory_t)(DWRITE_FACTORY_TYPE,
-        REFIID, IUnknown **);
-
-    static HINSTANCE mmD2d1, mmDWrite;
-    static pD2D1CreateFactory_t     D2D1CreateFactory;
-    static pDWriteCreateFactory_t   DWriteCreateFactory;
-
-public:
-    static bool InitModules();
-
-    explicit D2DWriteTextOutRenderer();
-    virtual ~D2DWriteTextOutRenderer() override;
-
-    bool operator ()(SalLayout const &rLayout, HDC hDC,
-        const Rectangle* pRectToErase,
-        Point* pPos, int* pGetNextGlypInfo) override;
-
-    inline bool BindDC(HDC hDC, Rectangle const & rRect = Rectangle(0, 0, 0, 0)) {
-        RECT const rc = { rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() };
-        return SUCCEEDED(mpRT->BindDC(hDC, &rc));
-    }
-
-    bool BindFont(HDC hDC) /*override*/;
-    bool ReleaseFont() /*override*/;
-
-    std::vector<Rectangle>  GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const /*override*/;
-    ID2D1RenderTarget * GetRenderTarget() const { return mpRT; }
-    IDWriteFontFace   * GetFontFace() const { return mpFontFace; }
-    float               GetEmHeight() const { return mlfEmHeight; }
-
-    inline HRESULT CreateRenderTarget() {
-        if (mpRT) mpRT->Release(); mpRT = nullptr;
-        return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT);
-    }
-
-    inline bool Ready() const { return mpGdiInterop && mpRT; }
-
-private:
-    static void CleanupModules();
-
-    // This is a singleton object disable copy ctor and assignemnt operator
-    D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete;
-    D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete;
-
-    bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const;
-    bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const;
-    bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd,
-        float * pAdvances, Point * pOffsets) /*override*/;
-
-    ID2D1Factory        * mpD2DFactory;
-    IDWriteFactory      * mpDWriteFactory;
-    IDWriteGdiInterop   * mpGdiInterop;
-    ID2D1DCRenderTarget * mpRT;
-    const D2D1_RENDER_TARGET_PROPERTIES mRTProps;
-
-    IDWriteFontFace * mpFontFace;
-    float             mlfEmHeight;
-    HDC               mhDC;
-};
-
 inline void WinFontInstance::CacheGlyphWidth( int nCharCode, int nCharWidth )
 {
     maWidthMap[ nCharCode ] = nCharWidth;
commit 0cbff4f9b6cbb262e268853d60d42656f69e328b
Author: Akash Jain <akash96j at gmail.com>
Date:   Sat Jul 23 21:41:40 2016 +0530

    GSoC: Add Graphite support for CommonSalLayout
    
    Enable Graphite font rendering in CommonSalLayout through Harfbuzz
    
    Change-Id: Ia6a00a1bb6ea1a7bd705ed91d4f4f6cb9803e062

diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx
index 6dabc15..d4bc0f7 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -532,23 +532,23 @@ SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackL
     if( mpServerFont[ nFallbackLevel ]
     && !(rArgs.mnFlags & SalLayoutFlags::DisableGlyphProcessing) )
     {
-#if ENABLE_GRAPHITE
-        // Is this a Graphite font?
-        if (!bDisableGraphite_ &&
-            GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
+        if(getenv("SAL_USE_COMMON_LAYOUT"))
         {
-            pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]);
+            pLayout = new CommonSalLayout( *mpServerFont[ nFallbackLevel ] );
         }
         else
-#endif
-            if(getenv("SAL_USE_COMMON_LAYOUT"))
+        {
+#if ENABLE_GRAPHITE
+            // Is this a Graphite font?
+            if (!bDisableGraphite_ &&
+                GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
             {
-                pLayout = new CommonSalLayout( *mpServerFont[ nFallbackLevel ] );
+                pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]);
             }
             else
-            {
+#endif
                 pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
-            }
+        }
     }
 
     return pLayout;
commit a8d799e0a8c4e3f770634b37a5700b2bb6b8b56d
Author: Akash Jain <akash96j at gmail.com>
Date:   Sat Jul 23 21:21:46 2016 +0530

    GSoC: Enable building Harfbuzz with Graphite
    
    Harfbuzz will now need to be built with Graphite support. This allows
    Harfbuzz to handle Graphite fonts. In case we all building with
    system Harfbuzz, then it should be built with Graphite support else
    we error out.
    
    Change-Id: I156ec08b9e5ad7ce87cc15e4b5852d9c57c98f7f

diff --git a/configure.ac b/configure.ac
index 6cc455a..5559e8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9252,10 +9252,14 @@ if test $_os != Darwin -a $_os != Android -a $_os != iOS -a \( -z "$enable_graph
     AC_MSG_RESULT([yes])
     ENABLE_GRAPHITE="TRUE"
     AC_DEFINE(ENABLE_GRAPHITE)
-    libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3])
+    libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3],["-I${WORKDIR}/UnpackedTarball/graphite/include"],["-L${WORKDIR}/LinkTarget/StaticLibrary -lgraphite"])
     if test "$with_system_graphite" = "yes"; then
         libo_MINGW_CHECK_DLL([libgraphite2])
     fi
+    if test "$COM" = "MSC"; then # override the above
+        GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib"
+    fi
+
 else
     AC_MSG_RESULT([no])
 fi
@@ -9348,6 +9352,16 @@ if test "$with_harfbuzz" = "yes" -o \( $_os != WINNT -a $_os != Darwin -a $_os !
     if test "$COM" = "MSC"; then # override the above
         HARFBUZZ_LIBS="${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs/libharfbuzz.lib"
     fi
+    if test "$with_system_harfbuzz" = "yes"; then
+        AC_MSG_CHECKING([whether system Harfbuzz is built with Graphite support])
+        _save_libs="$LIBS"
+        _save_cflags="$CFLAGS"
+        LIBS="$LIBS $HARFBUZZ_LIBS"
+        CFLAGS="$CFLAGS $HARFBUZZ_CFLAGS"
+        AC_CHECK_FUNC(hb_graphite2_face_get_gr_face,,[AC_MSG_ERROR([Harfbuzz needs to be built with Graphite support.])])
+        LIBS="$_save_libs"
+        CFLAGS="$_save_cflags"
+    fi
 else
     AC_MSG_RESULT([no])
 fi
diff --git a/external/harfbuzz/ExternalProject_harfbuzz.mk b/external/harfbuzz/ExternalProject_harfbuzz.mk
index 1bee5bb..4412815 100644
--- a/external/harfbuzz/ExternalProject_harfbuzz.mk
+++ b/external/harfbuzz/ExternalProject_harfbuzz.mk
@@ -23,6 +23,8 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) :
 	$(call gb_ExternalProject_run,build,\
 		$(if $(CROSS_COMPILING),ICU_CONFIG=$(SRCDIR)/external/icu/cross-bin/icu-config) \
 		$(if $(SYSTEM_ICU),,ICU_CONFIG=$(SRCDIR)/external/icu/cross-bin/icu-config) \
+		GRAPHITE2_CFLAGS="$(GRAPHITE_CFLAGS)" \
+		GRAPHITE2_LIBS="$(GRAPHITE_LIBS)" \
 		./configure \
 			--enable-static \
 			--disable-shared \
@@ -33,6 +35,7 @@ $(call gb_ExternalProject_get_state_target,harfbuzz,build) :
 			--with-fontconfig=no \
 			--with-cairo=no \
 			--with-glib=no \
+			--with-graphite2=yes \
 			$(if $(verbose),--disable-silent-rules,--enable-silent-rules) \
 			$(if $(CROSS_COMPILING),--build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM)) \
 			$(if $(filter LINUX,$(OS)),CXXFLAGS="$(CXXFLAGS) -fvisibility=hidden") \
commit b711d473886fd55dddd4ec89b0dd6b3666408278
Author: Akash Jain <akash96j at gmail.com>
Date:   Wed Jul 20 23:51:56 2016 +0530

    GSoC: Integrate new CommonSalLayout in quartz/ code
    
    Change-Id: I07a9c956f09be5d43ee58ff0784ba0f81f52cd9a

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 5a4c9a2..ba93855 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -23,6 +23,7 @@
 #elif defined(MACOSX) || defined(IOS)
 #include <com/sun/star/i18n/XBreakIterator.hpp>
 #include "quartz/ctfonts.hxx"
+#include <hb-coretext.h>
 
 #else
 #include "unx/freetype_glyphcache.hxx"
diff --git a/vcl/quartz/ctfonts.hxx b/vcl/inc/quartz/ctfonts.hxx
similarity index 100%
rename from vcl/quartz/ctfonts.hxx
rename to vcl/inc/quartz/ctfonts.hxx
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index ba0200b..104699b 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -111,6 +111,8 @@ private:
     CFMutableDictionaryRef  mpStyleDict;
 
     friend class CTLayout;
+    friend class AquaSalGraphics;
+    friend class CommonSalLayout;
     CFMutableDictionaryRef  GetStyleDict( void ) const { return mpStyleDict; }
 };
 
diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx
index 36b155d..28be80b 100644
--- a/vcl/quartz/ctfonts.cxx
+++ b/vcl/quartz/ctfonts.cxx
@@ -25,7 +25,7 @@
 #include <vcl/settings.hxx>
 
 
-#include "ctfonts.hxx"
+#include "quartz/ctfonts.hxx"
 #include "impfont.hxx"
 #ifdef MACOSX
 #include "osx/saldata.hxx"
diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx
index 35f7143..0e80020 100644
--- a/vcl/quartz/ctlayout.cxx
+++ b/vcl/quartz/ctlayout.cxx
@@ -25,9 +25,10 @@
 #include <sal/types.h>
 #include <tools/debug.hxx>
 
-#include "ctfonts.hxx"
+#include "quartz/ctfonts.hxx"
 #include "CTRunData.hxx"
 #include "quartz/utils.h"
+#include "CommonSalLayout.hxx"
 
 
 class CTLayout : public SalLayout
@@ -781,7 +782,14 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {}
 
 SalLayout* CoreTextStyle::GetTextLayout() const
 {
-    return new CTLayout( this);
+    if( getenv("SAL_USE_COMMON_LAYOUT") )
+    {
+        return new CommonSalLayout( *this );
+    }
+    else
+    {
+        return new CTLayout( this);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index d0f73a8..8362696 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -36,7 +36,7 @@
 #include <vcl/svapp.hxx>
 #include <vcl/sysdata.hxx>
 
-#include "ctfonts.hxx"
+#include "quartz/ctfonts.hxx"
 #include "fontsubset.hxx"
 #include "impfont.hxx"
 #include "impfontcharmap.hxx"
@@ -414,8 +414,39 @@ bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect
     return bRC;
 }
 
-void AquaSalGraphics::DrawSalLayout( const CommonSalLayout& )
-{
+void AquaSalGraphics::DrawSalLayout( const CommonSalLayout& rLayout )
+{
+    CGContextRef context = mrContext;
+    SAL_INFO( "vcl.ct", "CGContextSaveGState(" << context << ")" );
+    CGContextSaveGState( context );
+    SAL_INFO( "vcl.ct", "CGContextScaleCTM(" << context << ",1.0,-1.0)" );
+    const CoreTextStyle& rCTStyle = rLayout.getFontData();
+
+    CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue( rCTStyle.GetStyleDict(), kCTFontAttributeName ));
+    CGContextScaleCTM(context, 1.0, -1.0);
+    CGContextSetShouldAntialias(context, !mbNonAntialiasedText);
+    // rotate the matrix
+    const CGFloat fRadians = rCTStyle.mfFontRotation;
+    CGContextRotateCTM( context, +fRadians );
+    const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians );
+    CGContextSetFillColor( context, maTextColor.AsArray() );
+
+    // draw the text
+    Point aPos;
+    sal_GlyphId aGlyphId;
+    std::vector<CGGlyph> aGlyphIds;
+    std::vector<CGPoint> aGlyphPos;
+    int nStart = 0;
+    for(; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
+    {
+        aGlyphIds.push_back( aGlyphId & GF_IDXMASK );
+        aGlyphPos.push_back( CGPointApplyAffineTransform( CGPointMake( aPos.X(), -1*aPos.Y() ), aInvMatrix ) );
+    }
+    CTFontDrawGlyphs( pFont, aGlyphIds.data(), aGlyphPos.data(), nStart, context);
+
+    // restore the original graphic context transformations
+    SAL_INFO( "vcl.ct", "CGContextRestoreGState(" << context << ")" );
+    CGContextRestoreGState( context );
 }
 
 void AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index f37a257..eb5b6a2 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -57,7 +57,7 @@ static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
 
     hb_blob_t* pBlob = nullptr;
     if (pBuffer != nullptr)
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(MACOSX) || defined(IOS)
         pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY,
                                const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); } );
 #else
@@ -97,7 +97,13 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
     maFontSelData(rCoreTextStyle.maFontSelData),
     mrCoreTextStyle(rCoreTextStyle)
 {
-    mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
+    CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue(rCoreTextStyle.GetStyleDict(), kCTFontAttributeName));
+    CGFontRef pCGFont = CTFontCopyGraphicsFont(pCTFont, NULL);
+    if (pCGFont)
+        mpHbFace = hb_coretext_face_create(pCGFont);
+    else
+        mpHbFace = hb_face_create_for_tables(getFontTable, const_cast<CoreTextFontFace*>(rCoreTextStyle.mpFontData), nullptr);
+    CGFontRelease(pCGFont);
 }
 
 #else
commit 3f40cd8cab8168e941eb740206206a5bbf379853
Author: Akash Jain <akash96j at gmail.com>
Date:   Wed Jul 6 17:56:15 2016 +0530

    GSoC: Integrate new CommonSalLayout in win/ code
    
    Change-Id: Ifeb2fa7ca9e2cd0da1c504d4e770aa0bb1b0b0de

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index f19bcdd..f37a257 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -57,7 +57,12 @@ static hb_blob_t *getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
 
     hb_blob_t* pBlob = nullptr;
     if (pBuffer != nullptr)
+#if defined(_WIN32)
+        pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY,
+                               const_cast<unsigned char*>(pBuffer), [](void* data){ delete[] reinterpret_cast<unsigned char*>(data); } );
+#else
         pBlob = hb_blob_create(reinterpret_cast<const char*>(pBuffer), nLength, HB_MEMORY_MODE_READONLY, nullptr, nullptr);
+#endif
 
     return pBlob;
 }
@@ -74,12 +79,18 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 #if defined(_WIN32)
 CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance)
 :   mhDC(hDC),
+    mhFont((HFONT)GetCurrentObject(hDC, OBJ_FONT)),
     mpHbFace(nullptr),
     maFontSelData(rWinFontInstance.maFontSelData)
 {
     mpHbFace = hb_face_create_for_tables(getFontTable, &hDC, nullptr);
 }
 
+void CommonSalLayout::InitFont() const
+{
+    SelectObject( mhDC, mhFont );
+}
+
 #elif defined(MACOSX) || defined(IOS)
 CommonSalLayout::CommonSalLayout(const CoreTextStyle& rCoreTextStyle)
 :   mpHbFace(nullptr),
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 0d77b61..d86d881 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -2453,7 +2453,4 @@ void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
     }
 }
 
-void WinSalGraphics::DrawSalLayout( const CommonSalLayout& )
-{}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index cbf0b58..48c40af 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -34,6 +34,7 @@
 
 #include "sft.hxx"
 #include "sallayout.hxx"
+#include "CommonSalLayout.hxx"
 
 #include <cstdio>
 #include <cstdlib>
@@ -67,7 +68,7 @@ public:
 
     virtual ~TextOutRenderer() = default;
 
-    virtual bool operator ()(WinLayout const &rLayout, HDC hDC,
+    virtual bool operator ()(SalLayout const &rLayout, HDC hDC,
         const Rectangle* pRectToErase,
         Point* pPos, int* pGetNextGlypInfo) = 0;
 };
@@ -81,7 +82,7 @@ public:
     explicit ExTextOutRenderer() = default;
     virtual ~ExTextOutRenderer() override = default;
 
-    bool operator ()(WinLayout const &rLayout, HDC hDC,
+    bool operator ()(SalLayout const &rLayout, HDC hDC,
         const Rectangle* pRectToErase,
         Point* pPos, int* pGetNextGlypInfo) override;
 };
@@ -106,7 +107,7 @@ public:
     explicit D2DWriteTextOutRenderer();
     virtual ~D2DWriteTextOutRenderer() override;
 
-    bool operator ()(WinLayout const &rLayout, HDC hDC,
+    bool operator ()(SalLayout const &rLayout, HDC hDC,
         const Rectangle* pRectToErase,
         Point* pPos, int* pGetNextGlypInfo) override;
 
@@ -138,7 +139,7 @@ private:
     D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete;
 
     bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const;
-    bool GetDWriteInkBox(IDWriteFontFace & rFontFace, WinLayout const &rLayout, float const lfEmHeight, Rectangle &) const;
+    bool GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const lfEmHeight, Rectangle &) const;
     bool DrawGlyphs(const Point & origin, uint16_t * pGid, uint16_t * pGidEnd,
         float * pAdvances, Point * pOffsets) /*override*/;
 
@@ -3485,7 +3486,7 @@ TextOutRenderer & TextOutRenderer::get()
 }
 
 
-bool ExTextOutRenderer::operator ()(WinLayout const &rLayout, HDC hDC,
+bool ExTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC,
     const Rectangle* pRectToErase,
     Point* pPos, int* pGetNextGlypInfo)
 {
@@ -3544,7 +3545,7 @@ D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer()
     CleanupModules();
 }
 
-bool D2DWriteTextOutRenderer::operator ()(WinLayout const &rLayout, HDC hDC,
+bool D2DWriteTextOutRenderer::operator ()(SalLayout const &rLayout, HDC hDC,
     const Rectangle* pRectToErase,
     Point* pPos, int* pGetNextGlypInfo)
 {
@@ -3784,7 +3785,7 @@ bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** p
     return succeeded;
 }
 
-bool D2DWriteTextOutRenderer::GetDWriteInkBox(IDWriteFontFace & rFontFace, WinLayout const &rLayout, float const /*lfEmHeight*/, Rectangle & rOut) const
+bool D2DWriteTextOutRenderer::GetDWriteInkBox(IDWriteFontFace & rFontFace, SalLayout const &rLayout, float const /*lfEmHeight*/, Rectangle & rOut) const
 {
     rOut.SetEmpty();
 
@@ -3979,66 +3980,73 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
     const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ];
     WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
 
-    bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter;
-
-    if (!bUspInited)
-        InitUSP();
-
-    if( !(rArgs.mnFlags & SalLayoutFlags::ComplexDisabled) )
+    if( getenv("SAL_USE_COMMON_LAYOUT") )
     {
-#if ENABLE_GRAPHITE
-        if (rFontFace.SupportsGraphite())
-        {
-            pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
-        }
-        else
-#endif // ENABLE_GRAPHITE
-        {
-            // script complexity is determined in upper layers
-            pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
-            // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
-            // the created UniscribeLayout, otherwise the data passed into the
-            // constructor might become invalid too early
-        }
+        return new CommonSalLayout( getHDC(), rFontInstance );
     }
     else
     {
-#if ENABLE_GRAPHITE
-        if (rFontFace.SupportsGraphite())
-        {
-            pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
-        }
-        else
-#endif // ENABLE_GRAPHITE
-        {
-            static bool bAvoidSimpleWinLayout = (std::getenv("VCL_NO_SIMPLEWINLAYOUT") != NULL);
+        bool bUseOpenGL = OpenGLHelper::isVCLOpenGLEnabled() && !mbPrinter;
 
-            if (!bAvoidSimpleWinLayout)
-            {
-                if( (rArgs.mnFlags & SalLayoutFlags::KerningPairs) && !rFontInstance.HasKernData() )
-                {
-                    // TODO: directly cache kerning info in the rFontInstance
-                    // TODO: get rid of kerning methods+data in WinSalGraphics object
-                    GetKernPairs();
-                    rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
-                }
+        if (!bUspInited)
+            InitUSP();
 
-                pWinLayout = new SimpleWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
+        if( !(rArgs.mnFlags & SalLayoutFlags::ComplexDisabled) )
+        {
+#if ENABLE_GRAPHITE
+            if (rFontFace.SupportsGraphite())
+            {
+                pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
             }
             else
+#endif // ENABLE_GRAPHITE
             {
+                // script complexity is determined in upper layers
                 pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
                 // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
                 // the created UniscribeLayout, otherwise the data passed into the
                 // constructor might become invalid too early
             }
         }
-    }
+        else
+        {
+#if ENABLE_GRAPHITE
+            if (rFontFace.SupportsGraphite())
+            {
+                pWinLayout = new GraphiteWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
+            }
+            else
+#endif // ENABLE_GRAPHITE
+            {
+                static bool bAvoidSimpleWinLayout = (std::getenv("VCL_NO_SIMPLEWINLAYOUT") != NULL);
+
+                if (!bAvoidSimpleWinLayout)
+                {
+                    if( (rArgs.mnFlags & SalLayoutFlags::KerningPairs) && !rFontInstance.HasKernData() )
+                    {
+                        // TODO: directly cache kerning info in the rFontInstance
+                        // TODO: get rid of kerning methods+data in WinSalGraphics object
+                        GetKernPairs();
+                        rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
+                    }
+
+                    pWinLayout = new SimpleWinLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
+                }
+                else
+                {
+                    pWinLayout = new UniscribeLayout(getHDC(), rFontFace, rFontInstance, bUseOpenGL);
+                    // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
+                    // the created UniscribeLayout, otherwise the data passed into the
+                    // constructor might become invalid too early
+                }
+            }
+        }
 
-    if( mfFontScale[nFallbackLevel] != 1.0 )
-        pWinLayout->SetFontScale( mfFontScale[nFallbackLevel] );
+        if( mfFontScale[nFallbackLevel] != 1.0 )
+            pWinLayout->SetFontScale( mfFontScale[nFallbackLevel] );
 
-    return pWinLayout;
+        return pWinLayout;
+    }
 }
 
 int    WinSalGraphics::GetMinKashidaWidth()
@@ -4147,4 +4155,32 @@ LogicalFontInstance* WinFontFace::CreateFontInstance( FontSelectPattern& rFSD )
     return pFontInstance;
 }
 
+void WinSalGraphics::DrawSalLayout( const CommonSalLayout& rLayout )
+{
+    HDC hDC = getHDC();
+
+    if((std::getenv("SAL_DWRITE_COMMON_LAYOUT")))
+    {
+        Point aPos(0, 0);
+        int nGlyphCount(0);
+        TextOutRenderer &render = TextOutRenderer::get();
+        bool result = render( rLayout, hDC, nullptr, &aPos, &nGlyphCount );
+        assert( !result );
+    }
+    else
+    {
+        Point aPos;
+        sal_GlyphId aGlyphId;
+        int nFetchedGlyphs = 0;
+        UINT oldTa = GetTextAlign( hDC );
+        SetTextAlign( hDC, ( oldTa & ~TA_NOUPDATECP ) );
+        while( rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nFetchedGlyphs ) )
+        {
+            ExtTextOutW( hDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX, nullptr, reinterpret_cast<LPCWSTR>( &aGlyphId ),
+                         1, nullptr);
+        }
+        SetTextAlign(hDC, oldTa);
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit fdfec9514cd45c13a388738b92912a12f5faa6d6
Author: Akash Jain <akash96j at gmail.com>
Date:   Wed Jul 6 10:35:24 2016 +0530

    GSoC: Integrate new CommonSalLayout in unx/ code
    

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list