From cb01601870a6299e0da0a956269ef24ed79d5035 Mon Sep 17 00:00:00 2001 From: Lucian Poston Date: Mon, 21 May 2018 18:13:00 -0700 Subject: [PATCH] dwrite: Use font fallback when mapping characters Signed-off-by: Lucian Poston --- dlls/dwrite/analyzer.c | 77 +++++++++++++++++++++++++++++--------- dlls/dwrite/layout.c | 6 +++ dlls/dwrite/tests/layout.c | 54 +++++--------------------- 3 files changed, 74 insertions(+), 63 deletions(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 6b74a23540a..5827e87fdf5 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -2062,6 +2062,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; @@ -2073,9 +2074,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])); @@ -2132,32 +2139,66 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, ID 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); } - else { - if (*ret_font) - IDWriteFont_Release(*ret_font); - *ret_font = mapped_font; + } + + /** + * 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); } } + if (!*mapped_length) { + *mapped_length = length == 0 ? 0 : 1; + hr = S_OK; + } + done: heap_free(buff); return hr; diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 99048b97a3c..64d8eef6f59 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -958,6 +958,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 cea581a0bef..ecefbe9c87a 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -3368,35 +3368,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); @@ -4690,12 +4678,9 @@ 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); @@ -4707,16 +4692,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; @@ -4724,32 +4706,24 @@ 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); -} + 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) { IDWriteFont_Release(font); -} + /* Try with explicit collection, Tahoma will be forced. */ /* 1. Latin part */ g_source = str2W; @@ -4772,7 +4746,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; @@ -4782,7 +4759,6 @@ 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); @@ -6564,34 +6540,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.20.1