mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
7d49250016
By request from Nikolay Sivov.
353 lines
13 KiB
Diff
353 lines
13 KiB
Diff
From add69d1d24330592891222674844dccf104d6d73 Mon Sep 17 00:00:00 2001
|
|
From: Lucian Poston <lucianposton@pm.me>
|
|
Date: Mon, 21 May 2018 18:13:00 -0700
|
|
Subject: [PATCH 4/6] dwrite: Use font fallback when mapping characters
|
|
|
|
Signed-off-by: Lucian Poston <lucianposton@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,32 +2155,66 @@ 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);
|
|
}
|
|
- 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 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 c8f3f5a00f..430bb1f0eb 100644
|
|
--- a/dlls/dwrite/tests/layout.c
|
|
+++ b/dlls/dwrite/tests/layout.c
|
|
@@ -3310,35 +3310,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);
|
|
@@ -4637,16 +4625,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;
|
|
@@ -4654,16 +4639,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;
|
|
@@ -4671,38 +4653,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;
|
|
@@ -4725,7 +4701,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;
|
|
@@ -4735,17 +4714,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);
|
|
@@ -5708,34 +5689,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.18.0
|
|
|