From: Lucian Poston Subject: [PATCH 4/6] dwrite: Use font fallback when mapping characters Message-Id: <7Ei9atfeSNShD6shkYMPbIaQheIiNd1UbKE56q6pwd0YHIayIlPdhhChvF7i96mwo1NxfDL5-D43P0NmTl0fgemFJC0tzA9dCPN2LzyJu18=@pm.me> Date: Wed, 23 May 2018 14:07:06 -0400 In-Reply-To: References: Signed-off-by: Lucian Poston --- 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