[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