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;