[PATCH] gdi32/tests: Add tests for zero-width control characters.

Sven Baars sbaars at codeweavers.com
Mon Dec 14 08:53:02 CST 2020


Signed-off-by: Sven Baars <sbaars at codeweavers.com>
---
Some tests with zero-width control characters for inconsistent behavior
that I observed while trying to fix the ID3DXFont implementation. In our
implementation these functions all use the same internal function, but on
Windows none of them seem to do exactly the same.

 dlls/gdi32/tests/font.c | 151 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 86ccddd05ea..75a41f69ab9 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -7693,6 +7693,156 @@ done:
     ReleaseDC(0, hdc);
 }
 
+static void test_zero_width_control(void)
+{
+    int len, dx[20], nfit, pos[20];
+    DWORD size, charcount;
+    GCP_RESULTSW result;
+    WCHAR space_glyph;
+    WCHAR glyphs[20];
+    unsigned int i;
+    LOGFONTA lf;
+    HFONT hfont;
+    BOOL ret;
+    SIZE sz;
+    HDC hdc;
+    ABC abc;
+
+    static const WCHAR nul[] = {0};
+    static const WCHAR space[] = {' '};
+    static const WCHAR zero_width_control[] = {
+        0x0009, /* \t   */
+        0x000a, /* \n   */
+        0x000d, /* \r   */
+        0x001c, /* FS   */
+        0x001d, /* GS   */
+        0x001e, /* RS   */
+        0x001f, /* US   */
+        0x200b, /* ZWSP */
+        0x200c, /* ZWNJ */
+        0x200d, /* ZWJ  */
+        0x200e, /* LRM  */
+        0x200f, /* RLM  */
+        0x202a, /* LRE  */
+        0x202c, /* PDF  */
+        0x202d, /* LRO  */
+        0x202b, /* RLE  */
+        0x202e, /* RLO  */
+    };
+
+    memset(&lf, 0, sizeof(lf));
+    strcpy(lf.lfFaceName, "Tahoma");
+    lf.lfHeight = 20;
+
+    hfont = CreateFontIndirectA(&lf);
+    hdc = GetDC(NULL);
+    hfont = SelectObject(hdc, hfont);
+
+    memset(&result, 0, sizeof(result));
+    result.lStructSize = sizeof(result);
+    result.lpCaretPos = pos;
+    result.lpGlyphs = glyphs;
+
+    for (i = 0; i < ARRAY_SIZE(zero_width_control); ++i)
+    {
+        WCHAR test[] = {'W', 'i', 'n', 'e', ' ', zero_width_control[i], 'T', 'e', 's', 't', 0};
+
+        /* Some control characters are treated as space */
+        result.nGlyphs = 20;
+        size = GetCharacterPlacementW(hdc, test, 10, 0, &result, 0);
+        ok(size, "Test %d: GetCharacterPlacementA failed.\n", i);
+        ok(result.nGlyphs == 10, "Test %d: unexpected number of glyphs %u.\n", i, result.nGlyphs);
+        todo_wine ok(glyphs[5] == glyphs[4], "Test %d: unexpected glyphs %s.\n", i, wine_dbgstr_wn(glyphs, result.nGlyphs));
+        if (i < 15)
+            todo_wine ok(pos[6] - pos[5] == 0, "Test %d: unexpected width %d.\n", i, pos[6] - pos[5]);
+        else
+            ok(pos[6] - pos[5] > 0, "Test %d: unexpected width %d.\n", i, pos[6] - pos[5]);
+        ok(pos[5] - pos[4] > 0, "Test %d: unexpected width %d.\n", i, pos[5] - pos[4]);
+
+        /* They all have zero width in GetTextExtentExPoint */
+        nfit = -1;
+        dx[0] = -1;
+        sz.cx = -1;
+        ret = GetTextExtentExPointW(hdc, zero_width_control + i, 1, 1000, &nfit, dx, &sz);
+        ok(ret, "Test %d: expected TRUE.\n", i);
+        ok(nfit == 1, "Test %d: got %d.\n", i, nfit);
+        todo_wine ok(dx[0] == 0, "Test %d: got %d.\n", i, dx[0]);
+        todo_wine ok(sz.cx == 0, "Test %d: got %d.\n", i, sz.cx);
+
+        /* But are treated differently for the fit */
+        nfit = -1;
+        sz.cx = -1;
+        ret = GetTextExtentExPointW(hdc, test, 10, 1000, &nfit, dx, &sz);
+        ok(ret, "Test %d: expected TRUE.\n", i);
+        ok(nfit == 10, "Test %d: got %d.\n", i, nfit);
+        todo_wine ok(dx[4] == dx[5], "Test %d: expected %d got %d.\n", i, dx[4], dx[5]);
+
+        /* The ZW characters do fit, the others don't */
+        ret = GetTextExtentExPointW(hdc, test, 10, dx[5], &nfit, NULL, &sz);
+        ok(ret, "Test %d: expected TRUE.\n", i);
+        if (i < 7 || i > 9)
+            todo_wine ok(nfit == 5, "Test %d: got %d.\n", i, nfit);
+        else
+            ok(nfit == 6, "Test %d: got %d.\n", i, nfit);
+
+        /* They do not all have zero width in GetCharWidth32 */
+        len = -1;
+        ret = GetCharWidth32W(hdc, zero_width_control[i], zero_width_control[i], &len);
+        ok(ret, "Test %d: expected TRUE.\n", i);
+
+        /* In which case ABC also does not have zero width, but A+B+C
+         * is not always equal to the length from GetCharWidth32 */
+        memset(&abc, 0, sizeof(abc));
+        ret = GetCharABCWidthsW(hdc, zero_width_control[i], zero_width_control[i], &abc);
+        ok(ret, "Test %d: expected TRUE.\n", i);
+
+        if (i < 7)
+        {
+            ok(len > 0, "Test %d: got %d.\n", i, len);
+            ok(abc.abcA + abc.abcB + abc.abcC <= len && abc.abcA + abc.abcB + abc.abcC > 0,
+               "Test %d: expected %d >= %d > 0.\n", i, len, abc.abcA + abc.abcB + abc.abcC);
+            ok(abc.abcB > 0, "Test %d: got %d.\n", i, abc.abcB);
+        }
+        else
+        {
+            todo_wine ok(len == 0 || broken(i > 11) /* before Win10 */, "Test %d: got %d.\n", i, len);
+            ok(abc.abcA + abc.abcB + abc.abcC == len,
+               "Test %d: expected %d == 0.\n", i, abc.abcA + abc.abcB + abc.abcC);
+            ok(abc.abcB > 0, "Test %d: got %d.\n", i, abc.abcB);
+        }
+    }
+
+    /* The NUL character does not have zero width */
+    nfit = -1;
+    dx[0] = -1;
+    sz.cx = -1;
+    ret = GetTextExtentExPointW(hdc, nul, 1, 1000, &nfit, dx, &sz);
+    ok(ret, "Expected TRUE.\n");
+    ok(nfit == 1, "Got %d.\n", nfit);
+    ok(dx[0] > 0, "Got %d.\n", dx[0]);
+    ok(sz.cx > 0, "Got %d.\n", sz.cx);
+
+    memset(&abc, 0, sizeof(abc));
+    ret = GetCharABCWidthsW(hdc, 0, 0, &abc);
+    ok(ret, "Expected TRUE.\n");
+    todo_wine ok(abc.abcA == 0, "Got %d.\n", abc.abcA);
+    ok(abc.abcB > 0, "Got %d.\n", abc.abcB);
+    ok(abc.abcC >= 0, "Got %d.\n", abc.abcC);
+
+    /* Characters that are treated as spaces by GetCharacterPlacement */
+    /* are not treated as spaces by GetGlyphIndices. */
+    charcount = GetGlyphIndicesW(hdc, space, 1, &space_glyph, 0);
+    ok(charcount == 1, "Wrong character count %d.\n", charcount);
+
+    charcount = GetGlyphIndicesW(hdc, zero_width_control, ARRAY_SIZE(zero_width_control), glyphs, 0);
+    ok(charcount == ARRAY_SIZE(zero_width_control), "Wrong character count %d.\n", charcount);
+    for (i = 0; i < ARRAY_SIZE(zero_width_control); ++i)
+        ok(glyphs[i] != space_glyph, "Test %d: glyph is a space: %04x\n", i, glyphs[i]);
+
+    DeleteObject(hfont);
+    ReleaseDC(NULL, hdc);
+}
+
 START_TEST(font)
 {
     static const char *test_names[] =
@@ -7779,6 +7929,7 @@ START_TEST(font)
     test_ttf_names();
     test_lang_names();
     test_char_width();
+    test_zero_width_control();
 
     /* These tests should be last test until RemoveFontResource
      * is properly implemented.
-- 
2.25.1




More information about the wine-devel mailing list