[USP10_WINETEST] Sync with Wine Staging 2.9. CORE-13362
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 01:47:02 +0000 (01:47 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 01:47:02 +0000 (01:47 +0000)
svn path=/trunk/; revision=74852

rostests/winetests/usp10/usp10.c

index 3ee82e4..7a6bf56 100644 (file)
@@ -144,6 +144,7 @@ static inline void _test_items_ok(LPCWSTR string, DWORD cchString,
 #define thai_tag MS_MAKE_TAG('t','h','a','i')
 #define hebr_tag MS_MAKE_TAG('h','e','b','r')
 #define syrc_tag MS_MAKE_TAG('s','y','r','c')
 #define thai_tag MS_MAKE_TAG('t','h','a','i')
 #define hebr_tag MS_MAKE_TAG('h','e','b','r')
 #define syrc_tag MS_MAKE_TAG('s','y','r','c')
+#define thaa_tag MS_MAKE_TAG('t','h','a','a')
 #define deva_tag MS_MAKE_TAG('d','e','v','a')
 #define beng_tag MS_MAKE_TAG('b','e','n','g')
 #define guru_tag MS_MAKE_TAG('g','u','r','u')
 #define deva_tag MS_MAKE_TAG('d','e','v','a')
 #define beng_tag MS_MAKE_TAG('b','e','n','g')
 #define guru_tag MS_MAKE_TAG('g','u','r','u')
@@ -937,16 +938,22 @@ static inline void _test_shape_ok(int valid, HDC hdc, LPCWSTR string,
                          const SCRIPT_GLYPHPROP *props2)
 {
     HRESULT hr;
                          const SCRIPT_GLYPHPROP *props2)
 {
     HRESULT hr;
-    int x, outnItems=0, outnGlyphs=0;
+    int x, outnItems = 0, outnGlyphs = 0, outnGlyphs2 = 0;
+    const SCRIPT_PROPERTIES **script_properties;
     SCRIPT_ITEM outpItems[15];
     SCRIPT_CACHE sc = NULL;
     SCRIPT_ITEM outpItems[15];
     SCRIPT_CACHE sc = NULL;
-    WORD *glyphs;
-    WORD *logclust;
+    WORD *glyphs, *glyphs2;
+    WORD *logclust, *logclust2;
     int maxGlyphs = cchString * 1.5;
     int maxGlyphs = cchString * 1.5;
-    SCRIPT_GLYPHPROP *glyphProp;
-    SCRIPT_CHARPROP  *charProp;
+    SCRIPT_GLYPHPROP *glyphProp, *glyphProp2;
+    SCRIPT_CHARPROP  *charProp, *charProp2;
+    int script_count;
+    WCHAR *string2;
     ULONG tags[15];
 
     ULONG tags[15];
 
+    hr = ScriptGetProperties(&script_properties, &script_count);
+    winetest_ok(SUCCEEDED(hr), "Failed to get script properties, hr %#x.\n", hr);
+
     hr = pScriptItemizeOpenType(string, cchString, 15, Control, State, outpItems, tags, &outnItems);
     if (hr == USP_E_SCRIPT_NOT_IN_FONT)
     {
     hr = pScriptItemizeOpenType(string, cchString, 15, Control, State, outpItems, tags, &outnItems);
     if (hr == USP_E_SCRIPT_NOT_IN_FONT)
     {
@@ -979,6 +986,18 @@ static inline void _test_shape_ok(int valid, HDC hdc, LPCWSTR string,
     glyphProp = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_GLYPHPROP) * maxGlyphs);
     memset(glyphProp,'a',sizeof(SCRIPT_GLYPHPROP) * cchString);
 
     glyphProp = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_GLYPHPROP) * maxGlyphs);
     memset(glyphProp,'a',sizeof(SCRIPT_GLYPHPROP) * cchString);
 
+    string2 = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(*string2));
+    logclust2 = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(*logclust2));
+    memset(logclust2, 'a', cchString * sizeof(*logclust2));
+    charProp2 = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(*charProp2));
+    memset(charProp2, 'a', cchString * sizeof(*charProp2));
+    glyphs2 = HeapAlloc(GetProcessHeap(), 0, maxGlyphs * sizeof(*glyphs2));
+    memset(glyphs2, 'a', maxGlyphs * sizeof(*glyphs2));
+    glyphProp2 = HeapAlloc(GetProcessHeap(), 0, maxGlyphs * sizeof(*glyphProp2));
+    memset(glyphProp2, 'a', maxGlyphs * sizeof(*glyphProp2));
+
+    winetest_ok(!outpItems[item].a.fLogicalOrder, "Got unexpected fLogicalOrder %#x.\n",
+            outpItems[item].a.fLogicalOrder);
     hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0, string, cchString, maxGlyphs, logclust, charProp, glyphs, glyphProp, &outnGlyphs);
     if (valid > 0)
         winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
     hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0, string, cchString, maxGlyphs, logclust, charProp, glyphs, glyphProp, &outnGlyphs);
     if (valid > 0)
         winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
@@ -1020,11 +1039,16 @@ static inline void _test_shape_ok(int valid, HDC hdc, LPCWSTR string,
                 winetest_trace("%i: Glyph present when it should not be\n",x);
         }
         if (valid > 0)
                 winetest_trace("%i: Glyph present when it should not be\n",x);
         }
         if (valid > 0)
-            winetest_ok(glyphProp[x].sva.uJustification == glyphItems[x].GlyphProp.sva.uJustification ||
-                        (props2 && glyphProp[x].sva.uJustification == props2[x].sva.uJustification),
-                         "%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
+        {
+            todo_wine_if(tags[item] == syrc_tag && !x)
+                winetest_ok(glyphProp[x].sva.uJustification == glyphItems[x].GlyphProp.sva.uJustification ||
+                            (props2 && glyphProp[x].sva.uJustification == props2[x].sva.uJustification),
+                             "%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
+        }
         else if (glyphProp[x].sva.uJustification != glyphItems[x].GlyphProp.sva.uJustification)
         else if (glyphProp[x].sva.uJustification != glyphItems[x].GlyphProp.sva.uJustification)
+        {
             winetest_trace("%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
             winetest_trace("%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
+        }
         if (valid > 0)
             winetest_ok(glyphProp[x].sva.fClusterStart == glyphItems[x].GlyphProp.sva.fClusterStart ||
                         (props2 && glyphProp[x].sva.fClusterStart == props2[x].sva.fClusterStart),
         if (valid > 0)
             winetest_ok(glyphProp[x].sva.fClusterStart == glyphItems[x].GlyphProp.sva.fClusterStart ||
                         (props2 && glyphProp[x].sva.fClusterStart == props2[x].sva.fClusterStart),
@@ -1045,7 +1069,132 @@ static inline void _test_shape_ok(int valid, HDC hdc, LPCWSTR string,
             winetest_trace("%i: fZeroWidth incorrect (%i)\n",x,glyphProp[x].sva.fZeroWidth);
     }
 
             winetest_trace("%i: fZeroWidth incorrect (%i)\n",x,glyphProp[x].sva.fZeroWidth);
     }
 
+    outpItems[item].a.fLogicalOrder = 1;
+    hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0,
+            string, cchString, maxGlyphs, logclust2, charProp2, glyphs2, glyphProp2, &outnGlyphs2);
+    winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
+    /* Cluster maps are hard. */
+    if (tags[item] != thaa_tag && tags[item] != syrc_tag)
+    {
+        for (x = 0; x < cchString; ++x)
+        {
+            unsigned int compare_idx = outpItems[item].a.fRTL ? cchString - x - 1 : x;
+            winetest_ok(logclust2[x] == logclust[compare_idx],
+                    "Got unexpected logclust2[%u] %#x, expected %#x.\n",
+                    x, logclust2[x], logclust[compare_idx]);
+            winetest_ok(charProp2[x].fCanGlyphAlone == charProp[compare_idx].fCanGlyphAlone,
+                    "Got unexpected charProp2[%u].fCanGlyphAlone %#x, expected %#x.\n",
+                    x, charProp2[x].fCanGlyphAlone, charProp[compare_idx].fCanGlyphAlone);
+        }
+    }
+    winetest_ok(outnGlyphs2 == outnGlyphs, "Got unexpected glyph count %u.\n", outnGlyphs2);
+    for (x = 0; x < outnGlyphs2; ++x)
+    {
+        unsigned int compare_idx = outpItems[item].a.fRTL ? outnGlyphs2 - x - 1 : x;
+        winetest_ok(glyphs2[x] == glyphs[compare_idx], "Got unexpected glyphs2[%u] %#x, expected %#x.\n",
+                x, glyphs2[x], glyphs[compare_idx]);
+        winetest_ok(glyphProp2[x].sva.uJustification == glyphProp[compare_idx].sva.uJustification,
+                "Got unexpected glyphProp2[%u].sva.uJustification %#x, expected %#x.\n",
+                x, glyphProp2[x].sva.uJustification, glyphProp[compare_idx].sva.uJustification);
+        winetest_ok(glyphProp2[x].sva.fClusterStart == glyphProp[compare_idx].sva.fClusterStart,
+                "Got unexpected glyphProp2[%u].sva.fClusterStart %#x, expected %#x.\n",
+                x, glyphProp2[x].sva.fClusterStart, glyphProp[compare_idx].sva.fClusterStart);
+        winetest_ok(glyphProp2[x].sva.fDiacritic == glyphProp[compare_idx].sva.fDiacritic,
+                "Got unexpected glyphProp2[%u].sva.fDiacritic %#x, expected %#x.\n",
+                x, glyphProp2[x].sva.fDiacritic, glyphProp[compare_idx].sva.fDiacritic);
+        winetest_ok(glyphProp2[x].sva.fZeroWidth == glyphProp[compare_idx].sva.fZeroWidth,
+                "Got unexpected glyphProp2[%u].sva.fZeroWidth %#x, expected %#x.\n",
+                x, glyphProp2[x].sva.fZeroWidth, glyphProp[compare_idx].sva.fZeroWidth);
+    }
+
+    /* Most scripts get this wrong. For example, when the font has the
+     * appropriate ligatures, "ttfffi" get rendered as "<ttf><ffi>", but
+     * "<RLO>iffftt" gets rendered as "t<ft><ff>i". Arabic gets it right,
+     * and there exist applications that depend on that. */
+    if (tags[item] == arab_tag && broken(script_count <= 75))
+    {
+        winetest_win_skip("Test broken on this platform, skipping.\n");
+    }
+    else if (tags[item] == arab_tag)
+    {
+        for (x = 0; x < cchString; ++x)
+        {
+            string2[x] = string[cchString - x - 1];
+        }
+        outpItems[item].a.fLogicalOrder = 0;
+        outpItems[item].a.fRTL = !outpItems[item].a.fRTL;
+        hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0,
+                string2, cchString, maxGlyphs, logclust2, charProp2, glyphs2, glyphProp2, &outnGlyphs2);
+        winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
+        for (x = 0; x < cchString; ++x)
+        {
+            unsigned int compare_idx = cchString - x - 1;
+            winetest_ok(logclust2[x] == logclust[compare_idx],
+                    "Got unexpected logclust2[%u] %#x, expected %#x.\n",
+                    x, logclust2[x], logclust[compare_idx]);
+            winetest_ok(charProp2[x].fCanGlyphAlone == charProp[compare_idx].fCanGlyphAlone,
+                    "Got unexpected charProp2[%u].fCanGlyphAlone %#x, expected %#x.\n",
+                    x, charProp2[x].fCanGlyphAlone, charProp[compare_idx].fCanGlyphAlone);
+        }
+        winetest_ok(outnGlyphs2 == outnGlyphs, "Got unexpected glyph count %u.\n", outnGlyphs2);
+        for (x = 0; x < outnGlyphs2; ++x)
+        {
+            winetest_ok(glyphs2[x] == glyphs[x], "Got unexpected glyphs2[%u] %#x, expected %#x.\n",
+                    x, glyphs2[x], glyphs[x]);
+            winetest_ok(glyphProp2[x].sva.uJustification == glyphProp[x].sva.uJustification,
+                    "Got unexpected glyphProp2[%u].sva.uJustification %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.uJustification, glyphProp[x].sva.uJustification);
+            winetest_ok(glyphProp2[x].sva.fClusterStart == glyphProp[x].sva.fClusterStart,
+                    "Got unexpected glyphProp2[%u].sva.fClusterStart %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fClusterStart, glyphProp[x].sva.fClusterStart);
+            winetest_ok(glyphProp2[x].sva.fDiacritic == glyphProp[x].sva.fDiacritic,
+                    "Got unexpected glyphProp2[%u].sva.fDiacritic %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fDiacritic, glyphProp[x].sva.fDiacritic);
+            winetest_ok(glyphProp2[x].sva.fZeroWidth == glyphProp[x].sva.fZeroWidth,
+                    "Got unexpected glyphProp2[%u].sva.fZeroWidth %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fZeroWidth, glyphProp[x].sva.fZeroWidth);
+        }
+        outpItems[item].a.fLogicalOrder = 1;
+        hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0,
+                string2, cchString, maxGlyphs, logclust2, charProp2, glyphs2, glyphProp2, &outnGlyphs2);
+        winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
+        for (x = 0; x < cchString; ++x)
+        {
+            unsigned int compare_idx = outpItems[item].a.fRTL ? x : cchString - x - 1;
+            winetest_ok(logclust2[x] == logclust[compare_idx], "Got unexpected logclust2[%u] %#x, expected %#x.\n",
+                    x, logclust2[x], logclust[compare_idx]);
+            winetest_ok(charProp2[x].fCanGlyphAlone == charProp[compare_idx].fCanGlyphAlone,
+                    "Got unexpected charProp2[%u].fCanGlyphAlone %#x, expected %#x.\n",
+                    x, charProp2[x].fCanGlyphAlone, charProp[compare_idx].fCanGlyphAlone);
+        }
+        winetest_ok(outnGlyphs2 == outnGlyphs, "Got unexpected glyph count %u.\n", outnGlyphs2);
+        for (x = 0; x < outnGlyphs2; ++x)
+        {
+            unsigned int compare_idx = outpItems[item].a.fRTL ? outnGlyphs2 - x - 1 : x;
+            winetest_ok(glyphs2[x] == glyphs[compare_idx], "Got unexpected glyphs2[%u] %#x, expected %#x.\n",
+                    x, glyphs2[x], glyphs[compare_idx]);
+            winetest_ok(glyphProp2[x].sva.uJustification == glyphProp[compare_idx].sva.uJustification,
+                    "Got unexpected glyphProp2[%u].sva.uJustification %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.uJustification, glyphProp[compare_idx].sva.uJustification);
+            winetest_ok(glyphProp2[x].sva.fClusterStart == glyphProp[compare_idx].sva.fClusterStart,
+                    "Got unexpected glyphProp2[%u].sva.fClusterStart %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fClusterStart, glyphProp[compare_idx].sva.fClusterStart);
+            winetest_ok(glyphProp2[x].sva.fDiacritic == glyphProp[compare_idx].sva.fDiacritic,
+                    "Got unexpected glyphProp2[%u].sva.fDiacritic %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fDiacritic, glyphProp[compare_idx].sva.fDiacritic);
+            winetest_ok(glyphProp2[x].sva.fZeroWidth == glyphProp[compare_idx].sva.fZeroWidth,
+                    "Got unexpected glyphProp2[%u].sva.fZeroWidth %#x, expected %#x.\n",
+                    x, glyphProp2[x].sva.fZeroWidth, glyphProp[compare_idx].sva.fZeroWidth);
+        }
+    }
+
 cleanup:
 cleanup:
+    HeapFree(GetProcessHeap(),0,string2);
+    HeapFree(GetProcessHeap(),0,logclust2);
+    HeapFree(GetProcessHeap(),0,charProp2);
+    HeapFree(GetProcessHeap(),0,glyphs2);
+    HeapFree(GetProcessHeap(),0,glyphProp2);
+
     HeapFree(GetProcessHeap(),0,logclust);
     HeapFree(GetProcessHeap(),0,charProp);
     HeapFree(GetProcessHeap(),0,glyphs);
     HeapFree(GetProcessHeap(),0,logclust);
     HeapFree(GetProcessHeap(),0,charProp);
     HeapFree(GetProcessHeap(),0,glyphs);
@@ -1118,6 +1267,8 @@ static int _find_font_for_range(HDC hdc, const CHAR *recommended, BYTE range, co
                 rc = 1;
             }
         }
                 rc = 1;
             }
         }
+        if (!rc)
+            winetest_skip("Font %s is not available.\n", recommended);
     }
 
     if (!*hfont)
     }
 
     if (!*hfont)
@@ -1188,6 +1339,13 @@ static void test_ScriptShapeOpenType(HDC hdc)
                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
                             {0,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}} };
 
                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
                             {0,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}} };
 
+    static const WCHAR test3[] = {'t', 't', 'f', 'f', 'f', 'i', 0};
+    static const shapeTest_char t3_c[] = {{0, {0, 0}}, {0, {0, 0}}, {0, {0, 0}},
+            {1, {0, 0}}, {1, {0, 0}}, {1, {0, 0}}};
+    static const shapeTest_glyph t3_g[] = {
+                            {1, {{SCRIPT_JUSTIFY_CHARACTER, 1, 0, 0, 0, 0}, 0}},
+                            {1, {{SCRIPT_JUSTIFY_CHARACTER, 1, 0, 0, 0, 0}, 0}}};
+
     /* Hebrew */
     static const WCHAR test_hebrew[]  = {0x05e9, 0x05dc, 0x05d5, 0x05dd,0};
     static const shapeTest_char hebrew_c[] = {{3,{0,0}},{2,{0,0}},{1,{0,0}},{0,{0,0}}};
     /* Hebrew */
     static const WCHAR test_hebrew[]  = {0x05e9, 0x05dc, 0x05d5, 0x05dd,0};
     static const shapeTest_char hebrew_c[] = {{3,{0,0}},{2,{0,0}},{1,{0,0}},{0,{0,0}}};
@@ -1221,12 +1379,14 @@ static void test_ScriptShapeOpenType(HDC hdc)
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}}};
 
     /* Syriac */
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}}};
 
     /* Syriac */
-    static const WCHAR test_syriac[] = {0x0710, 0x0710, 0x0710, 0x0728, 0x0718, 0x0723,0};
-    static const shapeTest_char syriac_c[] = {{5,{0,0}},{4,{0,0}},{3,{0,0}},{2,{0,0}},{1,{0,0}},{0,{0,0}}};
+    static const WCHAR test_syriac[] = {0x0710, 0x072c, 0x0728, 0x0742, 0x0718, 0x0723, 0x0720, 0x0710, 0};
+    static const shapeTest_char syriac_c[] = {{6, {0, 0}}, {5, {0, 0}}, {4, {0, 0}},
+            {4, {0, 0}}, {2, {0, 0}}, {1, {0, 0}}, {0, {0, 0}}, {0, {0, 0}}};
     static const shapeTest_glyph syriac_g[] = {
     static const shapeTest_glyph syriac_g[] = {
+                            {1,{{SCRIPT_JUSTIFY_ARABIC_NORMAL,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
-                            {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
+                            {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}} };
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}} };
@@ -1470,6 +1630,14 @@ static void test_ScriptShapeOpenType(HDC hdc)
 
     test_shape_ok(hdc, test2, 4, &Control, &State, 1, 4, t2_c, glyph_test);
 
 
     test_shape_ok(hdc, test2, 4, &Control, &State, 1, 4, t2_c, glyph_test);
 
+    test_valid = find_font_for_range(hdc, "Calibri", 0, test3[0], &hfont, &hfont_orig);
+    if (hfont != NULL)
+    {
+        test_shape_ok_valid(test_valid, hdc, test3, 6, &Control, &State, 0, 2, t3_c, t3_g);
+        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_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 11, test_hebrew[0], &hfont, &hfont_orig);
     if (hfont != NULL)
     {
@@ -1497,7 +1665,7 @@ static void test_ScriptShapeOpenType(HDC hdc)
     test_valid = find_font_for_range(hdc, "Estrangelo Edessa", 71, test_syriac[0], &hfont, &hfont_orig);
     if (hfont != NULL)
     {
     test_valid = find_font_for_range(hdc, "Estrangelo Edessa", 71, test_syriac[0], &hfont, &hfont_orig);
     if (hfont != NULL)
     {
-        test_shape_ok_valid(test_valid, hdc, test_syriac, 6, &Control, &State, 0, 6, syriac_c, syriac_g);
+        test_shape_ok_valid(test_valid, hdc, test_syriac, 8, &Control, &State, 0, 7, syriac_c, syriac_g);
         SelectObject(hdc, hfont_orig);
         DeleteObject(hfont);
     }
         SelectObject(hdc, hfont_orig);
         DeleteObject(hfont);
     }
@@ -3746,6 +3914,68 @@ static void test_ScriptGetLogicalWidths(void)
     }
 }
 
     }
 }
 
+static void test_ScriptIsComplex(void)
+{
+    static const WCHAR testW[] = {0x202a,'1',0x202c,0};
+    static const WCHAR test2W[] = {'1',0};
+    static const struct complex_test
+    {
+        const WCHAR *text;
+        DWORD flags;
+        HRESULT hr;
+        BOOL todo;
+    } complex_tests[] =
+    {
+        { test2W, SIC_ASCIIDIGIT, S_OK },
+        { test2W, SIC_COMPLEX, S_FALSE },
+        { test2W, SIC_COMPLEX | SIC_ASCIIDIGIT, S_OK },
+        { testW, SIC_NEUTRAL | SIC_COMPLEX, S_OK },
+        { testW, SIC_NEUTRAL, S_FALSE, TRUE },
+        { testW, SIC_COMPLEX, S_OK },
+        { testW, 0, S_FALSE },
+    };
+    unsigned int i;
+    HRESULT hr;
+
+    hr = ScriptIsComplex(NULL, 0, 0);
+    ok(hr == E_INVALIDARG || broken(hr == S_FALSE) /* winxp/vista */, "got 0x%08x\n", hr);
+
+    if (hr == E_INVALIDARG)
+    {
+        hr = ScriptIsComplex(NULL, 1, 0);
+        ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    }
+
+    hr = ScriptIsComplex(test2W, -1, SIC_ASCIIDIGIT);
+    ok(hr == E_INVALIDARG || broken(hr == S_FALSE) /* winxp/vista */, "got 0x%08x\n", hr);
+
+    hr = ScriptIsComplex(test2W, 0, SIC_ASCIIDIGIT);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    for (i = 0; i < sizeof(complex_tests)/sizeof(complex_tests[0]); i++)
+    {
+        hr = ScriptIsComplex(complex_tests[i].text, lstrlenW(complex_tests[i].text), complex_tests[i].flags);
+    todo_wine_if(complex_tests[i].todo)
+        ok(hr == complex_tests[i].hr, "%u: got %#x, expected %#x, flags %#x\n", i, hr, complex_tests[i].hr,
+            complex_tests[i].flags);
+    }
+
+    hr = ScriptIsComplex(test2W, 1, ~0u);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = ScriptIsComplex(testW, 3, 0);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+
+    hr = ScriptIsComplex(testW, 3, SIC_NEUTRAL | SIC_COMPLEX);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = ScriptIsComplex(testW, 3, SIC_COMPLEX);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = ScriptIsComplex(test2W, 1, SIC_COMPLEX);
+    ok(hr == S_FALSE, "got 0x%08x\n", hr);
+}
+
 START_TEST(usp10)
 {
     HWND            hwnd;
 START_TEST(usp10)
 {
     HWND            hwnd;
@@ -3801,6 +4031,8 @@ START_TEST(usp10)
     test_ScriptGetFontFunctions(hdc);
     test_ScriptGetLogicalWidths();
 
     test_ScriptGetFontFunctions(hdc);
     test_ScriptGetLogicalWidths();
 
+    test_ScriptIsComplex();
+
     ReleaseDC(hwnd, hdc);
     DestroyWindow(hwnd);
 }
     ReleaseDC(hwnd, hdc);
     DestroyWindow(hwnd);
 }