[PATCH 4/5] dwrite: Initial implementation of MapCharacters()
Nikolay Sivov
nsivov at codeweavers.com
Sun Feb 14 10:05:09 CST 2016
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/analyzer.c | 176 +++++++++++++++++++++++++++++++++++++++++++--
dlls/dwrite/tests/layout.c | 31 ++++----
2 files changed, 185 insertions(+), 22 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 5bb9a2c..10ff0a2 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -182,9 +182,23 @@ const char *debugstr_sa_script(UINT16 script)
return script < Script_LastId ? debugstr_an((char*)&dwritescripts_properties[script].props.isoScriptCode, 4): "not defined";
}
+/* system font falback configuration */
+static const WCHAR meiryoW[] = {'M','e','i','r','y','o',0};
+
+struct fallback_mapping {
+ DWRITE_UNICODE_RANGE range;
+ const WCHAR *family;
+};
+
+static const struct fallback_mapping fontfallback_neutral_data[] = {
+ { { 0x4e00, 0x9fff }, meiryoW }, /* CJK Unified Ideographs */
+};
+
struct dwrite_fontfallback {
IDWriteFontFallback IDWriteFontFallback_iface;
IDWriteFactory2 *factory;
+ const struct fallback_mapping *mappings;
+ UINT32 count;
};
struct dwrite_numbersubstitution {
@@ -1719,17 +1733,169 @@ static ULONG WINAPI fontfallback_Release(IDWriteFontFallback *iface)
return IDWriteFactory2_Release(fallback->factory);
}
+static const struct fallback_mapping *find_fallback_mapping(struct dwrite_fontfallback *fallback, UINT32 ch)
+{
+ UINT32 i;
+
+ for (i = 0; i < fallback->count; i++) {
+ if (fallback->mappings[i].range.first <= ch && fallback->mappings[i].range.last >= ch)
+ return &fallback->mappings[i];
+ }
+
+ return NULL;
+}
+
+static HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name,
+ DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, IDWriteFont **font)
+{
+ IDWriteFontFamily *family;
+ BOOL exists = FALSE;
+ HRESULT hr;
+ UINT32 i;
+
+ *font = NULL;
+
+ hr = IDWriteFontCollection_FindFamilyName(collection, name, &i, &exists);
+ if (FAILED(hr))
+ return hr;
+
+ if (!exists)
+ return E_FAIL;
+
+ hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
+ if (FAILED(hr))
+ return hr;
+
+ hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, font);
+ IDWriteFontFamily_Release(family);
+ return hr;
+}
+
+static HRESULT fallback_map_characters(IDWriteFont *font, const WCHAR *text, UINT32 length, UINT32 *mapped_length)
+{
+ HRESULT hr = S_OK;
+ UINT32 i;
+
+ for (i = 0; i < length; i++) {
+ UINT16 script = get_char_script(text[i]);
+ BOOL exists;
+
+ if (script == Script_Unknown || script == Script_Common) {
+ ++*mapped_length;
+ continue;
+ }
+
+ /* stop on first unsupported character */
+ exists = FALSE;
+ hr = IDWriteFont_HasCharacter(font, text[i], &exists);
+ if (hr == S_OK && exists)
+ ++*mapped_length;
+ else
+ break;
+ }
+
+ return hr;
+}
+
+static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, const WCHAR *text, UINT32 length,
+ IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch,
+ UINT32 *mapped_length, IDWriteFont **mapped_font)
+{
+ const struct fallback_mapping *mapping;
+ HRESULT hr;
+
+ mapping = find_fallback_mapping(fallback, text[0]);
+ if (!mapping) {
+ WARN("no mapping for 0x%x\n", text[0]);
+ return E_FAIL;
+ }
+
+ /* now let's see what fallback can handle */
+ hr = create_matching_font(collection, mapping->family, weight, style, stretch, mapped_font);
+ if (FAILED(hr)) {
+ WARN("failed to create fallback font %s for range [0x%x,0x%x], 0x%08x\n", debugstr_w(mapping->family),
+ mapping->range.first, mapping->range.last, hr);
+ return hr;
+ }
+
+ hr = fallback_map_characters(*mapped_font, text, length, mapped_length);
+ if (FAILED(hr))
+ WARN("mapping with fallback font %s failed, 0x%08x\n", debugstr_w(mapping->family), hr);
+
+ if (!*mapped_length) {
+ IDWriteFont_Release(*mapped_font);
+ *mapped_font = NULL;
+ }
+
+ return *mapped_length ? S_OK : E_FAIL;
+}
+
static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback *iface, IDWriteTextAnalysisSource *source,
UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily,
DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length,
- IDWriteFont **mapped_font, FLOAT *scale)
+ IDWriteFont **ret_font, FLOAT *scale)
{
struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback(iface);
+ WCHAR *buff = NULL;
+ const WCHAR *text;
+ HRESULT hr;
- FIXME("(%p)->(%p %u %u %p, %s, %u, %u, %u, %p, %p, %p): stub\n", fallback, source, position, length,
- basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, mapped_font, scale);
+ TRACE("(%p)->(%p %u %u %p, %s, %u, %u, %u, %p, %p, %p)\n", fallback, source, position, length,
+ basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale);
- return E_NOTIMPL;
+ *mapped_length = 0;
+ *scale = 1.0f;
+ *ret_font = NULL;
+
+ if (!source)
+ return E_INVALIDARG;
+
+ if (length == 0)
+ return S_OK;
+
+ if (!basecollection) {
+ hr = IDWriteFactory2_GetSystemFontCollection(fallback->factory, &basecollection, FALSE);
+ if (FAILED(hr))
+ return hr;
+ }
+ else
+ IDWriteFontCollection_AddRef(basecollection);
+
+ hr = get_text_source_ptr(source, position, length, &text, &buff);
+ if (FAILED(hr))
+ goto done;
+
+ if (basefamily && *basefamily) {
+ IDWriteFont *mapped_font;
+
+ 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 (!*mapped_length) {
+ hr = fallback_get_fallback_font(fallback, text, length, basecollection, weight, style, stretch, mapped_length, &mapped_font);
+ if (FAILED(hr)) {
+ *mapped_length = length;
+ hr = S_OK;
+ goto done;
+ }
+ else {
+ IDWriteFont_Release(*ret_font);
+ *ret_font = mapped_font;
+ }
+ }
+ }
+ else
+ hr = fallback_get_fallback_font(fallback, text, length, basecollection, weight, style, stretch, mapped_length, ret_font);
+
+done:
+ IDWriteFontCollection_Release(basecollection);
+ heap_free(buff);
+ return hr;
}
static const IDWriteFontFallbackVtbl fontfallbackvtbl = {
@@ -1751,6 +1917,8 @@ HRESULT create_system_fontfallback(IDWriteFactory2 *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]);
*ret = &fallback->IDWriteFontFallback_iface;
return S_OK;
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 4df6e00..a6da532 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -4253,12 +4253,11 @@ static void test_MapCharacters(void)
font = (void*)0xdeadbeef;
hr = IDWriteFontFallback_MapCharacters(fallback, NULL, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
-todo_wine {
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
ok(mappedlength == 0, "got %u\n", mappedlength);
ok(scale == 1.0f, "got %f\n", scale);
ok(font == NULL, "got %p\n", font);
-}
+
/* zero length source */
g_source = strW;
mappedlength = 1;
@@ -4266,12 +4265,11 @@ todo_wine {
font = (void*)0xdeadbeef;
hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 0, 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 == 0, "got %u\n", mappedlength);
ok(scale == 1.0f, "got %f\n", scale);
ok(font == NULL, "got %p\n", font);
-}
+
g_source = strW;
mappedlength = 0;
scale = 0.0f;
@@ -4281,9 +4279,10 @@ todo_wine {
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);
@@ -4297,9 +4296,10 @@ if (font)
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);
@@ -4313,9 +4313,10 @@ if (font)
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);
@@ -4328,9 +4329,10 @@ if (font)
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;
@@ -4348,14 +4350,11 @@ if (font) {
font = NULL;
hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, &fallbackcollection, g_blahfontW, 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);
ok(font != NULL, "got %p\n", font);
-}
-if (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);
@@ -4363,9 +4362,8 @@ if (font) {
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);
-}
+
/* 2. Hiragana character, force Tahoma font does not support Japanese */
g_source = str2W;
mappedlength = 0;
@@ -4373,24 +4371,21 @@ if (font) {
font = NULL;
hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 1, &fallbackcollection, g_blahfontW, 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);
ok(font != NULL, "got %p\n", font);
-}
-if (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, sizeof(buffW)/sizeof(WCHAR));
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);
-}
+
IDWriteFontFallback_Release(fallback);
IDWriteFactory2_Release(factory2);
}
--
2.7.0
More information about the wine-patches
mailing list