Nikolay Sivov : dwrite: Add support for dlng/slng metadata.

Alexandre Julliard julliard at winehq.org
Mon Jan 27 15:00:20 CST 2020


Module: wine
Branch: master
Commit: 0a5747bfa1dfc5f0c4df084fe1d8bad17dce7d05
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=0a5747bfa1dfc5f0c4df084fe1d8bad17dce7d05

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Mon Jan 27 08:52:48 2020 +0300

dwrite: Add support for dlng/slng metadata.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dwrite/dwrite_private.h |   2 +-
 dlls/dwrite/font.c           |   6 +-
 dlls/dwrite/main.c           |  11 ++--
 dlls/dwrite/opentype.c       | 149 ++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 152 insertions(+), 16 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 6adba28280..e5ca5306c2 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -231,7 +231,7 @@ struct dwrite_fontface
     FONTSIGNATURE fontsig;
     UINT32 glyph_image_formats;
 
-    IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME + 1];
+    IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
     IDWriteLocalizedStrings *family_names;
     IDWriteLocalizedStrings *names;
 
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 8bcbe11fcb..847070816b 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -82,7 +82,7 @@ struct dwrite_font_data
     struct dwrite_font_propvec propvec;
 
     DWRITE_FONT_METRICS1 metrics;
-    IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME + 1];
+    IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
     IDWriteLocalizedStrings *family_names;
     IDWriteLocalizedStrings *names;
 
@@ -1291,8 +1291,8 @@ static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc,
     *exists = FALSE;
     *ret = NULL;
 
-    if (stringid > DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME
-            || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
+    if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
+            || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
     {
         return S_OK;
     }
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index 283cccb76c..b940d0d801 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -446,10 +446,13 @@ HRESULT add_localizedstring(IDWriteLocalizedStrings *iface, const WCHAR *locale,
     struct localizedstrings *strings = impl_from_IDWriteLocalizedStrings(iface);
     size_t i, count = strings->count;
 
-    /* make sure there's no duplicates */
-    for (i = 0; i < count; i++)
-        if (!strcmpW(strings->data[i].locale, locale))
-            return S_OK;
+    /* Make sure there's no duplicates, unless it's empty. This is used by dlng/slng entries of 'meta' table. */
+    if (*locale)
+    {
+        for (i = 0; i < count; i++)
+            if (!strcmpW(strings->data[i].locale, locale))
+                return S_OK;
+    }
 
     if (!dwrite_array_reserve((void **)&strings->data, &strings->size, strings->count + 1, sizeof(*strings->data)))
         return E_OUTOFMEMORY;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index fd420e4360..23d7669eb6 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -46,6 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
+#define MS_META_TAG DWRITE_MAKE_OPENTYPE_TAG('m','e','t','a')
 
 /* 'sbix' formats */
 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
@@ -55,6 +56,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
 
+/* 'meta' tags */
+#define MS_DLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('d','l','n','g')
+#define MS_SLNG_TAG DWRITE_MAKE_OPENTYPE_TAG('s','l','n','g')
+
 #ifdef WORDS_BIGENDIAN
 #define GET_BE_WORD(x) (x)
 #define GET_BE_DWORD(x) (x)
@@ -1164,6 +1169,22 @@ struct colr_layer_record
     USHORT palette_index;
 };
 
+struct meta_data_map
+{
+    DWORD tag;
+    DWORD offset;
+    DWORD length;
+};
+
+struct meta_header
+{
+    DWORD version;
+    DWORD flags;
+    DWORD reserved;
+    DWORD data_maps_count;
+    struct meta_data_map maps[1];
+};
+
 static const void *table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size)
 {
     if (size > table->size || offset > table->size - size)
@@ -2109,23 +2130,135 @@ static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OP
     return exists ? S_OK : E_FAIL;
 }
 
-/* Provides a conversion from DWRITE to OpenType name ids, input id should be valid, it's not checked. */
-HRESULT opentype_get_font_info_strings(const struct file_stream_desc *stream_desc, DWRITE_INFORMATIONAL_STRING_ID id,
-        IDWriteLocalizedStrings **strings)
+static WCHAR *meta_get_lng_name(WCHAR *str, WCHAR **ctx)
 {
-    struct dwrite_fonttable name;
+    static const WCHAR delimW[] = {',',' ',0};
+    WCHAR *ret;
+
+    if (!str) str = *ctx;
+    while (*str && strchrW(delimW, *str)) str++;
+    if (!*str) return NULL;
+    ret = str++;
+    while (*str && !strchrW(delimW, *str)) str++;
+    if (*str) *str++ = 0;
+    *ctx = str;
+
+    return ret;
+}
+
+static HRESULT opentype_get_font_strings_from_meta(const struct file_stream_desc *stream_desc,
+        DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **ret)
+{
+    static const WCHAR emptyW[] = { 0 };
+    const struct meta_data_map *maps;
+    IDWriteLocalizedStrings *strings;
+    struct dwrite_fonttable meta;
+    DWORD version, i, count, tag;
     HRESULT hr;
 
-    opentype_get_font_table(stream_desc, MS_NAME_TAG, &name);
+    *ret = NULL;
 
-    hr = opentype_get_font_strings_from_id(name.data, dwriteid_to_opentypeid[id], strings);
+    hr = create_localizedstrings(&strings);
+    if (FAILED(hr))
+        return hr;
 
-    if (name.context)
-        IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name.context);
+    switch (id)
+    {
+        case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG:
+            tag = MS_DLNG_TAG;
+            break;
+        case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG:
+            tag = MS_SLNG_TAG;
+            break;
+        default:
+            WARN("Unexpected id %d.\n", id);
+            return S_OK;
+    }
+
+    opentype_get_font_table(stream_desc, MS_META_TAG, &meta);
+
+    if (meta.data)
+    {
+        version = table_read_be_dword(&meta, 0);
+        if (version != 1)
+        {
+            WARN("Unexpected meta table version %d.\n", version);
+            goto end;
+        }
+
+        count = table_read_be_dword(&meta, FIELD_OFFSET(struct meta_header, data_maps_count));
+        if (!(maps = table_read_ensure(&meta, FIELD_OFFSET(struct meta_header, maps),
+                count * sizeof(struct meta_data_map))))
+            goto end;
+
+        for (i = 0; i < count; ++i)
+        {
+            const char *data;
+
+            if (maps[i].tag == tag && maps[i].length)
+            {
+                DWORD length = GET_BE_DWORD(maps[i].length), j;
+
+                if ((data = table_read_ensure(&meta, GET_BE_DWORD(maps[i].offset), length)))
+                {
+                    WCHAR *ptrW = heap_alloc((length + 1) * sizeof(WCHAR)), *ctx, *token;
+
+                    if (!ptrW)
+                    {
+                        hr = E_OUTOFMEMORY;
+                        goto end;
+                    }
+
+                    /* Data is stored in comma separated list, ASCII range only. */
+                    for (j = 0; j < length; ++j)
+                        ptrW[j] = data[j];
+                    ptrW[length] = 0;
+
+                    token = meta_get_lng_name(ptrW, &ctx);
+
+                    while (token)
+                    {
+                        add_localizedstring(strings, emptyW, token);
+                        token = meta_get_lng_name(NULL, &ctx);
+                    }
+
+                    heap_free(ptrW);
+                }
+            }
+        }
+end:
+        IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, meta.context);
+    }
+
+    if (IDWriteLocalizedStrings_GetCount(strings))
+        *ret = strings;
+    else
+        IDWriteLocalizedStrings_Release(strings);
 
     return hr;
 }
 
+HRESULT opentype_get_font_info_strings(const struct file_stream_desc *stream_desc, DWRITE_INFORMATIONAL_STRING_ID id,
+        IDWriteLocalizedStrings **strings)
+{
+    struct dwrite_fonttable name;
+
+    switch (id)
+    {
+        case DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG:
+        case DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG:
+            opentype_get_font_strings_from_meta(stream_desc, id, strings);
+            break;
+        default:
+            opentype_get_font_table(stream_desc, MS_NAME_TAG, &name);
+            opentype_get_font_strings_from_id(name.data, dwriteid_to_opentypeid[id], strings);
+            if (name.context)
+                IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name.context);
+    }
+
+    return S_OK;
+}
+
 /* FamilyName locating order is WWS Family Name -> Preferred Family Name -> Family Name. If font claims to
    have 'Preferred Family Name' in WWS format, then WWS name is not used. */
 HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names)




More information about the wine-cvs mailing list