Nikolay Sivov : dwrite: Keep locales separate for fallback data.

Alexandre Julliard julliard at winehq.org
Fri Jul 22 15:38:23 CDT 2022


Module: wine
Branch: master
Commit: 76e675a011dddcb141414c56d0da767aa3fd88e4
URL:    https://gitlab.winehq.org/wine/wine/-/commit/76e675a011dddcb141414c56d0da767aa3fd88e4

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Sun Jul 17 17:42:59 2022 +0300

dwrite: Keep locales separate for fallback data.

Each locale entry contains a "list" of its mappings.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>

---

 dlls/dwrite/analyzer.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 89 insertions(+), 4 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 1522d7638bc..c6c4fa2d654 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -220,16 +220,78 @@ static const DWRITE_UNICODE_RANGE cjk_ranges[] =
     { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */
 };
 
-struct fallback_mapping {
+struct fallback_mapping
+{
     DWRITE_UNICODE_RANGE *ranges;
     UINT32 ranges_count;
     WCHAR **families;
     UINT32 families_count;
     IDWriteFontCollection *collection;
-    WCHAR *locale;
-    FLOAT scale;
+    float scale;
+};
+
+struct fallback_locale
+{
+    struct list entry;
+    WCHAR name[LOCALE_NAME_MAX_LENGTH];
+    struct
+    {
+        size_t *data;
+        size_t count;
+        size_t size;
+    } ranges;
 };
 
+static void fallback_locale_list_destroy(struct list *locales)
+{
+    struct fallback_locale *cur, *cur2;
+
+    LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, locales, struct fallback_locale, entry)
+    {
+        list_remove(&cur->entry);
+        free(cur->ranges.data);
+        free(cur);
+    }
+}
+
+static HRESULT fallback_locale_add_mapping(struct fallback_locale *locale, size_t index)
+{
+    size_t count = locale->ranges.count;
+
+    /* Append to last range, or start a new one. */
+    if (count && locale->ranges.data[count - 1] == (index - 1))
+    {
+        locale->ranges.data[count - 1] = index;
+        return S_OK;
+    }
+
+    if (!dwrite_array_reserve((void **)&locale->ranges.data, &locale->ranges.size, count + 2,
+            sizeof(*locale->ranges.data)))
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    locale->ranges.data[count] = locale->ranges.data[count + 1] = index;
+    locale->ranges.count += 2;
+
+    return S_OK;
+}
+
+/* TODO: potentially needs improvement to consider partially matching locale names. */
+static struct fallback_locale * font_fallback_get_locale(const struct list *locales,
+        const WCHAR *locale_name)
+{
+    struct fallback_locale *locale, *neutral = NULL;
+
+    LIST_FOR_EACH_ENTRY(locale, locales, struct fallback_locale, entry)
+    {
+        if (!wcsicmp(locale->name, locale_name)) return locale;
+        if (!*locale->name) neutral = locale;
+    }
+
+    return neutral;
+}
+
 static const struct fallback_mapping fontfallback_neutral_data[] = {
 #define MAPPING_RANGE(ranges, families) \
         { (DWRITE_UNICODE_RANGE *)ranges, ARRAY_SIZE(ranges), \
@@ -244,6 +306,7 @@ struct fallback_data
 {
     struct fallback_mapping *mappings;
     size_t count;
+    struct list locales;
 };
 
 struct dwrite_fontfallback
@@ -284,6 +347,7 @@ static void release_fallback_data(struct fallback_data *data)
     for (i = 0; i < data->count; ++i)
         release_fallback_mapping(&data->mappings[i]);
     free(data->mappings);
+    fallback_locale_list_destroy(&data->locales);
 }
 
 struct dwrite_numbersubstitution
@@ -2368,12 +2432,26 @@ static ULONG WINAPI fontfallbackbuilder_Release(IDWriteFontFallbackBuilder *ifac
     return refcount;
 }
 
+static struct fallback_locale * fallback_builder_add_locale(struct dwrite_fontfallback_builder *builder,
+        const WCHAR *locale_name)
+{
+    struct fallback_locale *locale;
+
+    if (!locale_name) locale_name = L"";
+    if ((locale = font_fallback_get_locale(&builder->data.locales, locale_name))) return locale;
+    if (!(locale = calloc(1, sizeof(*locale)))) return NULL;
+    lstrcpynW(locale->name, locale_name, ARRAY_SIZE(locale->name));
+    list_add_tail(&builder->data.locales, &locale->entry);
+    return locale;
+}
+
 static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder *iface,
         const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **families, UINT32 families_count,
         IDWriteFontCollection *collection, WCHAR const *locale_name, WCHAR const *base_family, float scale)
 {
     struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface);
     struct fallback_mapping *mapping;
+    struct fallback_locale *locale;
     unsigned int i, count;
 
     TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count,
@@ -2394,6 +2472,11 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder
     mapping = &builder->data.mappings[builder->data.count];
     memset(mapping, 0, sizeof(*mapping));
 
+    /* Append new mapping, link to its locale node. */
+
+    if (!(locale = fallback_builder_add_locale(builder, locale_name)))
+        return E_FAIL;
+
     if (!(mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges))))
         goto failed;
 
@@ -2422,9 +2505,10 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder
     mapping->collection = collection;
     if (mapping->collection)
         IDWriteFontCollection_AddRef(mapping->collection);
-    mapping->locale = wcsdup(locale_name);
     mapping->scale = scale;
 
+    if (FAILED(fallback_locale_add_mapping(locale, builder->data.count))) goto failed;
+
     builder->data.count++;
     return S_OK;
 
@@ -2485,6 +2569,7 @@ HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbac
     builder->refcount = 1;
     builder->factory = factory;
     IDWriteFactory7_AddRef(builder->factory);
+    list_init(&builder->data.locales);
 
     *ret = &builder->IDWriteFontFallbackBuilder_iface;
     return S_OK;




More information about the wine-cvs mailing list