RepositoryExternal.mk                          |   20 
 config_host.mk.in                              |    1 
 configure.ac                                   |   47 -
 external/harfbuzz/ExternalProject_harfbuzz.mk  |    5 
 vcl/CppunitTest_vcl_wmf_test.mk                |    5 
 vcl/Library_vcl.mk                             |    6 
 vcl/README.vars                                |    1 
 vcl/headless/svptext.cxx                       |   10 
 vcl/inc/CommonSalLayout.hxx                    |   82 ++
 vcl/inc/headless/svpgdi.hxx                    |    3 
 vcl/inc/quartz/ctfonts.hxx                     |   34 +
 vcl/inc/quartz/salgdi.h                        |   18 
 vcl/inc/salgdi.hxx                             |    6 
 vcl/inc/sallayout.hxx                          |    6 
 vcl/inc/scrptrun.h                             |  160 +++++
 vcl/inc/textrender.hxx                         |    3 
 vcl/inc/unx/cairotextrender.hxx                |    2 
 vcl/inc/unx/genpspgraphics.h                   |    4 
 vcl/inc/unx/glyphcache.hxx                     |    4 
 vcl/inc/unx/salgdi.h                           |    3 
 vcl/inc/win/salgdi.h                           |   11 
 vcl/inc/win/winlayout.hxx                      |  519 ++++++++++++++++
 vcl/quartz/ctfonts.cxx                         |    6 
 vcl/quartz/ctfonts.hxx                         |   34 -
 vcl/quartz/ctlayout.cxx                        |    2 
 vcl/quartz/salgdi.cxx                          |  212 +++++-
 vcl/source/gdi/CommonSalLayout.cxx             |  784 +++++++++++++++++++++++++
 vcl/source/gdi/sallayout.cxx                   |    6 
 vcl/source/gdi/scrptrun.cxx                    |  234 +++++++
 vcl/unx/generic/gdi/cairotextrender.cxx        |   28 
 vcl/unx/generic/gdi/font.cxx                   |   10 
 vcl/unx/generic/glyphs/freetype_glyphcache.cxx |    6 
 vcl/unx/generic/glyphs/gcach_layout.cxx        |    3 
 vcl/unx/generic/glyphs/scrptrun.cxx            |  234 -------
 vcl/unx/generic/glyphs/scrptrun.h              |  160 -----
 vcl/unx/generic/print/genpspgraphics.cxx       |    2 
 vcl/win/gdi/salfont.cxx                        |   29 
 vcl/win/gdi/winlayout.cxx                      |  429 +++----------
 vcl/win/gdi/winlayout.hxx                      |  240 -------
 39 files changed, 2267 insertions(+), 1102 deletions(-)

New commits:
commit 8b9ec421accf344e0e6921c35ba53d8ff0b2de40
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Mon Oct 17 19:59:23 2016 +0200

    Fix debug build and few cleanups
    
    Change-Id: I805962667c3ef2dcaf07a0acebeacca74c74892a

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index abc5ea7..cd43bec 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -50,9 +50,10 @@ class CommonSalLayout : public GenericSalLayout
 #else
     ServerFont&             mrServerFont;
 #endif
-    OString mLang;
-    hb_feature_t * mpFeatures;
-    unsigned int mnFeats;
+
+    void                    ParseFeatures(const OUString& name);
+    OString                 msLanguage;
+    std::vector<hb_feature_t> maFeatures;
 
 public:
 #if defined(_WIN32)
@@ -66,7 +67,6 @@ public:
     const ServerFont&       getFontData() const { return mrServerFont; };
 #endif
 
-    void                    ParseFeatures(OUString name);
     void                    SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool);
     void                    AdjustLayout(ImplLayoutArgs&) override;
     bool                    LayoutText(ImplLayoutArgs&) override;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 0966b29..f6088b8 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -126,18 +126,16 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 }
 #endif
 
-void CommonSalLayout::ParseFeatures(OUString name)
+void CommonSalLayout::ParseFeatures(const OUString& name)
 {
-    mnFeats = 0;
-    mpFeatures = 0;
-    mLang = OString("");
+    int nFeatures = 0;
     int nStart = name.indexOf(':');
     if (nStart < 0)
         return;
     OString oName = OUStringToOString(name, RTL_TEXTENCODING_ASCII_US);
     for (int nNext = nStart; nNext > 0; nNext = name.indexOf('&', nNext + 1))
     {
-        if (name.match("lang=", nNext+1))
+        if (name.match("lang=", nNext + 1))
         {
             int endamp = name.indexOf('&', nNext+1);
             int enddelim = name.indexOf(' ', nNext+1);
@@ -151,23 +149,23 @@ void CommonSalLayout::ParseFeatures(OUString name)
                 end = endamp;
             else
                 end = enddelim;
-            mLang = oName.copy(nNext+6, end-nNext-6);
+            msLanguage = oName.copy(nNext + 6, end - nNext - 6);
         }
         else
-            ++mnFeats;
+            ++nFeatures;
     }
-    if (mnFeats == 0)
+    if (nFeatures == 0)
         return;
 
-    mpFeatures = new hb_feature_t[mnFeats];
-    mnFeats = 0;
-    for (int nThis = nStart, nNext = name.indexOf('&', nStart+1); nThis > 0; 
nThis = nNext, nNext = name.indexOf('&', nNext + 1))
+    maFeatures.reserve(nFeatures);
+    for (int nThis = nStart, nNext = name.indexOf('&', nStart + 1); nThis > 0; 
nThis = nNext, nNext = name.indexOf('&', nNext + 1))
     {
-        if (!name.match("lang=", nThis+1))
+        if (!name.match("lang=", nThis + 1))
         {
             int end = nNext > 0 ? nNext : name.getLength();
-            if (hb_feature_from_string(oName.getStr() + nThis + 1, end - nThis 
- 1, &mpFeatures[mnFeats]))
-                ++mnFeats;
+            hb_feature_t aFeature;
+            if (hb_feature_from_string(oName.getStr() + nThis + 1, end - nThis 
- 1, &aFeature))
+                maFeatures.push_back(aFeature);
         }
     }
 }
@@ -463,9 +461,9 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
             int nRunLen = nEndRunPos - nMinRunPos;
             aHbScript = hb_icu_script_to_script(aScriptRun.maScript);
 
-            // hb_language_from_string() accept ISO639-3 language tag except 
for Chinese.
-            LanguageTag &rTag = rArgs.maLanguageTag;
-            OString sLanguage = mLang.getLength() ? mLang : 
OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US);
+            OString sLanguage = msLanguage;
+            if (sLanguage.isEmpty())
+                sLanguage = OUStringToOString(rArgs.maLanguageTag.getBcp47(), 
RTL_TEXTENCODING_ASCII_US);
 
             bool bVertical = false;
             if ((rArgs.mnFlags & SalLayoutFlags::Vertical) &&
@@ -498,7 +496,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(mpHbFont, pHbBuffer, mpFeatures, mnFeats);
+            hb_shape(mpHbFont, pHbBuffer, maFeatures.data(), 
maFeatures.size());
 
             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
             hb_glyph_info_t *pHbGlyphInfos = 
hb_buffer_get_glyph_infos(pHbBuffer, nullptr);
commit 970db61951beebc44ca3dfff6dc14ad12733d97c
Author: Martin Hosken <martin_hos...@sil.org>
Date:   Mon Oct 17 15:22:32 2016 +0100

    Add feature support to CommonLayout
    
    Change-Id: I19a0e26cefa5e4185df961ae0f6f2f37811ae5bb
    Reviewed-on: https://gerrit.libreoffice.org/29978
    Reviewed-by: Khaled Hosny <khaledho...@eglug.org>
    Tested-by: Khaled Hosny <khaledho...@eglug.org>

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 513d2b9..abc5ea7 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -50,6 +50,9 @@ class CommonSalLayout : public GenericSalLayout
 #else
     ServerFont&             mrServerFont;
 #endif
+    OString mLang;
+    hb_feature_t * mpFeatures;
+    unsigned int mnFeats;
 
 public:
 #if defined(_WIN32)
@@ -63,6 +66,7 @@ public:
     const ServerFont&       getFontData() const { return mrServerFont; };
 #endif
 
+    void                    ParseFeatures(OUString name);
     void                    SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool);
     void                    AdjustLayout(ImplLayoutArgs&) override;
     bool                    LayoutText(ImplLayoutArgs&) override;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 9eb69b5..0966b29 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -126,6 +126,52 @@ static hb_unicode_funcs_t* getUnicodeFuncs()
 }
 #endif
 
+void CommonSalLayout::ParseFeatures(OUString name)
+{
+    mnFeats = 0;
+    mpFeatures = 0;
+    mLang = OString("");
+    int nStart = name.indexOf(':');
+    if (nStart < 0)
+        return;
+    OString oName = OUStringToOString(name, RTL_TEXTENCODING_ASCII_US);
+    for (int nNext = nStart; nNext > 0; nNext = name.indexOf('&', nNext + 1))
+    {
+        if (name.match("lang=", nNext+1))
+        {
+            int endamp = name.indexOf('&', nNext+1);
+            int enddelim = name.indexOf(' ', nNext+1);
+            int end = name.getLength();
+            if (endamp < 0)
+            {
+                if (enddelim > 0)
+                    end = enddelim;
+            }
+            else if (enddelim < 0 || endamp < enddelim)
+                end = endamp;
+            else
+                end = enddelim;
+            mLang = oName.copy(nNext+6, end-nNext-6);
+        }
+        else
+            ++mnFeats;
+    }
+    if (mnFeats == 0)
+        return;
+
+    mpFeatures = new hb_feature_t[mnFeats];
+    mnFeats = 0;
+    for (int nThis = nStart, nNext = name.indexOf('&', nStart+1); nThis > 0; 
nThis = nNext, nNext = name.indexOf('&', nNext + 1))
+    {
+        if (!name.match("lang=", nThis+1))
+        {
+            int end = nNext > 0 ? nNext : name.getLength();
+            if (hb_feature_from_string(oName.getStr() + nThis + 1, end - nThis 
- 1, &mpFeatures[mnFeats]))
+                ++mnFeats;
+        }
+    }
+}
+
 #if defined(_WIN32)
 CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, WinFontInstance& 
rWinFontInstance, const WinFontFace& rWinFontFace)
 :   mhFont((HFONT)GetCurrentObject(WSL->getHDC(), OBJ_FONT)),
@@ -155,6 +201,7 @@ CommonSalLayout::CommonSalLayout(WinSalGraphics* WSL, 
WinFontInstance& rWinFontI
     }
 
     scaleHbFont(mpHbFont, mrFontSelData);
+    ParseFeatures(mrFontSelData.maTargetName);
 }
 
 void CommonSalLayout::InitFont() const
@@ -186,6 +233,7 @@ CommonSalLayout::CommonSalLayout(const CoreTextStyle& 
rCoreTextStyle)
     }
 
     scaleHbFont(mpHbFont, mrFontSelData);
+    ParseFeatures(mrFontSelData.maTargetName);
 }
 
 #else
@@ -205,6 +253,7 @@ CommonSalLayout::CommonSalLayout(ServerFont& rServerFont)
     }
 
     scaleHbFont(mpHbFont, mrFontSelData);
+    ParseFeatures(mrFontSelData.maTargetName);
 }
 #endif
 
@@ -416,7 +465,7 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 
             // 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);
+            OString sLanguage = mLang.getLength() ? mLang : 
OUStringToOString(rTag.getBcp47(), RTL_TEXTENCODING_ASCII_US);
 
             bool bVertical = false;
             if ((rArgs.mnFlags & SalLayoutFlags::Vertical) &&
@@ -449,7 +498,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(mpHbFont, pHbBuffer, nullptr, 0);
+            hb_shape(mpHbFont, pHbBuffer, mpFeatures, mnFeats);
 
             int nRunGlyphCount = hb_buffer_get_length(pHbBuffer);
             hb_glyph_info_t *pHbGlyphInfos = 
hb_buffer_get_glyph_infos(pHbBuffer, nullptr);
commit 3a304a4e75d21fff5ba4775d9cb93b17f998e7ef
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Sat Oct 15 06:11:26 2016 -0700

    Rewrite AquaSalGraphics::DrawSalLayout()
    
    Slightly cleaner code and now handles glyph rotation for vertical text.
    
    Change-Id: I98cc8fd7df5e73068294e4d7dd6b38a71dcbdcc7

diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index 787ddbf..12dc1f1 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -485,37 +485,82 @@ bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId 
aGlyphId, Rectangle& rRect
 
 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
+    const CoreTextStyle& rStyle = rLayout.getFontData();
+    const FontSelectPattern& rFontSelect = rStyle.maFontSelData;
+    if (rFontSelect.mnHeight == 0)
+        return;
+
+    CTFontRef pFont = 
static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), 
kCTFontAttributeName));
+
     Point aPos;
     sal_GlyphId aGlyphId;
     std::vector<CGGlyph> aGlyphIds;
     std::vector<CGPoint> aGlyphPos;
+    std::vector<bool> aGlyphRotation;
     int nStart = 0;
-    for (; rLayout.GetNextGlyphs(1, &aGlyphId, aPos, nStart); )
+    while (rLayout.GetNextGlyphs(1, &aGlyphId, aPos, nStart))
     {
+        // Transform the position of non-vertical glyphs.
+        CGAffineTransform aMatrix = 
CGAffineTransformMakeRotation(-rStyle.mfFontRotation);
+
+        // Transform the position of vertical glyphs.
+        // We don’t handle GF_ROTR as it is not used in CommonSalLayout.
+        bool nGlyphRotation = false;
+        if ((aGlyphId & GF_ROTMASK) == GF_ROTL)
+        {
+            nGlyphRotation = true;
+            double nYdiff = CTFontGetAscent(pFont) - CTFontGetDescent(pFont);
+            aMatrix = CGAffineTransformTranslate(aMatrix, 0, -nYdiff);
+        }
+
         aGlyphIds.push_back(aGlyphId & GF_IDXMASK);
-        aGlyphPos.push_back(CGPointApplyAffineTransform(CGPointMake(aPos.X(), 
-1*aPos.Y()), aInvMatrix));
+        aGlyphPos.push_back(CGPointApplyAffineTransform(CGPointMake(aPos.X(), 
-aPos.Y()), aMatrix));
+        aGlyphRotation.push_back(nGlyphRotation);
+    }
+
+    if (aGlyphIds.empty())
+        return;
+
+    CGContextSaveGState(mrContext);
+
+    // Create a transformed font for drawing vertical glyphs.
+    CTFontRef pRotatedFont = nullptr;
+    if (rStyle.mfFontRotation)
+    {
+        CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFont);
+        CGFloat nSize = CTFontGetSize(pFont);
+        CGAffineTransform aMatrix = CTFontGetMatrix(pFont);
+        aMatrix = CGAffineTransformRotate(aMatrix, -rStyle.mfFontRotation);
+        pRotatedFont = CTFontCreateWithFontDescriptor(pDesc, nSize, &aMatrix);
+        CFRelease(pDesc);
+    }
+
+    CGContextScaleCTM(mrContext, 1.0, -1.0);
+    CGContextRotateCTM(mrContext, rStyle.mfFontRotation);
+    CGContextSetShouldAntialias(mrContext, !mbNonAntialiasedText);
+    CGContextSetFillColor(mrContext, maTextColor.AsArray());
+
+    auto aIt = aGlyphRotation.cbegin();
+    while (aIt != aGlyphRotation.cend())
+    {
+        bool nGlyphRotation = *aIt;
+        // Find the boundary of the run of glyphs with the same rotation, to be
+        // drawn together.
+        auto aNext = std::find(aIt, aGlyphRotation.cend(), !nGlyphRotation);
+        size_t nStartIndex = std::distance(aGlyphRotation.cbegin(), aIt);
+        size_t nLen = std::distance(aIt, aNext);
+
+        if (nGlyphRotation && pRotatedFont)
+            CTFontDrawGlyphs(pRotatedFont, &aGlyphIds[nStartIndex], 
&aGlyphPos[nStartIndex], nLen, mrContext);
+        else
+            CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], 
&aGlyphPos[nStartIndex], nLen, mrContext);
+
+        aIt = aNext;
     }
-    CTFontDrawGlyphs(pFont, aGlyphIds.data(), aGlyphPos.data(), nStart, 
context);
 
-    // restore the original graphic context transformations
-    SAL_INFO("vcl.ct", "CGContextRestoreGState(" << context << ")");
-    CGContextRestoreGState(context);
+    if (pRotatedFont)
+        CFRelease(pRotatedFont);
+    CGContextRestoreGState(mrContext);
 }
 
 void AquaSalGraphics::SetFont(FontSelectPattern* pReqFont, int nFallbackLevel)
commit 8f054454bf0703e154bb5964134c6f84f891a5b8
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Mon Sep 26 19:09:52 2016 +0200

    Support vertical text in CommonSalLayout
    
    Change-Id: I52a71c9c21ad75c7cb9c8574e5e7e3b7c1c0c0c3

diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 6ea559b..9eb69b5 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -212,12 +212,12 @@ struct HbScriptRun
 {
     int32_t mnMin;
     int32_t mnEnd;
-    hb_script_t maScript;
+    UScriptCode maScript;
 
     HbScriptRun(int32_t nMin, int32_t nEnd, UScriptCode aScript)
       : mnMin(nMin)
       , mnEnd(nEnd)
-      , maScript(hb_icu_script_to_script(aScript))
+      , maScript(aScript)
     {}
 };
 
@@ -307,6 +307,47 @@ void CommonSalLayout::DrawText(SalGraphics& rSalGraphics) 
const
     rSalGraphics.DrawSalLayout( *this );
 }
 
+/* https://drafts.csswg.org/css-writing-modes-3/#script-orientations */
+static int GetVerticalFlagsForScript(UScriptCode aScript)
+{
+    int nFlag = GF_NONE;
+
+    switch (aScript)
+    {
+        /* ttb 0° */
+        case USCRIPT_BOPOMOFO:
+        case USCRIPT_EGYPTIAN_HIEROGLYPHS:
+        case USCRIPT_HAN:
+        case USCRIPT_HANGUL:
+        case USCRIPT_HIRAGANA:
+        case USCRIPT_KATAKANA:
+        case USCRIPT_MEROITIC_CURSIVE:
+        case USCRIPT_MEROITIC_HIEROGLYPHS:
+        case USCRIPT_YI:
+            nFlag = GF_ROTL;
+            break;
+#if 0
+        /* ttb 90° */
+        case USCRIPT_MONGOLIAN:
+        case USCRIPT_PHAGS_PA:
+            nFlag = ??;
+            break;
+        /* ttb -90° */
+        case USCRIPT_ORKHON:
+            nFlag = ??;
+            break;
+        /* btt -90° */
+        case USCRIPT_MONGOLIAN:
+            nFlag = ??;
+            break;
+#endif
+        default:
+            break;
+    }
+
+    return nFlag;
+}
+
 bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 {
     hb_script_t aHbScript = HB_SCRIPT_INVALID;
@@ -371,11 +412,19 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
             int nMinRunPos = aScriptRun.mnMin;
             int nEndRunPos = aScriptRun.mnEnd;
             int nRunLen = nEndRunPos - nMinRunPos;
-            aHbScript = aScriptRun.maScript;
+            aHbScript = hb_icu_script_to_script(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);
 
+            bool bVertical = false;
+            if ((rArgs.mnFlags & SalLayoutFlags::Vertical) &&
+                GetVerticalFlagsForScript(aScriptRun.maScript) == GF_ROTL)
+            {
+                bVertical = true;
+            }
+
             int nHbFlags = HB_BUFFER_FLAGS_DEFAULT;
             if (nMinRunPos == 0)
                 nHbFlags |= HB_BUFFER_FLAG_BOT; /* Beginning-of-text */
@@ -387,7 +436,10 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
             static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
             hb_buffer_set_unicode_funcs(pHbBuffer, pHbUnicodeFuncs);
 #endif
-            hb_buffer_set_direction(pHbBuffer, bRightToLeft ? 
HB_DIRECTION_RTL: HB_DIRECTION_LTR);
+            if (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);
@@ -452,17 +504,35 @@ 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 nAdvance, nXOffset, nYOffset;
+                if (bVertical)
+                {
+                    int nVertFlag;
+#if 0               /* XXX: does not work as expected for Common script */
+                    UErrorCode error = U_ZERO_ERROR;
+                    nVertFlag = 
GetVerticalFlagsForScript(uscript_getScript(aChar, &error));
+#else
+                    nVertFlag = GetVerticalFlags(aChar);
+                    if (nVertFlag == GF_ROTR)
+                        nVertFlag = GF_ROTL;
+#endif
+                    nGlyphIndex |= nVertFlag;
+                    nAdvance = -pHbPositions[i].y_advance >> 6;
+                    nXOffset =  pHbPositions[i].y_offset >> 6;
+                    nYOffset = -pHbPositions[i].x_offset >> 6;
+                }
+                else
+                {
+                    nAdvance = pHbPositions[i].x_advance >> 6;
+                    nXOffset = pHbPositions[i].x_offset >> 6;
+                    nYOffset = pHbPositions[i].y_offset >> 6;
+                }
 
                 Point aNewPos = Point(aCurrPos.X() + nXOffset, -(aCurrPos.Y() 
+ nYOffset));
-                const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, 
nGlyphFlags, nXAdvance, nXOffset);
+                const GlyphItem aGI(nCharPos, nGlyphIndex, aNewPos, 
nGlyphFlags, nAdvance, nXOffset);
                 AppendGlyph(aGI);
 
-                aCurrPos.X() += nXAdvance;
-                aCurrPos.Y() += nYAdvance;
+                aCurrPos.X() += nAdvance;
             }
 
             hb_buffer_destroy(pHbBuffer);
diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx 
b/vcl/unx/generic/gdi/cairotextrender.cxx
index 35d086d..9fe2ea5 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -323,6 +323,11 @@ void CairoTextRender::DrawServerFontLayout( const 
GenericSalLayout& rLayout, con
             {
                 ydiff = font_extents.ascent/nHeight;
                 xdiff = -font_extents.descent/nHeight;
+                if (SalLayout::UseCommonLayout())
+                {
+                     ydiff -= font_extents.descent/nHeight;
+                     xdiff = 0;
+                }
             }
             else if (nGlyphRotation == -1)
             {
commit 2bfd8391d1ba05ee1c3ce01287cb6dfac8cb5c99
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Fri Oct 14 02:50:27 2016 -0700

    Support font fallback on macOS for CommonSalLayout
    
    Change-Id: Ifd26b7f14ed77a3aa2a38e5961cac5f9bbb6d796

diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index f7e5156..6958541 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -102,6 +102,8 @@ public:
     hb_font_t* GetHbFont() const { return mpHbFont; }
     void       SetHbFont(hb_font_t* pHbFont) const { mpHbFont = pHbFont; }
 
+    CFMutableDictionaryRef  GetStyleDict( void ) const { return mpStyleDict; }
+
     const CoreTextFontFace*  mpFontData;
     /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
     float               mfFontStretch;
@@ -113,11 +115,6 @@ private:
     /// CoreText text style object
     CFMutableDictionaryRef  mpStyleDict;
     mutable hb_font_t*      mpHbFont;
-
-    friend class CTLayout;
-    friend class AquaSalGraphics;
-    friend class CommonSalLayout;
-    CFMutableDictionaryRef  GetStyleDict( void ) const { return mpStyleDict; }
 };
 
 // TODO: move into cross-platform headers
@@ -172,8 +169,8 @@ protected:
     RGBAColor                               maFillColor;
 
     // Device Font settings
-    const CoreTextFontFace*                 mpFontData;
-    CoreTextStyle*                          mpTextStyle;
+    const CoreTextFontFace*                 mpFontData[MAX_FALLBACK];
+    CoreTextStyle*                          mpTextStyle[MAX_FALLBACK];
     RGBAColor                               maTextColor;
     /// allows text to be rendered without antialiasing
     bool                                    mbNonAntialiasedText;
diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx
index c327991..fcf474e 100644
--- a/vcl/quartz/ctlayout.cxx
+++ b/vcl/quartz/ctlayout.cxx
@@ -28,7 +28,6 @@
 #include "quartz/ctfonts.hxx"
 #include "CTRunData.hxx"
 #include "quartz/utils.h"
-#include "CommonSalLayout.hxx"
 
 
 class CTLayout : public SalLayout
@@ -782,10 +781,7 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {}
 
 SalLayout* CoreTextStyle::GetTextLayout() const
 {
-    if (SalLayout::UseCommonLayout())
-        return new CommonSalLayout(*this);
-    else
-        return new CTLayout( this);
+    return new CTLayout( this);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index f9e3e0c..787ddbf 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -42,6 +42,8 @@
 #include "impfontcharmap.hxx"
 #include "impfontmetricdata.hxx"
 #include "CommonSalLayout.hxx"
+#include "outdev.h"
+#include "PhysicalFontCollection.hxx"
 
 #ifdef MACOSX
 #include "osx/salframe.h"
@@ -55,6 +57,49 @@
 
 using namespace vcl;
 
+class CoreTextGlyphFallbackSubstititution
+:    public ImplGlyphFallbackFontSubstitution
+{
+public:
+    bool FindFontSubstitute(FontSelectPattern&, OUString&) const override;
+};
+
+bool 
CoreTextGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern& 
rPattern,
+    OUString& rMissingChars) const
+{
+    bool bFound = false;
+    CoreTextStyle rStyle(rPattern);
+    CTFontRef pFont = 
static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), 
kCTFontAttributeName));
+    CFStringRef pStr = CreateCFString(rMissingChars);
+    if (pStr)
+    {
+        CTFontRef pFallback = CTFontCreateForString(pFont, pStr, 
CFRangeMake(0, CFStringGetLength(pStr)));
+        if (pFallback)
+        {
+            bFound = true;
+
+            CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFallback);
+            FontAttributes rAttr = DevFontFromCTFontDescriptor(pDesc, nullptr);
+
+            rPattern.maSearchName = rAttr.GetFamilyName();
+
+            rPattern.SetWeight(rAttr.GetWeight());
+            rPattern.SetItalic(rAttr.GetItalic());
+            rPattern.SetPitch(rAttr.GetPitch());
+            rPattern.SetWidthType(rAttr.GetWidthType());
+
+            SalData* pSalData = GetSalData();
+            if (pSalData->mpFontList)
+                rPattern.mpFontData = 
pSalData->mpFontList->GetFontDataFromId(reinterpret_cast<sal_IntPtr>(pDesc));
+
+            CFRelease(pFallback);
+        }
+        CFRelease(pStr);
+    }
+
+    return bFound;
+}
+
 CoreTextFontFace::CoreTextFontFace( const CoreTextFontFace& rSrc )
   : PhysicalFontFace( rSrc )
   , mnFontId( rSrc.mnFontId )
@@ -245,8 +290,6 @@ AquaSalGraphics::AquaSalGraphics()
     , mxClipPath( nullptr )
     , maLineColor( COL_WHITE )
     , maFillColor( COL_BLACK )
-    , mpFontData( nullptr )
-    , mpTextStyle( nullptr )
     , maTextColor( COL_BLACK )
     , mbNonAntialiasedText( false )
     , mbPrinter( false )
@@ -258,6 +301,12 @@ AquaSalGraphics::AquaSalGraphics()
 #endif
 {
     SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this 
);
+
+    for (int i = 0; i < MAX_FALLBACK; ++i)
+    {
+        mpTextStyle[i] = nullptr;
+        mpFontData[i] = nullptr;
+    }
 }
 
 AquaSalGraphics::~AquaSalGraphics()
@@ -270,7 +319,8 @@ AquaSalGraphics::~AquaSalGraphics()
         CGPathRelease( mxClipPath );
     }
 
-    delete mpTextStyle;
+    for (int i = 0; i < MAX_FALLBACK; ++i)
+        delete mpTextStyle[i];
 
     if( mpXorEmulation )
         delete mpXorEmulation;
@@ -308,9 +358,12 @@ void AquaSalGraphics::SetTextColor( SalColor nSalColor )
     // SAL_ DEBUG(std::hex << nSalColor << std::dec << "={" << 
maTextColor.GetRed() << ", " << maTextColor.GetGreen() << ", " << 
maTextColor.GetBlue() << ", " << maTextColor.GetAlpha() << "}");
 }
 
-void AquaSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int 
/*nFallbackLevel*/ )
+void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int 
nFallbackLevel)
 {
-    mpTextStyle->GetFontMetric( rxFontMetric );
+    if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel])
+    {
+        mpTextStyle[nFallbackLevel]->GetFontMetric(rxFontMetric);
+    }
 }
 
 static bool AddTempDevFont(const OUString& rFontFileURL)
@@ -387,6 +440,12 @@ void AquaSalGraphics::GetDevFontList( 
PhysicalFontCollection* pFontCollection )
 
     // Copy all PhysicalFontFace objects contained in the SystemFontList
     pSalData->mpFontList->AnnounceFonts( *pFontCollection );
+
+    if (SalLayout::UseCommonLayout())
+    {
+        static CoreTextGlyphFallbackSubstititution aSubstFallback;
+        pFontCollection->SetFallbackHook(&aSubstFallback);
+    }
 }
 
 void AquaSalGraphics::ClearDevFontCache()
@@ -404,14 +463,24 @@ bool AquaSalGraphics::AddTempDevFont( 
PhysicalFontCollection*,
 
 bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, 
basegfx::B2DPolyPolygon& rPolyPoly )
 {
-    const bool bRC = mpTextStyle->GetGlyphOutline( aGlyphId, rPolyPoly );
-    return bRC;
+    const int nFallbackLevel = aGlyphId >> GF_FONTSHIFT;
+    if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel])
+    {
+        const bool bRC = 
mpTextStyle[nFallbackLevel]->GetGlyphOutline(aGlyphId, rPolyPoly);
+        return bRC;
+    }
+    return false;
 }
 
 bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& 
rRect )
 {
-    const bool bRC = mpTextStyle->GetGlyphBoundRect( aGlyphId, rRect );
-    return bRC;
+    const int nFallbackLevel = aGlyphId >> GF_FONTSHIFT;
+    if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel])
+    {
+        const bool bRC = 
mpTextStyle[nFallbackLevel]->GetGlyphBoundRect(aGlyphId, rRect);
+        return bRC;
+    }
+    return false;
 }
 
 void AquaSalGraphics::DrawSalLayout(const CommonSalLayout& rLayout)
@@ -449,60 +518,71 @@ void AquaSalGraphics::DrawSalLayout(const 
CommonSalLayout& rLayout)
     CGContextRestoreGState(context);
 }
 
-void AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int 
/*nFallbackLevel*/ )
+void AquaSalGraphics::SetFont(FontSelectPattern* pReqFont, int nFallbackLevel)
 {
     // release the text style
-    delete mpTextStyle;
-    mpTextStyle = nullptr;
+    for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i)
+    {
+        delete mpTextStyle[i];
+        mpTextStyle[i] = nullptr;
+    }
 
     // handle NULL request meaning: release-font-resources request
     if( !pReqFont )
     {
-        mpFontData = nullptr;
+        mpFontData[nFallbackLevel] = nullptr;
         return;
     }
 
     // update the text style
-    mpFontData = static_cast<const CoreTextFontFace*>( pReqFont->mpFontData );
-    mpTextStyle = new CoreTextStyle( *pReqFont );
+    mpFontData[nFallbackLevel] = static_cast<const 
CoreTextFontFace*>(pReqFont->mpFontData);
+    mpTextStyle[nFallbackLevel] = new CoreTextStyle(*pReqFont);
 
     SAL_INFO("vcl.ct",
             "SetFont"
-               " to "     << mpFontData->GetFamilyName()
-            << ", "       << mpFontData->GetStyleName()
-            << " fontid=" << mpFontData->GetFontId()
+               " to "     << mpFontData[nFallbackLevel]->GetFamilyName()
+            << ", "       << mpFontData[nFallbackLevel]->GetStyleName()
+            << " fontid=" << mpFontData[nFallbackLevel]->GetFontId()
             << " for "    << pReqFont->GetFamilyName()
             << ", "       << pReqFont->GetStyleName()
             << " weight=" << pReqFont->GetWeight()
             << " slant="  << pReqFont->GetItalic()
             << " size="   << pReqFont->mnHeight << "x" << pReqFont->mnWidth
             << " orientation=" << pReqFont->mnOrientation
+            << " fallback level " << nFallbackLevel
             );
 }
 
-SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int 
/*nFallbackLevel*/ )
+SalLayout* AquaSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int 
nFallbackLevel)
 {
-    SalLayout* pSalLayout = mpTextStyle->GetTextLayout();
+    SalLayout* pSalLayout = nullptr;
+    if (mpTextStyle[nFallbackLevel])
+    {
+        if (SalLayout::UseCommonLayout())
+            pSalLayout = new CommonSalLayout(*mpTextStyle[nFallbackLevel]);
+        else
+            pSalLayout = mpTextStyle[nFallbackLevel]->GetTextLayout();
+    }
     return pSalLayout;
 }
 
 const FontCharMapRef AquaSalGraphics::GetFontCharMap() const
 {
-    if( !mpFontData )
+    if (!mpFontData[0])
     {
         FontCharMapRef xFontCharMap( new FontCharMap() );
         return xFontCharMap;
     }
 
-    return mpFontData->GetFontCharMap();
+    return mpFontData[0]->GetFontCharMap();
 }
 
 bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities 
&rFontCapabilities) const
 {
-    if( !mpFontData )
+    if (!mpFontData[0])
         return false;
 
-    return mpFontData->GetFontCapabilities(rFontCapabilities);
+    return mpFontData[0]->GetFontCapabilities(rFontCapabilities);
 }
 
 // fake a SFNT font directory entry for a font table
@@ -772,7 +852,8 @@ void AquaSalGraphics::GetGlyphWidths( const 
PhysicalFontFace* pFontData, bool bV
             free( const_cast<TTSimpleGlyphMetrics *>(pGlyphMetrics) );
         }
 
-        FontCharMapRef xFCMap = mpFontData->GetFontCharMap();
+        CoreTextFontFace rCTFontData(*pFontData, pFontData->GetFontId());
+        FontCharMapRef xFCMap = rCTFontData.GetFontCharMap();
         SAL_WARN_IF( !xFCMap.Is() || !xFCMap->GetCharCount(), "vcl", "no 
charmap" );
 
         // get unicode<->glyph encoding
commit 9cea34ee8334f145ca4fffdd76d6d819c427383d
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Thu Oct 13 22:46:28 2016 +0200

    Check SAL_USE_COMMON_LAYOUT envar in one place
    
    Makes it easier to flip the switch in the future (or even do something
    more fancy other than checking envvar).
    
    Change-Id: Ie42ca012c167b2108f0fca1ce9ff7beee95f1be7

diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 1050943..364bd48 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -201,6 +201,8 @@ public:
     virtual std::shared_ptr<vcl::TextLayoutCache>
         CreateTextLayoutCache(OUString const&) const;
 
+    static bool     UseCommonLayout();
+
 protected:
     // used by layout engines
                     SalLayout();
diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx
index 4c841d4..c327991 100644
--- a/vcl/quartz/ctlayout.cxx
+++ b/vcl/quartz/ctlayout.cxx
@@ -782,7 +782,7 @@ void CTLayout::Simplify( bool /*bIsBase*/ ) {}
 
 SalLayout* CoreTextStyle::GetTextLayout() const
 {
-    if (getenv("SAL_USE_COMMON_LAYOUT"))
+    if (SalLayout::UseCommonLayout())
         return new CommonSalLayout(*this);
     else
         return new CTLayout( this);
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 8aaefbf..b865ff9 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -768,6 +768,12 @@ bool SalLayout::IsSpacingGlyph( sal_GlyphId nGlyph )
     return bRet;
 }
 
+bool SalLayout::UseCommonLayout()
+{
+    static bool bUse = getenv("SAL_USE_COMMON_LAYOUT") != nullptr;
+    return bUse;
+}
+
 GenericSalLayout::GenericSalLayout()
 {}
 
diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx 
b/vcl/unx/generic/gdi/cairotextrender.cxx
index 46b9326..35d086d 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -532,7 +532,7 @@ SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& 
rArgs, int nFallbackL
     if( mpServerFont[ nFallbackLevel ]
     && !(rArgs.mnFlags & SalLayoutFlags::DisableGlyphProcessing) )
     {
-        if (getenv("SAL_USE_COMMON_LAYOUT"))
+        if (SalLayout::UseCommonLayout())
         {
             pLayout = new CommonSalLayout(*mpServerFont[nFallbackLevel]);
         }
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index b036307..9b78a72 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -3826,7 +3826,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& 
rArgs, int nFallbackLe
     const WinFontFace& rFontFace = *mpWinFontData[ nFallbackLevel ];
     WinFontInstance& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
 
-    if (getenv("SAL_USE_COMMON_LAYOUT"))
+    if (SalLayout::UseCommonLayout())
     {
         return new CommonSalLayout(this, rFontInstance, rFontFace);
     }
commit e3429c5068e6ea8221ca6316bdaba3de9bce7e6d
Author: Khaled Hosny <khaledho...@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 3237620..6ea559b 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)
@@ -382,8 +383,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
             hb_buffer_set_direction(pHbBuffer, bRightToLeft ? 
HB_DIRECTION_RTL: HB_DIRECTION_LTR);
@@ -439,7 +440,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
@@ -599,8 +600,7 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
             // Don’t insert Kashida after space.
             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;
 
             // The total Kashida width.
commit f353cf9dad54a4fe9496a72c153479af1b38a095
Author: Khaled Hosny <khaledho...@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 3c017da..3237620 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -365,12 +365,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 9d0c7010240fc8ad4ff515b4969e254ee9a8e779
Author: Khaled Hosny <khaledho...@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 f9bc4e3..513d2b9 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -39,7 +39,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 56a59c9..3c017da 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 9de76cb136b8e383315e53f2433fdbda5bb3e354
Author: Khaled Hosny <khaledho...@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 b01a623..16eb38a 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 6ded1bd5485908b32c9fdd4ca0cac5d4a6007e98
Author: Khaled Hosny <khaledho...@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 8f94aa7631338a2cf093e5558d877a8ed3d325d0
Author: Khaled Hosny <khaledho...@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 7bda1cf..56a59c9 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -373,7 +373,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 3a543f1f57aed3beba8879ed46e1f92f657151cb
Author: Khaled Hosny <khaledho...@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 dfd58fe..f9bc4e3 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -71,6 +71,8 @@ public:
 
     virtual bool            GetCharWidths(DeviceCoordinate* pCharWidths) const 
override;
     virtual void            ApplyDXArray(ImplLayoutArgs&) override;
+
+    virtual bool            IsKashidaPosValid(int nCharPos) const override;
 };
 
 #endif
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index cc97e70..7bda1cf 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -500,6 +500,10 @@ bool CommonSalLayout::GetCharWidths(DeviceCoordinate* 
pCharWidths) const
 // This decision is communicated to us in a very indirect way; by increasing
 // the width of the character after which Kashidas should be inserted by the
 // desired amount.
+//
+// Writer eventually calls IsKashidaPosValid() to check whether it can insert a
+// Kashida between two characters or not.
+//
 // Here we do:
 // - In LayoutText() set KashidaJustification flag based on text script.
 // - In ApplyDXArray():
@@ -634,3 +638,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 df5e67e3801f673da5f7d8b8608e386fef3a3e8b
Author: Khaled Hosny <khaledho...@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 2be6dd8..cc97e70 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -286,27 +286,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
@@ -503,6 +494,19 @@ bool CommonSalLayout::GetCharWidths(DeviceCoordinate* 
pCharWidths) const
     return true;
 }
 
+// A note on how Kashida justification is implemented (because it took me 5
+// years to figure it out):
+// The decision to insert Kashidas, where and how much is taken by Writer.
+// This decision is communicated to us in a very indirect way; by increasing
+// the width of the character after which Kashidas should be inserted by the
+// desired amount.
+// Here we do:
+// - In LayoutText() set KashidaJustification flag based on text script.
+// - In ApplyDXArray():
+//   * Check the above flag to decide whether to insert Kashidas or not.
+//   * For any RTL glyph that has DX adjustment, insert enough Khashidas to
+//     fill in the added space.
+
 void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
 {
     if (rArgs.mpDXArray == nullptr)
@@ -524,6 +528,23 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
             pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1];
     }
 
+
+    bool bKashidaJustify = false;
+    DeviceCoordinate nKashidaWidth = 0;
+    hb_codepoint_t nKashidaIndex = 0;
+    if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification)
+    {
+        // Find Kashida glyph width and index.
+        scaleHbFont(mpHbFont, mrFontSelData);
+        if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex))
+            nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, 
nKashidaIndex) / 64;
+        bKashidaJustify = nKashidaWidth != 0;
+    }
+
+    // Map of Kashida insertion points (in the glyph items vector) and the
+    // requested width.
+    std::map<size_t, DeviceCoordinate> pKashidas;
+
     // The accumulated difference in X position.
     DeviceCoordinate nDelta = 0;
 
@@ -534,14 +555,21 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
         int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos;
         DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - 
pOldCharWidths[nCharPos];
 
-        m_GlyphItems[i].maLinearPos.X() += nDelta;
+        // nDiff > 1 to ignore rounding errors.
+        if (bKashidaJustify && nDiff > 1)
+            pKashidas[i] = nDiff;
+
+        // Apply the same delta to all glyphs belonging to the same character.
         size_t j = i;
-        // Apply the delta to other glyphs belonging to the same character.
-        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 DX adjustment space to the left of the glyph.
+            if (m_GlyphItems[i].IsRTLGlyph())
+                m_GlyphItems[j].maLinearPos.X() += nDiff;
+            ++j;
         }
 
         // Increment the delta, the loop above makes sure we do so only once
@@ -551,4 +579,58 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
         nDelta += nDiff;
         i = j;
     }
+
+    // Insert Kashida glyphs.
+    if (bKashidaJustify && !pKashidas.empty())
+    {
+        size_t nInserted = 0;
+        for (auto const& pKashida : pKashidas)
+        {
+            auto pGlyphIter = m_GlyphItems.begin() + nInserted + 
pKashida.first;
+
+            // Don’t insert Kashida after LTR glyphs.
+            if (!pGlyphIter->IsRTLGlyph())
+                continue;
+
+            // Don’t insert Kashida after space.
+            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;
+
+            // The total Kashida width.
+            DeviceCoordinate nTotalWidth = pKashida.second;
+
+            // Number of times to repeat each Kashida.
+            int nCopies = 1;
+            if (nTotalWidth > nKashidaWidth)
+                nCopies = nTotalWidth / nKashidaWidth;
+
+            // See if we can improve the fit by adding an extra Kashidas and
+            // squeezing them together a bit.
+            DeviceCoordinate nOverlap = 0;
+            DeviceCoordinate nShortfall = nTotalWidth - nKashidaWidth * 
nCopies;
+            if (nShortfall > 0)
+            {
+                ++nCopies;
+                DeviceCoordinate nExcess = nCopies * nKashidaWidth - 
nTotalWidth;
+                if (nExcess > 0)
+                    nOverlap = nExcess / (nCopies - 1);
+            }
+
+            Point aPos(pGlyphIter->maLinearPos.X() - nTotalWidth, 0);
+            int nCharPos = pGlyphIter->mnCharPos;
+            int nFlags = GlyphItem::IS_IN_CLUSTER | GlyphItem::IS_RTL_GLYPH;
+            while (nCopies--)
+            {
+                GlyphItem aKashida(nCharPos, nKashidaIndex, aPos, nFlags, 
nKashidaWidth);
+                pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida);
+                aPos.X() += nKashidaWidth;
+                aPos.X() -= nOverlap;
+                ++pGlyphIter;
+                ++nInserted;
+            }
+        }
+    }
 }
commit 15f6a97d9f23124c19471b9d8dd38f14f53829b3
Author: Khaled Hosny <khaledho...@eglug.org>
Date:   Sun Sep 11 10:25:46 2016 +0200

    Fix applying DX adjustments in CommonSalLayout
    
    By overriding GetCharWidths() and ApplyDXArray() with a simpler and
    saner implementation.
    
    This fixes rendering of Awami Nastaliq, as well as subtending marks in
    Amiri and potentially other bugs.
    
    Breaks 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 dbd7bc1..dfd58fe 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -68,6 +68,9 @@ public:
     bool                    LayoutText(ImplLayoutArgs&) override;
     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;
 };
 
 #endif
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 a303f70..2be6dd8 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -489,3 +489,66 @@ 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]);
+
+    // Get the natural character widths (i.e. before applying DX adjustments).
+    GetCharWidths(pOldCharWidths.get());
+
+    // Calculate the character widths after DX adjustments.
+    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];
+    }
+
+    // The accumulated difference in X position.
+    DeviceCoordinate nDelta = 0;
+
+    // Apply the DX adjustments to glyph positions and widths.
+    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;
+        // Apply the delta to other glyphs belonging to the same character.
+        while (++j < m_GlyphItems.size())
+        {
+            if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos)
+                break;
+            m_GlyphItems[j].maLinearPos.X() += nDelta;
+        }
+
+        // Increment the delta, the loop above makes sure we do so only once
+        // for every character not for every glyph (otherwise we would apply it
+        // multiple times for each glyphs belonging to the same character which
+        // is wrong since DX adjustments are character based).
+        nDelta += nDiff;
+        i = j;
+    }
+}
commit 66104ff9856ff1c81ec8c776a0467796f85efc01
Author: Khaled Hosny <khaledho...@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 b502d91..a303f70 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -442,9 +442,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 26e799a3f747723b428c29fbc314d5c42f12c030
Author: Khaled Hosny <khaledho...@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 73f680b..dbd7bc1 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -38,7 +38,7 @@
 
 class CommonSalLayout : public GenericSalLayout
 {
-    hb_face_t*              mpHbFace;
+    hb_font_t*              mpHbFont;
     FontSelectPattern       maFontSelData;
     css::uno::Reference<css::i18n::XBreakIterator> mxBreak;
 #ifdef _WIN32
@@ -51,7 +51,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 ad93410..473d756 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 2e012f3..b502d91 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
 {
@@ -270,18 +296,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);
     }
 }
 
@@ -293,7 +317,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);
@@ -382,7 +405,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);
@@ -415,10 +438,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;
                 }
@@ -454,8 +478,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 cf919c0..84952bb 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 a832b45..44580ff 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -866,7 +866,7 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
     mbAliasSymbolsHigh( false ),
     mbAliasSymbolsLow( false ),
     mbGsubRead( false ),
-    mpHbFace( nullptr )
+    mpHbFont( nullptr )
 {
     SetBitmapSize( 0, nHeight );
 
@@ -908,8 +908,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 fe724e4..b036307 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -3991,8 +3991,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 b285eaf5f866b995861c61bd4bfedc9abca2676a
Author: Khaled Hosny <khaledho...@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 b435ec7..b01a623 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 365599f..df7cb4c 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 610eceb035280ed5714b314051913d2412cde604
Author: Khaled Hosny <khaledho...@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 5365f6d..b435ec7 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 335b2d4..365599f 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 5e65efcaa38ea5fbe655a18082a3ba7c8cf7d5fe
Author: Akash Jain <akash...@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 1fe3a6e..73f680b 100644
--- a/vcl/inc/CommonSalLayout.hxx
+++ b/vcl/inc/CommonSalLayout.hxx
@@ -44,6 +44,7 @@ class CommonSalLayout : public GenericSalLayout
 #ifdef _WIN32
     HDC   mhDC;
     HFONT mhFont;
+    D2DWriteTextOutRenderer* mpD2DRenderer;
 #elif defined(MACOSX) || defined(IOS)
     const CoreTextStyle&    mrCoreTextStyle;
 #else
@@ -53,7 +54,7 @@ class CommonSalLayout : public GenericSalLayout
     hb_font_t*              GetHbFont();
 public:
 #if defined(_WIN32)
-    explicit                CommonSalLayout(HDC, WinFontInstance&);
+    explicit                CommonSalLayout(WinSalGraphics*, WinFontInstance&, 
const WinFontFace&);
     void                    InitFont() const override;
 #elif defined(MACOSX) || defined(IOS)
     explicit                CommonSalLayout(const CoreTextStyle&);
@@ -63,7 +64,6 @@ public:
     const ServerFont&       getFontData() const { return mrServerFont; };
 #endif
 
-                            ~CommonSalLayout();
     void                    SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool);
     void                    AdjustLayout(ImplLayoutArgs&) override;
     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 c4fb26d..ad93410 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/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index fd69ee0..1f04251 100755
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -482,6 +482,7 @@ public:
 
     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; }
 
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 89acdb7..2e012f3 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 bc46feb..cf919c0 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 6d4fd5e..a832b45 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -865,7 +865,8 @@ WinFontFace::WinFontFace( const FontAttributes& rDFS,
     mnPitchAndFamily( nPitchAndFamily ),
     mbAliasSymbolsHigh( false ),
     mbAliasSymbolsLow( false ),
-    mbGsubRead( false )
+    mbGsubRead( false ),
+    mpHbFace( nullptr )
 {
     SetBitmapSize( 0, nHeight );
 
@@ -906,6 +907,9 @@ WinFontFace::~WinFontFace()
 #endif
 #endif // ENABLE_GRAPHITE
     delete mpEncodingVector;
+
+    if( mpHbFace )
+        hb_face_destroy( mpHbFace );
 }
 
 sal_IntPtr WinFontFace::GetFontId() const
@@ -1058,16 +1062,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 051f354..fe724e4 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)

... etc. - the rest is truncated
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to