summaryrefslogtreecommitdiff
path: root/vcl/skia
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@centrum.cz>2021-02-25 10:05:36 +0000
committerLuboš Luňák <l.lunak@collabora.com>2021-03-01 15:56:46 +0100
commit13f53741dabc33c5ac12ae26538a2803c6ba1073 (patch)
tree9646a91f28e3f287f08dc0b18358a51f7805957b /vcl/skia
parent9cd95b10936450b5d1d60319192c25c4aea05fa3 (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.cxx40
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
}