[PATCH 5/5] dwrite: Use global cursor to glyph array for substitutions.

Nikolay Sivov nsivov at codeweavers.com
Tue May 26 03:16:12 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |   3 +-
 dlls/dwrite/opentype.c       | 273 ++++++++++++++++++++++-------------
 2 files changed, 177 insertions(+), 99 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index ce278e54992..b1391cb911a 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -505,6 +505,7 @@ struct scriptshaping_context
     unsigned int global_mask;
     struct shaping_glyph_info *glyph_infos;
 
+    unsigned int cur;
     unsigned int glyph_count;
     float emsize;
     DWRITE_MEASURING_MODE measuring_mode;
@@ -557,7 +558,7 @@ extern DWORD opentype_layout_find_script(const struct scriptshaping_cache *cache
         unsigned int *script_index) DECLSPEC_HIDDEN;
 extern DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWORD kind, DWORD tag,
         unsigned int script_index, unsigned int *language_index) DECLSPEC_HIDDEN;
-extern HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
+extern void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
         unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN;
 extern void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index,
         unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 7e35feb7f51..16abb4c93aa 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -4461,12 +4461,16 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
     heap_free(lookups.lookups);
 }
 
-static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct lookup *lookup)
+static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup)
 {
-    UINT16 format, coverage, orig_glyph = iter->context->u.subst.glyphs[iter->pos], glyph = orig_glyph;
-    struct scriptshaping_cache *cache = iter->context->cache;
+    struct scriptshaping_cache *cache = context->cache;
     const struct dwrite_fonttable *gsub = &cache->gsub.table;
-    unsigned int i;
+    UINT16 format, coverage, orig_glyph, glyph;
+    unsigned int i, idx;
+    BOOL ret;
+
+    idx = context->cur;
+    orig_glyph = glyph = context->u.subst.glyphs[idx];
 
     for (i = 0; i < lookup->subtable_count; ++i)
     {
@@ -4506,76 +4510,97 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator
             WARN("Unknown single substitution format %u.\n", format);
     }
 
-    if (glyph != orig_glyph)
+    if ((ret = (glyph != orig_glyph)))
     {
-        iter->context->u.subst.glyphs[iter->pos] = glyph;
-        opentype_set_subst_glyph_props(iter->context, iter->pos, glyph);
+        context->u.subst.glyphs[idx] = glyph;
+        opentype_set_subst_glyph_props(context, idx, glyph);
+        context->cur++;
     }
 
-    return FALSE;
+    return ret;
 }
 
-static BOOL opentype_layout_context_match_input(struct glyph_iterator *iter, unsigned int subtable_offset,
-        unsigned int count, const UINT16 *input)
+#define CHAIN_CONTEXT_MAX_LENGTH 64
+
+static BOOL opentype_layout_context_match_input(struct scriptshaping_context *context, unsigned int subtable_offset,
+        unsigned int count, const UINT16 *input, unsigned int *end_offset, unsigned int *match_positions)
 {
-    struct scriptshaping_cache *cache = iter->context->cache;
-    unsigned int i, pos;
+    struct scriptshaping_cache *cache = context->cache;
+    struct glyph_iterator iter;
+    unsigned int i;
+    UINT16 glyph;
 
-    if (iter->pos + count > iter->len)
+    if (count > CHAIN_CONTEXT_MAX_LENGTH)
         return FALSE;
 
-    pos = iter->pos;
+    match_positions[0] = context->cur;
 
-    for (i = 0; i < count; ++i, ++pos)
+    glyph_iterator_init(context, 0, context->cur, count - 1, &iter);
+
+    for (i = 1; i < count; ++i)
     {
-        UINT16 glyph = iter->context->u.subst.glyphs[pos];
+        if (!glyph_iterator_next(&iter))
+            return FALSE;
+
+        /* TODO: this only covers Format3 substitution */
+        glyph = context->u.subst.glyphs[iter.pos];
         if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(input[i]),
                 glyph) == GLYPH_NOT_COVERED)
         {
             return FALSE;
         }
+
+        match_positions[i] = iter.pos;
     }
 
+    *end_offset = iter.pos - context->cur + 1;
+
     return TRUE;
 }
 
-static BOOL opentype_layout_context_match_backtrack(struct glyph_iterator *iter, unsigned int subtable_offset,
-        unsigned int count, const UINT16 *backtrack)
+static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context *context, unsigned int subtable_offset,
+        unsigned int count, const UINT16 *backtrack, unsigned int *match_start)
 {
-    struct scriptshaping_cache *cache = iter->context->cache;
+    struct glyph_iterator iter;
     unsigned int i;
+    UINT16 glyph;
 
-    if (iter->pos < count)
-        return FALSE;
+    glyph_iterator_init(context, 0, context->cur, count, &iter);
 
     for (i = 0; i < count; ++i)
     {
-        UINT16 glyph = iter->context->u.subst.glyphs[iter->pos - i - 1];
+        if (!glyph_iterator_prev(&iter))
+            return FALSE;
 
-        if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]),
+        glyph = context->u.subst.glyphs[iter.pos];
+        if (opentype_layout_is_glyph_covered(&context->cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]),
                 glyph) == GLYPH_NOT_COVERED)
         {
             return FALSE;
         }
     }
 
+    *match_start = iter.pos;
+
     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)
+static BOOL opentype_layout_context_match_lookahead(struct scriptshaping_context *context, unsigned int subtable_offset,
+        unsigned int count, const UINT16 *lookahead, unsigned int offset, unsigned int *end_index)
 {
-    struct scriptshaping_cache *cache = iter->context->cache;
-    unsigned int i, pos;
-
-    if (iter->pos + offset + count > iter->len)
-        return FALSE;
+    struct scriptshaping_cache *cache = context->cache;
+    struct glyph_iterator iter;
+    unsigned int i;
+    UINT16 glyph;
 
-    pos = iter->pos + offset;
+    glyph_iterator_init(context, 0, context->cur + offset - 1, count, &iter);
 
-    for (i = 0; i < count; ++i, ++pos)
+    for (i = 0; i < count; ++i)
     {
-        UINT16 glyph = iter->context->u.subst.glyphs[pos];
+        if (!glyph_iterator_next(&iter))
+            return FALSE;
+
+        glyph = context->u.subst.glyphs[iter.pos];
         if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(lookahead[i]),
                 glyph) == GLYPH_NOT_COVERED)
         {
@@ -4583,47 +4608,104 @@ static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter,
         }
     }
 
+    *end_index = iter.pos;
+
     return TRUE;
 }
 
-static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
-        unsigned int glyph_count, struct lookup *lookup, BOOL only_single);
+static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup);
 
-static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *iter, unsigned int count,
-        unsigned int lookup_count, const UINT16 *lookup_records)
+static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_context *context, unsigned int count,
+        unsigned int *match_positions, unsigned int lookup_count, const UINT16 *lookup_records, unsigned int match_length)
 {
     struct lookup lookup = { 0 };
+    unsigned int i, j;
+    int end, delta;
+
+    end = context->cur + match_length;
+
+    for (i = 0; i < lookup_count; ++i)
+    {
+        unsigned int idx = GET_BE_WORD(lookup_records[i]);
+        unsigned int orig_len, lookup_index, next;
+
+        if (idx >= count)
+            continue;
+
+        context->cur = match_positions[idx];
+
+        orig_len = context->glyph_count;
+
+        lookup_index = GET_BE_WORD(lookup_records[i+1]);
+        if (opentype_layout_init_lookup(&context->cache->gsub, lookup_index, 0, &lookup))
+            opentype_layout_apply_gsub_lookup(context, &lookup);
+
+        delta = context->glyph_count - orig_len;
+        if (!delta)
+            continue;
+
+        end += delta;
+        if (end <= (int)match_positions[idx])
+        {
+            end = match_positions[idx];
+            break;
+        }
+
+        next = idx + 1;
+
+        if (delta > 0)
+        {
+            if (delta + count > CHAIN_CONTEXT_MAX_LENGTH)
+                break;
+        }
+        else
+        {
+            delta = max(delta, (int)next - (int)count);
+            next -= delta;
+        }
 
-    if (lookup_count > 1)
-        FIXME("Only first lookup used.\n");
+        memmove(match_positions + next + delta, match_positions + next,
+                (count - next) * sizeof (*match_positions));
+        next += delta;
+        count += delta;
 
-    if (opentype_layout_init_lookup(&iter->context->cache->gsub, GET_BE_WORD(lookup_records[1]), 0, &lookup))
-        opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count,
-                &lookup, TRUE);
+        for (j = idx + 1; j < next; j++)
+            match_positions[j] = match_positions[j - 1] + 1;
+
+        for (; next < count; next++)
+            match_positions[next] += delta;
+    }
+
+    context->cur = end;
 
     return TRUE;
 }
 
-static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct glyph_iterator *iter, unsigned int subtable_offset,
+static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping_context *context, 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);
+    unsigned int start_index = 0, match_length = 0, end_index = 0;
+    unsigned int match_positions[CHAIN_CONTEXT_MAX_LENGTH];
+
+    return opentype_layout_context_match_input(context, subtable_offset, input_count, input, &match_length, match_positions) &&
+            opentype_layout_context_match_backtrack(context, subtable_offset, backtrack_count, backtrack, &start_index) &&
+            opentype_layout_context_match_lookahead(context, subtable_offset, lookahead_count, lookahead, input_count, &end_index) &&
+            opentype_layout_context_gsub_apply_lookup(context, input_count, match_positions, lookup_count, lookup_records, match_length);
 }
 
-static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct lookup *lookup)
+static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context,
+        const struct lookup *lookup)
 {
-    struct scriptshaping_cache *cache = iter->context->cache;
+    struct scriptshaping_cache *cache = context->cache;
     UINT16 format, coverage;
+    BOOL ret = FALSE;
     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];
+        UINT16 glyph = context->u.subst.glyphs[context->cur];
         unsigned int coverage_index = GLYPH_NOT_COVERED;
 
         format = table_read_be_word(&cache->gsub.table, subtable_offset);
@@ -4687,8 +4769,8 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i
             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))
+            if ((ret = opentype_layout_apply_gsub_chain_context_lookup(context, subtable_offset, backtrack_count, backtrack,
+                input_count, input + 1, lookahead_count, lookahead, lookup_count, lookup_records)))
             {
                 break;
             }
@@ -4697,54 +4779,33 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i
             WARN("Unknown chaining contextual substitution format %u.\n", format);
     }
 
-    return FALSE;
+    return ret;
 }
 
-static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
-        unsigned int glyph_count, struct lookup *lookup, BOOL only_single)
+static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup)
 {
-    struct glyph_iterator iter;
-
-    if (lookup->type != GSUB_LOOKUP_SINGLE_SUBST && only_single)
-        return;
-
-    glyph_iterator_init(context, lookup->flags, first_glyph, glyph_count, &iter);
+    BOOL ret = FALSE;
 
-    while (iter.pos < first_glyph + iter.len)
+    switch (lookup->type)
     {
-        BOOL ret;
-
-        if (!glyph_iterator_match(&iter))
-        {
-            ++iter.pos;
-            continue;
-        }
-
-        switch (lookup->type)
-        {
-            case GSUB_LOOKUP_SINGLE_SUBST:
-                ret = opentype_layout_apply_gsub_single_substitution(&iter, lookup);
-                break;
-            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:
-            case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
-                ret = FALSE;
-                WARN("Unimplemented lookup %d.\n", lookup->type);
-                break;
-            default:
-                WARN("Unknown lookup type %u.\n", lookup->type);
-                return;
-        }
-
-        /* Some lookups update position after making changes. */
-        if (!ret)
-            ++iter.pos;
+        case GSUB_LOOKUP_SINGLE_SUBST:
+            ret = opentype_layout_apply_gsub_single_substitution(context, lookup);
+            break;
+        case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
+            ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup);
+            break;
+        case GSUB_LOOKUP_MULTIPLE_SUBST:
+        case GSUB_LOOKUP_ALTERNATE_SUBST:
+        case GSUB_LOOKUP_LIGATURE_SUBST:
+        case GSUB_LOOKUP_CONTEXTUAL_SUBST:
+        case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
+            WARN("Unimplemented lookup %d.\n", lookup->type);
+            break;
+        default:
+            WARN("Unknown lookup type %u.\n", lookup->type);
     }
+
+    return ret;
 }
 
 static unsigned int unicode_get_mirrored_char(unsigned int codepoint)
@@ -4809,11 +4870,12 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c
     }
 }
 
-HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
+void opentype_layout_apply_gsub_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;
+    BOOL ret;
 
     opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gsub, &lookups);
 
@@ -4821,9 +4883,24 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex
     opentype_layout_set_glyph_masks(context, features);
 
     for (i = 0; i < lookups.count; ++i)
-        opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, &lookups.lookups[i], FALSE);
+    {
+        const struct lookup *lookup = &lookups.lookups[i];
 
-    heap_free(lookups.lookups);
+        context->cur = 0;
+        while (context->cur < context->glyph_count)
+        {
+            ret = FALSE;
 
-    return S_OK;
+            if ((context->glyph_infos[context->cur].mask & lookup->mask) &&
+                    lookup_is_glyph_match(context->glyph_infos[context->cur].props, lookup->flags))
+            {
+                ret = opentype_layout_apply_gsub_lookup(context, lookup);
+            }
+
+            if (!ret)
+                context->cur++;
+        }
+    }
+
+    heap_free(lookups.lookups);
 }
-- 
2.26.2




More information about the wine-devel mailing list