[PATCH 3/5] dwrite: Collect and sort positional lookups.

Nikolay Sivov nsivov at codeweavers.com
Thu Jan 31 02:35:28 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |  27 +++++
 dlls/dwrite/opentype.c       | 201 +++++++++++++++++++++++++++--------
 2 files changed, 183 insertions(+), 45 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index d992abda2a..b7d5d4583c 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -76,6 +76,33 @@ static inline const char *debugstr_matrix(const DWRITE_MATRIX *m)
         m->dx, m->dy);
 }
 
+static inline BOOL dwrite_array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
+{
+    size_t new_capacity, max_capacity;
+    void *new_elements;
+
+    if (count <= *capacity)
+        return TRUE;
+
+    max_capacity = ~(SIZE_T)0 / size;
+    if (count > max_capacity)
+        return FALSE;
+
+    new_capacity = max(4, *capacity);
+    while (new_capacity < count && new_capacity <= max_capacity / 2)
+        new_capacity *= 2;
+    if (new_capacity < count)
+        new_capacity = max_capacity;
+
+    if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
+        return FALSE;
+
+    *elements = new_elements;
+    *capacity = new_capacity;
+
+    return TRUE;
+}
+
 static inline const char *debugstr_tag(DWORD tag)
 {
     return debugstr_an((char *)&tag, 4);
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 7d3db16049..02825c2d78 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -312,8 +312,6 @@ struct gasp_header
     struct gasp_range ranges[1];
 };
 
-#include "poppack.h"
-
 enum OS2_FSSELECTION {
     OS2_FSSELECTION_ITALIC           = 1 << 0,
     OS2_FSSELECTION_UNDERSCORE       = 1 << 1,
@@ -373,22 +371,25 @@ struct vdmx_group
     struct vdmx_vtable entries[1];
 };
 
-typedef struct {
-    CHAR FeatureTag[4];
-    WORD Feature;
-} OT_FeatureRecord;
+struct ot_feature_record
+{
+    DWORD tag;
+    WORD offset;
+};
 
-typedef struct {
-    WORD FeatureCount;
-    OT_FeatureRecord FeatureRecord[1];
-} OT_FeatureList;
+struct ot_feature_list
+{
+    WORD feature_count;
+    struct ot_feature_record features[1];
+};
 
-typedef struct {
-    WORD LookupOrder; /* Reserved */
-    WORD ReqFeatureIndex;
-    WORD FeatureCount;
-    WORD FeatureIndex[1];
-} OT_LangSys;
+struct ot_langsys
+{
+    WORD lookup_order; /* Reserved */
+    WORD required_feature_index;
+    WORD feature_count;
+    WORD feature_index[1];
+};
 
 struct ot_langsys_record
 {
@@ -432,11 +433,12 @@ enum OPENTYPE_PLATFORM_ID
     OPENTYPE_PLATFORM_CUSTOM
 };
 
-typedef struct {
-    WORD FeatureParams;
-    WORD LookupCount;
-    WORD LookupListIndex[1];
-} OT_Feature;
+struct ot_feature
+{
+    WORD feature_params;
+    WORD lookup_count;
+    WORD lookuplist_index[1];
+};
 
 typedef struct {
     WORD LookupCount;
@@ -469,10 +471,12 @@ typedef struct {
     DWORD ExtensionOffset;
 } GSUB_ExtensionPosFormat1;
 
-enum OPENTYPE_GPOS_LOOKUPS
+#include "poppack.h"
+
+enum gsub_lookup_type
 {
-    OPENTYPE_GPOS_SINGLE_SUBST = 1,
-    OPENTYPE_GPOS_EXTENSION_SUBST = 7
+    GSUB_LOOKUP_SINGLE_SUBST = 1,
+    GSUB_LOOKUP_EXTENSION_SUBST = 7,
 };
 
 enum TT_NAME_WINDOWS_ENCODING_ID
@@ -1852,31 +1856,30 @@ static inline const struct ot_script *opentype_get_script(const struct ot_script
     return NULL;
 }
 
-static inline const OT_LangSys *opentype_get_langsys(const struct ot_script *script, UINT32 languagetag)
+static inline const struct ot_langsys *opentype_get_langsys(const struct ot_script *script, UINT32 languagetag)
 {
     UINT16 j;
 
     for (j = 0; j < GET_BE_WORD(script->langsys_count); j++) {
         const char *tag = script->langsys[j].tag;
         if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]))
-            return (OT_LangSys*)((BYTE*)script + GET_BE_WORD(script->langsys[j].langsys));
+            return (struct ot_langsys *)((BYTE*)script + GET_BE_WORD(script->langsys[j].langsys));
     }
 
     return NULL;
 }
 
-static void opentype_add_font_features(const struct gpos_gsub_header *header, const OT_LangSys *langsys,
+static void opentype_add_font_features(const struct gpos_gsub_header *header, const struct ot_langsys *langsys,
     UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags)
 {
-    const OT_FeatureList *features = (const OT_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->feature_list));
+    const struct ot_feature_list *features = (const struct ot_feature_list *)((const BYTE*)header + GET_BE_WORD(header->feature_list));
     UINT16 j;
 
-    for (j = 0; j < GET_BE_WORD(langsys->FeatureCount); j++) {
-        const OT_FeatureRecord *feature = &features->FeatureRecord[langsys->FeatureIndex[j]];
-        const char *tag = feature->FeatureTag;
+    for (j = 0; j < GET_BE_WORD(langsys->feature_count); j++) {
+        const struct ot_feature_record *feature = &features->features[langsys->feature_index[j]];
 
         if (*count < max_tagcount)
-            tags[*count] = DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3]);
+            tags[*count] = GET_BE_DWORD(feature->tag);
 
         (*count)++;
     }
@@ -1912,7 +1915,7 @@ HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scri
 
         script = opentype_get_script(scriptlist, scripttag);
         if (script) {
-            const OT_LangSys *langsys = opentype_get_langsys(script, languagetag);
+            const struct ot_langsys *langsys = opentype_get_langsys(script, languagetag);
             if (langsys)
                 opentype_add_font_features(header, langsys, max_tagcount, count, tags);
         }
@@ -2162,27 +2165,27 @@ void opentype_colr_next_glyph(const struct dwrite_fonttable *colr, struct dwrite
 BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
 {
     const struct gpos_gsub_header *header;
-    const OT_FeatureList *featurelist;
+    const struct ot_feature_list *featurelist;
     const OT_LookupList *lookup_list;
     BOOL exists = FALSE, ret = FALSE;
+    unsigned int i, j;
     const void *data;
     void *context;
     UINT32 size;
     HRESULT hr;
-    UINT16 i;
 
     hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
     if (FAILED(hr) || !exists)
         return FALSE;
 
     header = data;
-    featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->feature_list));
+    featurelist = (struct ot_feature_list *)((BYTE*)header + GET_BE_WORD(header->feature_list));
     lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->lookup_list));
 
-    for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
-        if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
-            const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
-            UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
+    for (i = 0; i < GET_BE_WORD(featurelist->feature_count); i++) {
+        if (featurelist->features[i].tag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
+            const struct ot_feature *feature = (const struct ot_feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->features[i].offset));
+            UINT16 lookup_count = GET_BE_WORD(feature->lookup_count), index, count, type;
             const GSUB_SingleSubstFormat2 *subst2;
             const OT_LookupTable *lookup_table;
             UINT32 offset;
@@ -2190,13 +2193,13 @@ BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
             if (lookup_count == 0)
                 continue;
 
-            for (i = 0; i < lookup_count; i++) {
+            for (j = 0; j < lookup_count; ++j) {
                 /* check if lookup is empty */
-                index = GET_BE_WORD(feature->LookupListIndex[i]);
+                index = GET_BE_WORD(feature->lookuplist_index[j]);
                 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
 
                 type = GET_BE_WORD(lookup_table->LookupType);
-                if (type != OPENTYPE_GPOS_SINGLE_SUBST && type != OPENTYPE_GPOS_EXTENSION_SUBST)
+                if (type != GSUB_LOOKUP_SINGLE_SUBST && type != GSUB_LOOKUP_EXTENSION_SUBST)
                     continue;
 
                 count = GET_BE_WORD(lookup_table->SubTableCount);
@@ -2204,7 +2207,7 @@ BOOL opentype_has_vertical_variants(IDWriteFontFace4 *fontface)
                     continue;
 
                 offset = GET_BE_WORD(lookup_table->SubTable[0]);
-                if (type == OPENTYPE_GPOS_EXTENSION_SUBST) {
+                if (type == GSUB_LOOKUP_EXTENSION_SUBST) {
                     const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
                     if (GET_BE_WORD(ext->SubstFormat) == 1)
                         offset += GET_BE_DWORD(ext->ExtensionOffset);
@@ -2494,8 +2497,116 @@ DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWO
     return 0;
 }
 
+static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *context, int lookup_index)
+{
+    /* FIXME: stub */
+}
+
+struct lookups
+{
+    int *indexes;
+    size_t capacity;
+    size_t count;
+};
+
+static int lookups_sorting_compare(const void *left, const void *right)
+{
+    return *(int *)left - *(int *)right;
+};
+
 void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
         unsigned int script_index, unsigned int language_index, const struct shaping_features *features)
 {
-    /* FIXME: stub */
+    WORD 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;
+    struct lookups lookups = { 0 };
+    unsigned int i, j, l;
+
+    /* ScriptTable offset. */
+    table_offset = table_read_be_word(&cache->gpos.table, cache->gpos.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)
+        return;
+
+    if (language_index == ~0u)
+        langsys_offset = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset);
+    else
+        langsys_offset = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
+                FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) +
+                FIELD_OFFSET(struct ot_langsys_record, langsys));
+
+    script_feature_count = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
+            langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_count));
+    if (!script_feature_count)
+        return;
+
+    total_feature_count = table_read_be_word(&cache->gpos.table, cache->gpos.feature_list);
+    if (!total_feature_count)
+        return;
+
+    total_lookup_count = table_read_be_word(&cache->gpos.table, cache->gpos.lookup_list);
+    if (!total_lookup_count)
+        return;
+
+    feature_list = table_read_ensure(&cache->gpos.table, cache->gpos.feature_list,
+            FIELD_OFFSET(struct ot_feature_list, features[total_feature_count]));
+    if (!feature_list)
+        return;
+
+    /* Collect lookups for all given features. */
+    for (i = 0; i < features->count; ++i)
+    {
+        for (j = 0; j < script_feature_count; ++j)
+        {
+            WORD feature_index = table_read_be_word(&cache->gpos.table, cache->gpos.script_list + table_offset +
+                    langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_index[j]));
+            if (feature_index >= total_feature_count)
+                continue;
+
+            if (feature_list->features[feature_index].tag == features->tags[i])
+            {
+                WORD feature_offset = GET_BE_WORD(feature_list->features[feature_index].offset);
+                WORD lookup_count;
+
+                lookup_count = table_read_be_word(&cache->gpos.table, cache->gpos.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)))
+                {
+                    heap_free(lookups.indexes);
+                    return;
+                }
+
+                for (l = 0; l < lookup_count; ++l)
+                {
+                    WORD lookup_index = table_read_be_word(&cache->gpos.table, cache->gpos.feature_list +
+                            feature_offset + FIELD_OFFSET(struct ot_feature, lookuplist_index[l]));
+
+                    if (lookup_index >= total_lookup_count)
+                        continue;
+
+                    lookups.indexes[lookups.count++] = lookup_index;
+                }
+            }
+        }
+    }
+
+    /* Sort lookups. */
+    qsort(lookups.indexes, lookups.count, sizeof(*lookups.indexes), lookups_sorting_compare);
+
+    for (l = 0; l < lookups.count; ++l)
+    {
+        /* Skip duplicates. */
+        if (l && lookups.indexes[l] == lookups.indexes[l - 1])
+            continue;
+
+        opentype_layout_apply_gpos_lookup(context, lookups.indexes[l]);
+    }
+
+    heap_free(lookups.indexes);
 }
-- 
2.20.1




More information about the wine-devel mailing list