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 <zzhang@codeweavers.com>
This commit is contained in:
Zhiyi Zhang 2022-08-12 11:32:54 +08:00 committed by Alexandre Julliard
parent 821b36e00b
commit 58b477d158
2 changed files with 10 additions and 3 deletions

View file

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

View file

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