tdf#103725: Fix horizontal scaling on Windows

* 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 <khaledhosny@eglug.org>
Tested-by: Khaled Hosny <khaledhosny@eglug.org>
This commit is contained in:
Khaled Hosny
2016-11-14 00:52:14 +02:00
parent 098f7a4ac2
commit a5750d92b2
3 changed files with 45 additions and 5 deletions

View File

@@ -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

View File

@@ -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<HFONT>(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<HFONT>(SelectObject(hDC, hNewFont));
TEXTMETRICW aFontMetric;
GetTextMetricsW(hDC, &aFontMetric);
SelectObject(hDC, hOldFont);
DeleteObject(hNewFont);
mnAveWidthFactor = nUPEM / aFontMetric.tmAveCharWidth;
}
}
#elif defined(MACOSX) || defined(IOS)

View File

@@ -3599,9 +3599,19 @@ std::vector<Rectangle> 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<HFONT>(::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<HFONT>(::GetCurrentObject(hDC, OBJ_FONT));
GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont);
float dpix, dpiy;
mpRT->GetDpi(&dpix, &dpiy);
*lfSize = aLogFont.lfHeight * 96.0f / dpiy;