From 58b477d1581f715d75c2e117ffa9489c6e64a678 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 12 Aug 2022 11:32:54 +0800 Subject: [PATCH] win32u: Choose a smaller ppem to avoid exceeding the requested font height. When height > 0, CreateFontA/W() should not return a font face exceeding the requested height. For instance, Tahoma has 2049 units of ascent, 423 units of descent and its units per EM square is 2048. When requesting a font 20 pixels in height, ppem = units_per_EM * requested_height / (ascent + descent) = 2048 * 20 / (2049 + 423) = 16.57 ~= 17. When getting the resulting height back from the ppem, resulting_height = (ascent + descent) * ppem / units_per_EM = (2049.0 + 423) * 17 / 2048 = 20.52 ~=21. So it ends up getting a larger font than requested and violates the spec. Fix Nancy Drew: Legend of the Crystal Skull crash at start. Signed-off-by: Zhiyi Zhang --- dlls/gdi32/tests/font.c | 1 - dlls/win32u/freetype.c | 12 ++++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index b7624942ead..12a5bff5969 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -4124,7 +4124,6 @@ static void test_GetTextMetrics(void) old_hf = SelectObject(hdc, hf); ret = GetTextMetricsA(hdc, &tm); ok(ret, "GetTextMetricsA failed, error %lu\n", GetLastError()); - todo_wine ok(tm.tmHeight <= 20, "Got unexpected tmHeight %ld\n", tm.tmHeight); SelectObject(hdc, old_hf); DeleteObject(hf); diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index f6cdddd7819..d911039647b 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -1927,10 +1927,18 @@ static LONG calc_ppem_for_height(FT_Face ft_face, LONG height) if(height > 0) { USHORT windescent = get_fixed_windescent(pOS2->usWinDescent); + LONG units; + if(pOS2->usWinAscent + windescent == 0) - ppem = pFT_MulDiv(ft_face->units_per_EM, height, pHori->Ascender - pHori->Descender); + units = pHori->Ascender - pHori->Descender; else - ppem = pFT_MulDiv(ft_face->units_per_EM, height, pOS2->usWinAscent + windescent); + units = pOS2->usWinAscent + windescent; + ppem = pFT_MulDiv(ft_face->units_per_EM, height, units); + + /* If rounding ends up getting a font exceeding height, choose a smaller ppem */ + if(ppem > 1 && pFT_MulDiv(units, ppem, ft_face->units_per_EM) > height) + --ppem; + if(ppem > MAX_PPEM) { WARN("Ignoring too large height %d, ppem %d\n", height, ppem); ppem = 1; -- 2.11.4.GIT