[PATCH 1/2] usp10: Explicitly check for zero-width control characters in ScriptShapeOpenType().

Aric Stewart aric at codeweavers.com
Wed Feb 15 14:39:16 CST 2017


Signed-off-by: Aric Stewart <aric at codeweavers.com>

On 2/13/17 3:57 PM, Henri Verbeet wrote:
> Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
> ---
>  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-patches mailing list