diff options
author | Luboš Luňák <l.lunak@centrum.cz> | 2021-02-25 10:05:36 +0000 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2021-03-01 15:56:46 +0100 |
commit | 13f53741dabc33c5ac12ae26538a2803c6ba1073 (patch) | |
tree | 9646a91f28e3f287f08dc0b18358a51f7805957b /vcl/skia | |
parent | 9cd95b10936450b5d1d60319192c25c4aea05fa3 (diff) |
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.lunak@collabora.com>
Diffstat (limited to 'vcl/skia')
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 40 |
1 files changed, 30 insertions, 10 deletions
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 } |