[Libreoffice-commits] core.git: vcl/inc vcl/Library_vcl.mk vcl/win

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Mon Jul 17 09:39:11 UTC 2017


 vcl/Library_vcl.mk                 |    1 
 vcl/inc/win/DWriteTextRenderer.hxx |  110 ++++++++++++
 vcl/inc/win/winlayout.hxx          |   83 ---------
 vcl/win/gdi/DWriteTextRenderer.cxx |  334 +++++++++++++++++++++++++++++++++++++
 vcl/win/gdi/winlayout.cxx          |  301 ---------------------------------
 5 files changed, 447 insertions(+), 382 deletions(-)

New commits:
commit 9d82a8e606895a34c08c1c628053217bbecddb8c
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Sun Jul 9 19:53:29 2017 +0200

    factor out DWrite renderer from winlayout
    
    Change-Id: I7093d86593677a7d15f5b7f55aa0f29be2154f5a
    Reviewed-on: https://gerrit.libreoffice.org/40018
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 2ad89aced588..4ce2c5aab41b 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -694,6 +694,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/win/gdi/salprn \
     vcl/win/gdi/salvd \
     vcl/win/gdi/winlayout \
+    vcl/win/gdi/DWriteTextRenderer \
     vcl/win/window/salframe \
     vcl/win/window/keynames \
     vcl/win/window/salmenu \
diff --git a/vcl/inc/win/DWriteTextRenderer.hxx b/vcl/inc/win/DWriteTextRenderer.hxx
new file mode 100755
index 000000000000..462e99050083
--- /dev/null
+++ b/vcl/inc/win/DWriteTextRenderer.hxx
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX
+#define INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX
+
+#include <usp10.h>
+#include <d2d1.h>
+#include <dwrite.h>
+
+#include "win/winlayout.hxx"
+
+enum class D2DTextAntiAliasMode
+{
+    Default,
+    ClearType,
+    AntiAliased,
+};
+
+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 ()(CommonSalLayout const &rLayout,
+        SalGraphics &rGraphics,
+        HDC hDC) override;
+
+    bool BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1))
+    {
+        if (rRect.GetWidth() == 0 || rRect.GetHeight() == 0)
+            return false;
+        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<tools::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; }
+
+    HRESULT CreateRenderTarget() {
+        if (mpRT) mpRT->Release(); mpRT = nullptr;
+        return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT);
+    }
+
+    bool Ready() const { return mpGdiInterop && mpRT; }
+
+    void applyTextAntiAliasMode();
+    void setTextAntiAliasMode(D2DTextAntiAliasMode eMode)
+    {
+        meTextAntiAliasMode = eMode;
+    }
+private:
+    static void CleanupModules();
+
+    // This is a singleton object disable copy ctor and assignment operator
+    D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete;
+    D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete;
+
+    bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const;
+
+    ID2D1Factory        * mpD2DFactory;
+    IDWriteFactory      * mpDWriteFactory;
+    IDWriteGdiInterop   * mpGdiInterop;
+    ID2D1DCRenderTarget * mpRT;
+    const D2D1_RENDER_TARGET_PROPERTIES mRTProps;
+
+    IDWriteFontFace * mpFontFace;
+    float             mlfEmHeight;
+    HDC               mhDC;
+    D2DTextAntiAliasMode meTextAntiAliasMode;
+    IDWriteRenderingParams* mpRenderingParameters;
+};
+
+#endif // INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index 128ff1f96a47..9ab63fb311ee 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -26,10 +26,6 @@
 #include <svsys.h>
 #include <win/salgdi.h>
 
-#include <usp10.h>
-#include <d2d1.h>
-#include <dwrite.h>
-
 #include "opengl/PackedTextureAtlas.hxx"
 
 class WinFontInstance;
@@ -196,85 +192,6 @@ public:
         HDC hDC) override;
 };
 
-enum class D2DTextAntiAliasMode
-{
-    Default,
-    ClearType,
-    AntiAliased,
-};
-
-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 ()(CommonSalLayout const &rLayout,
-        SalGraphics &rGraphics,
-        HDC hDC) override;
-
-    bool BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1))
-    {
-        if (rRect.GetWidth() == 0 || rRect.GetHeight() == 0)
-            return false;
-        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<tools::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; }
-
-    HRESULT CreateRenderTarget() {
-        if (mpRT) mpRT->Release(); mpRT = nullptr;
-        return mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT);
-    }
-
-    bool Ready() const { return mpGdiInterop && mpRT; }
-
-    void applyTextAntiAliasMode();
-    void setTextAntiAliasMode(D2DTextAntiAliasMode eMode)
-    {
-        meTextAntiAliasMode = eMode;
-    }
-private:
-    static void CleanupModules();
-
-    // This is a singleton object disable copy ctor and assignment operator
-    D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete;
-    D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete;
-
-    bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const;
-
-    ID2D1Factory        * mpD2DFactory;
-    IDWriteFactory      * mpDWriteFactory;
-    IDWriteGdiInterop   * mpGdiInterop;
-    ID2D1DCRenderTarget * mpRT;
-    const D2D1_RENDER_TARGET_PROPERTIES mRTProps;
-
-    IDWriteFontFace * mpFontFace;
-    float             mlfEmHeight;
-    HDC               mhDC;
-    D2DTextAntiAliasMode meTextAntiAliasMode;
-    IDWriteRenderingParams* mpRenderingParameters;
-};
-
 #endif // INCLUDED_VCL_INC_WIN_WINLAYOUT_HXX
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/DWriteTextRenderer.cxx b/vcl/win/gdi/DWriteTextRenderer.cxx
new file mode 100755
index 000000000000..ea13e05b8a60
--- /dev/null
+++ b/vcl/win/gdi/DWriteTextRenderer.cxx
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <win/salgdi.h>
+#include <win/saldata.hxx>
+#include <outdev.h>
+
+#include "win/DWriteTextRenderer.hxx"
+
+#include "sft.hxx"
+#include "sallayout.hxx"
+#include "CommonSalLayout.hxx"
+
+#include <shlwapi.h>
+#include <winver.h>
+
+HINSTANCE D2DWriteTextOutRenderer::mmD2d1 = nullptr,
+          D2DWriteTextOutRenderer::mmDWrite = nullptr;
+D2DWriteTextOutRenderer::pD2D1CreateFactory_t D2DWriteTextOutRenderer::D2D1CreateFactory = nullptr;
+D2DWriteTextOutRenderer::pDWriteCreateFactory_t D2DWriteTextOutRenderer::DWriteCreateFactory = nullptr;
+
+bool D2DWriteTextOutRenderer::InitModules()
+{
+    mmD2d1 = LoadLibrary("D2d1.dll");
+    mmDWrite = LoadLibrary("dwrite.dll");
+    if (mmD2d1 && mmDWrite)
+    {
+        D2D1CreateFactory = pD2D1CreateFactory_t(GetProcAddress(mmD2d1, "D2D1CreateFactory"));
+        DWriteCreateFactory = pDWriteCreateFactory_t(GetProcAddress(mmDWrite, "DWriteCreateFactory"));
+    }
+
+    if (!D2D1CreateFactory || !DWriteCreateFactory)
+    {
+        CleanupModules();
+        return false;
+    }
+
+    return true;
+}
+
+void D2DWriteTextOutRenderer::CleanupModules()
+{
+    if (mmD2d1)
+        FreeLibrary(mmD2d1);
+    if (mmDWrite)
+        FreeLibrary(mmDWrite);
+
+    mmD2d1 = nullptr;
+    mmDWrite = nullptr;
+    D2D1CreateFactory = nullptr;
+    DWriteCreateFactory = nullptr;
+}
+
+namespace
+{
+
+D2DTextAntiAliasMode lclGetSystemTextAntiAliasMode()
+{
+    D2DTextAntiAliasMode eMode = D2DTextAntiAliasMode::Default;
+
+    BOOL bFontSmoothing;
+    if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &bFontSmoothing, 0))
+        return eMode;
+
+    if (bFontSmoothing)
+    {
+        UINT nType;
+        if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &nType, 0))
+            return eMode;
+
+        eMode = (nType == FE_FONTSMOOTHINGCLEARTYPE) ? D2DTextAntiAliasMode::ClearType
+                                                     : D2DTextAntiAliasMode::AntiAliased;
+    }
+
+    return eMode;
+}
+
+IDWriteRenderingParams* lclSetRenderingMode(IDWriteFactory* pDWriteFactory, DWRITE_RENDERING_MODE eRenderingMode)
+{
+    IDWriteRenderingParams* pDefaultParameters = nullptr;
+    pDWriteFactory->CreateRenderingParams(&pDefaultParameters);
+
+    IDWriteRenderingParams* pParameters = nullptr;
+    pDWriteFactory->CreateCustomRenderingParams(
+        pDefaultParameters->GetGamma(),
+        pDefaultParameters->GetEnhancedContrast(),
+        pDefaultParameters->GetClearTypeLevel(),
+        pDefaultParameters->GetPixelGeometry(),
+        eRenderingMode,
+        &pParameters);
+    return pParameters;
+}
+
+} // end anonymous namespace
+
+D2DWriteTextOutRenderer::D2DWriteTextOutRenderer()
+    : mpD2DFactory(nullptr),
+    mpDWriteFactory(nullptr),
+    mpGdiInterop(nullptr),
+    mpRT(nullptr),
+    mRTProps(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
+                                          D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
+                                          0, 0)),
+    mpFontFace(nullptr),
+    mlfEmHeight(0.0f),
+    mhDC(nullptr),
+    meTextAntiAliasMode(D2DTextAntiAliasMode::Default)
+{
+    HRESULT hr = S_OK;
+    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast<void **>(&mpD2DFactory));
+    hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&mpDWriteFactory));
+    if (SUCCEEDED(hr))
+    {
+        hr = mpDWriteFactory->GetGdiInterop(&mpGdiInterop);
+        hr = CreateRenderTarget();
+    }
+    meTextAntiAliasMode = lclGetSystemTextAntiAliasMode();
+    mpRenderingParameters = lclSetRenderingMode(mpDWriteFactory, DWRITE_RENDERING_MODE_GDI_CLASSIC);
+}
+
+D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer()
+{
+    if (mpRT)
+        mpRT->Release();
+    if (mpGdiInterop)
+        mpGdiInterop->Release();
+    if (mpDWriteFactory)
+        mpDWriteFactory->Release();
+    if (mpD2DFactory)
+        mpD2DFactory->Release();
+
+    CleanupModules();
+}
+
+void D2DWriteTextOutRenderer::applyTextAntiAliasMode()
+{
+    D2D1_TEXT_ANTIALIAS_MODE eMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
+    switch (meTextAntiAliasMode)
+    {
+        case D2DTextAntiAliasMode::Default:
+            eMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
+            break;
+        case D2DTextAntiAliasMode::AntiAliased:
+            eMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
+            break;
+        case D2DTextAntiAliasMode::ClearType:
+            eMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
+            break;
+        default:
+            break;
+    }
+    mpRT->SetTextAntialiasMode(eMode);
+    mpRT->SetTextRenderingParams(mpRenderingParameters);
+}
+
+bool D2DWriteTextOutRenderer::operator ()(CommonSalLayout const &rLayout,
+    SalGraphics &rGraphics,
+    HDC hDC)
+{
+    if (!Ready())
+        return false;
+
+    if (!BindFont(hDC))
+    {
+        // If for any reason we can't bind fallback to legacy APIs.
+        return ExTextOutRenderer()(rLayout, rGraphics, hDC);
+    }
+
+    tools::Rectangle bounds;
+    bool succeeded = rLayout.GetBoundRect(rGraphics, bounds);
+    succeeded &= BindDC(hDC, bounds);   // Update the bounding rect.
+
+    ID2D1SolidColorBrush* pBrush = nullptr;
+    COLORREF bgrTextColor = GetTextColor(mhDC);
+    succeeded &= SUCCEEDED(mpRT->CreateSolidColorBrush(D2D1::ColorF(GetRValue(bgrTextColor) / 255.0f, GetGValue(bgrTextColor) / 255.0f, GetBValue(bgrTextColor) / 255.0f), &pBrush));
+
+    HRESULT hr = S_OK;
+    if (succeeded)
+    {
+        mpRT->BeginDraw();
+        applyTextAntiAliasMode();
+
+        int nStart = 0;
+        Point aPos(0, 0);
+        const GlyphItem* pGlyph;
+        while (rLayout.GetNextGlyphs(1, &pGlyph, aPos, nStart))
+        {
+            UINT16 glyphIndices[] = { pGlyph->maGlyphId };
+            FLOAT glyphAdvances[] = { pGlyph->mnNewWidth };
+            DWRITE_GLYPH_OFFSET glyphOffsets[] = { { 0.0f, 0.0f }, };
+            D2D1_POINT_2F baseline = { aPos.X() - bounds.Left(), aPos.Y() - bounds.Top() };
+            DWRITE_GLYPH_RUN glyphs = {
+                mpFontFace,
+                mlfEmHeight,
+                1,
+                glyphIndices,
+                glyphAdvances,
+                glyphOffsets,
+                false,
+                0
+            };
+
+            mpRT->DrawGlyphRun(baseline, &glyphs, pBrush);
+        }
+
+        hr = mpRT->EndDraw();
+    }
+
+    if (pBrush)
+        pBrush->Release();
+
+    ReleaseFont();
+
+    if (hr == D2DERR_RECREATE_TARGET)
+        CreateRenderTarget();
+
+    return succeeded;
+}
+
+bool D2DWriteTextOutRenderer::BindFont(HDC hDC)
+{
+    // A TextOutRender can only be bound to one font at a time, so the
+    assert(mpFontFace == nullptr);
+    if (mpFontFace)
+    {
+        ReleaseFont();
+        return false;
+    }
+
+    // Initially bind to an empty rectangle to get access to the font face,
+    //  we'll update it once we've calculated a bounding rect in DrawGlyphs
+    if (!BindDC(mhDC = hDC))
+        return false;
+
+    mlfEmHeight = 0;
+    return GetDWriteFaceFromHDC(hDC, &mpFontFace, &mlfEmHeight);
+}
+
+bool D2DWriteTextOutRenderer::ReleaseFont()
+{
+    mpFontFace->Release();
+    mpFontFace = nullptr;
+    mhDC = nullptr;
+
+    return true;
+}
+
+// GetGlyphInkBoxes
+// The inkboxes returned have their origin on the baseline, to a -ve value
+// of Top() means the glyph extends abs(Top()) many pixels above the
+// baseline, and +ve means the ink starts that many pixels below.
+std::vector<tools::Rectangle> D2DWriteTextOutRenderer::GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const
+{
+    ptrdiff_t nGlyphs = pGidEnd - pGid;
+    if (nGlyphs < 0)
+        return std::vector<tools::Rectangle>();
+
+    DWRITE_FONT_METRICS aFontMetrics;
+    mpFontFace->GetMetrics(&aFontMetrics);
+
+    std::vector<DWRITE_GLYPH_METRICS> metrics(nGlyphs);
+    if (!SUCCEEDED(mpFontFace->GetDesignGlyphMetrics(pGid, nGlyphs, metrics.data())))
+        return std::vector<tools::Rectangle>();
+
+    std::vector<tools::Rectangle> aOut(nGlyphs);
+    auto pOut = aOut.begin();
+    for (auto &m : metrics)
+    {
+        const long left  = m.leftSideBearing,
+                   top   = m.topSideBearing - m.verticalOriginY,
+                   right = m.advanceWidth - m.rightSideBearing,
+                   bottom = INT32(m.advanceHeight) - m.verticalOriginY - m.bottomSideBearing;
+
+        // Scale to screen space.
+        pOut->Left()   = std::floor(left * mlfEmHeight / aFontMetrics.designUnitsPerEm);
+        pOut->Top()    = std::floor(top * mlfEmHeight / aFontMetrics.designUnitsPerEm);
+        pOut->Right()  = std::ceil(right * mlfEmHeight / aFontMetrics.designUnitsPerEm);
+        pOut->Bottom() = std::ceil(bottom * mlfEmHeight / aFontMetrics.designUnitsPerEm);
+
+        ++pOut;
+    }
+
+    return aOut;
+}
+
+bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const
+{
+    bool succeeded = false;
+    try
+    {
+        succeeded = SUCCEEDED(mpGdiInterop->CreateFontFaceFromHdc(hDC, ppFontFace));
+    }
+    catch (const std::exception& e)
+    {
+        SAL_WARN("vcl.gdi", "Error in dwrite while creating font face: " << e.what());
+        return false;
+    }
+
+    if (succeeded)
+    {
+        LOGFONTW aLogFont;
+        HFONT hFont = static_cast<HFONT>(::GetCurrentObject(hDC, OBJ_FONT));
+
+        GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont);
+        float dpix, dpiy;
+        mpRT->GetDpi(&dpix, &dpiy);
+        *lfSize = aLogFont.lfHeight * 96.0f / dpiy;
+
+        assert(*lfSize < 0);
+        *lfSize *= -1;
+    }
+
+    return succeeded;
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 81acf53b7ba2..facaf82ad93c 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -31,6 +31,8 @@
 #include <win/saldata.hxx>
 #include <outdev.h>
 
+#include "win/DWriteTextRenderer.hxx"
+
 #include "sft.hxx"
 #include "sallayout.hxx"
 #include "CommonSalLayout.hxx"
@@ -211,44 +213,6 @@ bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, S
     return true;
 }
 
-
-HINSTANCE D2DWriteTextOutRenderer::mmD2d1 = nullptr,
-          D2DWriteTextOutRenderer::mmDWrite = nullptr;
-D2DWriteTextOutRenderer::pD2D1CreateFactory_t D2DWriteTextOutRenderer::D2D1CreateFactory = nullptr;
-D2DWriteTextOutRenderer::pDWriteCreateFactory_t D2DWriteTextOutRenderer::DWriteCreateFactory = nullptr;
-
-bool D2DWriteTextOutRenderer::InitModules()
-{
-    mmD2d1 = LoadLibrary("D2d1.dll");
-    mmDWrite = LoadLibrary("dwrite.dll");
-    if (mmD2d1 && mmDWrite)
-    {
-        D2D1CreateFactory = pD2D1CreateFactory_t(GetProcAddress(mmD2d1, "D2D1CreateFactory"));
-        DWriteCreateFactory = pDWriteCreateFactory_t(GetProcAddress(mmDWrite, "DWriteCreateFactory"));
-    }
-
-    if (!D2D1CreateFactory || !DWriteCreateFactory)
-    {
-        CleanupModules();
-        return false;
-    }
-
-    return true;
-}
-
-void D2DWriteTextOutRenderer::CleanupModules()
-{
-    if (mmD2d1)
-        FreeLibrary(mmD2d1);
-    if (mmDWrite)
-        FreeLibrary(mmDWrite);
-
-    mmD2d1 = nullptr;
-    mmDWrite = nullptr;
-    D2D1CreateFactory = nullptr;
-    DWriteCreateFactory = nullptr;
-}
-
 TextOutRenderer & TextOutRenderer::get(bool bUseDWrite)
 {
     SalData *const pSalData = GetSalData();
@@ -321,267 +285,6 @@ bool ExTextOutRenderer::operator ()(CommonSalLayout const &rLayout,
 
     return true;
 }
-namespace
-{
-
-D2DTextAntiAliasMode lclGetSystemTextAntiAliasMode()
-{
-    D2DTextAntiAliasMode eMode = D2DTextAntiAliasMode::Default;
-
-    BOOL bFontSmoothing;
-    if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &bFontSmoothing, 0))
-        return eMode;
-
-    if (bFontSmoothing)
-    {
-        UINT nType;
-        if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &nType, 0))
-            return eMode;
-
-        eMode = (nType == FE_FONTSMOOTHINGCLEARTYPE) ? D2DTextAntiAliasMode::ClearType
-                                                     : D2DTextAntiAliasMode::AntiAliased;
-    }
-
-    return eMode;
-}
-
-IDWriteRenderingParams* lclSetRenderingMode(IDWriteFactory* pDWriteFactory, DWRITE_RENDERING_MODE eRenderingMode)
-{
-    IDWriteRenderingParams* pDefaultParameters = nullptr;
-    pDWriteFactory->CreateRenderingParams(&pDefaultParameters);
-
-    IDWriteRenderingParams* pParameters = nullptr;
-    pDWriteFactory->CreateCustomRenderingParams(
-        pDefaultParameters->GetGamma(),
-        pDefaultParameters->GetEnhancedContrast(),
-        pDefaultParameters->GetClearTypeLevel(),
-        pDefaultParameters->GetPixelGeometry(),
-        eRenderingMode,
-        &pParameters);
-    return pParameters;
-}
-
-} // end anonymous namespace
-
-D2DWriteTextOutRenderer::D2DWriteTextOutRenderer()
-    : mpD2DFactory(nullptr),
-    mpDWriteFactory(nullptr),
-    mpGdiInterop(nullptr),
-    mpRT(nullptr),
-    mRTProps(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
-                                          D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
-                                          0, 0)),
-    mpFontFace(nullptr),
-    mlfEmHeight(0.0f),
-    mhDC(nullptr),
-    meTextAntiAliasMode(D2DTextAntiAliasMode::Default)
-{
-    HRESULT hr = S_OK;
-    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, reinterpret_cast<void **>(&mpD2DFactory));
-    hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&mpDWriteFactory));
-    if (SUCCEEDED(hr))
-    {
-        hr = mpDWriteFactory->GetGdiInterop(&mpGdiInterop);
-        hr = CreateRenderTarget();
-    }
-    meTextAntiAliasMode = lclGetSystemTextAntiAliasMode();
-    mpRenderingParameters = lclSetRenderingMode(mpDWriteFactory, DWRITE_RENDERING_MODE_GDI_CLASSIC);
-}
-
-D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer()
-{
-    if (mpRT)
-        mpRT->Release();
-    if (mpGdiInterop)
-        mpGdiInterop->Release();
-    if (mpDWriteFactory)
-        mpDWriteFactory->Release();
-    if (mpD2DFactory)
-        mpD2DFactory->Release();
-
-    CleanupModules();
-}
-
-void D2DWriteTextOutRenderer::applyTextAntiAliasMode()
-{
-    D2D1_TEXT_ANTIALIAS_MODE eMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
-    switch (meTextAntiAliasMode)
-    {
-        case D2DTextAntiAliasMode::Default:
-            eMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
-            break;
-        case D2DTextAntiAliasMode::AntiAliased:
-            eMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
-            break;
-        case D2DTextAntiAliasMode::ClearType:
-            eMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
-            break;
-        default:
-            break;
-    }
-    mpRT->SetTextAntialiasMode(eMode);
-    mpRT->SetTextRenderingParams(mpRenderingParameters);
-}
-
-bool D2DWriteTextOutRenderer::operator ()(CommonSalLayout const &rLayout,
-    SalGraphics &rGraphics,
-    HDC hDC)
-{
-    if (!Ready())
-        return false;
-
-    if (!BindFont(hDC))
-    {
-        // If for any reason we can't bind fallback to legacy APIs.
-        return ExTextOutRenderer()(rLayout, rGraphics, hDC);
-    }
-
-    tools::Rectangle bounds;
-    bool succeeded = rLayout.GetBoundRect(rGraphics, bounds);
-    succeeded &= BindDC(hDC, bounds);   // Update the bounding rect.
-
-    ID2D1SolidColorBrush* pBrush = nullptr;
-    COLORREF bgrTextColor = GetTextColor(mhDC);
-    succeeded &= SUCCEEDED(mpRT->CreateSolidColorBrush(D2D1::ColorF(GetRValue(bgrTextColor) / 255.0f, GetGValue(bgrTextColor) / 255.0f, GetBValue(bgrTextColor) / 255.0f), &pBrush));
-
-    HRESULT hr = S_OK;
-    if (succeeded)
-    {
-        mpRT->BeginDraw();
-        applyTextAntiAliasMode();
-
-        int nStart = 0;
-        Point aPos(0, 0);
-        const GlyphItem* pGlyph;
-        while (rLayout.GetNextGlyphs(1, &pGlyph, aPos, nStart))
-        {
-            UINT16 glyphIndices[] = { pGlyph->maGlyphId };
-            FLOAT glyphAdvances[] = { pGlyph->mnNewWidth };
-            DWRITE_GLYPH_OFFSET glyphOffsets[] = { { 0.0f, 0.0f }, };
-            D2D1_POINT_2F baseline = { aPos.X() - bounds.Left(), aPos.Y() - bounds.Top() };
-            DWRITE_GLYPH_RUN glyphs = {
-                mpFontFace,
-                mlfEmHeight,
-                1,
-                glyphIndices,
-                glyphAdvances,
-                glyphOffsets,
-                false,
-                0
-            };
-
-            mpRT->DrawGlyphRun(baseline, &glyphs, pBrush);
-        }
-
-        hr = mpRT->EndDraw();
-    }
-
-    if (pBrush)
-        pBrush->Release();
-
-    ReleaseFont();
-
-    if (hr == D2DERR_RECREATE_TARGET)
-        CreateRenderTarget();
-
-    return succeeded;
-}
-
-bool D2DWriteTextOutRenderer::BindFont(HDC hDC)
-{
-    // A TextOutRender can only be bound to one font at a time, so the
-    assert(mpFontFace == nullptr);
-    if (mpFontFace)
-    {
-        ReleaseFont();
-        return false;
-    }
-
-    // Initially bind to an empty rectangle to get access to the font face,
-    //  we'll update it once we've calculated a bounding rect in DrawGlyphs
-    if (!BindDC(mhDC = hDC))
-        return false;
-
-    mlfEmHeight = 0;
-    return GetDWriteFaceFromHDC(hDC, &mpFontFace, &mlfEmHeight);
-}
-
-bool D2DWriteTextOutRenderer::ReleaseFont()
-{
-    mpFontFace->Release();
-    mpFontFace = nullptr;
-    mhDC = nullptr;
-
-    return true;
-}
-
-// GetGlyphInkBoxes
-// The inkboxes returned have their origin on the baseline, to a -ve value
-// of Top() means the glyph extends abs(Top()) many pixels above the
-// baseline, and +ve means the ink starts that many pixels below.
-std::vector<tools::Rectangle> D2DWriteTextOutRenderer::GetGlyphInkBoxes(uint16_t * pGid, uint16_t * pGidEnd) const
-{
-    ptrdiff_t nGlyphs = pGidEnd - pGid;
-    if (nGlyphs < 0)
-        return std::vector<tools::Rectangle>();
-
-    DWRITE_FONT_METRICS aFontMetrics;
-    mpFontFace->GetMetrics(&aFontMetrics);
-
-    std::vector<DWRITE_GLYPH_METRICS> metrics(nGlyphs);
-    if (!SUCCEEDED(mpFontFace->GetDesignGlyphMetrics(pGid, nGlyphs, metrics.data())))
-        return std::vector<tools::Rectangle>();
-
-    std::vector<tools::Rectangle> aOut(nGlyphs);
-    auto pOut = aOut.begin();
-    for (auto &m : metrics)
-    {
-        const long left  = m.leftSideBearing,
-                   top   = m.topSideBearing - m.verticalOriginY,
-                   right = m.advanceWidth - m.rightSideBearing,
-                   bottom = INT32(m.advanceHeight) - m.verticalOriginY - m.bottomSideBearing;
-
-        // Scale to screen space.
-        pOut->Left()   = std::floor(left * mlfEmHeight / aFontMetrics.designUnitsPerEm);
-        pOut->Top()    = std::floor(top * mlfEmHeight / aFontMetrics.designUnitsPerEm);
-        pOut->Right()  = std::ceil(right * mlfEmHeight / aFontMetrics.designUnitsPerEm);
-        pOut->Bottom() = std::ceil(bottom * mlfEmHeight / aFontMetrics.designUnitsPerEm);
-
-        ++pOut;
-    }
-
-    return aOut;
-}
-
-bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const
-{
-    bool succeeded = false;
-    try
-    {
-        succeeded = SUCCEEDED(mpGdiInterop->CreateFontFaceFromHdc(hDC, ppFontFace));
-    }
-    catch (const std::exception& e)
-    {
-        SAL_WARN("vcl.gdi", "Error in dwrite while creating font face: " << e.what());
-        return false;
-    }
-
-    if (succeeded)
-    {
-        LOGFONTW aLogFont;
-        HFONT hFont = static_cast<HFONT>(::GetCurrentObject(hDC, OBJ_FONT));
-
-        GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont);
-        float dpix, dpiy;
-        mpRT->GetDpi(&dpix, &dpiy);
-        *lfSize = aLogFont.lfHeight * 96.0f / dpiy;
-
-        assert(*lfSize < 0);
-        *lfSize *= -1;
-    }
-
-    return succeeded;
-}
 
 SalLayout* WinSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int nFallbackLevel)
 {


More information about the Libreoffice-commits mailing list