[PATCH 1/5] dwrite: Propagate feature mask to lookups collected from it.

Nikolay Sivov nsivov at codeweavers.com
Fri May 22 05:58:05 CDT 2020


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

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 8b5fefc66bd..3145daba4bb 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -492,6 +492,7 @@ struct scriptshaping_context
         const unsigned int *range_lengths;
         unsigned int range_count;
     } user_features;
+    unsigned int global_mask;
 
     unsigned int glyph_count;
     float emsize;
@@ -525,6 +526,8 @@ struct shaping_feature
     unsigned int flags;
     unsigned int max_value;
     unsigned int default_value;
+    unsigned int mask;
+    unsigned int shift;
 };
 
 struct shaping_features
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 8904dc546e9..d2a9318da87 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -3210,6 +3210,36 @@ static inline unsigned int dwrite_popcount(unsigned int x)
 #endif
 }
 
+static inline unsigned int dwrite_log2i(unsigned int x)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
+    return __builtin_clz(x) ^ 0x1f;
+#else
+    static const unsigned int l[] =
+    {
+        ~0u, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+          4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+          5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+          7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+    };
+    unsigned int i;
+
+    return (i = x >> 16) ? (x = i >> 8) ? l[x] + 24 : l[i] + 16 : (i = x >> 8) ? l[i] + 8 : l[x];
+#endif
+}
+
 static float opentype_scale_gpos_be_value(WORD value, float emsize, UINT16 upem)
 {
     return (short)GET_BE_WORD(value) * emsize / upem;
@@ -3333,7 +3363,7 @@ static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping
     return lookup_offset + subtable_offset;
 }
 
-struct lookup
+struct ot_lookup
 {
     unsigned int offset;
     unsigned int subtable_count;
@@ -3406,7 +3436,7 @@ static BOOL glyph_iterator_prev(struct glyph_iterator *iter)
 }
 
 static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     WORD format, value_format, value_len, coverage;
@@ -3469,7 +3499,7 @@ static int gpos_pair_adjustment_compare_format1(const void *g, const void *r)
 }
 
 static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     unsigned int i, first_glyph, second_glyph;
@@ -3676,7 +3706,7 @@ static void opentype_layout_gpos_get_anchor(const struct scriptshaping_context *
 }
 
 static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     unsigned int i;
@@ -3760,7 +3790,7 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c
 }
 
 static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     unsigned int i;
@@ -3843,7 +3873,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(struct scriptshap
 }
 
 static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     unsigned int i;
@@ -3889,7 +3919,7 @@ static BOOL opentype_layout_apply_gpos_mark_to_lig_attachment(struct scriptshapi
 }
 
 static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = context->cache;
     unsigned int i;
@@ -3974,13 +4004,13 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap
 }
 
 static BOOL opentype_layout_apply_gpos_contextual_positioning(const struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     return FALSE;
 }
 
 static BOOL opentype_layout_apply_gpos_chaining_contextual_positioning(const struct scriptshaping_context *context,
-        struct glyph_iterator *iter, const struct lookup *lookup)
+        struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     return FALSE;
 }
@@ -3990,7 +4020,7 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont
     struct scriptshaping_cache *cache = context->cache;
     const struct ot_lookup_table *lookup_table;
     struct glyph_iterator iter;
-    struct lookup lookup;
+    struct ot_lookup lookup;
     WORD lookup_type;
 
     lookup.offset = table_read_be_word(&cache->gpos.table, cache->gpos.lookup_list +
@@ -4081,16 +4111,24 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont
     }
 }
 
+struct lookup
+{
+    unsigned short index;
+    unsigned int mask;
+};
+
 struct lookups
 {
-    int *indexes;
+    struct lookup *lookups;
     size_t capacity;
     size_t count;
 };
 
-static int lookups_sorting_compare(const void *left, const void *right)
+static int lookups_sorting_compare(const void *a, const void *b)
 {
-    return *(int *)left - *(int *)right;
+    const struct lookup *left = (const struct lookup *)a;
+    const struct lookup *right = (const struct lookup *)b;
+    return left->index < right->index ? -1 : left->index > right->index ? 1 : 0;
 };
 
 static void opentype_layout_collect_lookups(struct scriptshaping_context *context, unsigned int script_index,
@@ -4099,8 +4137,11 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
 {
     UINT16 table_offset, langsys_offset, script_feature_count, total_feature_count, total_lookup_count;
     const struct ot_feature_list *feature_list;
+    struct shaping_feature *feature;
+    unsigned int i, j, l, next_bit;
+    unsigned int global_bit_shift = 1;
+    unsigned int global_bit_mask = 1;
     UINT16 feature_index;
-    unsigned int i, j, l;
 
     /* ScriptTable offset. */
     table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) +
@@ -4133,19 +4174,34 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
     if (!feature_list)
         return;
 
+    context->global_mask = global_bit_mask;
+    next_bit = global_bit_shift + 1;
     for (i = 0; i < features->count; ++i)
     {
+        unsigned int bits_needed;
         BOOL found = FALSE;
 
+        feature = &features->features[i];
+
+        feature->index = 0xffff;
+
+        if ((feature->flags & FEATURE_GLOBAL) && feature->max_value == 1)
+            bits_needed = 0;
+        else
+            bits_needed = min(8, dwrite_log2i(feature->max_value));
+
+        if (!feature->max_value || next_bit + bits_needed > 8 * sizeof (feature->mask))
+            continue;
+
         for (j = 0; j < script_feature_count; ++j)
         {
             feature_index = table_read_be_word(&table->table, table->script_list + table_offset +
                     langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j]));
             if (feature_index >= total_feature_count)
                 continue;
-            if ((found = feature_list->features[feature_index].tag == features->features[i].tag))
+            if ((found = feature_list->features[feature_index].tag == feature->tag))
             {
-                features->features[i].index = feature_index;
+                feature->index = feature_index;
                 break;
             }
         }
@@ -4154,16 +4210,29 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
         {
             for (j = 0; j < total_feature_count; ++j)
             {
-                if ((found = (feature_list->features[j].tag == features->features[i].tag)))
+                if ((found = (feature_list->features[j].tag == feature->tag)))
                 {
-                    features->features[i].index = j;
+                    feature->index = j;
                     break;
                 }
             }
         }
 
         if (!found)
-            features->features[i].index = 0xffff;
+            continue;
+
+        if (feature->flags & FEATURE_GLOBAL && feature->max_value == 1)
+        {
+            feature->shift = global_bit_shift;
+            feature->mask = global_bit_mask;
+        }
+        else
+        {
+            feature->shift = next_bit;
+            feature->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
+            next_bit += bits_needed;
+            context->global_mask |= (feature->default_value << feature->shift) & feature->mask;
+        }
     }
 
     /* Collect lookups for all given features. */
@@ -4171,25 +4240,25 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
     {
         UINT16 feature_offset, lookup_count;
 
-        feature_index = features->features[i].index;
+        feature = &features->features[i];
 
         /* Feature wasn't found */
-        if (feature_index == 0xffff)
+        if (feature->index == 0xffff)
             continue;
 
         /* FIXME: skip non-global ones for now. */
-        if (!(features->features[i].flags & FEATURE_GLOBAL))
+        if (!(feature->flags & FEATURE_GLOBAL))
             continue;
 
-        feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset);
+        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->indexes, &lookups->capacity, lookups->count + lookup_count,
-                sizeof(*lookups->indexes)))
+        if (!dwrite_array_reserve((void **)&lookups->lookups, &lookups->capacity, lookups->count + lookup_count,
+                sizeof(*lookups->lookups)))
         {
             return;
         }
@@ -4202,12 +4271,15 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex
             if (lookup_index >= total_lookup_count)
                 continue;
 
-            lookups->indexes[lookups->count++] = lookup_index;
+            j = lookups->count;
+            lookups->lookups[j].index = lookup_index;
+            lookups->lookups[j].mask = feature->mask;
+            lookups->count++;
         }
     }
 
     /* Sort lookups. */
-    qsort(lookups->indexes, lookups->count, sizeof(*lookups->indexes), lookups_sorting_compare);
+    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,
@@ -4221,16 +4293,16 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
     for (i = 0; i < lookups.count; ++i)
     {
         /* Skip duplicates. */
-        if (i && lookups.indexes[i] == lookups.indexes[i - 1])
+        if (i && lookups.lookups[i].index == lookups.lookups[i - 1].index)
             continue;
 
-        opentype_layout_apply_gpos_lookup(context, lookups.indexes[i]);
+        opentype_layout_apply_gpos_lookup(context, lookups.lookups[i].index);
     }
 
-    heap_free(lookups.indexes);
+    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 glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = iter->context->cache;
     UINT16 format, coverage;
@@ -4376,7 +4448,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct glyph_iterato
             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)
+static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct ot_lookup *lookup)
 {
     struct scriptshaping_cache *cache = iter->context->cache;
     UINT16 format, coverage;
@@ -4468,7 +4540,7 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont
     struct ot_gsubgpos_table *table = &context->cache->gsub;
     const struct ot_lookup_table *lookup_table;
     struct glyph_iterator iter;
-    struct lookup lookup;
+    struct ot_lookup lookup;
     WORD lookup_type;
 
     lookup.offset = table_read_be_word(&table->table, table->lookup_list + FIELD_OFFSET(struct ot_lookup_list, lookup[lookup_index]));
@@ -4537,13 +4609,13 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex
     for (i = 0; i < lookups.count; ++i)
     {
         /* Skip duplicates. */
-        if (i && lookups.indexes[i] == lookups.indexes[i - 1])
+        if (i && lookups.lookups[i].index == lookups.lookups[i - 1].index)
             continue;
 
-        opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.indexes[i]);
+        opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.lookups[i].index);
     }
 
-    heap_free(lookups.indexes);
+    heap_free(lookups.lookups);
 
     return S_OK;
 }
-- 
2.26.2




More information about the wine-devel mailing list