Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 46 +++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index f4e9d3305a4..c724327c507 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4403,9 +4403,10 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex unsigned int language_index, const struct shaping_features *features, const struct ot_gsubgpos_table *table, struct lookups *lookups) { - UINT16 table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count; + unsigned int last_num_lookups = 0, stage, script_feature_count = 0; + UINT16 total_feature_count, total_lookup_count; const struct ot_feature_list *feature_list; - unsigned int last_num_lookups = 0, stage; + const struct ot_langsys *langsys = NULL; struct shaping_feature *feature; unsigned int i, j, next_bit; unsigned int global_bit_shift = 1; @@ -4415,23 +4416,31 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex if (!table->table.data) return;
- /* ScriptTable offset. */ - table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) + - script_index * sizeof(struct ot_script_record) + FIELD_OFFSET(struct ot_script_record, script)); - if (!table_offset) - return; + if (script_index != ~0u) + { + unsigned int table_offset, langsys_offset;
- if (language_index == ~0u) - langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset); - else - langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset + - FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) + - FIELD_OFFSET(struct ot_langsys_record, langsys)); + /* ScriptTable offset. */ + table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) + + script_index * sizeof(struct ot_script_record) + FIELD_OFFSET(struct ot_script_record, script)); + if (!table_offset) + return;
- script_feature_count = table_read_be_word(&table->table, table->script_list + table_offset + langsys_offset + - FIELD_OFFSET(struct ot_langsys, feature_count)); - if (!script_feature_count) - return; + if (language_index == ~0u) + langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset); + else + langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset + + FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) + + FIELD_OFFSET(struct ot_langsys_record, langsys)); + langsys_offset += table->script_list + table_offset; + + script_feature_count = table_read_be_word(&table->table, langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_count)); + if (script_feature_count) + langsys = table_read_ensure(&table->table, langsys_offset, + FIELD_OFFSET(struct ot_langsys, feature_index[script_feature_count])); + if (!langsys) + script_feature_count = 0; + }
total_feature_count = table_read_be_word(&table->table, table->feature_list); if (!total_feature_count) @@ -4467,8 +4476,7 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
for (j = 0; j < script_feature_count; ++j) { - feature_index = table_read_be_word(&table->table, table->script_list + table_offset + - langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j])); + feature_index = GET_BE_WORD(langsys->feature_index[j]); if (feature_index >= total_feature_count) continue; if ((found = feature_list->features[feature_index].tag == feature->tag))
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 4 ++++ dlls/dwrite/scripts.h | 6 +++++- tools/make_unicode | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 56950a5baa3..cb58f362990 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -194,6 +194,10 @@ static const struct dwritescript_properties dwritescripts_properties[Script_Last { /* Medf */ { 0x6664654d, 265, 8, 0x0020, 0, 1, 1, 0, 0, 0, 0 }, { _OT('m','e','d','f') } }, { /* Sogo */ { 0x6f676f53, 142, 8, 0x0020, 1, 1, 1, 0, 0, 0, 0 }, { _OT('s','o','g','o') } }, { /* Sogd */ { 0x64676f53, 141, 8, 0x0020, 1, 1, 0, 0, 0, 1, 1 }, { _OT('s','o','g','d') } }, + { /* Elym */ { 0x6d796c45, 128, 1, 0x0020, 0, 0, 1, 0, 0, 0, 0 } }, + { /* Hmnp */ { 0x706e6d48, 451, 8, 0x0020, 1, 1, 0, 0, 0, 0, 0 } }, + { /* Nand */ { 0x646e614e, 311, 8, 0x0020, 1, 1, 0, 0, 0, 1, 0 } }, + { /* Wcho */ { 0x6f686357, 283, 8, 0x0020, 1, 1, 0, 0, 0, 0, 0 } }, }; #undef _OT
diff --git a/dlls/dwrite/scripts.h b/dlls/dwrite/scripts.h index 19cb89bd8a5..d1bdb49de4d 100644 --- a/dlls/dwrite/scripts.h +++ b/dlls/dwrite/scripts.h @@ -152,5 +152,9 @@ enum unicode_script_id { Script_Medefaidrin = 146, Script_Old_Sogdian = 147, Script_Sogdian = 148, - Script_LastId = 148 + Script_Elymaic = 149, + Script_Nyiakeng_Puachue_Hmong = 150, + Script_Nandinagari = 151, + Script_Wancho = 152, + Script_LastId = 152 }; diff --git a/tools/make_unicode b/tools/make_unicode index ec5d8eafb43..e18ec0a206f 100755 --- a/tools/make_unicode +++ b/tools/make_unicode @@ -1440,6 +1440,11 @@ my %scripts = "Medefaidrin" => 146, "Old_Sogdian" => 147, "Sogdian" => 148, + # Win10 2004 + "Elymaic" => 149, + "Nyiakeng_Puachue_Hmong" => 150, + "Nandinagari" => 151, + "Wancho" => 152, );
################################################################
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 165 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 7 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index c724327c507..f1b9fb4e474 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -610,7 +610,7 @@ struct ot_gsub_lig UINT16 components[1]; };
-struct ot_gsub_chaincontext_subst_format1 +struct ot_gsub_context_subst_format1 { UINT16 format; UINT16 coverage; @@ -5205,6 +5205,157 @@ static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, return FALSE; }
+static BOOL opentype_layout_apply_gsub_context_lookup(unsigned int input_count, const UINT16 *input, unsigned int lookup_count, + const UINT16 *lookup_records, const struct match_context *mc) +{ + unsigned int match_positions[GLYPH_CONTEXT_MAX_LENGTH]; + unsigned int match_length = 0; + + return opentype_layout_context_match_input(mc, input_count, input, &match_length, match_positions) && + opentype_layout_context_gsub_apply_lookup(mc->context, input_count, match_positions, lookup_count, + lookup_records, match_length); +} + +static BOOL opentype_layout_apply_rule_set(const struct match_context *mc, unsigned int offset) +{ + unsigned int input_count, lookup_count; + const struct dwrite_fonttable *table = &mc->context->table->table; + const UINT16 *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]); + + if (!(input_count = table_read_be_word(table, rule_offset))) + continue; + rule_offset += 2; + + if (!(lookup_count = table_read_be_word(table, rule_offset))) + continue; + rule_offset += 2; + + if (!(input = table_read_ensure(table, rule_offset, (input_count - 1) * sizeof(*input)))) + continue; + rule_offset += (input_count - 1) * sizeof(*input); + + if (!(lookup_records = table_read_ensure(table, rule_offset, lookup_count * 2 * sizeof(*lookup_records)))) + continue; + + /* First applicable rule is used. */ + if (opentype_layout_apply_gsub_context_lookup(input_count, input, lookup_count, lookup_records, mc)) + return TRUE; + } + + return FALSE; +} + +static BOOL opentype_layout_apply_gsub_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, count, offset; + UINT16 glyph, format, coverage; + BOOL ret = FALSE; + + glyph = context->u.subst.glyphs[context->cur]; + + format = table_read_be_word(table, subtable_offset); + + if (format == 1) + { + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, coverage)); + + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE; + + count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, + ruleset_count)); + if (coverage_index >= count) + return FALSE; + + offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, + rulesets[coverage_index])); + offset += subtable_offset; + + mc.match_func = opentype_match_glyph_func; + + ret = opentype_layout_apply_rule_set(&mc, offset); + } + else if (format == 2) + { + unsigned int input_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; + + input_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.input_offset = input_classdef; + mc.match_func = opentype_match_class_func; + + ret = opentype_layout_apply_rule_set(&mc, offset); + } + else if (format == 3) + { + unsigned int input_count, lookup_count; + const UINT16 *input, *lookup_records; + + offset = subtable_offset + 2 /* format */; + + input_count = table_read_be_word(table, offset); + offset += 2; + + if (!input_count) + return FALSE; + + lookup_count = table_read_be_word(table, offset); + offset += 2; + + if (!(input = table_read_ensure(table, offset, sizeof(*input) * input_count))) + return FALSE; + offset += sizeof(*input) * input_count; + + coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(input[0]), glyph); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE; + + lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records)); + + mc.input_offset = subtable_offset; + mc.match_func = opentype_match_coverage_func; + + ret = opentype_layout_apply_gsub_context_lookup(input_count, input + 1, lookup_count, lookup_records, &mc); + } + else + WARN("Unknown contextual substitution format %u.\n", format); + + return ret; +} + static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context, const struct lookup *lookup, unsigned int subtable_offset) { @@ -5220,19 +5371,17 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
if (format == 1) { - coverage = table_read_be_word(table, subtable_offset + - FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage)); + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, coverage));
coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
- count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, - ruleset_count)); + count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_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, + offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, rulesets[coverage_index])); offset += subtable_offset;
@@ -5357,10 +5506,12 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont case GSUB_LOOKUP_LIGATURE_SUBST: ret = opentype_layout_apply_gsub_lig_substitution(context, lookup, subtable_offset); break; + case GSUB_LOOKUP_CONTEXTUAL_SUBST: + ret = opentype_layout_apply_gsub_context_substitution(context, lookup, subtable_offset); + break; case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset); break; - case GSUB_LOOKUP_CONTEXTUAL_SUBST: case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: WARN("Unimplemented lookup %d.\n", lookup->type); break;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index f1b9fb4e474..29f2a95a8c1 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -5180,10 +5180,12 @@ static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, 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); + if (!(input_count = table_read_be_word(table, rule_offset))) + continue; + rule_offset += 2; - input = table_read_ensure(table, rule_offset, input_count * sizeof(*input)); - rule_offset += input_count * sizeof(*input); + input = table_read_ensure(table, rule_offset, (input_count - 1) * sizeof(*input)); + rule_offset += (input_count - 1) * sizeof(*input);
lookahead_count = table_read_be_word(table, rule_offset); rule_offset += 2;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 50 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 9 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 29f2a95a8c1..58e1a3941c7 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -5610,6 +5610,19 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c } }
+static BOOL opentype_is_gsub_lookup_reversed(const struct scriptshaping_context *context, const struct lookup *lookup) +{ + unsigned int subtable_offset, lookup_type = lookup->type; + + if (lookup->type == GSUB_LOOKUP_EXTENSION_SUBST) + { + subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, 0); + /* Assumes format 1. */ + lookup_type = table_read_be_word(&context->table->table, subtable_offset + 2); + } + return lookup_type == GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST; +} + void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) { @@ -5626,19 +5639,38 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, { const struct lookup *lookup = &lookups.lookups[i];
- context->cur = 0; - while (context->cur < context->glyph_count) + if (!opentype_is_gsub_lookup_reversed(context, lookup)) { - ret = FALSE; - - if ((context->glyph_infos[context->cur].mask & lookup->mask) && - lookup_is_glyph_match(context, context->cur, lookup->flags)) + context->cur = 0; + while (context->cur < context->glyph_count) { - ret = opentype_layout_apply_gsub_lookup(context, lookup); + ret = FALSE; + + if ((context->glyph_infos[context->cur].mask & lookup->mask) && + lookup_is_glyph_match(context, context->cur, lookup->flags)) + { + ret = opentype_layout_apply_gsub_lookup(context, lookup); + } + + if (!ret) + context->cur++; } + } + else + { + context->cur = context->glyph_count - 1;
- if (!ret) - context->cur++; + for (;;) + { + if ((context->glyph_infos[context->cur].mask & lookup->mask) && + lookup_is_glyph_match(context, context->cur, lookup->flags)) + { + opentype_layout_apply_gsub_lookup(context, lookup); + } + + if (context->cur == 0) break; + --context->cur; + } } }