summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2017-07-09 19:53:29 +0200
committerTomaž Vajngerl <quikee@gmail.com>2017-07-17 11:38:34 +0200
commit9d82a8e606895a34c08c1c628053217bbecddb8c (patch)
tree4e28fa8415782c6c1d17f8cd0b4f97811ec22bef /vcl
parentd5f94d931886a55ec3229e7b860d455037266622 (diff)
factor out DWrite renderer from winlayout
Change-Id: I7093d86593677a7d15f5b7f55aa0f29be2154f5a Reviewed-on: https://gerrit.libreoffice.org/40018 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/Library_vcl.mk1
-rwxr-xr-xvcl/inc/win/DWriteTextRenderer.hxx110
-rw-r--r--vcl/inc/win/winlayout.hxx83
-rwxr-xr-xvcl/win/gdi/DWriteTextRenderer.cxx334
-rw-r--r--vcl/win/gdi/winlayout.cxx301
5 files changed, 447 insertions, 382 deletions
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)
{