vcl/inc/skia/win/gdiimpl.hxx |    9 +++++----
 vcl/skia/win/gdiimpl.cxx     |   40 ++++++++++++++++++++++++++++++----------
 2 files changed, 35 insertions(+), 14 deletions(-)

New commits:
commit 13f53741dabc33c5ac12ae26538a2803c6ba1073
Author:     Luboš Luňák <l.lu...@centrum.cz>
AuthorDate: Thu Feb 25 10:05:36 2021 +0000
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Mar 1 15:56:46 2021 +0100

    make sure Skia DWrite matches the given HFONT exactly (tdf#137122)
    
    The problem appears to be that we use our private copy of the Dejavu
    Sans fonts, installed using AddFontResourceExW( FR_PRIVATE ),
    but that's not for whatever reason available for DirectWrite,
    which made CreateFontFromLOGFONT() find the system-installed Dejavu
    Sans, and if there was a difference between the two, then incorrect
    glyph ids were used. Use CreateFontFaceFromHdc(), which seems
    to match exactly. For private fonts this later fails the check
    with GetSystemFontCollection(), which would be nice to handle
    somehow, but I don't know how to get a font collection containing
    those fonts other than modifying SalFont to use DirectWrite
    API to install the fonts.
    
    Change-Id: I10d8fcb618f3b4decbb0198274331d7beaf843d6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111522
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 277c076323c8..594d4bad4b8c 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -11,8 +11,9 @@
 #define INCLUDED_VCL_INC_SKIA_WIN_GDIIMPL_HXX
 
 #include <memory>
-#include <vcl/dllapi.h>
+#include <systools/win32/comtools.hxx>
 
+#include <vcl/dllapi.h>
 #include <skia/gdiimpl.hxx>
 #include <win/salgdi.h>
 #include <win/wingdiimpl.hxx>
@@ -61,10 +62,10 @@ public:
 protected:
     virtual void createWindowContext(bool forceRaster = false) override;
     virtual void performFlush() override;
-    sk_sp<SkTypeface> createDirectWriteTypeface(const LOGFONTW& logFont);
+    sk_sp<SkTypeface> createDirectWriteTypeface(HDC hdc, HFONT hfont);
     static void initFontInfo();
-    inline static IDWriteFactory* dwriteFactory;
-    inline static IDWriteGdiInterop* dwriteGdiInterop;
+    inline static sal::systools::COMReference<IDWriteFactory> dwriteFactory;
+    inline static sal::systools::COMReference<IDWriteGdiInterop> 
dwriteGdiInterop;
     inline static sk_sp<SkFontMgr> dwriteFontMgr;
     inline static bool dwriteDone = false;
     static SkFont::Edging fontEdging;
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index 6d47f34ed84d..d296747936f5 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -144,7 +144,7 @@ static HRESULT checkResult(HRESULT hr, const char* file, 
size_t line)
 #define CHECKHR(funct) (funct)
 #endif
 
-sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const 
LOGFONTW& logFont)
+sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, 
HFONT hfont)
 {
     if (!dwriteDone)
     {
@@ -153,25 +153,43 @@ sk_sp<SkTypeface> 
WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const LOGFON
                                             
reinterpret_cast<IUnknown**>(&dwriteFactory)))))
         {
             if 
(SUCCEEDED(CHECKHR(dwriteFactory->GetGdiInterop(&dwriteGdiInterop))))
-                dwriteFontMgr = SkFontMgr_New_DirectWrite(dwriteFactory);
+                dwriteFontMgr = SkFontMgr_New_DirectWrite(dwriteFactory.get());
             else
-                dwriteFactory->Release();
+                dwriteFactory.clear();
         }
         dwriteDone = true;
     }
     if (!dwriteFontMgr)
         return nullptr;
-    IDWriteFont* font = nullptr;
-    IDWriteFontFace* fontFace;
-    IDWriteFontFamily* fontFamily;
-    if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFromLOGFONT(&logFont, 
&font))))
+
+    // tdf#137122: We need to get the exact same font as HFONT refers to,
+    // since VCL core computes things like glyph ids based on that, and getting
+    // a different font could lead to mismatches (e.g. if there's a slightly
+    // different version of the same font installed system-wide).
+    // For that CreateFromFaceFromHdc() is necessary. The simpler
+    // CreateFontFromLOGFONT() seems to search for the best matching font,
+    // which may not be the exact font. Our private fonts are installed
+    // using AddFontResourceExW( FR_PRIVATE ) and that apparently does
+    // not make them available to DirectWrite (at least, they are not
+    // included the DWrite system font collection). For such cases, we'll
+    // need to fall back to Skia's GDI-based font rendering.
+    HFONT oldFont = SelectFont(hdc, hfont);
+    auto restoreFont = [hdc, oldFont]() { SelectFont(hdc, oldFont); };
+    sal::systools::COMReference<IDWriteFontFace> fontFace;
+    if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFaceFromHdc(hdc, 
&fontFace))))
+        return nullptr;
+    sal::systools::COMReference<IDWriteFontCollection> collection;
+    if (FAILED(CHECKHR(dwriteFactory->GetSystemFontCollection(&collection))))
         return nullptr;
-    if (FAILED(CHECKHR(font->CreateFontFace(&fontFace))))
+    sal::systools::COMReference<IDWriteFont> font;
+    // Do not use CHECKHR() here, as said above, this fails for our fonts.
+    if (FAILED(collection->GetFontFromFontFace(fontFace.get(), &font)))
         return nullptr;
+    sal::systools::COMReference<IDWriteFontFamily> fontFamily;
     if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily))))
         return nullptr;
     return sk_sp<SkTypeface>(
-        SkCreateTypefaceDirectWrite(dwriteFontMgr, fontFace, font, 
fontFamily));
+        SkCreateTypefaceDirectWrite(dwriteFontMgr, fontFace.get(), font.get(), 
fontFamily.get()));
 }
 
 bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout)
@@ -188,7 +206,7 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const 
GenericSalLayout& rLayout)
         assert(false);
         return false;
     }
-    sk_sp<SkTypeface> typeface = createDirectWriteTypeface(logFont);
+    sk_sp<SkTypeface> typeface = 
createDirectWriteTypeface(mWinParent.getHDC(), hLayoutFont);
     GlyphOrientation glyphOrientation = GlyphOrientation::Apply;
     if (!typeface) // fall back to GDI text rendering
     {
@@ -250,6 +268,8 @@ void WinSkiaSalGraphicsImpl::initFontInfo()
 void WinSkiaSalGraphicsImpl::ClearDevFontCache()
 {
     dwriteFontMgr.reset();
+    dwriteFactory.clear();
+    dwriteGdiInterop.clear();
     dwriteDone = false;
     initFontInfo(); // get font info again, just in case
 }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to