[PATCH 4/6] dwrite: Use font fallback when mapping characters

Lucian Poston lucianposton at pm.me
Wed May 23 13:07:06 CDT 2018


Signed-off-by: Lucian Poston <lucianposton at pm.me>
---
 dlls/dwrite/analyzer.c     | 77 +++++++++++++++++++++++++++---------
 dlls/dwrite/layout.c       |  6 +++
 dlls/dwrite/tests/layout.c | 97 ++++++++++++++++------------------------------
 3 files changed, 98 insertions(+), 82 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 8d553c6d56..21da783fe6 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -2078,6 +2078,7 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
         IDWriteFont **mapped_font)
 {
     const struct fallback_mapping *mapping;
+    IDWriteFontCollection *collection;
     HRESULT hr;
     UINT32 i;
 
@@ -2089,9 +2090,15 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
         return E_FAIL;
     }
 
+    if (mapping->collection) {
+        collection = mapping->collection;
+    } else {
+        collection = (IDWriteFontCollection *)fallback->systemcollection;
+    }
+
     /* Now let's see what fallback can handle. Pick first font that could be created. */
     for (i = 0; i < mapping->families_count; i++) {
-        hr = create_matching_font((IDWriteFontCollection *)fallback->systemcollection, mapping->families[i],
+        hr = create_matching_font(collection, mapping->families[i],
                 weight, style, stretch, mapped_font);
         if (hr == S_OK) {
             TRACE("Created fallback font using family %s.\n", debugstr_w(mapping->families[i]));
@@ -2148,30 +2155,64 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback *iface, IDW
 
     if (basefamily && *basefamily) {
         hr = create_matching_font(basecollection, basefamily, weight, style, stretch, ret_font);
-        if (FAILED(hr))
-            goto done;
-
-        hr = fallback_map_characters(*ret_font, text, length, mapped_length);
-        if (FAILED(hr))
-            goto done;
+        if (SUCCEEDED(hr)) {
+            hr = fallback_map_characters(*ret_font, text, length, mapped_length);
+            if (FAILED(hr)) {
+                IDWriteFont_Release(*ret_font);
+                *ret_font = NULL;
+                WARN("Mapping with requested family %s failed, hr %#x.\n", debugstr_w(basefamily), hr);
+            }
+        }
     }
 
     if (!*mapped_length) {
-        IDWriteFont *mapped_font;
+        if (*ret_font) {
+            IDWriteFont_Release(*ret_font);
+            *ret_font = NULL;
+        }
 
-        hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, &mapped_font);
+        hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, ret_font);
         if (FAILED(hr)) {
-            /* fallback wasn't found, keep base font if any, so we can get at least some visual output */
-            if (*ret_font) {
-                *mapped_length = length;
-                hr = S_OK;
+            WARN("Mapping with fallback families failed, hr %#x.\n", hr);
+        }
+    }
+
+    /**
+     * This is a rough hack. We search the system font collection because
+     * the system fontfallback, which would have been searched above, is not
+     * fully implemented as it isn't populated with any system fonts. Once
+     * implemented, the block below can be removed.
+     * */
+    if (!*mapped_length) {
+        IDWriteFontFamily *family;
+        IDWriteFont *font;
+        UINT32 i, count = IDWriteFontCollection_GetFontFamilyCount((IDWriteFontCollection *)fallback->systemcollection);
+        for (i = 0; i < count; i++) {
+            hr = IDWriteFontCollection_GetFontFamily((IDWriteFontCollection *)fallback->systemcollection, i, &family);
+            if (FAILED(hr)) {
+                ERR("Failed to get font family.\n");
+                continue;
             }
+
+            hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, &font);
+            IDWriteFontFamily_Release(family);
+            if (FAILED(hr)) {
+                continue;
+            }
+
+            hr = fallback_map_characters(font, text, length, mapped_length);
+            if (SUCCEEDED(hr) && mapped_length > 0) {
+                *ret_font = font;
+                break;
+            }
+
+            IDWriteFont_Release(font);
         }
-        else {
-            if (*ret_font)
-                IDWriteFont_Release(*ret_font);
-            *ret_font = mapped_font;
-        }
+    }
+
+    if (!*mapped_length) {
+        *mapped_length = length == 0 ? 0 : 1;
+        hr = S_OK;
     }
 
 done:
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 65e0a57678..df3f3beabb 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -878,6 +878,12 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
                 goto fatal;
             }
 
+            if (!font) {
+                hr = E_FAIL;
+                WARN("Failed to create font face, hr %#x.\n", hr);
+                goto fatal;
+            }
+
             hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
             IDWriteFont_Release(font);
             if (FAILED(hr)) {
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 5157d0562d..85967e7ee8 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -3312,35 +3312,23 @@ todo_wine
 
     count = 0;
     hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
     ok(count == 4, "got %u\n", count);
     for (i = 0, width = 0.0; i < count; i++)
         width += clusters[i].width;
 
     memset(&metrics, 0xcc, sizeof(metrics));
     hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
-todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
     ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
-todo_wine
     ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
-todo_wine
     ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
-todo_wine
     ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
         metrics.widthIncludingTrailingWhitespace, width);
-todo_wine
     ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
-todo_wine
     ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
-todo_wine
     ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
-todo_wine
     ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
-todo_wine
     ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
 
     IDWriteTextLayout_Release(layout);
@@ -4639,16 +4627,13 @@ static void test_MapCharacters(void)
     font = NULL;
     hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
         DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
-todo_wine {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mappedlength == 1, "got %u\n", mappedlength);
-}
     ok(scale == 1.0f, "got %f\n", scale);
-todo_wine
     ok(font != NULL, "got %p\n", font);
-if (font) {
-    IDWriteFont_Release(font);
-}
+    if (font) {
+        IDWriteFont_Release(font);
+    }
     /* same latin text, full length */
     g_source = strW;
     mappedlength = 0;
@@ -4656,16 +4641,13 @@ if (font) {
     font = NULL;
     hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
         DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
-todo_wine {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mappedlength == 3, "got %u\n", mappedlength);
-}
     ok(scale == 1.0f, "got %f\n", scale);
-todo_wine
     ok(font != NULL, "got %p\n", font);
-if (font) {
-    IDWriteFont_Release(font);
-}
+    if (font) {
+        IDWriteFont_Release(font);
+    }
     /* string 'a\x3058b' */
     g_source = str2W;
     mappedlength = 0;
@@ -4673,38 +4655,32 @@ if (font) {
     font = NULL;
     hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
         DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
-todo_wine {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mappedlength == 1, "got %u\n", mappedlength);
-}
     ok(scale == 1.0f, "got %f\n", scale);
-todo_wine
     ok(font != NULL, "got %p\n", font);
-if (font) {
-    IDWriteFont_Release(font);
-}
+    if (font) {
+        IDWriteFont_Release(font);
+    }
     g_source = str2W;
     mappedlength = 0;
     scale = 0.0f;
     font = NULL;
     hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 2, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
         DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
-todo_wine {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mappedlength == 1, "got %u\n", mappedlength);
-}
     ok(scale == 1.0f, "got %f\n", scale);
-todo_wine
     ok(font != NULL, "got %p\n", font);
-if (font) {
-    /* font returned for Hiragana character, check if it supports Latin too */
-    exists = FALSE;
-    hr = IDWriteFont_HasCharacter(font, 'b', &exists);
-    ok(hr == S_OK, "got 0x%08x\n", hr);
-    ok(exists, "got %d\n", exists);
+    if (font) {
+        /* font returned for Hiragana character, check if it supports Latin too */
+        exists = FALSE;
+        hr = IDWriteFont_HasCharacter(font, 'b', &exists);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        ok(exists, "got %d\n", exists);
 
-    IDWriteFont_Release(font);
-}
+        IDWriteFont_Release(font);
+    }
     /* Try with explicit collection, Tahoma will be forced. */
     /* 1. Latin part */
     g_source = str2W;
@@ -4727,7 +4703,10 @@ if (font) {
     IDWriteLocalizedStrings_Release(strings);
     IDWriteFont_Release(font);
 
-    /* 2. Hiragana character, force Tahoma font does not support Japanese */
+    /**
+     * 2. Hiragana character. Tahoma is requested, but it doesn't support
+     * Japanese. A NULL font is returned if there is no fallback for Japanese.
+     */
     g_source = str2W;
     mappedlength = 0;
     scale = 0.0f;
@@ -4737,17 +4716,19 @@ if (font) {
     ok(hr == S_OK, "got 0x%08x\n", hr);
     ok(mappedlength == 1, "got %u\n", mappedlength);
     ok(scale == 1.0f, "got %f\n", scale);
-    ok(font != NULL, "got %p\n", font);
 
-    exists = FALSE;
-    hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
-    ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
-    hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
-    ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
-    ok(lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
-    IDWriteLocalizedStrings_Release(strings);
-    IDWriteFont_Release(font);
+    if (!font) {
+        skip("Missing system font for Japanese.\n");
+    } else {
+        exists = FALSE;
+        hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
+        ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
+        hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        ok(lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
+        IDWriteLocalizedStrings_Release(strings);
+        IDWriteFont_Release(font);
+    }
 
     IDWriteFontFallback_Release(fallback);
     IDWriteFactory2_Release(factory2);
@@ -5710,34 +5691,22 @@ static void test_GetMetrics_with_custom_fontcollection(void)
     ok(hr == S_OK, "got 0x%08x\n", hr);
     count = 9999;
     hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
-    todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
-    todo_wine
     ok(count == 4, "got %u\n", count);
     for (i = 0, width = 0.0; i < count; i++)
         width += clusters[i].width;
     memset(&metrics, 0xcc, sizeof(metrics));
     hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
-    todo_wine
     ok(hr == S_OK, "got 0x%08x\n", hr);
-    todo_wine
     ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
-    todo_wine
     ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
-    todo_wine
     ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
-    todo_wine
     ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
         metrics.widthIncludingTrailingWhitespace, width);
-    todo_wine
     ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
-    todo_wine
     ok(metrics.layoutWidth == 1000.0, "got %.2f\n", metrics.layoutWidth);
-    todo_wine
     ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
-    todo_wine
     ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
-    todo_wine
     ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
     IDWriteTextLayout_Release(layout);
 
-- 
2.16.1





More information about the wine-devel mailing list