From a5750d92b2136d60d698b41ef5760f2efac0ffce Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 14 Nov 2016 00:52:14 +0200 Subject: [PATCH] tdf#103725: Fix horizontal scaling on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create IDWriteFont from LOGFONT instead of HDC, as it seems the later will discard the font width. Without font width, GDI/DirectWrite will not scale the font horizontally. Does not seem to work with all Windows versions (at least not Windows 10 Anniversary Update), seems like this undocumented behaviour have been dropped :( * Adjusting font width on Windows during layout, see the inline comment. Change-Id: I19b788460b6b6ca2c83d75bbf09a0601a250c289 Reviewed-on: https://gerrit.libreoffice.org/30847 Reviewed-by: Khaled Hosny Tested-by: Khaled Hosny --- vcl/inc/CommonSalLayout.hxx | 1 + vcl/source/gdi/CommonSalLayout.cxx | 33 ++++++++++++++++++++++++++++++ vcl/win/gdi/winlayout.cxx | 16 ++++++++++----- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/vcl/inc/CommonSalLayout.hxx b/vcl/inc/CommonSalLayout.hxx index 825f77253bbc..5d54cb8e01b1 100644 --- a/vcl/inc/CommonSalLayout.hxx +++ b/vcl/inc/CommonSalLayout.hxx @@ -45,6 +45,7 @@ class CommonSalLayout : public GenericSalLayout #ifdef _WIN32 HDC mhDC; HFONT mhFont; + double mnAveWidthFactor; #elif defined(MACOSX) || defined(IOS) const CoreTextStyle& mrCoreTextStyle; #else diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 1031b9c17dc8..9ad19679056a 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -95,7 +95,15 @@ void CommonSalLayout::getScale(double* nXScale, double* nYScale) unsigned int nUPEM = hb_face_get_upem(pHbFace); double nHeight(mrFontSelData.mnHeight); +#if defined(_WIN32) + // On Windows, mnWidth is relative to average char width not font height, + // and wee need to keep it that way for GDI to correctly scale the glyphs. + // Here we compensate for this so that HarfBuzz gives us the correct glyph + // positions. + double nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth * mnAveWidthFactor : nHeight); +#else double nWidth(mrFontSelData.mnWidth ? mrFontSelData.mnWidth : nHeight); +#endif if (nYScale) *nYScale = nHeight / nUPEM; @@ -173,6 +181,7 @@ CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance, con : mrFontSelData(rWinFontInstance.maFontSelData) , mhDC(hDC) , mhFont(static_cast(GetCurrentObject(hDC, OBJ_FONT))) +, mnAveWidthFactor(1.0f) { mpHbFont = rWinFontFace.GetHbFont(); if (!mpHbFont) @@ -182,6 +191,30 @@ CommonSalLayout::CommonSalLayout(HDC hDC, WinFontInstance& rWinFontInstance, con mpHbFont = createHbFont(pHbFace); rWinFontFace.SetHbFont(mpHbFont); } + + // Calculate the mnAveWidthFactor, see the comment where it is used. + if (mrFontSelData.mnWidth) + { + double nUPEM = hb_face_get_upem(hb_font_get_face(mpHbFont)); + + LOGFONTW aLogFont; + GetObjectW(mhFont, sizeof(LOGFONTW), &aLogFont); + + // Set the height (font size) to EM to minimize rounding errors. + aLogFont.lfHeight = -nUPEM; + // Set width to the default to get the original value in the metrics. + aLogFont.lfWidth = 0; + + // Get the font metrics. + HFONT hNewFont = CreateFontIndirectW(&aLogFont); + HFONT hOldFont = static_cast(SelectObject(hDC, hNewFont)); + TEXTMETRICW aFontMetric; + GetTextMetricsW(hDC, &aFontMetric); + SelectObject(hDC, hOldFont); + DeleteObject(hNewFont); + + mnAveWidthFactor = nUPEM / aFontMetric.tmAveCharWidth; + } } #elif defined(MACOSX) || defined(IOS) diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index b7882e337f85..335bb8c9530e 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -3599,9 +3599,19 @@ std::vector D2DWriteTextOutRenderer::GetGlyphInkBoxes(uint16_t * pGid bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const { bool succeeded = false; + IDWriteFont* pFont; + + LOGFONTW aLogFont; + HFONT hFont = static_cast(::GetCurrentObject(hDC, OBJ_FONT)); + GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont); try { - succeeded = SUCCEEDED(mpGdiInterop->CreateFontFaceFromHdc(hDC, ppFontFace)); + succeeded = SUCCEEDED(mpGdiInterop->CreateFontFromLOGFONT(&aLogFont, &pFont)); + if (succeeded) + { + succeeded = SUCCEEDED(pFont->CreateFontFace(ppFontFace)); + pFont->Release(); + } } catch (const std::exception& e) { @@ -3611,10 +3621,6 @@ bool D2DWriteTextOutRenderer::GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** p if (succeeded) { - LOGFONTW aLogFont; - HFONT hFont = static_cast(::GetCurrentObject(hDC, OBJ_FONT)); - - GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont); float dpix, dpiy; mpRT->GetDpi(&dpix, &dpiy); *lfSize = aLogFont.lfHeight * 96.0f / dpiy;