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

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Aric Stewart <aric@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2017-02-13 22:57:13 +01:00 committed by Alexandre Julliard
parent ca8f056da1
commit 721fbf617b
2 changed files with 81 additions and 36 deletions

View File

@ -1614,7 +1614,7 @@ static void test_ScriptShape(HDC hdc)
SCRIPT_CACHE sc = NULL; SCRIPT_CACHE sc = NULL;
WORD glyphs[4], glyphs2[4], logclust[4], glyphs3[4]; WORD glyphs[4], glyphs2[4], logclust[4], glyphs3[4];
SCRIPT_VISATTR attrs[4]; SCRIPT_VISATTR attrs[4];
SCRIPT_ITEM items[2]; SCRIPT_ITEM items[4];
int nb, i, j; int nb, i, j;
hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL); 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++) for (i = 0; i < 2; i++)
{ {
static const WCHAR space[] = {' ', 0}; static const WCHAR space[] = {' ', 0};
static const WCHAR blanks[] = {'\t', '\r', '\n', 0x001c, 0x001d, 0x001e, 0x001f, static const struct
0x200b, 0x200c, 0x200d, 0x200e, 0x200f, /* ZWSP, ZWNJ, ZWJ, LRM, RLM */ {
0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0}; /* LRE, RLE, PDF, LRO, RLO */ 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; HFONT font, oldfont = NULL;
LOGFONTA lf; 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(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); 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); WCHAR c = test_data[j].c;
ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr); SCRIPT_ITEM *item;
ok(!items[0].a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n", chars[1] = c;
lf.lfFaceName, blanks[j], items[0].a.fNoGlyphIndex); hr = ScriptItemize(chars, 3, 4, NULL, NULL, items, &nb);
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, c, hr);
ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr); todo_wine_if(c == 0x200b) ok(nb == test_data[j].item_count, "%s: [%02x] Got unexpected item count %d.\n",
ok(nb == 1, "%s: [%02x] expected 1, got %d\n", lf.lfFaceName, blanks[j], nb); lf.lfFaceName, c, nb);
ok(!items[0].a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n", item = &items[test_data[j].item];
lf.lfFaceName, blanks[j], items[0].a.fNoGlyphIndex);
ok(glyphs[0] == glyphs2[0] || ok(!item->a.fNoGlyphIndex, "%s: [%02x] got unexpected fNoGlyphIndex %#x.\n",
broken(glyphs2[0] == blanks[j] && (blanks[j] < 0x10)), lf.lfFaceName, c, item->a.fNoGlyphIndex);
"%s: [%02x] expected %04x, got %04x\n", lf.lfFaceName, blanks[j], glyphs[0], glyphs2[0]); hr = ScriptShape(hdc, &sc, chars, 3, 3, &item->a, glyphs2, logclust, attrs, &nb);
ok(attrs[0].fZeroWidth || broken(!attrs[0].fZeroWidth && (blanks[j] < 0x10) /* Vista */), ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, c, hr);
"%s: [%02x] got unexpected fZeroWidth %#x.\n", lf.lfFaceName, blanks[j], attrs[0].fZeroWidth); 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);
items[0].a.fNoGlyphIndex = 1; ok(glyphs[0] == glyphs2[1] ||
hr = ScriptShape(hdc, &sc, &blanks[j], 1, 1, &items[0].a, glyphs2, logclust, attrs, &nb); broken(glyphs2[1] == c && (c < 0x10)),
ok(hr == S_OK, "%s: [%02x] expected S_OK, got %08x\n", lf.lfFaceName, blanks[j], hr); "%s: [%02x] expected %04x, got %04x\n", lf.lfFaceName, c, glyphs[0], glyphs2[1]);
ok(nb == 1, "%s: [%02x] expected 1, got %d\n", lf.lfFaceName, blanks[j], nb); ok(attrs[1].fZeroWidth || broken(!attrs[1].fZeroWidth && (c < 0x10) /* Vista */),
"%s: [%02x] got unexpected fZeroWidth %#x.\n", lf.lfFaceName, c, attrs[1].fZeroWidth);
if (blanks[j] == 0x200b || blanks[j] == 0x200c || blanks[j] == 0x200d) 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, ok(glyphs2[1] == 0x0020,
"%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, blanks[j], glyphs2[0]); "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, c, glyphs2[1]);
ok(attrs[0].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n", ok(attrs[1].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
lf.lfFaceName, blanks[j], attrs[0].fZeroWidth); lf.lfFaceName, c, attrs[1].fZeroWidth);
} }
else else
{ {
ok(glyphs2[0] == blanks[j], ok(glyphs2[1] == c,
"%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, blanks[j], glyphs2[0]); "%s: [%02x] got unexpected %04x.\n", lf.lfFaceName, c, glyphs2[1]);
ok(!attrs[0].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n", ok(!attrs[1].fZeroWidth, "%s: [%02x] got unexpected fZeroWidth %#x.\n",
lf.lfFaceName, blanks[j], attrs[0].fZeroWidth); lf.lfFaceName, c, attrs[1].fZeroWidth);
} }
} }
if (oldfont) if (oldfont)

View File

@ -3123,9 +3123,6 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
chInput = mirror_char(pwcChars[idx]); chInput = mirror_char(pwcChars[idx]);
else else
chInput = pwcChars[idx]; chInput = pwcChars[idx];
/* special case for tabs */
if (chInput == 0x0009)
chInput = 0x0020;
rChars[i] = chInput; rChars[i] = chInput;
} }
else 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_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, 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); 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); heap_free(rChars);
} }
else else
@ -3189,7 +3200,8 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
pOutGlyphProps[i].sva.fZeroWidth = 1; 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 || if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C) pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)