dwrite: Keep track of shaping stage feature applies to.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Nikolay Sivov 2020-05-22 13:58:06 +03:00 committed by Alexandre Julliard
parent 7780d7856b
commit b8625c7f03
3 changed files with 71 additions and 50 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;