Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/shape.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 0372d739b56..82ad3a2a1e7 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -210,6 +210,27 @@ static void shape_add_feature(struct shaping_features *features, unsigned int ta features->features[features->count++].tag = tag; }
+static int features_sorting_compare(const void *a, const void *b) +{ + const struct shaping_feature *left = a, *right = b; + return left->tag != right->tag ? (left->tag < right->tag ? -1 : 1) : 0; +}; + +static void shape_merge_features(struct shaping_features *features) +{ + unsigned int j = 0, i; + + /* Sort and merge duplicates. */ + qsort(features->features, features->count, sizeof(*features->features), features_sorting_compare); + + for (i = 1; i < features->count; ++i) + { + if (features->features[i].tag != features->features[j].tag) + features->features[++j] = features->features[i]; + } + features->count = j + 1; +} + HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigned int *scripts) { static const unsigned int common_features[] = @@ -239,6 +260,8 @@ HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigne shape_add_feature(&features, horizontal_features[i]); }
+ shape_merge_features(&features); + /* Resolve script tag to actually supported script. */ if (cache->gpos.table.data) { @@ -322,6 +345,8 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i shape_add_feature(&features, horizontal_features[i]); }
+ shape_merge_features(&features); + /* Resolve script tag to actually supported script. */ if (cache->gsub.table.data) {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/opentype.c | 60 +++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 22 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 0b863147af3..db3543d79ed 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -508,6 +508,7 @@ extern struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_font struct shaping_feature { unsigned int tag; + unsigned int index; };
struct shaping_features diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index f22cd7469b0..411b3df855e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4099,6 +4099,7 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex { UINT16 table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count; const struct ot_feature_list *feature_list; + UINT16 feature_index; unsigned int i, j, l;
/* ScriptTable offset. */ @@ -4132,42 +4133,57 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex if (!feature_list) return;
- /* Collect lookups for all given features. */ for (i = 0; i < features->count; ++i) { + BOOL found = FALSE; + for (j = 0; j < script_feature_count; ++j) { - UINT16 feature_index = table_read_be_word(&table->table, table->script_list + table_offset + + feature_index = table_read_be_word(&table->table, table->script_list + table_offset + langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j])); if (feature_index >= total_feature_count) continue; - if (feature_list->features[feature_index].tag == features->features[i].tag) { - WORD feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset); - WORD lookup_count; + found = TRUE; + features->features[i].index = feature_index; + break; + } + }
- 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 (!found) + features->features[i].index = 0xffff; + }
- if (!dwrite_array_reserve((void **)&lookups->indexes, &lookups->capacity, lookups->count + lookup_count, - sizeof(*lookups->indexes))) - { - return; - } + /* Collect lookups for all given features. */ + for (i = 0; i < features->count; ++i) + { + feature_index = features->features[i].index; + if (feature_index != 0xffff) + { + UINT16 feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset); + UINT16 lookup_count;
- for (l = 0; l < lookup_count; ++l) - { - UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + - FIELD_OFFSET(struct ot_feature, lookuplist_index[l])); + 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->indexes, &lookups->capacity, lookups->count + lookup_count, + sizeof(*lookups->indexes))) + { + return; + } + + for (l = 0; l < lookup_count; ++l) + { + UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + + FIELD_OFFSET(struct ot_feature, lookuplist_index[l]));
- if (lookup_index >= total_lookup_count) - continue; + if (lookup_index >= total_lookup_count) + continue;
- lookups->indexes[lookups->count++] = lookup_index; - } + lookups->indexes[lookups->count++] = lookup_index; } } }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 7 +++++++ dlls/dwrite/opentype.c | 15 +++++++++++++-- dlls/dwrite/shape.c | 13 +++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index db3543d79ed..06fcf8d7480 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -505,10 +505,17 @@ extern struct scriptshaping_cache *create_scriptshaping_cache(void *context, extern void release_scriptshaping_cache(struct scriptshaping_cache*) DECLSPEC_HIDDEN; extern struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface) DECLSPEC_HIDDEN;
+enum shaping_feature_flags +{ + FEATURE_GLOBAL = 0x1, + FEATURE_GLOBAL_SEARCH = 0x2, +}; + struct shaping_feature { unsigned int tag; unsigned int index; + unsigned int flags; };
struct shaping_features diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 411b3df855e..713a5002f35 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4143,14 +4143,25 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j])); if (feature_index >= total_feature_count) continue; - if (feature_list->features[feature_index].tag == features->features[i].tag) + if ((found = feature_list->features[feature_index].tag == features->features[i].tag)) { - found = TRUE; features->features[i].index = feature_index; break; } }
+ if (!found && (features->features[i].flags & FEATURE_GLOBAL_SEARCH)) + { + for (j = 0; j < total_feature_count; ++j) + { + if ((found = (feature_list->features[j].tag == features->features[i].tag))) + { + features->features[i].index = j; + break; + } + } + } + if (!found) features->features[i].index = 0xffff; } diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 82ad3a2a1e7..4de73953d47 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -201,13 +201,20 @@ static DWORD shape_select_language(const struct scriptshaping_cache *cache, DWOR return 0; }
-static void shape_add_feature(struct shaping_features *features, unsigned int tag) +static void shape_add_feature_flags(struct shaping_features *features, unsigned int tag, unsigned int flags) { if (!dwrite_array_reserve((void **)&features->features, &features->capacity, features->count + 1, sizeof(*features->features))) return;
- features->features[features->count++].tag = tag; + features->features[features->count].tag = tag; + features->features[features->count].flags = flags; + features->count++; +} + +static void shape_add_feature(struct shaping_features *features, unsigned int tag) +{ + shape_add_feature_flags(features, tag, FEATURE_GLOBAL); }
static int features_sorting_compare(const void *a, const void *b) @@ -344,6 +351,8 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i for (i = 0; i < ARRAY_SIZE(horizontal_features); ++i) shape_add_feature(&features, horizontal_features[i]); } + else + shape_add_feature_flags(&features, DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t'), FEATURE_GLOBAL_SEARCH);
shape_merge_features(&features);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 9 +++++++++ dlls/dwrite/dwrite_private.h | 7 +++++++ dlls/dwrite/shape.c | 23 ++++++++++++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 2cbac7700c7..98e1ef4a0dc 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1256,6 +1256,9 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, context.u.subst.max_glyph_count = max_glyph_count; context.glyph_count = g; context.language_tag = get_opentype_language(locale); + context.user_features.features = features; + context.user_features.range_lengths = feature_range_lengths; + context.user_features.range_count = feature_ranges;
script = analysis->script > Script_LastId ? Script_Unknown : analysis->script; scriptprops = &dwritescripts_properties[script]; @@ -1321,6 +1324,9 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 context.advances = advances; context.offsets = offsets; context.language_tag = get_opentype_language(locale); + context.user_features.features = features; + context.user_features.range_lengths = feature_range_lengths; + context.user_features.range_count = feature_ranges;
return shape_get_positions(&context, scriptprops->scripttags); } @@ -1380,6 +1386,9 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite context.advances = advances; context.offsets = offsets; context.language_tag = get_opentype_language(locale); + context.user_features.features = features; + context.user_features.range_lengths = feature_range_lengths; + context.user_features.range_count = feature_ranges;
return shape_get_positions(&context, scriptprops->scripttags); } diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 06fcf8d7480..cad74d9e947 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -486,6 +486,13 @@ struct scriptshaping_context } subst; } u;
+ struct + { + const DWRITE_TYPOGRAPHIC_FEATURES **features; + const unsigned int *range_lengths; + unsigned int range_count; + } user_features; + unsigned int glyph_count; float emsize; DWRITE_MEASURING_MODE measuring_mode; diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 4de73953d47..57c06f62e84 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -223,10 +223,27 @@ static int features_sorting_compare(const void *a, const void *b) return left->tag != right->tag ? (left->tag < right->tag ? -1 : 1) : 0; };
-static void shape_merge_features(struct shaping_features *features) +static void shape_merge_features(struct scriptshaping_context *context, struct shaping_features *features) { + const DWRITE_TYPOGRAPHIC_FEATURES **user_features = context->user_features.features; unsigned int j = 0, i;
+ /* For now only consider global, enabled user features. */ + if (user_features && context->user_features.range_lengths && context->user_features.range_count == 1) + { + for (i = 0; i < context->user_features.range_count; ++i) + { + if (context->user_features.range_lengths[i] != context->length) + break; + + for (j = 0; j < user_features[i]->featureCount; ++j) + { + if (user_features[i]->features[j].parameter == 1) + shape_add_feature(features, user_features[i]->features[j].nameTag); + } + } + } + /* Sort and merge duplicates. */ qsort(features->features, features->count, sizeof(*features->features), features_sorting_compare);
@@ -267,7 +284,7 @@ HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigne shape_add_feature(&features, horizontal_features[i]); }
- shape_merge_features(&features); + shape_merge_features(context, &features);
/* Resolve script tag to actually supported script. */ if (cache->gpos.table.data) @@ -354,7 +371,7 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i else shape_add_feature_flags(&features, DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t'), FEATURE_GLOBAL_SEARCH);
- shape_merge_features(&features); + shape_merge_features(context, &features);
/* Resolve script tag to actually supported script. */ if (cache->gsub.table.data)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 2 ++ dlls/dwrite/opentype.c | 49 ++++++++++++++++++++---------------- dlls/dwrite/shape.c | 43 +++++++++++++++++++++---------- 3 files changed, 60 insertions(+), 34 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index cad74d9e947..8b5fefc66bd 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -523,6 +523,8 @@ struct shaping_feature unsigned int tag; unsigned int index; unsigned int flags; + unsigned int max_value; + unsigned int default_value; };
struct shaping_features diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 713a5002f35..8904dc546e9 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4169,33 +4169,40 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex /* Collect lookups for all given features. */ for (i = 0; i < features->count; ++i) { + UINT16 feature_offset, lookup_count; + feature_index = features->features[i].index; - if (feature_index != 0xffff) - { - UINT16 feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset); - UINT16 lookup_count;
- lookup_count = table_read_be_word(&table->table, table->feature_list + feature_offset + - FIELD_OFFSET(struct ot_feature, lookup_count)); - if (!lookup_count) - continue; + /* Feature wasn't found */ + if (feature_index == 0xffff) + continue;
- if (!dwrite_array_reserve((void **)&lookups->indexes, &lookups->capacity, lookups->count + lookup_count, - sizeof(*lookups->indexes))) - { - return; - } + /* FIXME: skip non-global ones for now. */ + if (!(features->features[i].flags & FEATURE_GLOBAL)) + continue;
- for (l = 0; l < lookup_count; ++l) - { - UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + - FIELD_OFFSET(struct ot_feature, lookuplist_index[l])); + feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset);
- if (lookup_index >= total_lookup_count) - continue; + lookup_count = table_read_be_word(&table->table, table->feature_list + feature_offset + + FIELD_OFFSET(struct ot_feature, lookup_count)); + if (!lookup_count) + continue;
- lookups->indexes[lookups->count++] = lookup_index; - } + if (!dwrite_array_reserve((void **)&lookups->indexes, &lookups->capacity, lookups->count + lookup_count, + sizeof(*lookups->indexes))) + { + return; + } + + for (l = 0; l < lookup_count; ++l) + { + UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset + + FIELD_OFFSET(struct ot_feature, lookuplist_index[l])); + + if (lookup_index >= total_lookup_count) + continue; + + lookups->indexes[lookups->count++] = lookup_index; } }
diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 57c06f62e84..df680373a24 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -201,20 +201,24 @@ static DWORD shape_select_language(const struct scriptshaping_cache *cache, DWOR return 0; }
-static void shape_add_feature_flags(struct shaping_features *features, unsigned int tag, unsigned int flags) +static void shape_add_feature_full(struct shaping_features *features, unsigned int tag, unsigned int flags, unsigned int value) { + unsigned int i = features->count; + if (!dwrite_array_reserve((void **)&features->features, &features->capacity, features->count + 1, sizeof(*features->features))) return;
- features->features[features->count].tag = tag; - features->features[features->count].flags = flags; + features->features[i].tag = tag; + features->features[i].flags = flags; + features->features[i].max_value = value; + features->features[i].default_value = flags & FEATURE_GLOBAL ? value : 0; features->count++; }
static void shape_add_feature(struct shaping_features *features, unsigned int tag) { - shape_add_feature_flags(features, tag, FEATURE_GLOBAL); + shape_add_feature_full(features, tag, FEATURE_GLOBAL, 1); }
static int features_sorting_compare(const void *a, const void *b) @@ -229,18 +233,16 @@ static void shape_merge_features(struct scriptshaping_context *context, struct s unsigned int j = 0, i;
/* For now only consider global, enabled user features. */ - if (user_features && context->user_features.range_lengths && context->user_features.range_count == 1) + if (user_features && context->user_features.range_lengths) { + unsigned int flags = context->user_features.range_count == 1 && + context->user_features.range_lengths[0] == context->length ? FEATURE_GLOBAL : 0; + for (i = 0; i < context->user_features.range_count; ++i) { - if (context->user_features.range_lengths[i] != context->length) - break; - for (j = 0; j < user_features[i]->featureCount; ++j) - { - if (user_features[i]->features[j].parameter == 1) - shape_add_feature(features, user_features[i]->features[j].nameTag); - } + shape_add_feature_full(features, user_features[i]->features[j].nameTag, flags, + user_features[i]->features[j].parameter); } }
@@ -251,6 +253,21 @@ static void shape_merge_features(struct scriptshaping_context *context, struct s { if (features->features[i].tag != features->features[j].tag) features->features[++j] = features->features[i]; + else + { + if (features->features[i].flags & FEATURE_GLOBAL) + { + features->features[j].flags |= FEATURE_GLOBAL; + features->features[j].max_value = features->features[i].max_value; + features->features[j].default_value = features->features[i].default_value; + } + else + { + if (features->features[j].flags & FEATURE_GLOBAL) + features->features[j].flags ^= FEATURE_GLOBAL; + features->features[j].max_value = max(features->features[j].max_value, features->features[i].max_value); + } + } } features->count = j + 1; } @@ -369,7 +386,7 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i shape_add_feature(&features, horizontal_features[i]); } else - shape_add_feature_flags(&features, DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t'), FEATURE_GLOBAL_SEARCH); + shape_add_feature_full(&features, DWRITE_MAKE_OPENTYPE_TAG('v','e','r','t'), FEATURE_GLOBAL | FEATURE_GLOBAL_SEARCH, 1);
shape_merge_features(context, &features);