Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 3 + dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/opentype.c | 114 +++++++++++++++-------------------- 3 files changed, 54 insertions(+), 64 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 3754fe39a19..a7186a68156 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1184,6 +1184,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, context.user_features.range_lengths = feature_range_lengths; context.user_features.range_count = feature_ranges; context.glyph_infos = heap_alloc_zero(sizeof(*context.glyph_infos) * max_glyph_count); + context.table = &context.cache->gsub;
script = analysis->script > Script_LastId ? Script_Unknown : analysis->script; scriptprops = &dwritescripts_properties[script]; @@ -1260,6 +1261,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 context.user_features.range_lengths = feature_range_lengths; context.user_features.range_count = feature_ranges; context.glyph_infos = heap_alloc_zero(sizeof(*context.glyph_infos) * glyph_count); + context.table = &context.cache->gpos;
hr = shape_get_positions(&context, scriptprops->scripttags);
@@ -1328,6 +1330,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite context.user_features.range_lengths = feature_range_lengths; context.user_features.range_count = feature_ranges; context.glyph_infos = heap_alloc_zero(sizeof(*context.glyph_infos) * glyph_count); + context.table = &context.cache->gpos;
hr = shape_get_positions(&context, scriptprops->scripttags);
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index b1391cb911a..ad86422d50f 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -496,6 +496,7 @@ struct scriptshaping_context } subst; } u;
+ const struct ot_gsubgpos_table *table; /* Either GSUB or GPOS. */ struct { const DWRITE_TYPOGRAPHIC_FEATURES **features; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 16abb4c93aa..d21397f30a2 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3200,9 +3200,10 @@ static int coverage_compare_format2(const void *g, const void *r) return 0; }
-static unsigned int opentype_layout_is_glyph_covered(const struct dwrite_fonttable *table, DWORD coverage, +static unsigned int opentype_layout_is_glyph_covered(const struct scriptshaping_context *context, 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); @@ -3505,7 +3506,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(&cache->gpos.table, subtable_offset + coverage, + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, context->u.pos.glyphs[iter->pos]); if (coverage_index == GLYPH_NOT_COVERED) continue; @@ -3520,7 +3521,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(&cache->gpos.table, subtable_offset + coverage, + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, context->u.pos.glyphs[iter->pos]); if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= value_count) continue; @@ -3579,8 +3580,8 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont if (!coverage) continue;
- coverage_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - coverage, context->u.pos.glyphs[first_glyph]); + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, + context->u.pos.glyphs[first_glyph]); if (coverage_index == GLYPH_NOT_COVERED) continue;
@@ -3777,8 +3778,8 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c entry_count = table_read_be_word(&cache->gpos.table, subtable_offset + FIELD_OFFSET(struct ot_gpos_cursive_format1, count));
- glyph_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - coverage_offset, context->u.pos.glyphs[iter->pos]); + glyph_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage_offset, + context->u.pos.glyphs[iter->pos]); if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count) continue;
@@ -3791,8 +3792,8 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c if (!glyph_iterator_prev(&prev_iter)) continue;
- glyph_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - coverage_offset, context->u.pos.glyphs[prev_iter.pos]); + glyph_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage_offset, + context->u.pos.glyphs[prev_iter.pos]); if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count) continue;
@@ -3882,8 +3883,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap
mark_class_count = GET_BE_WORD(format1->mark_class_count);
- mark_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->mark_coverage), context->u.pos.glyphs[iter->pos]); + mark_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark_coverage), + context->u.pos.glyphs[iter->pos]);
if (mark_index == GLYPH_NOT_COVERED || mark_index >= GET_BE_WORD(mark_array->count)) continue; @@ -3893,8 +3894,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap if (!glyph_iterator_prev(&base_iter)) continue;
- base_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->base_coverage), context->u.pos.glyphs[base_iter.pos]); + base_index = opentype_layout_is_glyph_covered(context, 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)) continue;
@@ -3940,8 +3941,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshapi if (!format1) continue;
- mark_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->mark_coverage), context->u.pos.glyphs[iter->pos]); + mark_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark_coverage), + context->u.pos.glyphs[iter->pos]); if (mark_index == GLYPH_NOT_COVERED) continue;
@@ -3949,8 +3950,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshapi if (!glyph_iterator_prev(&lig_iter)) continue;
- lig_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->lig_coverage), context->u.pos.glyphs[lig_iter.pos]); + lig_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->lig_coverage), + context->u.pos.glyphs[lig_iter.pos]); if (lig_index == GLYPH_NOT_COVERED) continue;
@@ -3990,8 +3991,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap if (!format1) continue;
- mark1_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->mark1_coverage), context->u.pos.glyphs[iter->pos]); + mark1_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark1_coverage), + context->u.pos.glyphs[iter->pos]);
mark1_array_offset = subtable_offset + GET_BE_WORD(format1->mark1_array); if (!(count = table_read_be_word(&cache->gpos.table, mark1_array_offset))) @@ -4023,8 +4024,8 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap if (!mark2_array) continue;
- mark2_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset + - GET_BE_WORD(format1->mark2_coverage), context->u.pos.glyphs[mark_iter.pos]); + mark2_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(format1->mark2_coverage), + context->u.pos.glyphs[mark_iter.pos]);
if (mark2_index == GLYPH_NOT_COVERED || mark2_index >= count) continue; @@ -4181,7 +4182,7 @@ static int lookups_sorting_compare(const void *a, const void *b) return left->index < right->index ? -1 : left->index > right->index ? 1 : 0; };
-static BOOL opentype_layout_init_lookup(struct ot_gsubgpos_table *table, unsigned short lookup_index, unsigned int mask, +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; @@ -4216,7 +4217,7 @@ static BOOL opentype_layout_init_lookup(struct ot_gsubgpos_table *table, unsigne }
static void opentype_layout_add_lookups(const struct ot_feature_list *feature_list, UINT16 total_lookup_count, - struct ot_gsubgpos_table *table, struct shaping_feature *feature, struct lookups *lookups) + const struct ot_gsubgpos_table *table, struct shaping_feature *feature, struct lookups *lookups) { UINT16 feature_offset, lookup_count; unsigned int i; @@ -4256,7 +4257,7 @@ static void opentype_layout_add_lookups(const struct ot_feature_list *feature_li }
static void opentype_layout_collect_lookups(struct scriptshaping_context *context, unsigned int script_index, - unsigned int language_index, const struct shaping_features *features, struct ot_gsubgpos_table *table, + 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; @@ -4464,7 +4465,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup) { struct scriptshaping_cache *cache = context->cache; - const struct dwrite_fonttable *gsub = &cache->gsub.table; + const struct dwrite_fonttable *gsub = &context->table->table; UINT16 format, coverage, orig_glyph, glyph; unsigned int i, idx; BOOL ret; @@ -4477,16 +4478,15 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i); unsigned int coverage_index;
- format = table_read_be_word(&cache->gsub.table, subtable_offset); + format = table_read_be_word(gsub, subtable_offset);
- coverage = table_read_be_word(&cache->gsub.table, subtable_offset + - FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage)); + coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
if (format == 1) { const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1));
- coverage_index = opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) continue;
@@ -4499,7 +4499,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(gsub, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count) continue;
@@ -4525,7 +4525,6 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ 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) { - struct scriptshaping_cache *cache = context->cache; struct glyph_iterator iter; unsigned int i; UINT16 glyph; @@ -4544,11 +4543,8 @@ 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(&cache->gsub.table, subtable_offset + GET_BE_WORD(input[i]), - glyph) == GLYPH_NOT_COVERED) - { + if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[i]), glyph) == GLYPH_NOT_COVERED) return FALSE; - }
match_positions[i] = iter.pos; } @@ -4573,11 +4569,8 @@ 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->cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]), - glyph) == GLYPH_NOT_COVERED) - { + if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(backtrack[i]), glyph) == GLYPH_NOT_COVERED) return FALSE; - } }
*match_start = iter.pos; @@ -4588,7 +4581,6 @@ static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context 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) { - struct scriptshaping_cache *cache = context->cache; struct glyph_iterator iter; unsigned int i; UINT16 glyph; @@ -4601,11 +4593,8 @@ 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(&cache->gsub.table, subtable_offset + GET_BE_WORD(lookahead[i]), - glyph) == GLYPH_NOT_COVERED) - { + if (opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(lookahead[i]), glyph) == GLYPH_NOT_COVERED) return FALSE; - } }
*end_index = iter.pos; @@ -4637,7 +4626,7 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_conte orig_len = context->glyph_count;
lookup_index = GET_BE_WORD(lookup_records[i+1]); - if (opentype_layout_init_lookup(&context->cache->gsub, lookup_index, 0, &lookup)) + if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) opentype_layout_apply_gsub_lookup(context, &lookup);
delta = context->glyph_count - orig_len; @@ -4698,6 +4687,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts const struct lookup *lookup) { struct scriptshaping_cache *cache = context->cache; + const struct dwrite_fonttable *table = &context->table->table; UINT16 format, coverage; BOOL ret = FALSE; unsigned int i; @@ -4708,14 +4698,14 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts UINT16 glyph = context->u.subst.glyphs[context->cur]; unsigned int coverage_index = GLYPH_NOT_COVERED;
- format = table_read_be_word(&cache->gsub.table, subtable_offset); + format = table_read_be_word(&context->table->table, subtable_offset);
if (format == 1) { - coverage = table_read_be_word(&cache->gsub.table, subtable_offset + + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) continue;
@@ -4724,10 +4714,9 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts } else if (format == 2) { - coverage = table_read_be_word(&cache->gsub.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_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + coverage, glyph); + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) continue;
@@ -4741,30 +4730,27 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
unsigned int offset = subtable_offset + 2 /* format */;
- backtrack_count = table_read_be_word(&cache->gsub.table, offset); + backtrack_count = table_read_be_word(table, offset); offset += 2; - backtrack = table_read_ensure(&cache->gsub.table, offset, backtrack_count * sizeof(*backtrack)); + backtrack = table_read_ensure(table, offset, backtrack_count * sizeof(*backtrack)); offset += backtrack_count * sizeof(*backtrack);
- input_count = table_read_be_word(&cache->gsub.table, offset); + input_count = table_read_be_word(table, offset); offset += 2; - input = table_read_ensure(&cache->gsub.table, offset, input_count * sizeof(*input)); + input = table_read_ensure(table, offset, input_count * sizeof(*input)); offset += input_count * sizeof(*input);
- lookahead_count = table_read_be_word(&cache->gsub.table, offset); + lookahead_count = table_read_be_word(table, offset); offset += 2; - lookahead = table_read_ensure(&cache->gsub.table, offset, lookahead_count * sizeof(*lookahead)); + lookahead = table_read_ensure(table, offset, lookahead_count * sizeof(*lookahead)); offset += lookahead_count * sizeof(*lookahead);
- lookup_count = table_read_be_word(&cache->gsub.table, offset); + lookup_count = table_read_be_word(table, offset); offset += 2; - lookup_records = table_read_ensure(&cache->gsub.table, offset, lookup_count * 2 * sizeof(*lookup_records)); + lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records));
if (input) - { - coverage_index = opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(input[0]), - glyph); - } + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph);
if (coverage_index == GLYPH_NOT_COVERED) continue; @@ -4877,7 +4863,7 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int i; BOOL ret;
- opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gsub, &lookups); + opentype_layout_collect_lookups(context, script_index, language_index, features, context->table, &lookups);
opentype_get_nominal_glyphs(context, features); opentype_layout_set_glyph_masks(context, features);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 255 ++++++++++++++++++++++------------------- 1 file changed, 135 insertions(+), 120 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index d21397f30a2..81b6aaa229b 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -547,7 +547,7 @@ enum OPENTYPE_PLATFORM_ID OPENTYPE_PLATFORM_CUSTOM };
-struct ot_gsubgpos_extensionpos_format1 +struct ot_gsubgpos_extension_format1 { UINT16 format; UINT16 lookup_type; @@ -3385,7 +3385,7 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping FIELD_OFFSET(struct ot_lookup_table, subtable[subtable])); if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION) { - const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gpos.table, + const struct ot_gsubgpos_extension_format1 *format1 = table_read_ensure(&cache->gpos.table, lookup_offset + subtable_offset, sizeof(*format1)); subtable_offset += GET_BE_DWORD(format1->extension_offset); } @@ -3393,18 +3393,11 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping return lookup_offset + subtable_offset; }
-static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_cache *cache, +static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_context *context, unsigned int lookup_offset, unsigned int subtable) { - UINT16 lookup_type = table_read_be_word(&cache->gsub.table, lookup_offset); - unsigned int subtable_offset = table_read_be_word(&cache->gsub.table, lookup_offset + + unsigned int subtable_offset = table_read_be_word(&context->table->table, lookup_offset + FIELD_OFFSET(struct ot_lookup_table, subtable[subtable])); - if (lookup_type == GSUB_LOOKUP_EXTENSION_SUBST) - { - const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gsub.table, - lookup_offset + subtable_offset, sizeof(*format1)); - subtable_offset += GET_BE_DWORD(format1->extension_offset); - }
return lookup_offset + subtable_offset; } @@ -4086,7 +4079,7 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont lookup_type = GET_BE_WORD(lookup_table->lookup_type); if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION) { - const struct ot_gsubgpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table, + const struct ot_gsubgpos_extension_format1 *extension = table_read_ensure(&cache->gpos.table, lookup.offset + GET_BE_WORD(lookup_table->subtable[0]), sizeof(*extension)); WORD format;
@@ -4462,53 +4455,45 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, heap_free(lookups.lookups); }
-static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup) +static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup, + unsigned int subtable_offset) { - struct scriptshaping_cache *cache = context->cache; const struct dwrite_fonttable *gsub = &context->table->table; UINT16 format, coverage, orig_glyph, glyph; - unsigned int i, idx; + unsigned int idx, coverage_index; BOOL ret;
idx = context->cur; orig_glyph = glyph = context->u.subst.glyphs[idx];
- for (i = 0; i < lookup->subtable_count; ++i) - { - unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i); - unsigned int coverage_index; - - format = table_read_be_word(gsub, subtable_offset); + format = table_read_be_word(gsub, subtable_offset);
- coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage)); + coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
- if (format == 1) - { - const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1)); + if (format == 1) + { + 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); - if (coverage_index == GLYPH_NOT_COVERED) - continue; + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE;
- glyph = orig_glyph + GET_BE_WORD(format1->delta); - break; - } - else if (format == 2) - { - UINT16 count = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count)); - const struct ot_gsub_singlesubst_format2 *format2 = table_read_ensure(gsub, subtable_offset, - FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count) + count * sizeof(UINT16)); + glyph = orig_glyph + GET_BE_WORD(format1->delta); + } + else if (format == 2) + { + UINT16 count = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count)); + 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); - if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count) - continue; + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count) + return FALSE;
- glyph = GET_BE_WORD(format2->substitutes[coverage_index]); - break; - } - else - WARN("Unknown single substitution format %u.\n", format); + glyph = GET_BE_WORD(format2->substitutes[coverage_index]); } + else + WARN("Unknown single substitution format %u.\n", format);
if ((ret = (glyph != orig_glyph))) { @@ -4684,111 +4669,141 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping }
static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context, - const struct lookup *lookup) + const struct lookup *lookup, unsigned int subtable_offset) { - struct scriptshaping_cache *cache = context->cache; const struct dwrite_fonttable *table = &context->table->table; - UINT16 format, coverage; + unsigned int coverage_index = GLYPH_NOT_COVERED; + UINT16 glyph, format, coverage; BOOL ret = FALSE; - unsigned int i;
- for (i = 0; i < lookup->subtable_count; ++i) - { - unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i); - UINT16 glyph = context->u.subst.glyphs[context->cur]; - unsigned int coverage_index = GLYPH_NOT_COVERED; + glyph = context->u.subst.glyphs[context->cur];
- format = table_read_be_word(&context->table->table, subtable_offset); + format = table_read_be_word(table, subtable_offset);
- if (format == 1) - { - coverage = table_read_be_word(table, subtable_offset + - FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage)); + if (format == 1) + { + 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); - if (coverage_index == GLYPH_NOT_COVERED) - continue; + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE;
- WARN("Chaining contextual substitution (1) is not supported.\n"); - break; - } - else if (format == 2) - { - coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage)); + WARN("Chaining contextual substitution (1) is not supported.\n"); + } + else if (format == 2) + { + 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); - if (coverage_index == GLYPH_NOT_COVERED) - continue; + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE;
- WARN("Chaining contextual substitution (2) is not supported.\n"); - break; - } - else if (format == 3) - { - unsigned int backtrack_count, input_count, lookahead_count, lookup_count; - const UINT16 *backtrack, *lookahead, *input, *lookup_records; + WARN("Chaining contextual substitution (2) is not supported.\n"); + } + else if (format == 3) + { + unsigned int backtrack_count, input_count, lookahead_count, lookup_count; + const UINT16 *backtrack, *lookahead, *input, *lookup_records;
- unsigned int offset = subtable_offset + 2 /* format */; + unsigned int offset = subtable_offset + 2 /* format */;
- backtrack_count = table_read_be_word(table, offset); - offset += 2; - backtrack = table_read_ensure(table, offset, backtrack_count * sizeof(*backtrack)); - offset += backtrack_count * sizeof(*backtrack); + backtrack_count = table_read_be_word(table, offset); + offset += 2; + backtrack = table_read_ensure(table, offset, backtrack_count * sizeof(*backtrack)); + offset += backtrack_count * sizeof(*backtrack);
- input_count = table_read_be_word(table, offset); - offset += 2; - input = table_read_ensure(table, offset, input_count * sizeof(*input)); - offset += input_count * sizeof(*input); + input_count = table_read_be_word(table, offset); + offset += 2; + input = table_read_ensure(table, offset, input_count * sizeof(*input)); + offset += input_count * sizeof(*input);
- lookahead_count = table_read_be_word(table, offset); - offset += 2; - lookahead = table_read_ensure(table, offset, lookahead_count * sizeof(*lookahead)); - offset += lookahead_count * sizeof(*lookahead); + lookahead_count = table_read_be_word(table, offset); + offset += 2; + lookahead = table_read_ensure(table, offset, lookahead_count * sizeof(*lookahead)); + offset += lookahead_count * sizeof(*lookahead);
- lookup_count = table_read_be_word(table, offset); - offset += 2; - lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records)); + lookup_count = table_read_be_word(table, offset); + offset += 2; + 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); + if (input) + coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph);
- if (coverage_index == GLYPH_NOT_COVERED) - continue; + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE;
- if ((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))) - { - break; - } - } - else - WARN("Unknown chaining contextual substitution format %u.\n", format); + 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); } + else + WARN("Unknown chaining contextual substitution format %u.\n", format);
return ret; }
+static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshaping_context *context, + unsigned int *subtable_offset) +{ + const struct ot_gsubgpos_extension_format1 *format1; + + if (!(format1 = table_read_ensure(&context->table->table, *subtable_offset, sizeof(*format1)))) + return 0; + + if (GET_BE_WORD(format1->format) != 1) + { + WARN("Unexpected extension table format %#x.\n", format1->format); + return 0; + } + + *subtable_offset = *subtable_offset + GET_BE_DWORD(format1->extension_offset); + + return GET_BE_WORD(format1->lookup_type); +} + static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup) { + unsigned int i, lookup_type; BOOL ret = FALSE;
- switch (lookup->type) + for (i = 0; i < lookup->subtable_count; ++i) { - case GSUB_LOOKUP_SINGLE_SUBST: - ret = opentype_layout_apply_gsub_single_substitution(context, lookup); - break; - case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: - ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup); - break; - case GSUB_LOOKUP_MULTIPLE_SUBST: - case GSUB_LOOKUP_ALTERNATE_SUBST: - case GSUB_LOOKUP_LIGATURE_SUBST: - case GSUB_LOOKUP_CONTEXTUAL_SUBST: - case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: - WARN("Unimplemented lookup %d.\n", lookup->type); + unsigned int subtable_offset = opentype_layout_get_gsub_subtable(context, lookup->offset, i); + + if (lookup->type == GSUB_LOOKUP_EXTENSION_SUBST) + { + lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset); + if (!lookup_type) + continue; + } + else + lookup_type = lookup->type; + + switch (lookup_type) + { + case GSUB_LOOKUP_SINGLE_SUBST: + ret = opentype_layout_apply_gsub_single_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_MULTIPLE_SUBST: + case GSUB_LOOKUP_ALTERNATE_SUBST: + case GSUB_LOOKUP_LIGATURE_SUBST: + case GSUB_LOOKUP_CONTEXTUAL_SUBST: + case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: + WARN("Unimplemented lookup %d.\n", lookup->type); + break; + case GSUB_LOOKUP_EXTENSION_SUBST: + WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type); + break; + default: + WARN("Unknown lookup type %u.\n", lookup_type); + } + + if (ret) break; - default: - WARN("Unknown lookup type %u.\n", lookup->type); }
return ret;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 84 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 81b6aaa229b..c815165505e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -569,6 +569,14 @@ struct ot_gsub_singlesubst_format2 UINT16 substitutes[1]; };
+struct ot_gsub_altsubst_format1 +{ + UINT16 format; + UINT16 coverage; + UINT16 count; + UINT16 sets[1]; +}; + struct ot_gsub_chaincontext_subst_format1 { UINT16 format; @@ -3256,6 +3264,23 @@ static inline unsigned int dwrite_popcount(unsigned int x) #endif }
+static inline unsigned int dwrite_ctz(unsigned int x) +{ +#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))) + return __builtin_ctz(x); +#else + unsigned int c = 32; + x &= - (int) x; + if (x) c--; + if (x & 0x0000ffff) c -= 16; + if (x & 0x00ff00ff) c -= 8; + if (x & 0x0f0f0f0f) c -= 4; + if (x & 0x33333333) c -= 2; + if (x & 0x55555555) c -= 1; + return c; +#endif +} + static inline unsigned int dwrite_log2i(unsigned int x) { #if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))) @@ -4505,6 +4530,61 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_ return ret; }
+static BOOL opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_context *context, const struct lookup *lookup, + unsigned int subtable_offset) +{ + const struct dwrite_fonttable *gsub = &context->table->table; + UINT16 format, coverage, orig_glyph, glyph; + unsigned int idx, coverage_index, offset; + BOOL ret; + + idx = context->cur; + orig_glyph = glyph = context->u.subst.glyphs[idx]; + + format = table_read_be_word(gsub, subtable_offset); + + if (format == 1) + { + const struct ot_gsub_altsubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1)); + unsigned int count, shift, alt_index; + + 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); + if (coverage_index == GLYPH_NOT_COVERED) + return FALSE; + + if (coverage_index >= GET_BE_WORD(format1->count)) + return FALSE; + + offset = table_read_be_word(gsub, subtable_offset + + FIELD_OFFSET(struct ot_gsub_altsubst_format1, sets[coverage_index])); + + count = table_read_be_word(gsub, subtable_offset + offset); + if (!count) + return FALSE; + + shift = dwrite_ctz(lookup->mask); + alt_index = (lookup->mask & context->glyph_infos[idx].mask) >> shift; + + if (alt_index > count || !alt_index) + return FALSE; + + glyph = table_read_be_word(gsub, subtable_offset + offset + sizeof(count) + (alt_index - 1) * sizeof(glyph)); + } + else + WARN("Unexpected alternate substitution format %d.\n", format); + + if ((ret = (glyph != orig_glyph))) + { + context->u.subst.glyphs[idx] = glyph; + opentype_set_subst_glyph_props(context, idx, glyph); + context->cur++; + } + + return ret; +} + #define CHAIN_CONTEXT_MAX_LENGTH 64
static BOOL opentype_layout_context_match_input(struct scriptshaping_context *context, unsigned int subtable_offset, @@ -4785,11 +4865,13 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont case GSUB_LOOKUP_SINGLE_SUBST: ret = opentype_layout_apply_gsub_single_substitution(context, lookup, subtable_offset); break; + case GSUB_LOOKUP_ALTERNATE_SUBST: + ret = opentype_layout_apply_gsub_alt_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_MULTIPLE_SUBST: - case GSUB_LOOKUP_ALTERNATE_SUBST: case GSUB_LOOKUP_LIGATURE_SUBST: case GSUB_LOOKUP_CONTEXTUAL_SUBST: case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 2 ++ dlls/dwrite/dwrite_private.h | 7 +++++++ dlls/dwrite/opentype.c | 32 +++++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index a7186a68156..556191a13d7 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1251,6 +1251,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 context.is_sideways = is_sideways; context.u.pos.glyphs = glyphs; context.u.pos.glyph_props = glyph_props; + context.u.pos.clustermap = clustermap; context.glyph_count = glyph_count; context.emsize = emSize; context.measuring_mode = DWRITE_MEASURING_MODE_NATURAL; @@ -1320,6 +1321,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite context.is_sideways = is_sideways; context.u.pos.glyphs = glyphs; context.u.pos.glyph_props = glyph_props; + context.u.pos.clustermap = clustermap; context.glyph_count = glyph_count; context.emsize = emSize * ppdip; context.measuring_mode = measuring_mode; diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index ad86422d50f..cf3e0f7c123 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -484,6 +484,7 @@ struct scriptshaping_context { const UINT16 *glyphs; const DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; + const UINT16 *clustermap; } pos; struct { @@ -494,6 +495,12 @@ struct scriptshaping_context unsigned int capacity; const WCHAR *digits; } subst; + struct + { + UINT16 *glyphs; + DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; + UINT16 *clustermap; + } buffer; } u;
const struct ot_gsubgpos_table *table; /* Either GSUB or GPOS. */ diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index c815165505e..f687740fa47 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4436,18 +4436,40 @@ static unsigned int shaping_features_get_mask(const struct shaping_features *fea return feature->mask; }
+static void opentype_layout_get_glyph_range_for_text(struct scriptshaping_context *context, unsigned int start_char, + unsigned int end_char, unsigned int *start_glyph, unsigned int *end_glyph) +{ + *start_glyph = context->u.buffer.clustermap[start_char]; + if (end_char >= context->length - 1) + *end_glyph = context->glyph_count - 1; + else + *end_glyph = context->u.buffer.clustermap[end_char + 1] - 1; +} + static void opentype_layout_set_glyph_masks(struct scriptshaping_context *context, const struct shaping_features *features) { const DWRITE_TYPOGRAPHIC_FEATURES **user_features = context->user_features.features; - unsigned int f, r, g, start_glyph = 0, mask, shift, value; + unsigned int f, r, g, start_char, mask, shift, value;
for (g = 0; g < context->glyph_count; ++g) context->glyph_infos[g].mask = context->global_mask;
/* FIXME: set shaper masks */
- for (r = 0; r < context->user_features.range_count; ++r) + for (r = 0, start_char = 0; r < context->user_features.range_count; ++r) { + unsigned int start_glyph, end_glyph; + + if (start_char >= context->length) + break; + + opentype_layout_get_glyph_range_for_text(context, start_char, start_char + context->user_features.range_lengths[r], + &start_glyph, &end_glyph); + start_char += context->user_features.range_lengths[r]; + + if (start_glyph > end_glyph || end_glyph >= context->glyph_count) + continue; + for (f = 0; f < user_features[r]->featureCount; ++f) { mask = shaping_features_get_mask(features, user_features[r]->features[f].nameTag, &shift); @@ -4455,9 +4477,9 @@ static void opentype_layout_set_glyph_masks(struct scriptshaping_context *contex continue;
value = (user_features[r]->features[f].parameter << shift) & mask; - for (g = 0; g < context->user_features.range_lengths[r]; ++g) - context->glyph_infos[g + start_glyph].mask = (context->glyph_infos[g + start_glyph].mask & ~mask) | value; - start_glyph += context->user_features.range_lengths[r]; + + for (g = start_glyph; g <= end_glyph; ++g) + context->glyph_infos[g].mask = (context->glyph_infos[g].mask & ~mask) | value; } } }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index f687740fa47..18bffc3fa2e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4923,6 +4923,20 @@ static unsigned int unicode_get_mirrored_char(unsigned int codepoint) return mirror ? mirror : codepoint; }
+/* + * 034F # Mn COMBINING GRAPHEME JOINER + * 061C # Cf ARABIC LETTER MARK + * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE + * 180E # Cf MONGOLIAN VOWEL SEPARATOR + * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK + * FEFF # Cf ZERO WIDTH NO-BREAK SPACE +*/ +static unsigned int opentype_is_default_ignorable(unsigned int codepoint) +{ + return codepoint == 0x34f || codepoint == 0x61c || codepoint == 0xfeff || + (codepoint >= 0x180b && codepoint <= 0x180e) || (codepoint >= 0x200b && codepoint <= 0x200f); +} + static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, const struct shaping_features *features) { unsigned int rtlm_mask = shaping_features_get_mask(features, DWRITE_MAKE_OPENTYPE_TAG('r','t','l','m'), NULL); @@ -4964,6 +4978,8 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c context->u.subst.glyph_props[g].justification = SCRIPT_JUSTIFY_CHARACTER; context->u.subst.glyph_props[g].isClusterStart = 1; opentype_set_subst_glyph_props(context, g, context->u.subst.glyphs[g]); + if (opentype_is_default_ignorable(codepoint)) + context->u.subst.glyph_props[g].isZeroWidthSpace = 1; context->glyph_count++;
clustermap[i] = i;