From: Arkadiusz Hiler Subject: [PATCH v2] gdi32: Limit GetGlyphOutlineW(uChar) to a WORD. Message-Id: <20200922123928.483926-1-ahiler@codeweavers.com> Date: Tue, 22 Sep 2020 15:39:28 +0300 Turns out GetGlyphOutlineW() is using only two bytes for the character. This limits us to chars in the range 0x0000 - 0xffff. Fixes eden* PLUS+MOSAIC. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45400 Signed-off-by: Arkadiusz Hiler --- Supersedes: 192997 v2: While investigating the failures with zh_CN locale I figured out that I did some mistakes in my font definition and that I can just reuse wine-test.ttf: * It has .notdef with a distinct width * It has a few characters defined which are handy to test The changes are: * use wine_test font, it's even better than what I had * make sure that our character is different than .notdef * test multiple characters * test multiple values in the higher bytes * make sure that no matter what we put past the two lower bytes we get the same character dlls/gdi32/font.c | 2 ++ dlls/gdi32/tests/font.c | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index e099bec5e81..0fa1722d621 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -2905,6 +2905,8 @@ DWORD WINAPI GetGlyphOutlineW( HDC hdc, UINT uChar, UINT fuFormat, dc = get_dc_ptr(hdc); if(!dc) return GDI_ERROR; + uChar &= 0xFFFF; + dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline ); ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 ); release_dc_ptr( dc ); diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index f5c8d4dac3b..6410778c0e0 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -5800,6 +5800,58 @@ todo_wine ReleaseDC(NULL, hdc); } +static void test_GetGlyphOutlineW_character_limited_to_a_word(void) +{ + HFONT hfont, hfont_old; + LOGFONTA lf; + HDC hdc; + DWORD ret; + GLYPHMETRICS gm1, gm2, gmn; + char test_chars[] = { 'A', 'D', '!', '\0' }; + + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = 72; + lstrcpyA(lf.lfFaceName, "wine_test"); + + hfont = CreateFontIndirectA(&lf); + ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError()); + + hdc = GetDC(NULL); + + hfont_old = SelectObject(hdc, hfont); + ok(hfont_old != NULL, "SelectObject failed\n"); + + ret = GetGlyphOutlineW(hdc, 'Z', GGO_METRICS, &gmn, 0, NULL, &mat); /* .notdef */ + ok(ret != GDI_ERROR, "GetGlyphOutlineW failed with %d, lest error %d\n", ret, GetLastError()); + + for (char *current_char = test_chars; *current_char != '\0'; current_char++) + { + ret = GetGlyphOutlineW(hdc, *current_char, GGO_METRICS, &gm1, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineW failed with %d, lest error %d\n", ret, GetLastError()); + + /* make sure we differ from .notdef */ + ok(memcmp(&gm1, &gmn, sizeof(gmn)) != 0, "one of the test characters matches .notdef\n"); + + for (UINT offset = 0x10000; offset < 0xF0FF0000; offset += 0x1000000) + { + ret = GetGlyphOutlineW(hdc, offset + *current_char, GGO_METRICS, &gm2, 0, NULL, &mat); + ok(ret != GDI_ERROR, "GetGlyphOutlineW failed with %d, lest error %d\n", ret, GetLastError()); + + ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX, "gmBlackBoxX differs, %d should equal %d\n", gm1.gmBlackBoxX, gm2.gmBlackBoxX); + ok(gm1.gmBlackBoxY == gm2.gmBlackBoxY, "gmBlackBoxY differs, %d should equal %d\n", gm1.gmBlackBoxY, gm2.gmBlackBoxY); + ok(gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x, "gmptGlyphOrigin.x differs, %d should equal %d\n", gm1.gmptGlyphOrigin.x, gm2.gmptGlyphOrigin.x); + ok(gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y, "gmptGlyphOrigin.y difference, %d should equal %d\n", gm1.gmptGlyphOrigin.y, gm2.gmptGlyphOrigin.y); + ok(gm1.gmCellIncX == gm2.gmCellIncX, "gmCellIncX differs, %d should equal %d\n", gm1.gmCellIncX, gm2.gmCellIncX); + ok(gm1.gmCellIncY == gm2.gmCellIncY, "gmCellIncY differs, %d should equal %d\n", gm1.gmCellIncY, gm2.gmCellIncY); + } + } + + SelectObject(hdc, hfont_old); + DeleteObject(hfont); + + DeleteDC(hdc); +} + static void test_fstype_fixup(void) { HDC hdc; @@ -5922,6 +5974,7 @@ static void test_CreateScalableFontResource(void) test_GetGlyphOutline_empty_contour(); test_GetGlyphOutline_metric_clipping(); + test_GetGlyphOutlineW_character_limited_to_a_word(); test_fstype_fixup(); ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0); -- 2.28.0