From b8625c7f035deddcc3129d76627c54b6faabd3ae Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 22 May 2020 13:58:06 +0300 Subject: [PATCH] dwrite: Keep track of shaping stage feature applies to. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/dwrite_private.h | 2 + dlls/dwrite/opentype.c | 117 ++++++++++++++++++++--------------- dlls/dwrite/shape.c | 2 + 3 files changed, 71 insertions(+), 50 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 3145daba4bb..ef48ec18c4a 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -528,6 +528,7 @@ struct shaping_feature unsigned int default_value; unsigned int mask; unsigned int shift; + unsigned int stage; }; struct shaping_features @@ -535,6 +536,7 @@ struct shaping_features struct shaping_feature *features; size_t count; size_t capacity; + unsigned int stage; }; extern void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache *cache) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index d2a9318da87..1cb61027b4e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4131,14 +4131,57 @@ static int lookups_sorting_compare(const void *a, const void *b) return left->index < right->index ? -1 : left->index > right->index ? 1 : 0; }; +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) +{ + UINT16 feature_offset, lookup_count; + unsigned int i, j; + + /* Feature wasn't found */ + 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 + + FIELD_OFFSET(struct ot_feature, lookup_count)); + if (!lookup_count) + return; + + if (!dwrite_array_reserve((void **)&lookups->lookups, &lookups->capacity, lookups->count + lookup_count, + sizeof(*lookups->lookups))) + { + return; + } + + for (i = 0; i < lookup_count; ++i) + { + UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + + FIELD_OFFSET(struct ot_feature, lookuplist_index[i])); + + if (lookup_index >= total_lookup_count) + continue; + + j = lookups->count; + lookups->lookups[j].index = lookup_index; + lookups->lookups[j].mask = feature->mask; + lookups->count++; + } +} + 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, struct lookups *lookups) { UINT16 table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count; const struct ot_feature_list *feature_list; + unsigned int last_num_lookups = 0, stage; struct shaping_feature *feature; - unsigned int i, j, l, next_bit; + unsigned int i, j, next_bit; unsigned int global_bit_shift = 1; unsigned int global_bit_mask = 1; UINT16 feature_index; @@ -4235,51 +4278,37 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex } } - /* Collect lookups for all given features. */ - for (i = 0; i < features->count; ++i) + for (stage = 0; stage <= features->stage; ++stage) { - UINT16 feature_offset, lookup_count; - - feature = &features->features[i]; - - /* Feature wasn't found */ - if (feature->index == 0xffff) - continue; - - /* FIXME: skip non-global ones for now. */ - if (!(feature->flags & FEATURE_GLOBAL)) - continue; - - feature_offset = GET_BE_WORD(feature_list->features[feature->index].offset); - - lookup_count = table_read_be_word(&table->table, table->feature_list + feature_offset + - FIELD_OFFSET(struct ot_feature, lookup_count)); - if (!lookup_count) - continue; - - if (!dwrite_array_reserve((void **)&lookups->lookups, &lookups->capacity, lookups->count + lookup_count, - sizeof(*lookups->lookups))) + for (i = 0; i < features->count; ++i) { - return; + if (features->features[i].stage == stage) + opentype_layout_add_lookups(feature_list, total_lookup_count, table, &features->features[i], lookups); } - for (l = 0; l < lookup_count; ++l) + /* Sort and merge lookups for current stage. */ + if (last_num_lookups < lookups->count) { - UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + - FIELD_OFFSET(struct ot_feature, lookuplist_index[l])); + qsort(lookups->lookups + last_num_lookups, lookups->count - last_num_lookups, sizeof(*lookups->lookups), + lookups_sorting_compare); - if (lookup_index >= total_lookup_count) - continue; - - j = lookups->count; - lookups->lookups[j].index = lookup_index; - lookups->lookups[j].mask = feature->mask; - lookups->count++; + j = last_num_lookups; + for (i = j + 1; i < lookups->count; ++i) + { + if (lookups->lookups[i].index != lookups->lookups[j].index) + { + lookups->lookups[++j] = lookups->lookups[i]; + } + else + { + lookups->lookups[j].mask |= lookups->lookups[i].mask; + } + } + lookups->count = j + 1; } + + last_num_lookups = lookups->count; } - - /* Sort lookups. */ - qsort(lookups->lookups, lookups->count, sizeof(*lookups->lookups), lookups_sorting_compare); } void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index, @@ -4291,13 +4320,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 < lookups.count; ++i) - { - /* Skip duplicates. */ - if (i && lookups.lookups[i].index == lookups.lookups[i - 1].index) - continue; - opentype_layout_apply_gpos_lookup(context, lookups.lookups[i].index); - } heap_free(lookups.lookups); } @@ -4607,13 +4630,7 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gsub, &lookups); for (i = 0; i < lookups.count; ++i) - { - /* Skip duplicates. */ - if (i && lookups.lookups[i].index == lookups.lookups[i - 1].index) - continue; - opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.lookups[i].index); - } heap_free(lookups.lookups); diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index df680373a24..0f88ad48215 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -213,6 +213,7 @@ static void shape_add_feature_full(struct shaping_features *features, unsigned i features->features[i].flags = flags; features->features[i].max_value = value; features->features[i].default_value = flags & FEATURE_GLOBAL ? value : 0; + features->features[i].stage = features->stage; features->count++; } @@ -267,6 +268,7 @@ static void shape_merge_features(struct scriptshaping_context *context, struct s features->features[j].flags ^= FEATURE_GLOBAL; features->features[j].max_value = max(features->features[j].max_value, features->features[i].max_value); } + features->features[j].stage = min(features->features[j].stage, features->features[i].stage); } } features->count = j + 1;