Nikolay Sivov : dwrite: Implement GetSystemFontSet().

Alexandre Julliard julliard at winehq.org
Thu Mar 11 15:59:34 CST 2021


Module: wine
Branch: master
Commit: 318ebc89dcb590c6afa71e5b1504669037979a60
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=318ebc89dcb590c6afa71e5b1504669037979a60

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Thu Mar 11 12:41:23 2021 +0300

dwrite: Implement GetSystemFontSet().

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dwrite/main.c       | 159 +++++++++++++++++++++++++++++++++++++++++++++--
 dlls/dwrite/tests/font.c |  25 ++++++++
 2 files changed, 178 insertions(+), 6 deletions(-)

diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index 51020d6f586..3326b1550ce 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -1509,11 +1509,152 @@ static HRESULT WINAPI dwritefactory3_CreateFontFaceReference(IDWriteFactory7 *if
     return hr;
 }
 
+static HRESULT create_system_path_list(WCHAR ***ret, unsigned int *ret_count)
+{
+    unsigned int index = 0, value_size, name_count, max_name_count, type, data_size;
+    WCHAR **paths = NULL, *name, *value = NULL;
+    size_t capacity = 0, count = 0;
+    HKEY hkey;
+    LONG r;
+
+    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
+            0, GENERIC_READ, &hkey))
+    {
+        return E_UNEXPECTED;
+    }
+
+    value_size = MAX_PATH * sizeof(*value);
+    value = heap_alloc(value_size);
+
+    max_name_count = MAX_PATH;
+    name = heap_alloc(max_name_count * sizeof(*name));
+
+    for (;;)
+    {
+        if (!value)
+        {
+            value_size = MAX_PATH * sizeof(*value);
+            value = heap_alloc(value_size);
+        }
+
+        do
+        {
+            name_count = max_name_count;
+            data_size = value_size - sizeof(*value);
+
+            r = RegEnumValueW(hkey, index, name, &name_count, NULL, &type, (BYTE *)value, &data_size);
+            if (r == ERROR_MORE_DATA)
+            {
+                if (name_count >= max_name_count)
+                {
+                    max_name_count *= 2;
+                    heap_free(name);
+                    name = heap_alloc(max_name_count * sizeof(*name));
+                }
+
+                if (data_size > value_size - sizeof(*value))
+                {
+                    heap_free(value);
+                    value_size = max(data_size + sizeof(*value), value_size * 2);
+                    value = heap_alloc(value_size);
+                }
+            }
+        } while (r == ERROR_MORE_DATA);
+
+        if (r != ERROR_SUCCESS)
+            break;
+
+        value[data_size / sizeof(*value)] = 0;
+        if (type == REG_SZ && *name != '@')
+        {
+            if (dwrite_array_reserve((void **)&paths, &capacity, count + 1, sizeof(*paths)))
+            {
+                if (!strchrW(value, '\\'))
+                {
+                    static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
+                    WCHAR *ptrW;
+
+                    ptrW = heap_alloc((MAX_PATH + lstrlenW(value)) * sizeof(WCHAR));
+                    GetWindowsDirectoryW(ptrW, MAX_PATH);
+                    lstrcatW(ptrW, fontsW);
+                    lstrcatW(ptrW, value);
+
+                    heap_free(value);
+                    value = ptrW;
+                }
+
+                paths[count++] = value;
+                value = NULL;
+            }
+        }
+        index++;
+    }
+
+    heap_free(name);
+
+    *ret = paths;
+    *ret_count = count;
+
+    RegCloseKey(hkey);
+
+    return S_OK;
+}
+
+static int create_system_fontset_compare(const void *left, const void *right)
+{
+    const WCHAR *_l = *(WCHAR **)left, *_r = *(WCHAR **)right;
+    return lstrcmpiW(_l, _r);
+};
+
+static HRESULT create_system_fontset(IDWriteFactory7 *factory, REFIID riid, void **obj)
+{
+    IDWriteFontSetBuilder2 *builder;
+    IDWriteFontSet *fontset;
+    unsigned int i, j, count;
+    WCHAR **paths;
+    HRESULT hr;
+
+    *obj = NULL;
+
+    if (FAILED(hr = create_fontset_builder(factory, &builder))) return hr;
+
+    if (SUCCEEDED(hr = create_system_path_list(&paths, &count)))
+    {
+        /* Sort, skip duplicates. */
+
+        qsort(paths, count, sizeof(*paths), create_system_fontset_compare);
+
+        for (i = 0, j = 0; i < count; ++i)
+        {
+            if (i != j && !lstrcmpiW(paths[i], paths[j])) continue;
+
+            if (FAILED(hr = IDWriteFontSetBuilder2_AddFontFile(builder, paths[i])) && hr != DWRITE_E_FILEFORMAT)
+                WARN("Failed to add font file, hr %#x, path %s.\n", hr, debugstr_w(paths[i]));
+
+            j = i;
+        }
+
+        for (i = 0; i < count; ++i)
+            heap_free(paths[i]);
+        heap_free(paths);
+    }
+
+    if (SUCCEEDED(hr = IDWriteFontSetBuilder2_CreateFontSet(builder, &fontset)))
+    {
+        hr = IDWriteFontSet_QueryInterface(fontset, riid, obj);
+        IDWriteFontSet_Release(fontset);
+    }
+
+    IDWriteFontSetBuilder2_Release(builder);
+
+    return hr;
+}
+
 static HRESULT WINAPI dwritefactory3_GetSystemFontSet(IDWriteFactory7 *iface, IDWriteFontSet **fontset)
 {
-    FIXME("%p, %p: stub\n", iface, fontset);
+    TRACE("%p, %p.\n", iface, fontset);
 
-    return E_NOTIMPL;
+    return create_system_fontset(iface, &IID_IDWriteFontSet, (void **)fontset);
 }
 
 static HRESULT WINAPI dwritefactory3_CreateFontSetBuilder(IDWriteFactory7 *iface, IDWriteFontSetBuilder **builder)
@@ -1691,9 +1832,12 @@ static HRESULT WINAPI dwritefactory6_CreateFontResource(IDWriteFactory7 *iface,
 static HRESULT WINAPI dwritefactory6_GetSystemFontSet(IDWriteFactory7 *iface, BOOL include_downloadable,
         IDWriteFontSet1 **fontset)
 {
-    FIXME("%p, %d, %p.\n", iface, include_downloadable, fontset);
+    TRACE("%p, %d, %p.\n", iface, include_downloadable, fontset);
 
-    return E_NOTIMPL;
+    if (include_downloadable)
+        FIXME("Downloadable fonts are not supported.\n");
+
+    return create_system_fontset(iface, &IID_IDWriteFontSet1, (void **)fontset);
 }
 
 static HRESULT WINAPI dwritefactory6_GetSystemFontCollection(IDWriteFactory7 *iface, BOOL include_downloadable,
@@ -1732,9 +1876,12 @@ static HRESULT WINAPI dwritefactory6_CreateTextFormat(IDWriteFactory7 *iface, co
 static HRESULT WINAPI dwritefactory7_GetSystemFontSet(IDWriteFactory7 *iface, BOOL include_downloadable,
         IDWriteFontSet2 **fontset)
 {
-    FIXME("%p, %d, %p.\n", iface, include_downloadable, fontset);
+    TRACE("%p, %d, %p.\n", iface, include_downloadable, fontset);
 
-    return E_NOTIMPL;
+    if (include_downloadable)
+        FIXME("Downloadable fonts are not supported.\n");
+
+    return create_system_fontset(iface, &IID_IDWriteFontSet2, (void **)fontset);
 }
 
 static HRESULT WINAPI dwritefactory7_GetSystemFontCollection(IDWriteFactory7 *iface, BOOL include_downloadable,
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 4367f1d95c8..bded40a53c7 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -10009,6 +10009,30 @@ static void test_family_font_set(void)
     ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
 }
 
+static void test_system_font_set(void)
+{
+    IDWriteFactory3 *factory;
+    IDWriteFontSet *fontset;
+    unsigned int count;
+    HRESULT hr;
+
+    if (!(factory = create_factory_iid(&IID_IDWriteFactory3)))
+    {
+        win_skip("System font set is not supported.\n");
+        return;
+    }
+
+    hr = IDWriteFactory3_GetSystemFontSet(factory, &fontset);
+    ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+    count = IDWriteFontSet_GetFontCount(fontset);
+    ok(!!count, "Unexpected font count %u.\n", count);
+
+    IDWriteFontSet_Release(fontset);
+
+    IDWriteFactory3_Release(factory);
+}
+
 START_TEST(font)
 {
     IDWriteFactory *factory;
@@ -10081,6 +10105,7 @@ START_TEST(font)
     test_GetVerticalGlyphVariants();
     test_expiration_event();
     test_family_font_set();
+    test_system_font_set();
 
     IDWriteFactory_Release(factory);
 }




More information about the wine-cvs mailing list