Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index c6cfdb6133b..8ed52d3be4d 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3167,14 +3167,15 @@ static unsigned int opentype_layout_get_glyph_class(const struct dwrite_fonttabl return glyph_class; }
-static unsigned int opentype_set_glyph_props(struct scriptshaping_context *context, unsigned int g, UINT16 glyph) +static unsigned int opentype_set_glyph_props(struct scriptshaping_context *context, unsigned int idx) { struct scriptshaping_cache *cache = context->cache; unsigned int glyph_class = 0, props;
if (cache->gdef.classdef) { - glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.classdef, glyph); + glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.classdef, + context->u.buffer.glyphs[idx]); }
switch (glyph_class) @@ -3192,16 +3193,16 @@ static unsigned int opentype_set_glyph_props(struct scriptshaping_context *conte props = 0; }
- context->glyph_infos[g].props = props; + context->glyph_infos[idx].props = props;
return props; }
-static void opentype_set_subst_glyph_props(struct scriptshaping_context *context, unsigned int g, UINT16 glyph) +static void opentype_set_subst_glyph_props(struct scriptshaping_context *context, unsigned int idx) { - unsigned int glyph_props = opentype_set_glyph_props(context, g, glyph); - context->u.subst.glyph_props[g].isDiacritic = !!(glyph_props == GLYPH_PROP_MARK); - context->u.subst.glyph_props[g].isZeroWidthSpace = !!(glyph_props == GLYPH_PROP_MARK); + unsigned int glyph_props = opentype_set_glyph_props(context, idx); + context->u.subst.glyph_props[idx].isDiacritic = !!(glyph_props == GLYPH_PROP_MARK); + context->u.subst.glyph_props[idx].isZeroWidthSpace = !!(glyph_props == GLYPH_PROP_MARK); }
struct coverage_compare_format1_context @@ -4459,7 +4460,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gpos, &lookups);
for (i = 0; i < context->glyph_count; ++i) - opentype_set_glyph_props(context, i, context->u.pos.glyphs[i]); + opentype_set_glyph_props(context, i); opentype_layout_set_glyph_masks(context, features);
for (i = 0; i < lookups.count; ++i) @@ -4491,7 +4492,7 @@ static void opentype_layout_replace_glyph(struct scriptshaping_context *context, if (glyph != orig_glyph) { context->u.subst.glyphs[context->cur] = glyph; - opentype_set_subst_glyph_props(context, context->cur, glyph); + opentype_set_subst_glyph_props(context, context->cur); } context->cur++; } @@ -4673,7 +4674,7 @@ static BOOL opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_co context->u.subst.glyph_props[idx + i].isClusterStart = 0; context->u.buffer.glyph_props[idx + i].components = 0; } - opentype_set_subst_glyph_props(context, idx + i, glyph); + opentype_set_subst_glyph_props(context, idx + i); /* Inherit feature mask from original matched glyph. */ context->glyph_infos[idx + i].mask = mask; } @@ -5181,10 +5182,10 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c if (*context->u.subst.digits && codepoint >= '0' && codepoint <= '9') codepoint = context->u.subst.digits[codepoint - '0'];
- context->u.subst.glyphs[g] = font->get_glyph(context->cache->context, codepoint); + context->u.buffer.glyphs[g] = font->get_glyph(context->cache->context, codepoint); context->u.buffer.glyph_props[g].justification = SCRIPT_JUSTIFY_CHARACTER; context->u.buffer.glyph_props[g].isClusterStart = 1; - opentype_set_subst_glyph_props(context, g, context->u.subst.glyphs[g]); + opentype_set_subst_glyph_props(context, g); if (opentype_is_default_ignorable(codepoint)) context->u.buffer.glyph_props[g].isZeroWidthSpace = 1; context->u.buffer.glyph_props[g].components = 1;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 2 + dlls/dwrite/opentype.c | 214 ++++++++++++++++++++++------------- 2 files changed, 140 insertions(+), 76 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 94705b0d636..f8b7e0d139d 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -459,6 +459,8 @@ struct scriptshaping_cache { struct dwrite_fonttable table; unsigned int classdef; + unsigned int markattachclassdef; + unsigned int markglyphsetdef; } gdef; };
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 8ed52d3be4d..05fc38bad3f 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -448,10 +448,11 @@ enum ot_gdef_class struct gdef_header { DWORD version; - WORD classdef; - WORD attach_list; - WORD ligcaret_list; - WORD markattach_classdef; + UINT16 classdef; + UINT16 attach_list; + UINT16 ligcaret_list; + UINT16 markattach_classdef; + UINT16 markglyphsetdef; };
struct ot_gdef_classdef_format1 @@ -486,12 +487,15 @@ struct gpos_gsub_header
enum gsub_gpos_lookup_flags { - LOOKUP_FLAG_RTL = 0x1, + LOOKUP_FLAG_RTL = 0x1, /* Only used for GPOS cursive attachments. */ + LOOKUP_FLAG_IGNORE_BASE = 0x2, LOOKUP_FLAG_IGNORE_LIGATURES = 0x4, LOOKUP_FLAG_IGNORE_MARKS = 0x8, - LOOKUP_FLAG_IGNORE_MASK = 0xe, + + LOOKUP_FLAG_USE_MARK_FILTERING_SET = 0x10, + LOOKUP_FLAG_MARK_ATTACHMENT_TYPE = 0xff00, };
enum glyph_prop_flags @@ -3041,7 +3045,16 @@ void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache *cache) &cache->gdef.table.context);
if (cache->gdef.table.data) + { + unsigned int version = table_read_be_dword(&cache->gdef.table, 0); + cache->gdef.classdef = table_read_be_word(&cache->gdef.table, FIELD_OFFSET(struct gdef_header, classdef)); + cache->gdef.markattachclassdef = table_read_be_word(&cache->gdef.table, + FIELD_OFFSET(struct gdef_header, markattach_classdef)); + if (version >= 0x00010002) + cache->gdef.markglyphsetdef = table_read_be_word(&cache->gdef.table, + FIELD_OFFSET(struct gdef_header, markglyphsetdef)); + } }
unsigned int opentype_layout_find_script(const struct scriptshaping_cache *cache, unsigned int kind, DWORD script, @@ -3188,6 +3201,12 @@ static unsigned int opentype_set_glyph_props(struct scriptshaping_context *conte break; case GDEF_CLASS_MARK: props = GLYPH_PROP_MARK; + if (cache->gdef.markattachclassdef) + { + glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.markattachclassdef, + context->u.buffer.glyphs[idx]); + props |= glyph_class << 8; + } break; default: props = 0; @@ -3200,7 +3219,7 @@ static unsigned int opentype_set_glyph_props(struct scriptshaping_context *conte
static void opentype_set_subst_glyph_props(struct scriptshaping_context *context, unsigned int idx) { - unsigned int glyph_props = opentype_set_glyph_props(context, idx); + unsigned int glyph_props = opentype_set_glyph_props(context, idx) & LOOKUP_FLAG_IGNORE_MASK; context->u.subst.glyph_props[idx].isDiacritic = !!(glyph_props == GLYPH_PROP_MARK); context->u.subst.glyph_props[idx].isZeroWidthSpace = !!(glyph_props == GLYPH_PROP_MARK); } @@ -3238,10 +3257,9 @@ static int coverage_compare_format2(const void *g, const void *r) return 0; }
-static unsigned int opentype_layout_is_glyph_covered(const struct scriptshaping_context *context, unsigned int coverage, +static unsigned int opentype_layout_is_glyph_covered(const struct dwrite_fonttable *table, unsigned int coverage, UINT16 glyph) { - const struct dwrite_fonttable *table = &context->table->table; WORD format = table_read_be_word(table, coverage), count;
count = table_read_be_word(table, coverage + 2); @@ -3465,19 +3483,61 @@ static void glyph_iterator_init(struct scriptshaping_context *context, unsigned iter->len = len; }
-static BOOL lookup_is_glyph_match(unsigned int glyph_props, unsigned int lookup_flags) +struct ot_gdef_mark_glyph_sets +{ + UINT16 format; + UINT16 count; + DWORD offsets[1]; +}; + +static BOOL opentype_layout_mark_set_covers(const struct scriptshaping_cache *cache, unsigned int set_index, + UINT16 glyph) +{ + unsigned int format, offset = cache->gdef.markglyphsetdef, coverage_offset, set_count; + + if (!offset) + return FALSE; + + format = table_read_be_word(&cache->gdef.table, offset); + + if (format == 1) + { + set_count = table_read_be_word(&cache->gdef.table, offset + 2); + if (!set_count || set_index >= set_count) + return FALSE; + + coverage_offset = table_read_be_dword(&cache->gdef.table, offset + 2 + set_index * sizeof(coverage_offset)); + return opentype_layout_is_glyph_covered(&cache->gdef.table, offset + coverage_offset, glyph) != GLYPH_NOT_COVERED; + } + else + WARN("Unexpected MarkGlyphSets format %#x.\n", format); + + return FALSE; +} + +static BOOL lookup_is_glyph_match(const struct scriptshaping_context *context, unsigned int idx, unsigned int match_props) { - if (glyph_props & lookup_flags & LOOKUP_FLAG_IGNORE_MASK) + unsigned int glyph_props = context->glyph_infos[idx].props; + UINT16 glyph = context->u.buffer.glyphs[idx]; + + if (glyph_props & match_props & LOOKUP_FLAG_IGNORE_MASK) return FALSE;
- /* FIXME: match mark properties */ + if (!(glyph_props & GLYPH_PROP_MARK)) + return TRUE; + + if (match_props & LOOKUP_FLAG_USE_MARK_FILTERING_SET) + return opentype_layout_mark_set_covers(context->cache, match_props >> 16, glyph); + + if (match_props & LOOKUP_FLAG_MARK_ATTACHMENT_TYPE) + return (match_props & LOOKUP_FLAG_MARK_ATTACHMENT_TYPE) == (glyph_props & LOOKUP_FLAG_MARK_ATTACHMENT_TYPE);
return TRUE; }
static BOOL glyph_iterator_match(const struct glyph_iterator *iter) { - return lookup_is_glyph_match(iter->context->glyph_infos[iter->pos].props, iter->flags); + return lookup_is_glyph_match(iter->context, iter->pos, iter->flags); }
static BOOL glyph_iterator_next(struct glyph_iterator *iter) @@ -3527,6 +3587,7 @@ struct lookup static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context *context, const struct lookup *lookup, unsigned int subtable_offset) { + const struct dwrite_fonttable *table = &context->table->table; struct scriptshaping_cache *cache = context->cache; UINT16 format, value_format, value_len, coverage, glyph;
@@ -3547,7 +3608,7 @@ static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_co const struct ot_gpos_singlepos_format1 *format1 = table_read_ensure(&cache->gpos.table, subtable_offset, FIELD_OFFSET(struct ot_gpos_singlepos_format1, value[value_len]));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -3560,7 +3621,7 @@ static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_co const struct ot_gpos_singlepos_format2 *format2 = table_read_ensure(&cache->gpos.table, subtable_offset, FIELD_OFFSET(struct ot_gpos_singlepos_format2, values) + value_count * value_len * sizeof(WORD));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= value_count) return FALSE;
@@ -3589,6 +3650,7 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont const struct lookup *lookup, unsigned int subtable_offset) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &cache->gpos.table; unsigned int first_glyph, second_glyph; struct glyph_iterator iter_pair; WORD format, coverage; @@ -3611,13 +3673,13 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont second_glyph = iter_pair.pos; }
- format = table_read_be_word(&cache->gpos.table, subtable_offset); + format = table_read_be_word(table, subtable_offset);
- coverage = table_read_be_word(&cache->gpos.table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format1, coverage)); + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format1, coverage)); if (!coverage) return FALSE;
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, context->u.pos.glyphs[first_glyph]); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, context->u.pos.glyphs[first_glyph]); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -3634,14 +3696,12 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont if (!pairset_count || coverage_index >= pairset_count) return FALSE;
- format1 = table_read_ensure(&cache->gpos.table, subtable_offset, - FIELD_OFFSET(struct ot_gpos_pairpos_format1, pairsets[pairset_count])); + format1 = table_read_ensure(table, subtable_offset, FIELD_OFFSET(struct ot_gpos_pairpos_format1, pairsets[pairset_count])); if (!format1) return FALSE;
/* Ordered paired values. */ - pairvalue_count = table_read_be_word(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->pairsets[coverage_index])); + pairvalue_count = table_read_be_word(table, subtable_offset + GET_BE_WORD(format1->pairsets[coverage_index])); if (!pairvalue_count) return FALSE;
@@ -3681,28 +3741,25 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont unsigned int class1, class2; const WCHAR *values;
- value_format1 = table_read_be_word(&cache->gpos.table, subtable_offset + + value_format1 = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format2, value_format1)) & 0xff; - value_format2 = table_read_be_word(&cache->gpos.table, subtable_offset + + value_format2 = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format2, value_format2)) & 0xff;
- class1_count = table_read_be_word(&cache->gpos.table, subtable_offset + - FIELD_OFFSET(struct ot_gpos_pairpos_format2, class1_count)); - class2_count = table_read_be_word(&cache->gpos.table, subtable_offset + - FIELD_OFFSET(struct ot_gpos_pairpos_format2, class2_count)); + class1_count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format2, class1_count)); + class2_count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_pairpos_format2, class2_count));
value_len1 = dwrite_popcount(value_format1); value_len2 = dwrite_popcount(value_format2);
- format2 = table_read_ensure(&cache->gpos.table, subtable_offset, - FIELD_OFFSET(struct ot_gpos_pairpos_format2, + format2 = table_read_ensure(table, subtable_offset, FIELD_OFFSET(struct ot_gpos_pairpos_format2, values[class1_count * class2_count * (value_len1 + value_len2)])); if (!format2) return FALSE;
- class1 = opentype_layout_get_glyph_class(&cache->gpos.table, subtable_offset + GET_BE_WORD(format2->class_def1), + class1 = opentype_layout_get_glyph_class(table, subtable_offset + GET_BE_WORD(format2->class_def1), context->u.pos.glyphs[first_glyph]); - class2 = opentype_layout_get_glyph_class(&cache->gpos.table, subtable_offset + GET_BE_WORD(format2->class_def2), + class2 = opentype_layout_get_glyph_class(table, subtable_offset + GET_BE_WORD(format2->class_def2), context->u.pos.glyphs[second_glyph]);
if (!(class1 < class1_count && class2 < class2_count)) @@ -3787,12 +3844,13 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c const struct lookup *lookup, unsigned int subtable_offset) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &cache->gpos.table; WORD format = table_read_be_word(&cache->gpos.table, subtable_offset); UINT16 glyph = context->u.pos.glyphs[context->cur];
if (format == 1) { - WORD coverage_offset = table_read_be_word(&cache->gpos.table, subtable_offset + + WORD coverage_offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_cursive_format1, coverage)); unsigned int glyph_index, entry_count, entry_anchor, exit_anchor; float entry_x, entry_y, exit_x, exit_y, delta; @@ -3801,14 +3859,13 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c if (!coverage_offset) return FALSE;
- entry_count = table_read_be_word(&cache->gpos.table, subtable_offset + - FIELD_OFFSET(struct ot_gpos_cursive_format1, count)); + entry_count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_cursive_format1, count));
- glyph_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage_offset, glyph); + glyph_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage_offset, glyph); if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count) return FALSE;
- entry_anchor = table_read_be_word(&cache->gpos.table, subtable_offset + + entry_anchor = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_cursive_format1, anchors[glyph_index * 2])); if (!entry_anchor) return FALSE; @@ -3817,12 +3874,12 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c if (!glyph_iterator_prev(&prev_iter)) return FALSE;
- glyph_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage_offset, + glyph_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage_offset, context->u.pos.glyphs[prev_iter.pos]); if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count) return FALSE;
- exit_anchor = table_read_be_word(&cache->gpos.table, subtable_offset + + exit_anchor = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gpos_cursive_format1, anchors[glyph_index * 2 + 1])); if (!exit_anchor) return FALSE; @@ -3865,14 +3922,14 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap const struct lookup *lookup, unsigned int subtable_offset) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &cache->gpos.table; WORD format;
- format = table_read_be_word(&cache->gpos.table, subtable_offset); + format = table_read_be_word(table, subtable_offset);
if (format == 1) { - const struct ot_gpos_mark_to_base_format1 *format1 = table_read_ensure(&cache->gpos.table, subtable_offset, - sizeof(*format1)); + const struct ot_gpos_mark_to_base_format1 *format1 = table_read_ensure(table, subtable_offset, sizeof(*format1)); unsigned int mark_class_count, count, mark_array_offset, base_array_offset; const struct ot_gpos_mark_array *mark_array; const struct ot_gpos_base_array *base_array; @@ -3885,26 +3942,25 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap return FALSE;
mark_array_offset = subtable_offset + GET_BE_WORD(format1->mark_array); - if (!(count = table_read_be_word(&cache->gpos.table, mark_array_offset))) + if (!(count = table_read_be_word(table, mark_array_offset))) return FALSE;
- mark_array = table_read_ensure(&cache->gpos.table, mark_array_offset, - FIELD_OFFSET(struct ot_gpos_mark_array, records[count])); + mark_array = table_read_ensure(table, mark_array_offset, FIELD_OFFSET(struct ot_gpos_mark_array, records[count])); if (!mark_array) return FALSE;
base_array_offset = subtable_offset + GET_BE_WORD(format1->base_array); - if (!(count = table_read_be_word(&cache->gpos.table, base_array_offset))) + if (!(count = table_read_be_word(table, base_array_offset))) return FALSE;
- base_array = table_read_ensure(&cache->gpos.table, base_array_offset, + base_array = table_read_ensure(table, base_array_offset, FIELD_OFFSET(struct ot_gpos_base_array, offsets[count * GET_BE_WORD(format1->mark_class_count)])); if (!base_array) return FALSE;
mark_class_count = GET_BE_WORD(format1->mark_class_count);
- mark_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark_coverage), + mark_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->mark_coverage), context->u.pos.glyphs[context->cur]);
if (mark_index == GLYPH_NOT_COVERED || mark_index >= GET_BE_WORD(mark_array->count)) @@ -3915,7 +3971,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap if (!glyph_iterator_prev(&base_iter)) return FALSE;
- base_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->base_coverage), + base_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->base_coverage), context->u.pos.glyphs[base_iter.pos]); if (base_index == GLYPH_NOT_COVERED || base_index >= GET_BE_WORD(base_array->count)) return FALSE; @@ -3945,21 +4001,21 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshapi const struct lookup *lookup, unsigned int subtable_offset) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &cache->gpos.table; WORD format;
format = table_read_be_word(&cache->gpos.table, subtable_offset);
if (format == 1) { - const struct ot_gpos_mark_to_lig_format1 *format1 = table_read_ensure(&cache->gpos.table, - subtable_offset, sizeof(*format1)); + const struct ot_gpos_mark_to_lig_format1 *format1 = table_read_ensure(table, subtable_offset, sizeof(*format1)); unsigned int mark_index, lig_index; struct glyph_iterator lig_iter;
if (!format1) return FALSE;
- mark_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark_coverage), + mark_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->mark_coverage), context->u.pos.glyphs[context->cur]); if (mark_index == GLYPH_NOT_COVERED) return FALSE; @@ -3968,7 +4024,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshapi if (!glyph_iterator_prev(&lig_iter)) return FALSE;
- lig_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->lig_coverage), + lig_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->lig_coverage), context->u.pos.glyphs[lig_iter.pos]); if (lig_index == GLYPH_NOT_COVERED) return FALSE; @@ -3985,14 +4041,14 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap const struct lookup *lookup, unsigned int subtable_offset) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &cache->gpos.table; WORD format;
- format = table_read_be_word(&cache->gpos.table, subtable_offset); + format = table_read_be_word(table, subtable_offset);
if (format == 1) { - const struct ot_gpos_mark_to_mark_format1 *format1 = table_read_ensure(&cache->gpos.table, - subtable_offset, sizeof(*format1)); + const struct ot_gpos_mark_to_mark_format1 *format1 = table_read_ensure(table, subtable_offset, sizeof(*format1)); unsigned int count, mark1_array_offset, mark2_array_offset, mark_class_count; unsigned int mark1_index, mark2_index, mark2_anchor; const struct ot_gpos_mark_array *mark1_array; @@ -4003,15 +4059,14 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap if (!format1) return FALSE;
- mark1_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark1_coverage), + mark1_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->mark1_coverage), context->u.pos.glyphs[context->cur]);
mark1_array_offset = subtable_offset + GET_BE_WORD(format1->mark1_array); - if (!(count = table_read_be_word(&cache->gpos.table, mark1_array_offset))) + if (!(count = table_read_be_word(table, mark1_array_offset))) return FALSE;
- mark1_array = table_read_ensure(&cache->gpos.table, mark1_array_offset, - FIELD_OFFSET(struct ot_gpos_mark_array, records[count])); + mark1_array = table_read_ensure(table, mark1_array_offset, FIELD_OFFSET(struct ot_gpos_mark_array, records[count])); if (!mark1_array) return FALSE;
@@ -4031,12 +4086,12 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap
mark_class_count = GET_BE_WORD(format1->mark_class_count);
- mark2_array = table_read_ensure(&cache->gpos.table, mark2_array_offset, + mark2_array = table_read_ensure(table, mark2_array_offset, FIELD_OFFSET(struct ot_gpos_base_array, offsets[count * mark_class_count])); if (!mark2_array) return FALSE;
- mark2_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark2_coverage), + mark2_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(format1->mark2_coverage), context->u.pos.glyphs[mark_iter.pos]);
if (mark2_index == GLYPH_NOT_COVERED || mark2_index >= count) @@ -4169,7 +4224,7 @@ static int lookups_sorting_compare(const void *a, const void *b) static BOOL opentype_layout_init_lookup(const struct ot_gsubgpos_table *table, unsigned short lookup_index, unsigned int mask, struct lookup *lookup) { - unsigned short subtable_count, lookup_type, flags; + unsigned short subtable_count, lookup_type, flags, mark_filtering_set; const struct ot_lookup_table *lookup_table; unsigned int offset;
@@ -4190,6 +4245,13 @@ static BOOL opentype_layout_init_lookup(const struct ot_gsubgpos_table *table, u lookup_type = GET_BE_WORD(lookup_table->lookup_type); flags = GET_BE_WORD(lookup_table->flags);
+ if (flags & LOOKUP_FLAG_USE_MARK_FILTERING_SET) + { + mark_filtering_set = table_read_be_word(&table->table, offset + + FIELD_OFFSET(struct ot_lookup_table, subtable[subtable_count])); + flags |= mark_filtering_set << 16; + } + lookup->index = lookup_index; lookup->type = lookup_type; lookup->flags = flags; @@ -4473,7 +4535,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, ret = FALSE;
if ((context->glyph_infos[context->cur].mask & lookup->mask) && - lookup_is_glyph_match(context->glyph_infos[context->cur].props, lookup->flags)) + lookup_is_glyph_match(context, context->cur, lookup->flags)) { ret = opentype_layout_apply_gpos_lookup(context, lookup); } @@ -4515,7 +4577,7 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ { const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -4527,7 +4589,7 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ const struct ot_gsub_singlesubst_format2 *format2 = table_read_ensure(gsub, subtable_offset, FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count) + count * sizeof(UINT16));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count) return FALSE;
@@ -4612,7 +4674,7 @@ static BOOL opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_co
if (format == 1) { - coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -4719,7 +4781,7 @@ static BOOL opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_con
coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_altsubst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -4797,7 +4859,7 @@ static BOOL opentype_layout_apply_gsub_lig_substitution(struct scriptshaping_con
coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_ligsubst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -4853,7 +4915,7 @@ static BOOL opentype_layout_context_match_input(struct scriptshaping_context *co
/* TODO: this only covers Format3 substitution */ glyph = context->u.subst.glyphs[iter.pos]; - if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[i]), glyph) == GLYPH_NOT_COVERED) + 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; @@ -4879,7 +4941,7 @@ static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context return FALSE;
glyph = context->u.subst.glyphs[iter.pos]; - if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(backtrack[i]), glyph) == GLYPH_NOT_COVERED) + if (opentype_layout_is_glyph_covered(&context->table->table, subtable_offset + GET_BE_WORD(backtrack[i]), glyph) == GLYPH_NOT_COVERED) return FALSE; }
@@ -4903,7 +4965,7 @@ static BOOL opentype_layout_context_match_lookahead(struct scriptshaping_context return FALSE;
glyph = context->u.subst.glyphs[iter.pos]; - if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(lookahead[i]), glyph) == GLYPH_NOT_COVERED) + if (opentype_layout_is_glyph_covered(&context->table->table, subtable_offset + GET_BE_WORD(lookahead[i]), glyph) == GLYPH_NOT_COVERED) return FALSE; }
@@ -5010,7 +5072,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -5021,7 +5083,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
@@ -5054,7 +5116,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records));
if (input) - coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph); + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(input[0]), glyph);
if (coverage_index == GLYPH_NOT_COVERED) return FALSE; @@ -5222,7 +5284,7 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, ret = FALSE;
if ((context->glyph_infos[context->cur].mask & lookup->mask) && - lookup_is_glyph_match(context->glyph_infos[context->cur].props, lookup->flags)) + lookup_is_glyph_match(context, context->cur, lookup->flags)) { ret = opentype_layout_apply_gsub_lookup(context, lookup); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/tests/analyzer.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c index 38d6a68ef8d..c5cf0954fee 100644 --- a/dlls/dwrite/tests/analyzer.c +++ b/dlls/dwrite/tests/analyzer.c @@ -1748,9 +1748,6 @@ if (0) { IDWriteFontFace_Release(fontface);
/* Test setting glyph properties from GDEF. */ -if (strcmp(winetest_platform, "wine")) -{ - hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE); ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
@@ -1794,7 +1791,6 @@ if (strcmp(winetest_platform, "wine")) }
IDWriteFontCollection_Release(syscoll); -}
IDWriteTextAnalyzer_Release(analyzer); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=72474
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/dwrite/opentype.c:4491 error: patch failed: dlls/dwrite/opentype.c:3200 Task: Patch failed to apply
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 67 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 05fc38bad3f..468368bcc03 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3466,12 +3466,26 @@ struct ot_lookup unsigned int flags; };
+enum iterator_match +{ + /* First two to fit matching callback result. */ + ITER_NO = 0, + ITER_YES = 1, + ITER_MAYBE, +}; + +typedef BOOL (*p_match_func)(UINT16 glyph, UINT16 glyph_data, const void *match_data); + struct glyph_iterator { struct scriptshaping_context *context; unsigned int flags; unsigned int pos; unsigned int len; + unsigned int mask; + p_match_func match_func; + const UINT16 *glyph_data; + const void *match_data; };
static void glyph_iterator_init(struct scriptshaping_context *context, unsigned int flags, unsigned int pos, @@ -3481,6 +3495,10 @@ 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->match_func = NULL; + iter->match_data = NULL; + iter->glyph_data = NULL; }
struct ot_gdef_mark_glyph_sets @@ -3535,21 +3553,48 @@ static BOOL lookup_is_glyph_match(const struct scriptshaping_context *context, u return TRUE; }
-static BOOL glyph_iterator_match(const struct glyph_iterator *iter) +static enum iterator_match glyph_iterator_may_skip(const struct glyph_iterator *iter) +{ + if (!lookup_is_glyph_match(iter->context, iter->pos, iter->flags)) + return ITER_YES; + + return ITER_NO; +} + +static enum iterator_match glyph_iterator_may_match(const struct glyph_iterator *iter) { - return lookup_is_glyph_match(iter->context, iter->pos, iter->flags); + if (!(iter->mask & iter->context->glyph_infos[iter->pos].mask)) + return ITER_NO; + + if (iter->match_func) + return !!iter->match_func(iter->context->u.buffer.glyphs[iter->pos], *iter->glyph_data, iter->match_data); + + return ITER_MAYBE; }
static BOOL glyph_iterator_next(struct glyph_iterator *iter) { + enum iterator_match skip, match; + while (iter->pos + iter->len < iter->context->glyph_count) { ++iter->pos; - if (glyph_iterator_match(iter)) + + skip = glyph_iterator_may_skip(iter); + if (skip == ITER_YES) + continue; + + match = glyph_iterator_may_match(iter); + if (match == ITER_YES || (match == ITER_MAYBE && skip == ITER_NO)) { --iter->len; + if (iter->glyph_data) + ++iter->glyph_data; return TRUE; } + + if (skip == ITER_NO) + return FALSE; }
return FALSE; @@ -3557,17 +3602,27 @@ static BOOL glyph_iterator_next(struct glyph_iterator *iter)
static BOOL glyph_iterator_prev(struct glyph_iterator *iter) { - if (!iter->pos) - return FALSE; + enum iterator_match skip, match;
while (iter->pos > iter->len - 1) { --iter->pos; - if (glyph_iterator_match(iter)) + + skip = glyph_iterator_may_skip(iter); + if (skip == ITER_YES) + continue; + + match = glyph_iterator_may_match(iter); + if (match == ITER_YES || (match == ITER_MAYBE && skip == ITER_NO)) { --iter->len; + if (iter->glyph_data) + ++iter->glyph_data; return TRUE; } + + if (skip == ITER_NO) + return FALSE; }
return FALSE;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 105 ++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 38 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 468368bcc03..198da43f2cd 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -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);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 198da43f2cd..5114e900df6 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -618,6 +618,12 @@ struct ot_gsub_chaincontext_subst_format1 UINT16 rulesets[1]; };
+struct ot_gsub_ruleset +{ + UINT16 count; + UINT16 offsets[1]; +}; + struct ot_feature { WORD feature_params; @@ -3525,6 +3531,11 @@ struct ot_gdef_mark_glyph_sets DWORD offsets[1]; };
+static BOOL opentype_match_glyph_func(UINT16 glyph, UINT16 glyph_data, const struct match_data *data) +{ + return glyph == glyph_data; +} + static BOOL opentype_match_coverage_func(UINT16 glyph, UINT16 glyph_data, const struct match_data *data) { const struct match_context *mc = data->mc; @@ -5139,7 +5150,9 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts { struct match_context mc = { .context = context, .mask = lookup->mask }; const struct dwrite_fonttable *table = &context->table->table; - unsigned int coverage_index = GLYPH_NOT_COVERED; + unsigned int i, coverage_index = GLYPH_NOT_COVERED, count, offset; + unsigned int backtrack_count, input_count, lookahead_count, lookup_count; + const UINT16 *backtrack, *lookahead, *input, *lookup_records; UINT16 glyph, format, coverage; BOOL ret = FALSE;
@@ -5149,6 +5162,8 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
if (format == 1) { + const struct ot_gsub_ruleset *ruleset; + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
@@ -5156,7 +5171,49 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
- WARN("Chaining contextual substitution (1) is not supported.\n"); + count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, + ruleset_count)); + if (coverage_index >= count) + return FALSE; + + offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, + rulesets[coverage_index])); + offset += subtable_offset; + + count = table_read_be_word(table, offset); + ruleset = table_read_ensure(table, offset, count * sizeof(ruleset->offsets)); + + mc.match_func = opentype_match_glyph_func; + for (i = 0; i < count; ++i) + { + unsigned int rule_offset = offset + GET_BE_WORD(ruleset->offsets[i]); + + backtrack_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + backtrack = table_read_ensure(table, rule_offset, backtrack_count * sizeof(*backtrack)); + rule_offset += backtrack_count * sizeof(*backtrack); + + input_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + input = table_read_ensure(table, rule_offset, input_count * sizeof(*input)); + rule_offset += input_count * sizeof(*input); + + lookahead_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + lookahead = table_read_ensure(table, rule_offset, lookahead_count * sizeof(*lookahead)); + rule_offset += lookahead_count * sizeof(*lookahead); + + lookup_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + lookup_records = table_read_ensure(table, rule_offset, lookup_count * 2 * sizeof(*lookup_records)); + + /* First applicable rule is used. */ + if (opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input, lookahead_count, + lookahead, lookup_count, lookup_records, &mc)) + { + return TRUE; + } + } } else if (format == 2) { @@ -5174,7 +5231,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts unsigned int backtrack_count, input_count, lookahead_count, lookup_count; const UINT16 *backtrack, *lookahead, *input, *lookup_records;
- unsigned int offset = subtable_offset + 2 /* format */; + offset = subtable_offset + 2 /* format */;
backtrack_count = table_read_be_word(table, offset); offset += 2;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 128 ++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 41 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 5114e900df6..f4e9d3305a4 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3536,6 +3536,13 @@ static BOOL opentype_match_glyph_func(UINT16 glyph, UINT16 glyph_data, const str return glyph == glyph_data; }
+static BOOL opentype_match_class_func(UINT16 glyph, UINT16 glyph_data, const struct match_data *data) +{ + const struct match_context *mc = data->mc; + UINT16 glyph_class = opentype_layout_get_glyph_class(&mc->context->table->table, data->subtable_offset, glyph); + return glyph_class == glyph_data; +} + static BOOL opentype_match_coverage_func(UINT16 glyph, UINT16 glyph_data, const struct match_data *data) { const struct match_context *mc = data->mc; @@ -5145,14 +5152,57 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(unsigned int backtra opentype_layout_context_gsub_apply_lookup(mc->context, input_count, match_positions, lookup_count, lookup_records, match_length); }
+static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, unsigned int offset) +{ + unsigned int backtrack_count, input_count, lookahead_count, lookup_count; + const struct dwrite_fonttable *table = &mc->context->table->table; + const UINT16 *backtrack, *lookahead, *input, *lookup_records; + const struct ot_gsub_ruleset *ruleset; + unsigned int i, count; + + count = table_read_be_word(table, offset); + ruleset = table_read_ensure(table, offset, count * sizeof(ruleset->offsets)); + + for (i = 0; i < count; ++i) + { + unsigned int rule_offset = offset + GET_BE_WORD(ruleset->offsets[i]); + + backtrack_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + backtrack = table_read_ensure(table, rule_offset, backtrack_count * sizeof(*backtrack)); + rule_offset += backtrack_count * sizeof(*backtrack); + + input_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + input = table_read_ensure(table, rule_offset, input_count * sizeof(*input)); + rule_offset += input_count * sizeof(*input); + + lookahead_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + lookahead = table_read_ensure(table, rule_offset, lookahead_count * sizeof(*lookahead)); + rule_offset += lookahead_count * sizeof(*lookahead); + + lookup_count = table_read_be_word(table, rule_offset); + rule_offset += 2; + lookup_records = table_read_ensure(table, rule_offset, lookup_count * 2 * sizeof(*lookup_records)); + + /* First applicable rule is used. */ + if (opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input, lookahead_count, + lookahead, lookup_count, lookup_records, mc)) + { + return TRUE; + } + } + + return FALSE; +} + 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 i, coverage_index = GLYPH_NOT_COVERED, count, offset; - unsigned int backtrack_count, input_count, lookahead_count, lookup_count; - const UINT16 *backtrack, *lookahead, *input, *lookup_records; + unsigned int coverage_index = GLYPH_NOT_COVERED, count, offset; UINT16 glyph, format, coverage; BOOL ret = FALSE;
@@ -5162,8 +5212,6 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
if (format == 1) { - const struct ot_gsub_ruleset *ruleset; - coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
@@ -5180,51 +5228,48 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts rulesets[coverage_index])); offset += subtable_offset;
- count = table_read_be_word(table, offset); - ruleset = table_read_ensure(table, offset, count * sizeof(ruleset->offsets)); - mc.match_func = opentype_match_glyph_func; - for (i = 0; i < count; ++i) - { - unsigned int rule_offset = offset + GET_BE_WORD(ruleset->offsets[i]); - - backtrack_count = table_read_be_word(table, rule_offset); - rule_offset += 2; - backtrack = table_read_ensure(table, rule_offset, backtrack_count * sizeof(*backtrack)); - rule_offset += backtrack_count * sizeof(*backtrack); - - input_count = table_read_be_word(table, rule_offset); - rule_offset += 2; - input = table_read_ensure(table, rule_offset, input_count * sizeof(*input)); - rule_offset += input_count * sizeof(*input); - - lookahead_count = table_read_be_word(table, rule_offset); - rule_offset += 2; - lookahead = table_read_ensure(table, rule_offset, lookahead_count * sizeof(*lookahead)); - rule_offset += lookahead_count * sizeof(*lookahead); - - lookup_count = table_read_be_word(table, rule_offset); - rule_offset += 2; - lookup_records = table_read_ensure(table, rule_offset, lookup_count * 2 * sizeof(*lookup_records)); - - /* First applicable rule is used. */ - if (opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input, lookahead_count, - lookahead, lookup_count, lookup_records, &mc)) - { - return TRUE; - } - } + + ret = opentype_layout_apply_chain_rule_set(&mc, offset); } else if (format == 2) { - coverage = table_read_be_word(table, subtable_offset + - FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage)); + unsigned int backtrack_classdef, input_classdef, lookahead_classdef, rule_set_idx; + + offset = subtable_offset + 2 /* format */; + + coverage = table_read_be_word(table, offset); + offset += 2;
coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
- WARN("Chaining contextual substitution (2) is not supported.\n"); + backtrack_classdef = table_read_be_word(table, offset) + subtable_offset; + offset += 2; + + input_classdef = table_read_be_word(table, offset) + subtable_offset; + offset += 2; + + lookahead_classdef = table_read_be_word(table, offset) + subtable_offset; + offset += 2; + + count = table_read_be_word(table, offset); + offset+= 2; + + rule_set_idx = opentype_layout_get_glyph_class(table, input_classdef, glyph); + if (rule_set_idx >= count) + return FALSE; + + offset = table_read_be_word(table, offset + rule_set_idx * 2); + offset += subtable_offset; + + mc.backtrack_offset = backtrack_classdef; + mc.input_offset = input_classdef; + mc.lookahead_offset = lookahead_classdef; + mc.match_func = opentype_match_class_func; + + ret = opentype_layout_apply_chain_rule_set(&mc, offset); } else if (format == 3) { @@ -5262,6 +5307,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts 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); }