[PATCH v2 6/7] gdi32/tests: Add more tests for GetCharacterPlacement.

Sven Baars sbaars at codeweavers.com
Mon Nov 9 08:07:19 CST 2020


Similar to the tests already present for usp10.

Signed-off-by: Sven Baars <sbaars at codeweavers.com>
---
v2: Fixed test failures.

 dlls/gdi32/tests/font.c | 444 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 443 insertions(+), 1 deletion(-)

diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 5b5efc88743..f08b42ff66e 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -4895,12 +4895,310 @@ static void test_GetTextMetrics2(const char *fontname, int font_height)
     ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
 }
 
+struct enum_font_range_param {
+    BYTE range;
+    LOGFONTA lf;
+};
+
+static int CALLBACK enum_font_range_proc(const LOGFONTA *lf, const TEXTMETRICA *tm, DWORD type, LPARAM param)
+{
+    NEWTEXTMETRICEXA *ntme = (NEWTEXTMETRICEXA *)tm;
+    struct enum_font_range_param *efrp = (struct enum_font_range_param *)param;
+    int idx = 0;
+    DWORD i;
+    DWORD mask = 0;
+
+    if (type != TRUETYPE_FONTTYPE)
+        return 1;
+
+    i = efrp->range;
+    while (i >= sizeof(DWORD)*8)
+    {
+        idx++;
+        i -= (sizeof(DWORD)*8);
+    }
+    if (idx > 3)
+        return 0;
+
+    mask = 1 << i;
+
+    if (ntme->ntmFontSig.fsUsb[idx] & mask)
+    {
+        memcpy(&(efrp->lf), lf, sizeof(LOGFONTA));
+        return 0;
+    }
+    return 1;
+}
+
+static int _find_font_for_range(HDC hdc, const CHAR *recommended, BYTE range, const WCHAR check, HFONT *hfont, HFONT *hfont_orig)
+{
+    int rc = 0;
+    struct enum_font_range_param param;
+
+    param.range = range;
+    memset(&param.lf, 0, sizeof(LOGFONTA));
+    *hfont = NULL;
+
+    if (recommended)
+    {
+        lstrcpyA(param.lf.lfFaceName, recommended);
+        if (!EnumFontFamiliesExA(hdc, &param.lf, enum_font_range_proc, (LPARAM)&param, 0))
+        {
+            *hfont = CreateFontIndirectA(&param.lf);
+            if (*hfont)
+            {
+                winetest_trace("Using font %s.\n", param.lf.lfFaceName);
+                rc = 1;
+            }
+        }
+        if (!rc)
+            winetest_skip("Font %s is not available.\n", recommended);
+    }
+
+    if (!*hfont)
+    {
+        memset(&param.lf, 0, sizeof(LOGFONTA));
+        param.lf.lfCharSet = DEFAULT_CHARSET;
+
+        if (!EnumFontFamiliesExA(hdc, &param.lf, enum_font_range_proc, (LPARAM)&param, 0) && param.lf.lfFaceName[0])
+        {
+            *hfont = CreateFontIndirectA(&param.lf);
+            if (*hfont)
+                winetest_trace("Trying font %s: failures will only be warnings.\n",param.lf.lfFaceName);
+        }
+    }
+
+    if (*hfont)
+    {
+        WORD glyph = 0;
+
+        *hfont_orig = SelectObject(hdc, *hfont);
+        if (GetGlyphIndicesW(hdc, &check, 1, &glyph, 0) == GDI_ERROR || glyph == 0)
+        {
+            winetest_trace("Font fails to contain required glyphs.\n");
+            SelectObject(hdc, *hfont_orig);
+            DeleteObject(*hfont);
+            *hfont = NULL;
+            rc = 0;
+        }
+        else if (!rc)
+            rc = -1;
+    }
+    else
+        winetest_trace("Failed to find usable font.\n");
+
+    return rc;
+}
+
+#define find_font_for_range(a, b, c, d, e, f) \
+        (winetest_set_location(__FILE__, __LINE__),  0) ? 0 : \
+        _find_font_for_range(a, b, c, d, e, f)
+
+struct expected_character_placement
+{
+    int order;
+    int dx;
+    int reorder;
+};
+
+static inline void _test_character_placement_ok(int valid, HDC hdc, const WCHAR *string, unsigned int str_len,
+                                                const struct expected_character_placement *expected, unsigned int expected_len)
+{
+    GCP_RESULTSW result;
+    unsigned int i, max_glyphs = 1.5 * str_len;
+    DWORD size;
+    int dx;
+
+    memset(&result, 0, sizeof(result));
+    result.lStructSize = sizeof(result);
+    result.lpCaretPos = heap_alloc(max_glyphs * sizeof(*result.lpCaretPos));
+    result.lpGlyphs = heap_alloc(max_glyphs * sizeof(*result.lpGlyphs));
+    result.lpOrder = heap_alloc(max_glyphs * sizeof(*result.lpOrder));
+    result.lpDx = heap_alloc(max_glyphs * sizeof(*result.lpDx));
+    result.nGlyphs = max_glyphs;
+
+    memset(result.lpOrder, -1, max_glyphs * sizeof(*result.lpOrder));
+    memset(result.lpDx, -1, max_glyphs * sizeof(*result.lpDx));
+
+    size = GetCharacterPlacementW(hdc, string, str_len, 0, &result, 0);
+    winetest_ok(size, "GetCharacterPlacementW failed.\n");
+    if (valid > 0)
+        winetest_ok(result.nGlyphs == expected_len, "Expected %d, got %d.\n", expected_len, result.nGlyphs);
+    else if (result.nGlyphs != expected_len)
+        winetest_trace("Expected %d, got %d.\n", expected_len, result.nGlyphs);
+    for (i = 0; i < result.nGlyphs; ++i)
+    {
+        if (valid > 0)
+            todo_wine_if(expected[i].order != i)
+                winetest_ok(result.lpOrder[i] == expected[i].order ||
+                            broken(result.lpOrder[i] == expected[expected_len - i - 1].reorder) /* Win2008 */,
+                            "Character %d, expected order %d, got %d.\n",
+                            i, expected[i].order, result.lpOrder[i]);
+        else if (result.lpOrder[i] != expected[i].reorder)
+            winetest_trace("Character %d, expected order %d, got %d.\n", i, expected[i].reorder, result.lpOrder[i]);
+        if (expected[i].dx)
+        {
+            GetCharWidthI(hdc, result.lpGlyphs[result.lpOrder[i]], 1, NULL, &dx);
+            if (valid > 0)
+                winetest_ok(result.lpDx[result.lpOrder[i]] == dx, "Character %d, expected dx %d, got %d.\n",
+                            i, dx, result.lpDx[result.lpOrder[i]]);
+            else if (result.lpDx[result.lpOrder[i]] != dx)
+                winetest_trace("Character %d, expected dx %d, got %d.\n",
+                               i, dx, result.lpDx[result.lpOrder[i]]);
+        }
+    }
+
+    if (expected[0].reorder >= 0)
+    {
+        memset(result.lpOrder, -1, max_glyphs * sizeof(*result.lpOrder));
+        memset(result.lpDx, -1, max_glyphs * sizeof(*result.lpDx));
+
+        size = GetCharacterPlacementW(hdc, string, str_len, 0, &result, GCP_REORDER);
+        winetest_ok(size, "GetCharacterPlacementW failed with GCP_REORDER.\n");
+        if (valid > 0)
+            winetest_ok(result.nGlyphs == expected_len, "Expected %d with GCP_REORDER, got %d.\n", expected_len, result.nGlyphs);
+        else if (result.nGlyphs != expected_len)
+            winetest_trace("Expected %d with GCP_REORDER, got %d.\n", expected_len, result.nGlyphs);
+        for (i = 0; i < result.nGlyphs; ++i)
+        {
+            if (valid > 0)
+                todo_wine_if(expected[i].order != i)
+                    winetest_ok(result.lpOrder[i] == expected[i].reorder, "Character %d, expected GCP_REORDER order %d, got %d.\n",
+                                i, expected[i].reorder, result.lpOrder[i]);
+            else if (result.lpOrder[i] != expected[i].reorder)
+                winetest_trace("Character %d, expected GCP_REORDER order %d, got %d.\n", i, expected[i].reorder, result.lpOrder[i]);
+            if (expected[i].dx)
+            {
+                GetCharWidthI(hdc, result.lpGlyphs[result.lpOrder[i]], 1, NULL, &dx);
+                if (valid > 0)
+                    winetest_ok(result.lpDx[result.lpOrder[i]] == dx, "Character %d, expected GCP_REORDER dx %d, got %d.\n",
+                                i, dx, result.lpDx[result.lpOrder[i]]);
+                else if (result.lpDx[result.lpOrder[i]] != dx)
+                    winetest_trace("Character %d, expected GCP_REORDER dx %d, got %d.\n",
+                                   i, dx, result.lpDx[result.lpOrder[i]]);
+            }
+        }
+    }
+
+    heap_free(result.lpCaretPos);
+    heap_free(result.lpGlyphs);
+    heap_free(result.lpOrder);
+    heap_free(result.lpDx);
+}
+
+#define test_character_placement_ok(a, b, c, d, e, f)           \
+    (winetest_set_location(__FILE__, __LINE__), 0) ? 0 :        \
+    _test_character_placement_ok(a, b, c, d, e, f)
+
 static void test_GetCharacterPlacement(void)
 {
+    static const WCHAR test1[] = {'w', 'i', 'n', 'e'};
+    static const struct expected_character_placement t1_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{3,1,3}};
+
+    static const WCHAR test2[] = {0x202B, 'i', 'n', 0x202C};
+    static const struct expected_character_placement t2_expected[] =
+        {{0,0,0},{1,1,1},{2,1,2},{3,0,3}};
+
+    static const WCHAR test3[] = {'t', 't', 'f', 'f', 'f', 'i',};
+    static const struct expected_character_placement t3_expected[] =
+        {{0,1,0},{0,1,0},{0,1,0},{1,1,1},{1,1,1},{1,1,1}};
+
+    /* Hebrew */
+    static const WCHAR test_hebrew[] =
+        {0x05e9, 0x05dc, 0x05d5, 0x05dd};
+    static const struct expected_character_placement hebrew_expected[] =
+        {{0,1,3},{1,1,2},{2,1,1},{3,1,0}};
+
+    /* Arabic */
+    static const WCHAR test_arabic[] =
+        {0x0633, 0x0644, 0x0627, 0x0645};
+    static const struct expected_character_placement arabic_expected[] =
+        {{0,1,2},{1,1,1},{2,1,1},{3,1,0}};
+
+    /* Thai */
+    static const WCHAR test_thai[] =
+        {0x0e2a, 0x0e04, 0x0e23, 0x0e34, 0x0e1b, 0x0e15, 0x0e4c, 0x0e44, 0x0e17, 0x0e22};
+    static const struct expected_character_placement thai_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{3,1,3},{4,1,4},{5,1,5},{6,1,6},{7,1,7},{8,1,8},{9,1,9}};
+
+    /* Thaana */
+    static const WCHAR test_thaana[] =
+        {0x078a, 0x07ae, 0x0792, 0x07b0, 0x0020, 0x0796, 0x07aa, 0x0789, 0x07b0, 0x0795, 0x07ac, 0x0791, 0x07b0};
+    static const struct expected_character_placement thaana_expected[] =
+        {{0,1,12},{1,1,11},{2,0,10},{3,1,9},{4,1,8},{5,1,7},{6,1,6},{7,1,5},{8,1,4},{9,1,3},{10,1,2},{11,0,1},{12,1,0}};
+
+    /* Phags-pa */
+    static const WCHAR test_phagspa[] =
+        {0xa84f, 0xa861, 0xa843, 0x0020, 0xa863, 0xa861, 0xa859, 0x0020, 0xa850, 0xa85c, 0xa85e};
+    static const struct expected_character_placement phagspa_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1},{6,1,-1},{7,1,-1},{8,1,-1},{9,1,-1},{10,1,-1}};
+
+    /* Lao */
+    static const WCHAR test_lao[] =
+        {0x0ead, 0x0eb1, 0x0e81, 0x0eaa, 0x0ead, 0x0e99, 0x0ea5, 0x0eb2, 0x0ea7};
+    static const struct expected_character_placement lao_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{3,1,3},{4,1,4},{5,1,5},{6,1,6},{7,1,7},{8,1,8}};
+
+    /* Tibetan */
+    static const WCHAR test_tibetan[] =
+        {0x0f04, 0x0f05, 0x0f0e, 0x0020, 0x0f51, 0x0f7c, 0x0f53, 0x0f0b, 0x0f5a, 0x0f53, 0x0f0b, 0x0f51, 0x0f44, 0x0f0b, 0x0f54, 0x0f7c, 0x0f0d};
+    static const struct expected_character_placement tibetan_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1},{6,1,-1},{7,1,-1},{8,1,-1},{9,1,-1},{10,1,-1},{11,1,-1},{12,1,-1},{13,1,-1},{14,1,-1},{15,1,-1},{16,1,-1}};
+
+    /* Devanagari */
+    static const WCHAR test_devanagari[] =
+        {0x0926, 0x0947, 0x0935, 0x0928, 0x093e, 0x0917, 0x0930, 0x0940};
+    static const struct expected_character_placement devanagari_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1},{6,1,-1},{7,1,-1}};
+
+    /* Bengali */
+    static const WCHAR test_bengali[] =
+        {0x09ac, 0x09be, 0x0982, 0x09b2, 0x09be};
+    static const struct expected_character_placement bengali_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1}};
+
+    /* Gurmukhi */
+    static const WCHAR test_gurmukhi[] =
+        {0x0a17, 0x0a41, 0x0a30, 0x0a2e, 0x0a41, 0x0a16, 0x0a40};
+    static const struct expected_character_placement gurmukhi_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1},{6,1,-1}};
+
+    /* Gujarati */
+    static const WCHAR test_gujarati[] =
+        {0x0a97, 0x0ac1, 0x0a9c, 0x0ab0, 0x0abe, 0x0aa4, 0x0ac0};
+    static const struct expected_character_placement gujarati_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1},{6,1,-1}};
+
+    /* Oriya */
+    static const WCHAR test_oriya[] =
+        {0x0b13, 0x0b21, 0x0b3c, 0x0b3f, 0x0b06};
+    static const struct expected_character_placement oriya_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{2,1,2},{3,1,3}};
+
+    /* Tamil */
+    static const WCHAR test_tamil[] =
+        {0x0ba4, 0x0bae, 0x0bbf, 0x0bb4, 0x0bcd};
+    static const struct expected_character_placement tamil_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{3,1,3},{3,1,3}};
+
+    /* Malayalam */
+    static const WCHAR test_malayalam[] =
+        {0x0d2e, 0x0d32, 0x0d2f, 0x0d3e, 0x0d33, 0x0d02};
+    static const struct expected_character_placement malayalam_expected[] =
+        {{0,1,-1},{1,1,-1},{2,1,-1},{3,1,-1},{4,1,-1},{5,1,-1}};
+
+    /* Kannada */
+    static const WCHAR test_kannada[] =
+        {0x0c95, 0x0ca8, 0x0ccd, 0x0ca8, 0x0ca1};
+    static const struct expected_character_placement kannada_expected[] =
+        {{0,1,0},{1,1,1},{2,1,2},{2,1,2},{3,1,3}};
+
+    HFONT hfont, hfont_orig;
     GCP_RESULTSA result;
     DWORD size, size2;
     WCHAR glyphs[20];
-    int pos[20];
+    int test_valid, pos[20];
     HDC hdc;
 
     hdc = CreateCompatibleDC(0);
@@ -4947,6 +5245,150 @@ static void test_GetCharacterPlacement(void)
     ok(glyphs[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs, 1));
     todo_wine ok(pos[0] == 0, "Unexpected caret position %d\n", pos[0]);
 
+    test_valid = find_font_for_range(hdc, "Tahoma", 0, test1[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test1, 4, t1_expected, ARRAY_SIZE(t1_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Tahoma", 0, test2[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test2, 4, t2_expected, ARRAY_SIZE(t2_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Calibri", 0, test3[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test3, 6, t3_expected, ARRAY_SIZE(t3_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 11, test_hebrew[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_hebrew, 4, hebrew_expected, ARRAY_SIZE(hebrew_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 13, test_arabic[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_arabic, 4, arabic_expected, ARRAY_SIZE(arabic_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 24, test_thai[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_thai, 10, thai_expected, ARRAY_SIZE(thai_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "MV Boli", 72, test_thaana[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_thaana, 13, thaana_expected, ARRAY_SIZE(thaana_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Microsoft PhagsPa", 53, test_phagspa[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_phagspa, 11, phagspa_expected, ARRAY_SIZE(phagspa_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "DokChampa", 25, test_lao[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_lao, 9, lao_expected, ARRAY_SIZE(lao_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Microsoft Himalaya", 70, test_tibetan[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_tibetan, 17, tibetan_expected, ARRAY_SIZE(tibetan_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Mangal", 15, test_devanagari[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_devanagari, 8, devanagari_expected, ARRAY_SIZE(devanagari_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Vrinda", 16, test_bengali[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_bengali, 5, bengali_expected, ARRAY_SIZE(bengali_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Raavi", 17, test_gurmukhi[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_gurmukhi, 7, gurmukhi_expected, ARRAY_SIZE(gurmukhi_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Shruti", 18, test_gujarati[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_gujarati, 7, gujarati_expected, ARRAY_SIZE(gujarati_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Kalinga", 19, test_oriya[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_oriya, 5, oriya_expected, ARRAY_SIZE(oriya_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Latha", 20, test_tamil[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_tamil, 5, tamil_expected, ARRAY_SIZE(tamil_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Kartika", 23, test_malayalam[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_malayalam, 6, malayalam_expected, ARRAY_SIZE(malayalam_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
+    test_valid = find_font_for_range(hdc, "Tunga", 22, test_kannada[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_character_placement_ok(test_valid, hdc, test_kannada, 5, kannada_expected, ARRAY_SIZE(kannada_expected));
+        SelectObject(hdc, hfont_orig);
+        DeleteObject(hfont);
+    }
+
     DeleteDC(hdc);
 }
 
-- 
2.25.1




More information about the wine-devel mailing list