[PATCH v2] gdi32: Limit GetGlyphOutlineW(uChar) to a WORD.

Arkadiusz Hiler ahiler at codeweavers.com
Tue Sep 22 07:39:28 CDT 2020


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 <ahiler at codeweavers.com>
---

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




More information about the wine-devel mailing list