[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