Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 69 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 58e1a3941c7..fe25c6b692e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4661,7 +4661,6 @@ static void opentype_layout_replace_glyph(struct scriptshaping_context *context, context->u.subst.glyphs[context->cur] = glyph; opentype_set_subst_glyph_props(context, context->cur); } - context->cur++; }
static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup, @@ -4707,6 +4706,7 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ }
opentype_layout_replace_glyph(context, glyph); + context->cur++;
return TRUE; } @@ -4801,6 +4801,7 @@ static BOOL opentype_layout_apply_gsub_mult_substitution(struct scriptshaping_co { /* Equivalent of single substitution. */ opentype_layout_replace_glyph(context, GET_BE_WORD(glyphs[0])); + context->cur++; } else if (glyph_count == 0) { @@ -4915,6 +4916,7 @@ static BOOL opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_con }
opentype_layout_replace_glyph(context, glyph); + context->cur++;
return TRUE; } @@ -4937,6 +4939,7 @@ static BOOL opentype_layout_apply_ligature(struct scriptshaping_context *context if (comp_count == 1) { opentype_layout_replace_glyph(context, GET_BE_WORD(lig->lig_glyph)); + context->cur++; return TRUE; }
@@ -5476,6 +5479,68 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts return ret; }
+static BOOL opentype_layout_apply_gsub_reverse_chain_context_substitution(struct scriptshaping_context *context, + const struct lookup *lookup, unsigned int subtable_offset) +{ + const struct dwrite_fonttable *table = &context->table->table; + unsigned int offset = subtable_offset; + UINT16 glyph, format; + + glyph = context->u.subst.glyphs[context->cur]; + + format = table_read_be_word(table, offset); + offset += 2; + + if (format == 1) + { + struct match_context mc = { .context = context, .mask = lookup->mask }; + unsigned int start_index = 0, end_index = 0, backtrack_count, lookahead_count; + unsigned int coverage, coverage_index; + const UINT16 *backtrack, *lookahead; + + 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; + + backtrack_count = table_read_be_word(table, offset); + offset += 2; + + backtrack = table_read_ensure(table, offset, sizeof(*backtrack) * backtrack_count); + offset += sizeof(*backtrack) * backtrack_count; + + lookahead_count = table_read_be_word(table, offset); + offset += 2; + + lookahead = table_read_ensure(table, offset, sizeof(*lookahead) * lookahead_count); + offset += sizeof(*lookahead) * lookahead_count; + + mc.match_func = opentype_match_coverage_func; + mc.backtrack_offset = subtable_offset; + mc.lookahead_offset = subtable_offset; + + if (opentype_layout_context_match_backtrack(&mc, backtrack_count, backtrack, &start_index) && + opentype_layout_context_match_lookahead(&mc, lookahead_count, lookahead, 1, &end_index)) + { + unsigned int glyph_count = table_read_be_word(table, offset); + if (coverage_index >= glyph_count) + return FALSE; + offset += 2; + + glyph = table_read_be_word(table, offset + coverage_index * sizeof(glyph)); + opentype_layout_replace_glyph(context, glyph); + + return TRUE; + } + } + else + WARN("Unknown reverse chaining contextual substitution format %u.\n", format); + + return FALSE; +} + static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup) { unsigned int i, lookup_type; @@ -5515,7 +5580,7 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset); break; case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: - WARN("Unimplemented lookup %d.\n", lookup->type); + ret = opentype_layout_apply_gsub_reverse_chain_context_substitution(context, lookup, subtable_offset); break; case GSUB_LOOKUP_EXTENSION_SUBST: WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index fe25c6b692e..fd59f40dcb6 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3496,7 +3496,7 @@ struct match_context unsigned int input_offset; unsigned int lookahead_offset; p_match_func match_func; - unsigned int mask; + const struct lookup *lookup; };
struct glyph_iterator @@ -5015,8 +5015,8 @@ static BOOL opentype_layout_context_match_input(const struct match_context *mc,
match_positions[0] = context->cur;
- glyph_iterator_init(context, 0, context->cur, count - 1, &iter); - iter.mask = mc->mask; + glyph_iterator_init(context, mc->lookup->flags, context->cur, count - 1, &iter); + iter.mask = mc->lookup->mask; iter.match_func = mc->match_func; iter.match_data = &match_data; iter.glyph_data = input; @@ -5042,7 +5042,7 @@ static BOOL opentype_layout_context_match_backtrack(const struct match_context * struct glyph_iterator iter; unsigned int i;
- glyph_iterator_init(context, 0, context->cur, count, &iter); + glyph_iterator_init(context, mc->lookup->flags, context->cur, count, &iter); iter.match_func = mc->match_func; iter.match_data = &match_data; iter.glyph_data = backtrack; @@ -5066,7 +5066,7 @@ static BOOL opentype_layout_context_match_lookahead(const struct match_context * struct glyph_iterator iter; unsigned int i;
- glyph_iterator_init(context, 0, context->cur + offset - 1, count, &iter); + glyph_iterator_init(context, mc->lookup->flags, context->cur + offset - 1, count, &iter); iter.match_func = mc->match_func; iter.match_data = &match_data; iter.glyph_data = lookahead; @@ -5262,7 +5262,7 @@ static BOOL opentype_layout_apply_rule_set(const struct match_context *mc, unsig 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 }; + struct match_context mc = { .context = context, .lookup = lookup }; const struct dwrite_fonttable *table = &context->table->table; unsigned int coverage_index = GLYPH_NOT_COVERED, count, offset; UINT16 glyph, format, coverage; @@ -5364,7 +5364,7 @@ static BOOL opentype_layout_apply_gsub_context_substitution(struct scriptshaping 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 }; + struct match_context mc = { .context = context, .lookup = lookup }; const struct dwrite_fonttable *table = &context->table->table; unsigned int coverage_index = GLYPH_NOT_COVERED, count, offset; UINT16 glyph, format, coverage; @@ -5493,7 +5493,7 @@ static BOOL opentype_layout_apply_gsub_reverse_chain_context_substitution(struct
if (format == 1) { - struct match_context mc = { .context = context, .mask = lookup->mask }; + struct match_context mc = { .context = context, .lookup = lookup }; unsigned int start_index = 0, end_index = 0, backtrack_count, lookahead_count; unsigned int coverage, coverage_index; const UINT16 *backtrack, *lookahead;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index fd59f40dcb6..629bc7f407b 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4405,6 +4405,7 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex { unsigned int last_num_lookups = 0, stage, script_feature_count = 0; UINT16 total_feature_count, total_lookup_count; + struct shaping_feature required_feature = { 0 }; const struct ot_feature_list *feature_list; const struct ot_langsys *langsys = NULL; struct shaping_feature *feature; @@ -4455,6 +4456,12 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex if (!feature_list) return;
+ /* Required feature. */ + required_feature.index = langsys ? GET_BE_WORD(langsys->required_feature_index) : 0xffff; + if (required_feature.index < total_feature_count) + required_feature.tag = feature_list->features[required_feature.index].tag; + required_feature.mask = global_bit_mask; + context->global_mask = global_bit_mask; next_bit = global_bit_shift + 1; for (i = 0; i < features->count; ++i) @@ -4474,6 +4481,9 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex if (!feature->max_value || next_bit + bits_needed > 8 * sizeof (feature->mask)) continue;
+ if (required_feature.tag == feature->tag) + required_feature.stage = feature->stage; + for (j = 0; j < script_feature_count; ++j) { feature_index = GET_BE_WORD(langsys->feature_index[j]); @@ -4517,6 +4527,9 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
for (stage = 0; stage <= features->stage; ++stage) { + if (required_feature.index != 0xffff && required_feature.stage == stage) + opentype_layout_add_lookups(feature_list, total_lookup_count, table, &required_feature, lookups); + for (i = 0; i < features->count; ++i) { if (features->features[i].stage == stage)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 629bc7f407b..64fba562024 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4369,10 +4369,6 @@ static void opentype_layout_add_lookups(const struct ot_feature_list *feature_li if (feature->index == 0xffff) return;
- /* FIXME: skip non-global ones for now. */ - if (!(feature->flags & FEATURE_GLOBAL)) - return; - feature_offset = GET_BE_WORD(feature_list->features[feature->index].offset);
lookup_count = table_read_be_word(&table->table, table->feature_list + feature_offset +
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 58 ++++++++++++++++++++++++++++--- dlls/dwrite/tests/analyzer.c | 67 ++++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 33 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index cb58f362990..a8a3e7c359b 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1539,13 +1539,63 @@ static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnaly return S_OK; }
-static HRESULT WINAPI dwritetextanalyzer1_GetBaseline(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *face, +static HRESULT WINAPI dwritetextanalyzer1_GetBaseline(IDWriteTextAnalyzer2 *iface, IDWriteFontFace *fontface, DWRITE_BASELINE baseline, BOOL vertical, BOOL is_simulation_allowed, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *localeName, INT32 *baseline_coord, BOOL *exists) { - FIXME("(%p %d %d %u %s %p %p): stub\n", face, vertical, is_simulation_allowed, sa.script, debugstr_w(localeName), - baseline_coord, exists); - return E_NOTIMPL; + struct dwrite_fontface *font_obj; + const DWRITE_FONT_METRICS1 *metrics; + + TRACE("%p, %d, %d, %u, %s, %p, %p.\n", fontface, vertical, is_simulation_allowed, sa.script, debugstr_w(localeName), + baseline_coord, exists); + + *exists = FALSE; + *baseline_coord = 0; + + if (baseline == DWRITE_BASELINE_DEFAULT) + baseline = vertical ? DWRITE_BASELINE_CENTRAL : DWRITE_BASELINE_ROMAN; + + if ((unsigned int)baseline > DWRITE_BASELINE_MAXIMUM) + return E_INVALIDARG; + + /* TODO: fetch BASE table data if available. */ + + if (!*exists && is_simulation_allowed) + { + font_obj = unsafe_impl_from_IDWriteFontFace(fontface); + metrics = &font_obj->metrics; + + switch (baseline) + { + case DWRITE_BASELINE_ROMAN: + *baseline_coord = vertical ? metrics->descent : 0; + break; + case DWRITE_BASELINE_CENTRAL: + *baseline_coord = vertical ? (metrics->ascent + metrics->descent) / 2 : + -(metrics->ascent - metrics->descent) / 2; + break; + case DWRITE_BASELINE_MATH: + *baseline_coord = vertical ? (metrics->ascent + metrics->descent) / 2 : + -(metrics->ascent + metrics->descent) / 2; + break; + case DWRITE_BASELINE_HANGING: + /* FIXME: this one isn't accurate, but close. */ + *baseline_coord = vertical ? metrics->capHeight * 6 / 7 + metrics->descent : metrics->capHeight * 6 / 7; + break; + case DWRITE_BASELINE_IDEOGRAPHIC_BOTTOM: + case DWRITE_BASELINE_MINIMUM: + *baseline_coord = vertical ? 0 : metrics->descent; + break; + case DWRITE_BASELINE_IDEOGRAPHIC_TOP: + case DWRITE_BASELINE_MAXIMUM: + *baseline_coord = vertical ? metrics->ascent + metrics->descent : -metrics->ascent; + break; + default: + ; + } + } + + return S_OK; }
static HRESULT WINAPI dwritetextanalyzer1_AnalyzeVerticalGlyphOrientation(IDWriteTextAnalyzer2 *iface, diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c index c5cf0954fee..70becb55ee5 100644 --- a/dlls/dwrite/tests/analyzer.c +++ b/dlls/dwrite/tests/analyzer.c @@ -2484,39 +2484,48 @@ static void test_GetBaseline(void)
fontface = create_fontface();
- /* Tahoma doesn't have BASE table, it doesn't work even with simulation enabled */ + /* Tahoma does not have a BASE table. */ + exists = TRUE; baseline = 456; - hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, - fontface, - DWRITE_BASELINE_DEFAULT, - FALSE, - TRUE, - sa, - NULL, - &baseline, - &exists); -todo_wine { - ok(hr == S_OK, "got 0x%08x\n", hr); - ok(baseline == 0, "got %d\n", baseline); - ok(exists == FALSE, "got %d\n", exists); -} + hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, fontface, DWRITE_BASELINE_DEFAULT, FALSE, + TRUE, sa, NULL, &baseline, &exists); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!baseline, "Unexpected baseline %d.\n", baseline); + ok(!exists, "Unexpected flag %d.\n", exists); + exists = TRUE; baseline = 456; - hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, - fontface, - DWRITE_BASELINE_ROMAN, - FALSE, - TRUE, - sa, - NULL, - &baseline, - &exists); -todo_wine { - ok(hr == S_OK, "got 0x%08x\n", hr); - ok(baseline == 0, "got %d\n", baseline); - ok(exists == FALSE, "got %d\n", exists); -} + hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, fontface, DWRITE_BASELINE_DEFAULT, FALSE, + FALSE, sa, NULL, &baseline, &exists); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!baseline, "Unexpected baseline %d.\n", baseline); + ok(!exists, "Unexpected flag %d.\n", exists); + + exists = TRUE; + baseline = 0; + hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, fontface, DWRITE_BASELINE_CENTRAL, FALSE, + TRUE, sa, NULL, &baseline, &exists); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(baseline != 0, "Unexpected baseline %d.\n", baseline); + ok(!exists, "Unexpected flag %d.\n", exists); + + exists = TRUE; + baseline = 0; + hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, fontface, DWRITE_BASELINE_CENTRAL, FALSE, + FALSE, sa, NULL, &baseline, &exists); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!baseline, "Unexpected baseline %d.\n", baseline); + ok(!exists, "Unexpected flag %d.\n", exists); + + exists = TRUE; + baseline = 456; + hr = IDWriteTextAnalyzer1_GetBaseline(analyzer1, fontface, DWRITE_BASELINE_DEFAULT + 100, FALSE, + TRUE, sa, NULL, &baseline, &exists); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + ok(!baseline, "Unexpected baseline %d.\n", baseline); + ok(!exists, "Unexpected flag %d.\n", exists); + IDWriteFontFace_Release(fontface); IDWriteTextAnalyzer1_Release(analyzer1); }