dwrite: Add a helper to collect gsub/gpos lookups.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
bd6a500ab0
commit
5eb742687d
|
@ -4054,43 +4054,41 @@ static int lookups_sorting_compare(const void *left, const void *right)
|
||||||
return *(int *)left - *(int *)right;
|
return *(int *)left - *(int *)right;
|
||||||
};
|
};
|
||||||
|
|
||||||
void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
|
static void opentype_layout_collect_lookups(struct scriptshaping_context *context, unsigned int script_index,
|
||||||
unsigned int script_index, unsigned int language_index, const struct shaping_features *features)
|
unsigned int language_index, const struct shaping_features *features, struct ot_gsubgpos_table *table,
|
||||||
|
struct lookups *lookups)
|
||||||
{
|
{
|
||||||
WORD table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count;
|
UINT16 table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count;
|
||||||
struct scriptshaping_cache *cache = context->cache;
|
|
||||||
const struct ot_feature_list *feature_list;
|
const struct ot_feature_list *feature_list;
|
||||||
struct lookups lookups = { 0 };
|
|
||||||
unsigned int i, j, l;
|
unsigned int i, j, l;
|
||||||
|
|
||||||
/* ScriptTable offset. */
|
/* ScriptTable offset. */
|
||||||
table_offset = table_read_be_word(&cache->gpos.table, cache->gpos.script_list +
|
table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) +
|
||||||
FIELD_OFFSET(struct ot_script_list, scripts) + script_index * sizeof(struct ot_script_record) +
|
script_index * sizeof(struct ot_script_record) + FIELD_OFFSET(struct ot_script_record, script));
|
||||||
FIELD_OFFSET(struct ot_script_record, script));
|
|
||||||
if (!table_offset)
|
if (!table_offset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (language_index == ~0u)
|
if (language_index == ~0u)
|
||||||
langsys_offset = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset);
|
langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset);
|
||||||
else
|
else
|
||||||
langsys_offset = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
|
langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset +
|
||||||
FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) +
|
FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) +
|
||||||
FIELD_OFFSET(struct ot_langsys_record, langsys));
|
FIELD_OFFSET(struct ot_langsys_record, langsys));
|
||||||
|
|
||||||
script_feature_count = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
|
script_feature_count = table_read_be_word(&table->table, table->script_list + table_offset + langsys_offset +
|
||||||
langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_count));
|
FIELD_OFFSET(struct ot_langsys, feature_count));
|
||||||
if (!script_feature_count)
|
if (!script_feature_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
total_feature_count = table_read_be_word(&cache->gpos.table, cache->gpos.feature_list);
|
total_feature_count = table_read_be_word(&table->table, table->feature_list);
|
||||||
if (!total_feature_count)
|
if (!total_feature_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
total_lookup_count = table_read_be_word(&cache->gpos.table, cache->gpos.lookup_list);
|
total_lookup_count = table_read_be_word(&table->table, table->lookup_list);
|
||||||
if (!total_lookup_count)
|
if (!total_lookup_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
feature_list = table_read_ensure(&cache->gpos.table, cache->gpos.feature_list,
|
feature_list = table_read_ensure(&table->table, table->feature_list,
|
||||||
FIELD_OFFSET(struct ot_feature_list, features[total_feature_count]));
|
FIELD_OFFSET(struct ot_feature_list, features[total_feature_count]));
|
||||||
if (!feature_list)
|
if (!feature_list)
|
||||||
return;
|
return;
|
||||||
|
@ -4100,7 +4098,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
|
||||||
{
|
{
|
||||||
for (j = 0; j < script_feature_count; ++j)
|
for (j = 0; j < script_feature_count; ++j)
|
||||||
{
|
{
|
||||||
WORD feature_index = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
|
UINT16 feature_index = table_read_be_word(&table->table, table->script_list + table_offset +
|
||||||
langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j]));
|
langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j]));
|
||||||
if (feature_index >= total_feature_count)
|
if (feature_index >= total_feature_count)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4110,49 +4108,78 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
|
||||||
WORD feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset);
|
WORD feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset);
|
||||||
WORD lookup_count;
|
WORD lookup_count;
|
||||||
|
|
||||||
lookup_count = table_read_be_word(&cache->gpos.table, cache->gpos.feature_list + feature_offset +
|
lookup_count = table_read_be_word(&table->table, table->feature_list + feature_offset +
|
||||||
FIELD_OFFSET(struct ot_feature, lookup_count));
|
FIELD_OFFSET(struct ot_feature, lookup_count));
|
||||||
if (!lookup_count)
|
if (!lookup_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!dwrite_array_reserve((void **)&lookups.indexes, &lookups.capacity, lookups.count + lookup_count,
|
if (!dwrite_array_reserve((void **)&lookups->indexes, &lookups->capacity, lookups->count + lookup_count,
|
||||||
sizeof(*lookups.indexes)))
|
sizeof(*lookups->indexes)))
|
||||||
{
|
{
|
||||||
heap_free(lookups.indexes);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (l = 0; l < lookup_count; ++l)
|
for (l = 0; l < lookup_count; ++l)
|
||||||
{
|
{
|
||||||
WORD lookup_index = table_read_be_word(&cache->gpos.table, cache->gpos.feature_list +
|
UINT16 lookup_index = table_read_be_word(&table->table, table->feature_list + feature_offset +
|
||||||
feature_offset + FIELD_OFFSET(struct ot_feature, lookuplist_index[l]));
|
FIELD_OFFSET(struct ot_feature, lookuplist_index[l]));
|
||||||
|
|
||||||
if (lookup_index >= total_lookup_count)
|
if (lookup_index >= total_lookup_count)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lookups.indexes[lookups.count++] = lookup_index;
|
lookups->indexes[lookups->count++] = lookup_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort lookups. */
|
/* Sort lookups. */
|
||||||
qsort(lookups.indexes, lookups.count, sizeof(*lookups.indexes), lookups_sorting_compare);
|
qsort(lookups->indexes, lookups->count, sizeof(*lookups->indexes), lookups_sorting_compare);
|
||||||
|
}
|
||||||
|
|
||||||
for (l = 0; l < lookups.count; ++l)
|
void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index,
|
||||||
|
unsigned int language_index, const struct shaping_features *features)
|
||||||
|
{
|
||||||
|
struct lookups lookups = { 0 };
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gpos, &lookups);
|
||||||
|
|
||||||
|
for (i = 0; i < lookups.count; ++i)
|
||||||
{
|
{
|
||||||
/* Skip duplicates. */
|
/* Skip duplicates. */
|
||||||
if (l && lookups.indexes[l] == lookups.indexes[l - 1])
|
if (i && lookups.indexes[i] == lookups.indexes[i - 1])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
opentype_layout_apply_gpos_lookup(context, lookups.indexes[l]);
|
opentype_layout_apply_gpos_lookup(context, lookups.indexes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_free(lookups.indexes);
|
heap_free(lookups.indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
|
||||||
|
unsigned int glyph_count, int lookup_index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
|
HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
|
||||||
unsigned int language_index, const struct shaping_features *features)
|
unsigned int language_index, const struct shaping_features *features)
|
||||||
{
|
{
|
||||||
|
struct lookups lookups = { 0 };
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
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.indexes[i] == lookups.indexes[i - 1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.indexes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_free(lookups.indexes);
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,7 +189,7 @@ const struct scriptshaping_ops default_shaping_ops =
|
||||||
default_set_text_glyphs_props
|
default_set_text_glyphs_props
|
||||||
};
|
};
|
||||||
|
|
||||||
static DWORD shape_select_script(const struct scriptshaping_cache *cache, DWORD kind, const DWORD *scripts,
|
static unsigned int shape_select_script(const struct scriptshaping_cache *cache, DWORD kind, const DWORD *scripts,
|
||||||
unsigned int *script_index)
|
unsigned int *script_index)
|
||||||
{
|
{
|
||||||
static const DWORD fallback_scripts[] =
|
static const DWORD fallback_scripts[] =
|
||||||
|
@ -199,10 +199,10 @@ static DWORD shape_select_script(const struct scriptshaping_cache *cache, DWORD
|
||||||
DWRITE_MAKE_OPENTYPE_TAG('l','a','t','n'),
|
DWRITE_MAKE_OPENTYPE_TAG('l','a','t','n'),
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
DWORD script;
|
unsigned int script;
|
||||||
|
|
||||||
/* Passed scripts in ascending priority. */
|
/* Passed scripts in ascending priority. */
|
||||||
while (*scripts)
|
while (scripts && *scripts)
|
||||||
{
|
{
|
||||||
if ((script = opentype_layout_find_script(cache, kind, *scripts, script_index)))
|
if ((script = opentype_layout_find_script(cache, kind, *scripts, script_index)))
|
||||||
return script;
|
return script;
|
||||||
|
|
Loading…
Reference in New Issue