[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