dwrite: Use iterator matching for chain substitution.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-05-29 19:01:07 +03:00 committed by Alexandre Julliard
parent 4d23336882
commit a1d1647131
1 changed files with 67 additions and 38 deletions

View File

@ -3474,7 +3474,24 @@ enum iterator_match
ITER_MAYBE,
};
typedef BOOL (*p_match_func)(UINT16 glyph, UINT16 glyph_data, const void *match_data);
struct match_context;
struct match_data
{
const struct match_context *mc;
unsigned int subtable_offset;
};
typedef BOOL (*p_match_func)(UINT16 glyph, UINT16 glyph_data, const struct match_data *match_data);
struct match_context
{
struct scriptshaping_context *context;
unsigned int backtrack_offset;
unsigned int input_offset;
unsigned int lookahead_offset;
p_match_func match_func;
unsigned int mask;
};
struct glyph_iterator
{
@ -3485,7 +3502,7 @@ struct glyph_iterator
unsigned int mask;
p_match_func match_func;
const UINT16 *glyph_data;
const void *match_data;
const struct match_data *match_data;
};
static void glyph_iterator_init(struct scriptshaping_context *context, unsigned int flags, unsigned int pos,
@ -3495,7 +3512,7 @@ static void glyph_iterator_init(struct scriptshaping_context *context, unsigned
iter->flags = flags;
iter->pos = pos;
iter->len = len;
iter->mask = ~0u; /* TODO: input sequences should be using actual mask */
iter->mask = ~0u;
iter->match_func = NULL;
iter->match_data = NULL;
iter->glyph_data = NULL;
@ -3508,6 +3525,13 @@ struct ot_gdef_mark_glyph_sets
DWORD offsets[1];
};
static BOOL opentype_match_coverage_func(UINT16 glyph, UINT16 glyph_data, const struct match_data *data)
{
const struct match_context *mc = data->mc;
return opentype_layout_is_glyph_covered(&mc->context->table->table, data->subtable_offset + GET_BE_WORD(glyph_data), glyph)
!= GLYPH_NOT_COVERED;
}
static BOOL opentype_layout_mark_set_covers(const struct scriptshaping_cache *cache, unsigned int set_index,
UINT16 glyph)
{
@ -4947,32 +4971,32 @@ static BOOL opentype_layout_apply_gsub_lig_substitution(struct scriptshaping_con
return FALSE;
}
#define CHAIN_CONTEXT_MAX_LENGTH 64
#define GLYPH_CONTEXT_MAX_LENGTH 64
static BOOL opentype_layout_context_match_input(struct scriptshaping_context *context, unsigned int subtable_offset,
unsigned int count, const UINT16 *input, unsigned int *end_offset, unsigned int *match_positions)
static BOOL opentype_layout_context_match_input(const struct match_context *mc, unsigned int count, const UINT16 *input,
unsigned int *end_offset, unsigned int *match_positions)
{
struct match_data match_data = { .mc = mc, .subtable_offset = mc->input_offset };
struct scriptshaping_context *context = mc->context;
struct glyph_iterator iter;
unsigned int i;
UINT16 glyph;
if (count > CHAIN_CONTEXT_MAX_LENGTH)
if (count > GLYPH_CONTEXT_MAX_LENGTH)
return FALSE;
match_positions[0] = context->cur;
glyph_iterator_init(context, 0, context->cur, count - 1, &iter);
iter.mask = mc->mask;
iter.match_func = mc->match_func;
iter.match_data = &match_data;
iter.glyph_data = input;
for (i = 1; i < count; ++i)
{
if (!glyph_iterator_next(&iter))
return FALSE;
/* TODO: this only covers Format3 substitution */
glyph = context->u.subst.glyphs[iter.pos];
if (opentype_layout_is_glyph_covered(&context->table->table, subtable_offset + GET_BE_WORD(input[i]), glyph) == GLYPH_NOT_COVERED)
return FALSE;
match_positions[i] = iter.pos;
}
@ -4981,23 +5005,23 @@ static BOOL opentype_layout_context_match_input(struct scriptshaping_context *co
return TRUE;
}
static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context *context, unsigned int subtable_offset,
unsigned int count, const UINT16 *backtrack, unsigned int *match_start)
static BOOL opentype_layout_context_match_backtrack(const struct match_context *mc, unsigned int count,
const UINT16 *backtrack, unsigned int *match_start)
{
struct match_data match_data = { .mc = mc, .subtable_offset = mc->backtrack_offset };
struct scriptshaping_context *context = mc->context;
struct glyph_iterator iter;
unsigned int i;
UINT16 glyph;
glyph_iterator_init(context, 0, context->cur, count, &iter);
iter.match_func = mc->match_func;
iter.match_data = &match_data;
iter.glyph_data = backtrack;
for (i = 0; i < count; ++i)
{
if (!glyph_iterator_prev(&iter))
return FALSE;
glyph = context->u.subst.glyphs[iter.pos];
if (opentype_layout_is_glyph_covered(&context->table->table, subtable_offset + GET_BE_WORD(backtrack[i]), glyph) == GLYPH_NOT_COVERED)
return FALSE;
}
*match_start = iter.pos;
@ -5005,23 +5029,23 @@ static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context
return TRUE;
}
static BOOL opentype_layout_context_match_lookahead(struct scriptshaping_context *context, unsigned int subtable_offset,
unsigned int count, const UINT16 *lookahead, unsigned int offset, unsigned int *end_index)
static BOOL opentype_layout_context_match_lookahead(const struct match_context *mc, unsigned int count,
const UINT16 *lookahead, unsigned int offset, unsigned int *end_index)
{
struct match_data match_data = { .mc = mc, .subtable_offset = mc->lookahead_offset };
struct scriptshaping_context *context = mc->context;
struct glyph_iterator iter;
unsigned int i;
UINT16 glyph;
glyph_iterator_init(context, 0, context->cur + offset - 1, count, &iter);
iter.match_func = mc->match_func;
iter.match_data = &match_data;
iter.glyph_data = lookahead;
for (i = 0; i < count; ++i)
{
if (!glyph_iterator_next(&iter))
return FALSE;
glyph = context->u.subst.glyphs[iter.pos];
if (opentype_layout_is_glyph_covered(&context->table->table, subtable_offset + GET_BE_WORD(lookahead[i]), glyph) == GLYPH_NOT_COVERED)
return FALSE;
}
*end_index = iter.pos;
@ -5071,7 +5095,7 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_conte
if (delta > 0)
{
if (delta + count > CHAIN_CONTEXT_MAX_LENGTH)
if (delta + count > GLYPH_CONTEXT_MAX_LENGTH)
break;
}
else
@ -5097,22 +5121,23 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_conte
return TRUE;
}
static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping_context *context, unsigned int subtable_offset,
unsigned int backtrack_count, const UINT16 *backtrack, unsigned int input_count, const UINT16 *input,
unsigned int lookahead_count, const UINT16 *lookahead, unsigned int lookup_count, const UINT16 *lookup_records)
static BOOL opentype_layout_apply_gsub_chain_context_lookup(unsigned int backtrack_count, const UINT16 *backtrack,
unsigned int input_count, const UINT16 *input, unsigned int lookahead_count, const UINT16 *lookahead,
unsigned int lookup_count, const UINT16 *lookup_records, const struct match_context *mc)
{
unsigned int start_index = 0, match_length = 0, end_index = 0;
unsigned int match_positions[CHAIN_CONTEXT_MAX_LENGTH];
unsigned int match_positions[GLYPH_CONTEXT_MAX_LENGTH];
return opentype_layout_context_match_input(context, subtable_offset, input_count, input, &match_length, match_positions) &&
opentype_layout_context_match_backtrack(context, subtable_offset, backtrack_count, backtrack, &start_index) &&
opentype_layout_context_match_lookahead(context, subtable_offset, lookahead_count, lookahead, input_count, &end_index) &&
opentype_layout_context_gsub_apply_lookup(context, input_count, match_positions, lookup_count, lookup_records, match_length);
return opentype_layout_context_match_input(mc, input_count, input, &match_length, match_positions) &&
opentype_layout_context_match_backtrack(mc, backtrack_count, backtrack, &start_index) &&
opentype_layout_context_match_lookahead(mc, lookahead_count, lookahead, input_count, &end_index) &&
opentype_layout_context_gsub_apply_lookup(mc->context, input_count, match_positions, lookup_count, lookup_records, match_length);
}
static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context,
const struct lookup *lookup, unsigned int subtable_offset)
{
struct match_context mc = { .context = context, .mask = lookup->mask };
const struct dwrite_fonttable *table = &context->table->table;
unsigned int coverage_index = GLYPH_NOT_COVERED;
UINT16 glyph, format, coverage;
@ -5176,8 +5201,12 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
if (coverage_index == GLYPH_NOT_COVERED)
return FALSE;
ret = opentype_layout_apply_gsub_chain_context_lookup(context, subtable_offset, backtrack_count, backtrack,
input_count, input + 1, lookahead_count, lookahead, lookup_count, lookup_records);
mc.backtrack_offset = subtable_offset;
mc.input_offset = subtable_offset;
mc.lookahead_offset = subtable_offset;
mc.match_func = opentype_match_coverage_func;
ret = opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input + 1,
lookahead_count, lookahead, lookup_count, lookup_records, &mc);
}
else
WARN("Unknown chaining contextual substitution format %u.\n", format);