[PATCH 6/6] dwrite: Partially implement chaining contextual substitution (GSUB lookup 6).
Nikolay Sivov
nsivov at codeweavers.com
Mon May 4 03:29:35 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/opentype.c | 214 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 200 insertions(+), 14 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index e1bfee097b..0feb2feadc 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -562,6 +562,14 @@ struct ot_gsub_singlesubst_format2
UINT16 substitutes[1];
};
+struct ot_gsub_chaincontext_subst_format1
+{
+ UINT16 format;
+ UINT16 coverage;
+ UINT16 ruleset_count;
+ UINT16 rulesets[1];
+};
+
struct ot_feature
{
WORD feature_params;
@@ -2994,15 +3002,12 @@ void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache *cache)
unsigned int opentype_layout_find_script(const struct scriptshaping_cache *cache, unsigned int kind, DWORD script,
unsigned int *script_index)
{
- const struct ot_gsubgpos_table *table = &cache->gpos;
+ const struct ot_gsubgpos_table *table = kind == MS_GSUB_TAG ? &cache->gsub : &cache->gpos;
UINT16 script_count;
unsigned int i;
*script_index = ~0u;
- if (kind != MS_GPOS_TAG)
- return 0;
-
script_count = table_read_be_word(&table->table, table->script_list);
if (!script_count)
return 0;
@@ -3027,15 +3032,12 @@ unsigned int opentype_layout_find_script(const struct scriptshaping_cache *cache
unsigned int opentype_layout_find_language(const struct scriptshaping_cache *cache, unsigned int kind, DWORD language,
unsigned int script_index, unsigned int *language_index)
{
- const struct ot_gsubgpos_table *table = &cache->gpos;
+ const struct ot_gsubgpos_table *table = kind == MS_GSUB_TAG ? &cache->gsub : &cache->gpos;
UINT16 table_offset, lang_count;
unsigned int i;
*language_index = ~0u;
- if (kind != MS_GPOS_TAG)
- return 0;
-
table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) +
script_index * sizeof(struct ot_script_record) + FIELD_OFFSET(struct ot_script_record, script));
if (!table_offset)
@@ -3340,13 +3342,13 @@ struct lookup
struct glyph_iterator
{
- const struct scriptshaping_context *context;
+ struct scriptshaping_context *context;
unsigned int flags;
unsigned int pos;
unsigned int len;
};
-static void glyph_iterator_init(const struct scriptshaping_context *context, unsigned int flags, unsigned int pos,
+static void glyph_iterator_init(struct scriptshaping_context *context, unsigned int flags, unsigned int pos,
unsigned int len, struct glyph_iterator *iter)
{
iter->context = context;
@@ -3757,7 +3759,7 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c
return FALSE;
}
-static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(const struct scriptshaping_context *context,
+static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshaping_context *context,
struct glyph_iterator *iter, const struct lookup *lookup)
{
struct scriptshaping_cache *cache = context->cache;
@@ -3840,7 +3842,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(const struct scri
return FALSE;
}
-static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(const struct scriptshaping_context *context,
+static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshaping_context *context,
struct glyph_iterator *iter, const struct lookup *lookup)
{
struct scriptshaping_cache *cache = context->cache;
@@ -3886,7 +3888,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(const struct scrip
return FALSE;
}
-static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(const struct scriptshaping_context *context,
+static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshaping_context *context,
struct glyph_iterator *iter, const struct lookup *lookup)
{
struct scriptshaping_cache *cache = context->cache;
@@ -4244,6 +4246,188 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator
return FALSE;
}
+static BOOL opentype_layout_context_match_input(struct glyph_iterator *iter, unsigned int subtable_offset,
+ unsigned int count, const UINT16 *input)
+{
+ struct scriptshaping_cache *cache = iter->context->cache;
+ unsigned int i, pos;
+
+ if (iter->pos + count > iter->len)
+ return FALSE;
+
+ pos = iter->pos;
+
+ for (i = 0; i < count; ++i, ++pos)
+ {
+ UINT16 glyph = iter->context->u.subst.glyphs[pos];
+ if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(input[i]),
+ glyph) == GLYPH_NOT_COVERED)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static BOOL opentype_layout_context_match_backtrack(struct glyph_iterator *iter, unsigned int subtable_offset,
+ unsigned int count, const UINT16 *backtrack)
+{
+ struct scriptshaping_cache *cache = iter->context->cache;
+ unsigned int i;
+
+ if (iter->pos < count)
+ return FALSE;
+
+ for (i = 0; i < count; ++i)
+ {
+ UINT16 glyph = iter->context->u.subst.glyphs[iter->pos - i - 1];
+
+ if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]),
+ glyph) == GLYPH_NOT_COVERED)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter, unsigned int subtable_offset,
+ unsigned int count, const UINT16 *lookahead, unsigned int offset)
+{
+ struct scriptshaping_cache *cache = iter->context->cache;
+ unsigned int i, pos;
+
+ if (iter->pos + offset + count > iter->len)
+ return FALSE;
+
+ pos = iter->pos + offset;
+
+ for (i = 0; i < count; ++i, ++pos)
+ {
+ UINT16 glyph = iter->context->u.subst.glyphs[pos];
+ if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(lookahead[i]),
+ glyph) == GLYPH_NOT_COVERED)
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
+ unsigned int glyph_count, int lookup_index);
+
+static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *iter, unsigned int count,
+ unsigned int lookup_count, const UINT16 *lookup_records)
+{
+ if (lookup_count > 1)
+ FIXME("Only first lookup used.\n");
+
+ opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count,
+ GET_BE_WORD(lookup_records[1]));
+
+ return TRUE;
+}
+
+static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct glyph_iterator *iter, unsigned int subtable_offset,
+ unsigned int backtrack_count, const UINT16 *backtrack, unsigned int input_count, const UINT16 *input,
+ unsigned int lookahead_count, const UINT16 *lookahead, unsigned int lookup_count, const UINT16 *lookup_records)
+{
+ return opentype_layout_context_match_input(iter, subtable_offset, input_count, input) &&
+ opentype_layout_context_match_backtrack(iter, subtable_offset, backtrack_count, backtrack) &&
+ opentype_layout_context_match_lookahead(iter, subtable_offset, lookahead_count, lookahead, input_count) &&
+ opentype_layout_context_gsub_apply_lookup(iter, input_count, lookup_count, lookup_records);
+}
+
+static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct lookup *lookup)
+{
+ struct scriptshaping_cache *cache = iter->context->cache;
+ UINT16 format, coverage;
+ 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 = iter->context->u.subst.glyphs[iter->pos];
+ unsigned int coverage_index = GLYPH_NOT_COVERED;
+
+ format = table_read_be_word(&cache->gsub.table, subtable_offset);
+
+ if (format == 1)
+ {
+ coverage = table_read_be_word(&cache->gsub.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);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ continue;
+
+ WARN("Chaining contextual substitution (1) is not supported.\n");
+ break;
+ }
+ else if (format == 2)
+ {
+ coverage = table_read_be_word(&cache->gsub.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);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ continue;
+
+ 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;
+
+ unsigned int offset = subtable_offset + 2 /* format */;
+
+ backtrack_count = table_read_be_word(&cache->gsub.table, offset);
+ offset += 2;
+ backtrack = table_read_ensure(&cache->gsub.table, offset, backtrack_count * sizeof(*backtrack));
+ offset += backtrack_count * sizeof(*backtrack);
+
+ input_count = table_read_be_word(&cache->gsub.table, offset);
+ offset += 2;
+ input = table_read_ensure(&cache->gsub.table, offset, input_count * sizeof(*input));
+ offset += input_count * sizeof(*input);
+
+ lookahead_count = table_read_be_word(&cache->gsub.table, offset);
+ offset += 2;
+ lookahead = table_read_ensure(&cache->gsub.table, offset, lookahead_count * sizeof(*lookahead));
+ offset += lookahead_count * sizeof(*lookahead);
+
+ lookup_count = table_read_be_word(&cache->gsub.table, offset);
+ offset += 2;
+ lookup_records = table_read_ensure(&cache->gsub.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);
+ }
+
+ if (coverage_index == GLYPH_NOT_COVERED)
+ continue;
+
+ if (opentype_layout_apply_gsub_chain_context_lookup(iter, subtable_offset, backtrack_count, backtrack,
+ input_count, input, lookahead_count, lookahead, lookup_count, lookup_records))
+ {
+ break;
+ }
+ }
+ else
+ WARN("Unknown chaining contextual substitution format %u.\n", format);
+ }
+
+ return FALSE;
+}
+
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
unsigned int glyph_count, int lookup_index)
{
@@ -4286,8 +4470,10 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont
case GSUB_LOOKUP_SINGLE_SUBST:
ret = opentype_layout_apply_gsub_single_substitution(&iter, &lookup);
break;
- case GSUB_LOOKUP_MULTIPLE_SUBST:
case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
+ ret = opentype_layout_apply_gsub_chain_context_substitution(&iter, &lookup);
+ break;
+ case GSUB_LOOKUP_MULTIPLE_SUBST:
case GSUB_LOOKUP_ALTERNATE_SUBST:
case GSUB_LOOKUP_LIGATURE_SUBST:
case GSUB_LOOKUP_CONTEXTUAL_SUBST:
--
2.26.2
More information about the wine-devel
mailing list