[Libreoffice-commits] core.git: Branch 'feature/commonsallayout' - 404 commits - accessibility/inc accessibility/source avmedia/Module_avmedia.mk basctl/inc basctl/source basctl/uiconfig basegfx/source basic/qa basic/source bean/native bin/check-elf-dynamic-objects bin/count-src-resources bin/count-todo-dialogs chart2/source chart2/uiconfig codemaker/source comphelper/Library_comphelper.mk comphelper/source compilerplugins/clang config_host.mk.in configmgr/source configure.ac connectivity/source cui/source cui/uiconfig dbaccess/source dbaccess/uiconfig desktop/qa desktop/source download.lst drawinglayer/source editeng/source embedserv/source extensions/source extensions/uiconfig external/harfbuzz external/liblangtag external/nss external/poppler extras/source filter/source forms/source formula/source fpicker/Library_fps.mk fpicker/source framework/dtd framework/source framework/uiconfig helpcontent2 i18npool/source idlc/inc idlc/source idl/inc idl/source include/basegfx include/basic include/comp helper include/connectivity include/drawinglayer include/editeng include/filter include/oox include/postwin.h include/rtl include/sal include/sfx2 include/svl include/svtools include/svx include/test include/toolkit include/tools include/unotools include/vbahelper include/vcl include/xmloff instsetoo_native/CustomTarget_setup.mk libreofficekit/source lingucomponent/source Makefile.in offapi/com officecfg/registry oox/source postprocess/CustomTarget_images.mk postprocess/Rdb_services.mk qadevOOo/Jar_OOoRunner.mk qadevOOo/JunitTest_qadevOOo_unoapi.mk qadevOOo/Module_qadevOOo.mk qadevOOo/objdsc qadevOOo/qa qadevOOo/runner qadevOOo/tests readlicense_oo/license README.md reportdesign/source reportdesign/uiconfig RepositoryExternal.mk Repository.mk rsc/inc rsc/source salhelper/qa sal/osl sal/qa sal/rtl sax/qa sc/inc scp2/source sc/qa scripting/source sc/sdi sc/source sc/uiconfig sd/AllLangResTarget_sd.mk sdext/source sd/inc sd/qa sd/sdi sd/source sd/uiconfig sd/UIConfig_simpress.mk sd/xml setup_native/source sfx2/classification sfx2/Library_sfx.mk sfx2/Package_classification.mk sfx2/sdi sfx2/source sfx2/uiconfig sfx2/UIConfig_sfx.mk shell/inc shell/qa shell/source solenv/bin solenv/gbuild solenv/gcc-wrappers solenv/Module_solenv.mk solenv/PythonTest_solenv_python.mk solenv/qa sot/source starmath/inc starmath/qa starmath/source starmath/uiconfig stoc/source store/source svgio/qa svl/Library_svl.mk svl/source svtools/inc svtools/source svx/AllLangResTarget_svx.mk svx/inc svx/Library_svxcore.mk svx/Library_svx.mk svx/qa svx/sdi svx/source svx/uiconfig svx/UIConfig_svx.mk svx/util sw/CppunitTest_sw_ooxmlexport8.mk sw/CppunitTest_sw_ooxmlexport9.mk sw/inc sw/Library_sw.mk sw/Module_sw.mk sw/ooxmlexport_setup.mk sw/qa sw/sdi sw/source sw/uiconfig sw/UIConfig_swriter.mk TEMPLATE.SOURCECODE.HEADER test/source toolkit/source tools/qa tools/source translations ucb/qa ucb/source uitest/calc_tests uitest/demo_ui uitest/libreoffice uitest/test_main.py uitest/uitest unotools/sour ce uui/source uui/util vbahelper/source vcl/AllLangResTarget_vcl.mk vcl/backendtest vcl/CppunitTest_vcl_wmf_test.mk vcl/glyphy vcl/headless vcl/inc vcl/Library_vcl.mk vcl/opengl vcl/qa vcl/quartz vcl/README.vars vcl/source vcl/unx vcl/win vcl/workben winaccessibility/inc winaccessibility/source wizards/source writerfilter/source writerperfect/source xmlhelp/source xmloff/inc xmloff/source xmlsecurity/CppunitTest_xmlsecurity_signing.mk xmlsecurity/Executable_pdfverify.mk xmlsecurity/inc xmlsecurity/Library_xmlsecurity.mk xmlsecurity/Module_xmlsecurity.mk xmlsecurity/qa xmlsecurity/source

Khaled Hosny khaledhosny at eglug.org
Sat Oct 15 23:07:10 UTC 2016


Rebased ref, commits from common ancestor:
commit 23c9ccfd1b6fc5cdee4913e96cd02e04c68459fe
Author: Khaled Hosny <khaledhosny at 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..28e7e99 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -485,37 +485,78 @@ 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))
     {
+        CGAffineTransform aMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation);
+        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);
+
+    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());
+
+    std::vector<bool>::const_iterator aStart = aGlyphRotation.begin();
+    std::vector<bool>::const_iterator aEnd = aGlyphRotation.end();
+    std::vector<bool>::const_iterator aI = aStart;
+    while (aI != aEnd)
+    {
+        bool nGlyphRotation = *aI;
+        std::vector<bool>::const_iterator aNext = std::find(aI + 1, aEnd, !nGlyphRotation);
+
+        size_t nStartIndex = std::distance(aStart, aI);
+        size_t nLen = std::distance(aI, aNext);
+
+        if (nGlyphRotation && pRotatedFont)
+            CTFontDrawGlyphs(pRotatedFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, mrContext);
+        else
+            CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, mrContext);
+
+        aI = 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 3c7f4735cd1c1e5d9f594699447bbf0eabe8e2f3
Author: Khaled Hosny <khaledhosny at 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 feb37eb..7ee034a 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 ac3df4c384e1641c4a41c42d602ab38ec8db528b
Author: Khaled Hosny <khaledhosny at 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 856e066..983f50b 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 ba95ee638e3363f5ce401dbaf29de4ef93a5e868
Author: Khaled Hosny <khaledhosny at 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 f7fe0af..856e066 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 b9962f2ad547d842486849d5c7a2c2bca2b12986
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Oct 10 01:36:45 2016 +0200

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

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 47d24ee..feb37eb 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
@@ -561,8 +562,7 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
 
             sal_Int32 indexUtf16 = pGlyphIter->mnCharPos;
             sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0);
-            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
-            if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)
+            if (u_isUWhiteSpace(aChar))
                 continue;
 
             DeviceCoordinate nGapWidth = pKashida.second;
commit 1689a2f7b833e9287aab8fe3edd1035fea641168
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Mon Oct 10 00:54:00 2016 +0200

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

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 3115cee..513d2b9 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 3212994..47d24ee 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -588,3 +588,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 b42220770365812d8040790cc5a0a091cbd866e6
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Oct 9 23:23:45 2016 +0200

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

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index d19506f..3212994 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
@@ -522,6 +513,16 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
             pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1];
     }
 
+    DeviceCoordinate nKashidaWidth = 0;
+    hb_codepoint_t nKashidaIndex;
+    if (rArgs.mnFlags & SalLayoutFlags::KashidaJustification)
+    {
+        if (hb_font_get_glyph(mpHbFont, 0x0640, 0, &nKashidaIndex))
+            nKashidaWidth = hb_font_get_glyph_h_advance(mpHbFont, nKashidaIndex) / 64;
+    }
+
+    std::map<size_t, DeviceCoordinate> pKashidas;
+
     DeviceCoordinate nDelta = 0;
     size_t i = 0;
     while (i < m_GlyphItems.size())
@@ -529,16 +530,61 @@ void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
         int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos;
         DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos];
 
-        m_GlyphItems[i].maLinearPos.X() += nDelta;
+        if (nKashidaWidth && nDiff)
+            pKashidas[i] = nDiff;
+
         size_t j = i;
-        while (++j < m_GlyphItems.size())
+        while (j < m_GlyphItems.size())
         {
             if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos)
                 break;
             m_GlyphItems[j].maLinearPos.X() += nDelta;
+            // For RTL, put all justification space to the left of the glyph.
+            if (m_GlyphItems[i].IsRTLGlyph())
+                m_GlyphItems[j].maLinearPos.X() += nDiff;
+            ++j;
         }
 
         nDelta += nDiff;
         i = j;
     }
+
+    if (!pKashidas.empty())
+    {
+        size_t nInserted = 0;
+        for (auto const& pKashida : pKashidas)
+        {
+            auto pGlyphIter = m_GlyphItems.begin() + nInserted + pKashida.first;
+
+            if (!pGlyphIter->IsRTLGlyph())
+                continue;
+
+            sal_Int32 indexUtf16 = pGlyphIter->mnCharPos;
+            sal_UCS4 aChar = rArgs.mrStr.iterateCodePoints(&indexUtf16, 0);
+            static hb_unicode_funcs_t* pHbUnicodeFuncs = getUnicodeFuncs();
+            if (hb_unicode_general_category (pHbUnicodeFuncs, aChar) == HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)
+                continue;
+
+            DeviceCoordinate nGapWidth = pKashida.second;
+            int nKashidaCount = ceil(nGapWidth / nKashidaWidth);
+            DeviceCoordinate nInsertedKashidaWidth;
+            if (nGapWidth < nKashidaWidth)
+                nInsertedKashidaWidth = nGapWidth;
+            else
+                nInsertedKashidaWidth = nGapWidth / nKashidaCount;
+
+            Point aPos(pGlyphIter->maLinearPos.X() - nGapWidth, 0);
+            int nCharPos = pGlyphIter->mnCharPos;
+            int nFlags = GlyphItem::IS_IN_CLUSTER | GlyphItem::IS_RTL_GLYPH;
+            while (nKashidaCount)
+            {
+                GlyphItem aKashida(nCharPos, nKashidaIndex, aPos, nFlags, nInsertedKashidaWidth);
+                pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida);
+                aPos.X() += nInsertedKashidaWidth;
+                ++pGlyphIter;
+                ++nInserted;
+                --nKashidaCount;
+            }
+        }
+    }
 }
commit 1c52e56500c2c292b15ee2265d23562c9e999a2b
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Oct 9 19:08:18 2016 +0200

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

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

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

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

    Use range loop
    
    Change-Id: I5ce49e57ed57378b4b9e16c8bb020048644252a9

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 92e0597..d19506f 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -374,12 +374,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 80753e7638db5f160b23d1f73926cd75574716d2
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sat Sep 24 23:04:39 2016 +0200

    Use const reference
    
    Change-Id: I0f632f3a8b480f785608aa081add1b1d2fefd312

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index dfd58fe..3115cee 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 64f55a8..92e0597 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 c8a8cbf185f873138a8d6d2f32da43eca7fd7e8d
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Fri Sep 23 18:34:09 2016 +0200

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

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

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

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

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

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 0695810..64f55a8 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -382,7 +382,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 ea1439a864672683ea272e2af9e49b45c3503955
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 19:45:23 2016 +0200

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

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index e0f1337..64eeacf 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1357,8 +1357,6 @@ endef
 
 endif # SYSTEM_FONTCONFIG
 
-ifeq ($(ENABLE_GRAPHITE),TRUE)
-
 ifneq ($(SYSTEM_GRAPHITE),)
 
 define gb_LinkTarget__use_graphite
@@ -1386,12 +1384,6 @@ endef
 
 endif # SYSTEM_GRAPHITE
 
-else # !ENABLE_GRAPHITE
-
-gb_LinkTarget__use_graphite :=
-
-endif # ENABLE_GRAPHITE
-
 ifneq ($(SYSTEM_ICU),)
 
 gb_LinkTarget__use_icu_headers:=
diff --git a/configure.ac b/configure.ac
index 8cb25a7..c8fe67b 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 b59739659e61dc4787b39692b344e96e012fbda1
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Thu Sep 22 19:29:04 2016 +0200

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

diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index 95241ab..e0f1337 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -1490,7 +1490,6 @@ endef
 
 endif # SYSTEM_ICU
 
-ifeq ($(ENABLE_HARFBUZZ),TRUE)
 ifneq ($(SYSTEM_HARFBUZZ),)
 
 define gb_LinkTarget__use_harfbuzz
@@ -1515,11 +1514,6 @@ $(call gb_LinkTarget_use_external_project,$(1),harfbuzz)
 endef
 
 endif # SYSTEM_HARFBUZZ
-else # ENABLE_HARFBUZZ != YES
-
-gb_LinkTarget__use_harfbuzz :=
-
-endif # ENABLE_HARFBUZZ
 
 ifeq ($(DISABLE_OPENSSL),TRUE)
 
diff --git a/config_host.mk.in b/config_host.mk.in
index 2e6d007..90c25a6 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -133,7 +133,6 @@ export ENABLE_FIREBIRD_SDBC=@ENABLE_FIREBIRD_SDBC@
 export ENABLE_GIO=@ENABLE_GIO@
 export ENABLE_GRAPHITE=@ENABLE_GRAPHITE@
 export ENABLE_ORCUS=@ENABLE_ORCUS@
-export ENABLE_HARFBUZZ=@ENABLE_HARFBUZZ@
 export ENABLE_GLTF=@ENABLE_GLTF@
 export SYSTEM_LIBGLTF=@SYSTEM_LIBGLTF@
 export LIBGLTF_CFLAGS=@LIBGLTF_CFLAGS@
diff --git a/configure.ac b/configure.ac
index 459966b..8cb25a7 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 c66bbe0c7b6e9b8abadc3fc3c66115f6345e609f
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Sep 11 10:25:46 2016 +0200

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

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 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..0695810 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -489,3 +489,56 @@ bool CommonSalLayout::LayoutText(ImplLayoutArgs& rArgs)
 
     return true;
 }
+
+bool CommonSalLayout::GetCharWidths(DeviceCoordinate* pCharWidths) const
+{
+    int nCharCount = mnEndCharPos - mnMinCharPos;
+
+    for (int i = 0; i < nCharCount; ++i)
+        pCharWidths[i] = 0;
+
+    for (auto const& aGlyphItem : m_GlyphItems)
+        pCharWidths[aGlyphItem.mnCharPos - mnMinCharPos] += aGlyphItem.mnNewWidth;
+
+    return true;
+}
+
+void CommonSalLayout::ApplyDXArray(ImplLayoutArgs& rArgs)
+{
+    if (rArgs.mpDXArray == nullptr)
+        return;
+
+    int nCharCount = mnEndCharPos - mnMinCharPos;
+    std::unique_ptr<DeviceCoordinate[]> const pOldCharWidths(new DeviceCoordinate[nCharCount]);
+    std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new DeviceCoordinate[nCharCount]);
+
+    GetCharWidths(pOldCharWidths.get());
+
+    for (int i = 0; i < nCharCount; ++i)
+    {
+        if (i == 0)
+            pNewCharWidths[i] = rArgs.mpDXArray[i];
+        else
+            pNewCharWidths[i] = rArgs.mpDXArray[i] - rArgs.mpDXArray[i - 1];
+    }
+
+    DeviceCoordinate nDelta = 0;
+    size_t i = 0;
+    while (i < m_GlyphItems.size())
+    {
+        int nCharPos = m_GlyphItems[i].mnCharPos - mnMinCharPos;
+        DeviceCoordinate nDiff = pNewCharWidths[nCharPos] - pOldCharWidths[nCharPos];
+
+        m_GlyphItems[i].maLinearPos.X() += nDelta;
+        size_t j = i;
+        while (++j < m_GlyphItems.size())
+        {
+            if (m_GlyphItems[j].mnCharPos != m_GlyphItems[i].mnCharPos)
+                break;
+            m_GlyphItems[j].maLinearPos.X() += nDelta;
+        }
+
+        nDelta += nDiff;
+        i = j;
+    }
+}
commit 33deea24c0931a1123ceb0b2a22143fb21b48701
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Wed Sep 7 23:26:14 2016 +0200

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

diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index 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 903a784e2b88e30dbad4df8102593b3d14706cee
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Wed Sep 7 19:40:11 2016 +0200

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

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 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 6f6bc939810f616b3c4d326ea09805b76aa65139
Author: Akash Jain <akash96j at gmail.com>
Date:   Wed Aug 17 21:31:22 2016 +0530

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

diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx
index 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)
+    return pFontFace;
+    else return nullptr;
+}
+
 bool D2DWriteTextOutRenderer::BindFont(HDC hDC)
 {
     // A TextOutRender can only be bound to one font at a time, so the
@@ -3810,7 +3828,7 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe
 
     if (getenv("SAL_USE_COMMON_LAYOUT"))
     {
-        return new CommonSalLayout(getHDC(), rFontInstance);
+        return new CommonSalLayout(this, rFontInstance, rFontFace);
     }
     else
     {
@@ -3973,6 +3991,9 @@ PhysicalFontFace* WinFontFace::Clone() const
     if ( mpGraphiteData )
         mpGraphiteData->AddReference();
 #endif
+    if( mpHbFace )
+        hb_face_reference( mpHbFace );
+
     PhysicalFontFace* pClone = new WinFontFace( *this );
     return pClone;
 }
commit c899bbf97368bb47260b4b93d29feccbc863cdfb
Author: Akash Jain <akash96j at gmail.com>
Date:   Thu Aug 18 20:51:25 2016 +0530

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

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

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list