[PATCH 3/3] dwrite: Implement AddMapping()

Nikolay Sivov nsivov at codeweavers.com
Fri Sep 22 07:34:52 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/analyzer.c     | 136 ++++++++++++++++++++++++++++++++++++---------
 dlls/dwrite/tests/layout.c |  15 +++--
 2 files changed, 121 insertions(+), 30 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index e26892f3d9..4424110f6b 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -196,15 +196,33 @@ const char *debugstr_sa_script(UINT16 script)
 /* system font falback configuration */
 static const WCHAR meiryoW[] = {'M','e','i','r','y','o',0};
 
+static const WCHAR *cjk_families[] = { meiryoW };
+
+static const DWRITE_UNICODE_RANGE cjk_ranges[] =
+{
+    { 0x3000, 0x30ff }, /* CJK Symbols and Punctuation, Hiragana, Katakana */
+    { 0x31f0, 0x31ff }, /* Katakana Phonetic Extensions */
+    { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */
+};
+
 struct fallback_mapping {
-    DWRITE_UNICODE_RANGE range;
-    const WCHAR *families[5];
+    DWRITE_UNICODE_RANGE *ranges;
+    UINT32 ranges_count;
+    WCHAR **families;
+    UINT32 families_count;
+    IDWriteFontCollection *collection;
+    WCHAR *locale;
+    FLOAT scale;
 };
 
 static const struct fallback_mapping fontfallback_neutral_data[] = {
-    { { 0x3000, 0x30ff }, { meiryoW } }, /* CJK Symbols and Punctuation, Hiragana, Katakana */
-    { { 0x31f0, 0x31ff }, { meiryoW } }, /* Katakana Phonetic Extensions */
-    { { 0x4e00, 0x9fff }, { meiryoW } }, /* CJK Unified Ideographs */
+#define MAPPING_RANGE(ranges, families) \
+        { (DWRITE_UNICODE_RANGE *)ranges, sizeof(ranges)/sizeof(ranges[0]), \
+          (WCHAR **)families, sizeof(families)/sizeof(families[0]) }
+
+    MAPPING_RANGE(cjk_ranges, cjk_families),
+
+#undef MAPPING_RANGE
 };
 
 struct dwrite_fontfallback {
@@ -212,14 +230,17 @@ struct dwrite_fontfallback {
     LONG ref;
     IDWriteFactory5 *factory;
     IDWriteFontCollection1 *systemcollection;
-    const struct fallback_mapping *mappings;
-    UINT32 count;
+    struct fallback_mapping *mappings;
+    UINT32 mappings_count;
 };
 
 struct dwrite_fontfallback_builder {
     IDWriteFontFallbackBuilder IDWriteFontFallbackBuilder_iface;
     LONG ref;
     IDWriteFactory5 *factory;
+    struct fallback_mapping *mappings;
+    UINT32 mappings_count;
+    UINT32 mappings_capacity;
 };
 
 struct dwrite_numbersubstitution {
@@ -1972,14 +1993,14 @@ static ULONG WINAPI fontfallback_Release(IDWriteFontFallback *iface)
     return IDWriteFactory5_Release(fallback->factory);
 }
 
-static int compare_fallback_mapping(const void *a, const void *b)
+static int compare_mapping_range(const void *a, const void *b)
 {
-    UINT32 ch = *(UINT32*)a;
-    struct fallback_mapping *mapping = (struct fallback_mapping*)b;
+    UINT32 ch = *(UINT32 *)a;
+    DWRITE_UNICODE_RANGE *range = (DWRITE_UNICODE_RANGE *)b;
 
-    if (ch > mapping->range.last)
+    if (ch > range->last)
         return 1;
-    else if (ch < mapping->range.first)
+    else if (ch < range->first)
         return -1;
     else
         return 0;
@@ -1987,8 +2008,17 @@ static int compare_fallback_mapping(const void *a, const void *b)
 
 static const struct fallback_mapping *find_fallback_mapping(struct dwrite_fontfallback *fallback, UINT32 ch)
 {
-    return bsearch(&ch, fallback->mappings, fallback->count, sizeof(*fallback->mappings),
-        compare_fallback_mapping);
+    UINT32 i;
+
+    for (i = 0; i < fallback->mappings_count; i++) {
+        struct fallback_mapping *mapping = &fallback->mappings[i];
+
+        if (bsearch(&ch, mapping->ranges, mapping->ranges_count, sizeof(*mapping->ranges),
+                compare_mapping_range) != NULL)
+            return mapping;
+    }
+
+    return NULL;
 }
 
 HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name,
@@ -2048,8 +2078,8 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
         IDWriteFont **mapped_font)
 {
     const struct fallback_mapping *mapping;
-    UINT32 i = 0;
     HRESULT hr;
+    UINT32 i;
 
     *mapped_font = NULL;
 
@@ -2060,19 +2090,17 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
     }
 
     /* Now let's see what fallback can handle. Pick first font that could be created. */
-    while (mapping->families[i]) {
+    for (i = 0; i < mapping->families_count; i++) {
         hr = create_matching_font((IDWriteFontCollection *)fallback->systemcollection, mapping->families[i],
                 weight, style, stretch, mapped_font);
         if (hr == S_OK) {
-            TRACE("Created fallback font for range [%#x, %#x], using family %s.\n", mapping->range.first,
-                    mapping->range.last, debugstr_w(mapping->families[i]));
+            TRACE("Created fallback font using family %s.\n", debugstr_w(mapping->families[i]));
             break;
         }
-        i++;
     }
 
     if (!*mapped_font) {
-        WARN("Failed to create fallback font for range [%#x, %#x].\n", mapping->range.first, mapping->range.last);
+        WARN("Failed to create fallback font.\n");
         return E_FAIL;
     }
 
@@ -2170,8 +2198,8 @@ HRESULT create_system_fontfallback(IDWriteFactory5 *factory, IDWriteFontFallback
 
     fallback->IDWriteFontFallback_iface.lpVtbl = &fontfallbackvtbl;
     fallback->factory = factory;
-    fallback->mappings = fontfallback_neutral_data;
-    fallback->count = sizeof(fontfallback_neutral_data)/sizeof(fontfallback_neutral_data[0]);
+    fallback->mappings = (struct fallback_mapping *)fontfallback_neutral_data;
+    fallback->mappings_count = sizeof(fontfallback_neutral_data) / sizeof(*fontfallback_neutral_data);
     IDWriteFactory5_GetSystemFontCollection(fallback->factory, FALSE, &fallback->systemcollection, FALSE);
 
     *ret = &fallback->IDWriteFontFallback_iface;
@@ -2263,6 +2291,23 @@ static ULONG WINAPI fontfallbackbuilder_Release(IDWriteFontFallbackBuilder *ifac
     TRACE("(%p)->(%d)\n", fallbackbuilder, ref);
 
     if (!ref) {
+        UINT32 i;
+
+        for (i = 0; i < fallbackbuilder->mappings_count; i++) {
+            struct fallback_mapping *mapping = &fallbackbuilder->mappings[i];
+            UINT32 j;
+
+            for (j = 0; j < mapping->families_count; j++)
+                heap_free(mapping->families[i]);
+            heap_free(mapping->families);
+
+            if (mapping->collection)
+                IDWriteFontCollection_Release(mapping->collection);
+            heap_free(mapping->ranges);
+            heap_free(mapping->locale);
+            heap_free(mapping);
+        }
+
         IDWriteFactory5_Release(fallbackbuilder->factory);
         heap_free(fallbackbuilder);
     }
@@ -2275,11 +2320,52 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder
         IDWriteFontCollection *collection, WCHAR const *locale, WCHAR const *base_family, FLOAT scale)
 {
     struct dwrite_fontfallback_builder *fallbackbuilder = impl_from_IDWriteFontFallbackBuilder(iface);
+    struct fallback_mapping *mapping;
+    UINT32 i;
 
-    FIXME("(%p)->(%p, %u, %p, %u, %p, %s, %s, %f): stub\n", fallbackbuilder, ranges, ranges_count, target_families,
+    TRACE("(%p)->(%p, %u, %p, %u, %p, %s, %s, %f)\n", fallbackbuilder, ranges, ranges_count, target_families,
             families_count, collection, debugstr_w(locale), debugstr_w(base_family), scale);
 
-    return E_NOTIMPL;
+    if (!ranges || ranges_count == 0 || !target_families || families_count == 0 || scale < 0.0f)
+        return E_INVALIDARG;
+
+    if (base_family)
+        FIXME("base family ignored.\n");
+
+    if (fallbackbuilder->mappings_count == fallbackbuilder->mappings_capacity) {
+        struct fallback_mapping *mappings;
+
+        if (fallbackbuilder->mappings_capacity == 0) {
+            if ((mappings = heap_alloc(sizeof(*fallbackbuilder->mappings) * 16)))
+                fallbackbuilder->mappings_capacity = 16;
+        }
+        else {
+            if ((mappings = heap_realloc(fallbackbuilder->mappings, sizeof(*fallbackbuilder->mappings) *
+                    fallbackbuilder->mappings_capacity * 2)))
+                fallbackbuilder->mappings_capacity *= 2;
+        }
+        if (!mappings)
+            return E_OUTOFMEMORY;
+
+        fallbackbuilder->mappings = mappings;
+    }
+
+    mapping = &fallbackbuilder->mappings[fallbackbuilder->mappings_count++];
+
+    mapping->ranges = heap_alloc(sizeof(*mapping->ranges) * ranges_count);
+    memcpy(mapping->ranges, ranges, sizeof(*mapping->ranges) * ranges_count);
+    mapping->ranges_count = ranges_count;
+    mapping->families = heap_alloc_zero(sizeof(*mapping->families) * families_count);
+    mapping->families_count = families_count;
+    for (i = 0; i < families_count; i++)
+        mapping->families[i] = heap_strdupW(target_families[i]);
+    mapping->collection = collection;
+    if (mapping->collection)
+        IDWriteFontCollection_AddRef(mapping->collection);
+    mapping->locale = heap_strdupW(locale);
+    mapping->scale = scale;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI fontfallbackbuilder_AddMappings(IDWriteFontFallbackBuilder *iface, IDWriteFontFallback *fallback)
@@ -2330,7 +2416,7 @@ HRESULT create_fontfallback_builder(IDWriteFactory5 *factory, IDWriteFontFallbac
 
     *ret = NULL;
 
-    builder = heap_alloc(sizeof(*builder));
+    builder = heap_alloc_zero(sizeof(*builder));
     if (!builder)
         return E_OUTOFMEMORY;
 
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 493eaf317f..3b0bf98125 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -4702,7 +4702,6 @@ static void test_FontFallbackBuilder(void)
     ok(fallback != fallback2, "Unexpected fallback instance.\n");
     IDWriteFontFallback_Release(fallback2);
 
-todo_wine {
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 
@@ -4714,12 +4713,21 @@ todo_wine {
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 1.0f);
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 
+    hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, &familyW, 1, NULL, NULL, NULL, 1.0f);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, &familyW, 1, NULL, NULL, NULL, 1.0f);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
     /* negative scaling factor */
     range.first = range.last = 0;
     familyW = g_blahfontW;
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, -1.0f);
     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
 
+    hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 0.0f);
+    ok(hr == S_OK, "Unexected hr %#x.\n", hr);
+
     /* empty range */
     range.first = range.last = 0;
     familyW = g_blahfontW;
@@ -4738,7 +4746,7 @@ todo_wine {
     range.last = 'A';
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 4.0f);
     ok(hr == S_OK, "got 0x%08x\n", hr);
-}
+
     IDWriteFontFallback_Release(fallback);
 
     if (0) /* crashes on native */
@@ -4765,7 +4773,6 @@ todo_wine {
     /* remap with custom collection */
     range.first = range.last = 'A';
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 5.0f);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
@@ -4791,7 +4798,6 @@ todo_wine {
     range.first = 'B';
     range.last = 'A';
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 6.0f);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
@@ -4818,7 +4824,6 @@ todo_wine {
     range.first = 'A';
     range.last = 'B';
     hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, localeW, NULL, 6.0f);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
-- 
2.14.1




More information about the wine-patches mailing list