Henri Verbeet : usp10: Explicitly check for zero-width control characters in ScriptShapeOpenType ().

Alexandre Julliard julliard at winehq.org
Wed Feb 15 16:06:24 CST 2017


Module: wine
Branch: master
Commit: 721fbf617b06d2ac3ab44ca7074ca9b0862d6426
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=721fbf617b06d2ac3ab44ca7074ca9b0862d6426

Author: Henri Verbeet <hverbeet at codeweavers.com>
Date:   Mon Feb 13 22:57:13 2017 +0100

usp10: Explicitly check for zero-width control characters in ScriptShapeOpenType().

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/usp10/tests/usp10.c | 105 +++++++++++++++++++++++++++++++----------------
 dlls/usp10/usp10.c       |  20 +++++++--
 2 files changed, 85 insertions(+), 40 deletions(-)

diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c
index b6fc038..2e87d3c 100644
--- a/dlls/usp10/tests/usp10.c
+++ b/dlls/usp10/tests/usp10.c
@@ -1614,7 +1614,7 @@ static void test_ScriptShape(HDC hdc)
     SCRIPT_CACHE sc = NULL;
     WORD glyphs[4], glyphs2[4], logclust[4], glyphs3[4];
     SCRIPT_VISATTR attrs[4];
-    SCRIPT_ITEM items[2];
+    SCRIPT_ITEM items[4];
     int nb, i, j;
 
     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
@@ -1744,9 +1744,33 @@ static void test_ScriptShape(HDC hdc)
     for (i = 0; i < 2; i++)
     {
         static const WCHAR space[]  = {' ', 0};
-        static const WCHAR blanks[] = {'\t', '\r', '\n', 0x001c, 0x001d, 0x001e, 0x001f,
-                                       0x200b, 0x200c, 0x200d, 0x200e, 0x200f,          /* ZWSP, ZWNJ, ZWJ, LRM, RLM */
-                                       0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0};      /* LRE, RLE, PDF, LRO, RLO */
+        static const struct
+        {
+            WCHAR c;
+            unsigned int item_count;
+            unsigned int item;
+        }
+        test_data[] =
+        {
+            {0x0009, 3, 1}, /* \t   */
+            {0x000a, 3, 1}, /* \n   */
+            {0x000d, 3, 1}, /* \r   */
+            {0x001c, 3, 1}, /* FS   */
+            {0x001d, 3, 1}, /* GS   */
+            {0x001e, 3, 1}, /* RS   */
+            {0x001f, 3, 1}, /* US   */
+            {0x200b, 1, 0}, /* ZWSP */
+            {0x200c, 1, 0}, /* ZWNJ */
+            {0x200d, 1, 0}, /* ZWJ  */
+            {0x200e, 3, 1}, /* LRM  */
+            {0x200f, 3, 1}, /* RLM  */
+            {0x202a, 3, 1}, /* LRE  */
+            {0x202b, 3, 1}, /* RLE  */
+            {0x202c, 3, 1}, /* PDF  */
+            {0x202d, 3, 1}, /* LRO  */
+            {0x202e, 3, 1}, /* RLO  */
+        };
+        WCHAR chars[3];
         HFONT font, oldfont = NULL;
         LOGFONTA lf;
 
@@ -1765,43 +1789,52 @@ static void test_ScriptShape(HDC hdc)
         ok(hr == S_OK, "%s: expected S_OK, got %08x\n", lf.lfFaceName, hr);
         ok(nb == 1, "%s: expected 1, got %d\n", lf.lfFaceName, nb);
 
-        for (j = 0; blanks[j]; j++)
+        chars[0] = 'A';
+        chars[2] = 'A';
+        for (j = 0; j < sizeof(test_data) / sizeof(*test_data); ++j)
         {
-            hr = ScriptItemize(&blanks[j], 1, 2, NULL, NULL, items, NULL);
-            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr);
-
-            ok(!items[0].a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n",
-               lf.lfFaceName, blanks[j], items[0].a.fNoGlyphIndex);
-            hr = ScriptShape(hdc, &sc, &blanks[j], 1, 1, &items[0].a, glyphs2, logclust, attrs, &nb);
-            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr);
-            ok(nb == 1, "%s: [%02x] expected 1, got %d\n", lf.lfFaceName, blanks[j], nb);
-            ok(!items[0].a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n",
-               lf.lfFaceName, blanks[j], items[0].a.fNoGlyphIndex);
-
-            ok(glyphs[0] == glyphs2[0] ||
-               broken(glyphs2[0] == blanks[j] && (blanks[j] < 0x10)),
-               "%s: [%02x] expected %04x, got %04x\n", lf.lfFaceName, blanks[j], glyphs[0], glyphs2[0]);
-            ok(attrs[0].fZeroWidth || broken(!attrs[0].fZeroWidth && (blanks[j] < 0x10) /* Vista */),
-               "%s: [%02x] got unexpected fZeroWidth %#x.\n", lf.lfFaceName, blanks[j], attrs[0].fZeroWidth);
-
-            items[0].a.fNoGlyphIndex = 1;
-            hr = ScriptShape(hdc, &sc, &blanks[j], 1, 1, &items[0].a, glyphs2, logclust, attrs, &nb);
-            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr);
-            ok(nb == 1, "%s: [%02x] expected 1, got %d\n", lf.lfFaceName, blanks[j], nb);
-
-            if (blanks[j] == 0x200b || blanks[j] == 0x200c || blanks[j] == 0x200d)
+            WCHAR c = test_data[j].c;
+            SCRIPT_ITEM *item;
+
+            chars[1] = c;
+            hr = ScriptItemize(chars, 3, 4, NULL, NULL, items, &nb);
+            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, c, hr);
+            todo_wine_if(c == 0x200b) ok(nb == test_data[j].item_count, "%s: [%02x] Got unexpected item count %d.\n",
+               lf.lfFaceName, c, nb);
+            item = &items[test_data[j].item];
+
+            ok(!item->a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n",
+               lf.lfFaceName, c, item->a.fNoGlyphIndex);
+            hr = ScriptShape(hdc, &sc, chars, 3, 3, &item->a, glyphs2, logclust, attrs, &nb);
+            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, c, hr);
+            ok(nb == 3, "%s: [%02x] expected 3, got %d\n", lf.lfFaceName, c, nb);
+            ok(!item->a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n",
+               lf.lfFaceName, c, item->a.fNoGlyphIndex);
+
+            ok(glyphs[0] == glyphs2[1] ||
+               broken(glyphs2[1] == c && (c < 0x10)),
+               "%s: [%02x] expected %04x, got %04x\n", lf.lfFaceName, c, glyphs[0], glyphs2[1]);
+            ok(attrs[1].fZeroWidth || broken(!attrs[1].fZeroWidth && (c < 0x10) /* Vista */),
+               "%s: [%02x] got unexpected fZeroWidth %#x.\n", lf.lfFaceName, c, attrs[1].fZeroWidth);
+
+            item->a.fNoGlyphIndex = 1;
+            hr = ScriptShape(hdc, &sc, chars, 3, 3, &item->a, glyphs2, logclust, attrs, &nb);
+            ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, c, hr);
+            ok(nb == 3, "%s: [%02x] expected 1, got %d\n", lf.lfFaceName, c, nb);
+
+            if (c == 0x200b || c == 0x200c || c == 0x200d)
             {
-                ok(glyphs2[0] == 0x0020,
-                   "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, blanks[j], glyphs2[0]);
-                ok(attrs[0].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
-                   lf.lfFaceName, blanks[j], attrs[0].fZeroWidth);
+                ok(glyphs2[1] == 0x0020,
+                   "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, c, glyphs2[1]);
+                ok(attrs[1].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
+                   lf.lfFaceName, c, attrs[1].fZeroWidth);
             }
             else
             {
-                ok(glyphs2[0] == blanks[j],
-                   "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, blanks[j], glyphs2[0]);
-                ok(!attrs[0].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
-                   lf.lfFaceName, blanks[j], attrs[0].fZeroWidth);
+                ok(glyphs2[1] == c,
+                   "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, c, glyphs2[1]);
+                ok(!attrs[1].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
+                   lf.lfFaceName, c, attrs[1].fZeroWidth);
             }
         }
         if (oldfont)
diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c
index 0471fc6..221aab4 100644
--- a/dlls/usp10/usp10.c
+++ b/dlls/usp10/usp10.c
@@ -3123,9 +3123,6 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
                         chInput = mirror_char(pwcChars[idx]);
                     else
                         chInput = pwcChars[idx];
-                    /* special case for tabs */
-                    if (chInput == 0x0009)
-                        chInput = 0x0020;
                     rChars[i] = chInput;
                 }
                 else
@@ -3165,6 +3162,20 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
+
+        for (i = 0; i < cChars; ++i)
+        {
+            /* Special case for tabs and joiners. As control characters, ZWNJ
+             * and ZWJ would in principle get handled by the corresponding
+             * shaping functions. However, since ZWNJ and ZWJ can get merged
+             * into adjoining runs during itemisation, these don't generally
+             * get classified as Script_Control. */
+            if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
+            {
+                pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
+                pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
+            }
+        }
         heap_free(rChars);
     }
     else
@@ -3189,7 +3200,8 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
                     pOutGlyphProps[i].sva.fZeroWidth = 1;
                 }
             }
-            else if (psa->eScript == Script_Control)
+            else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
+                    || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
             {
                 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
                     pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)




More information about the wine-cvs mailing list