[PATCH] dwrite: Implement IDWriteInMemoryFontFileLoader

Nikolay Sivov nsivov at codeweavers.com
Fri Oct 6 04:45:20 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |   1 +
 dlls/dwrite/font.c           | 317 +++++++++++++++++++++++++++++++++++++++++++
 dlls/dwrite/main.c           |   4 +-
 dlls/dwrite/tests/font.c     | 116 ++++++++++++++--
 4 files changed, 421 insertions(+), 17 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 9001420290..38cf11a1e0 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -210,6 +210,7 @@ extern HRESULT create_gdiinterop(IDWriteFactory5*,IDWriteGdiInterop1**) DECLSPEC
 extern void fontface_detach_from_cache(IDWriteFontFace4*) DECLSPEC_HIDDEN;
 extern void factory_lock(IDWriteFactory5*) DECLSPEC_HIDDEN;
 extern void factory_unlock(IDWriteFactory5*) DECLSPEC_HIDDEN;
+extern HRESULT create_inmemory_fileloader(IDWriteFontFileLoader**) DECLSPEC_HIDDEN;
 
 /* Opentype font table functions */
 struct dwrite_font_props {
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 81d1624509..1916bf22fc 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -4480,6 +4480,32 @@ struct dwrite_localfontfileloader {
 
 static struct dwrite_localfontfileloader local_fontfile_loader;
 
+struct dwrite_inmemory_stream_data
+{
+    LONG ref;
+    IUnknown *owner;
+    void *data;
+    UINT32 size;
+};
+
+struct dwrite_inmemory_filestream
+{
+    IDWriteFontFileStream IDWriteFontFileStream_iface;
+    LONG ref;
+
+    struct dwrite_inmemory_stream_data *data;
+};
+
+struct dwrite_inmemory_fileloader
+{
+    IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
+    LONG ref;
+
+    struct dwrite_inmemory_stream_data **streams;
+    UINT32 filecount;
+    UINT32 capacity;
+};
+
 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
 {
     return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
@@ -4490,6 +4516,27 @@ static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream
     return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
 }
 
+static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
+{
+    return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
+}
+
+static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
+{
+    return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
+}
+
+static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
+{
+    if (InterlockedDecrement(&stream->ref) == 0) {
+        if (stream->owner)
+            IUnknown_Release(stream->owner);
+        else
+            heap_free(stream->data);
+        heap_free(stream);
+    }
+}
+
 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
 {
     struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
@@ -5967,3 +6014,273 @@ HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file
 
     return S_OK;
 }
+
+static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+
+    TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
+        *obj = iface;
+        IDWriteFontFileStream_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+
+    WARN("%s not implemented.\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+    ULONG ref = InterlockedIncrement(&stream->ref);
+    TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
+    return ref;
+}
+
+static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+    ULONG ref = InterlockedDecrement(&stream->ref);
+
+    TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
+
+    if (!ref) {
+        release_inmemory_stream(stream->data);
+        heap_free(stream);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
+        UINT64 offset, UINT64 fragment_size, void **fragment_context)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+
+    TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
+          wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
+
+    *fragment_context = NULL;
+
+    if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
+        *fragment_start = NULL;
+        return E_FAIL;
+    }
+
+    *fragment_start = (char *)stream->data->data + offset;
+    return S_OK;
+}
+
+static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+
+    TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
+}
+
+static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+
+    TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
+
+    *size = stream->data->size;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
+{
+    struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
+
+    TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
+
+    *last_writetime = 0;
+
+    return E_NOTIMPL;
+}
+
+static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
+    inmemoryfilestream_QueryInterface,
+    inmemoryfilestream_AddRef,
+    inmemoryfilestream_Release,
+    inmemoryfilestream_ReadFileFragment,
+    inmemoryfilestream_ReleaseFileFragment,
+    inmemoryfilestream_GetFileSize,
+    inmemoryfilestream_GetLastWriteTime,
+};
+
+static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
+        REFIID riid, void **obj)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+
+    TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
+        IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
+        IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        IDWriteInMemoryFontFileLoader_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("%s not implemented.\n", debugstr_guid(riid));
+
+    *obj = NULL;
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+    ULONG ref = InterlockedIncrement(&loader->ref);
+    TRACE("(%p)->(%u)\n", loader, ref);
+    return ref;
+}
+
+static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+    ULONG ref = InterlockedDecrement(&loader->ref);
+
+    TRACE("(%p)->(%u)\n", loader, ref);
+
+    if (!ref) {
+        UINT32 i;
+
+        for (i = 0; i < loader->filecount; i++)
+            release_inmemory_stream(loader->streams[i]);
+        heap_free(loader->streams);
+        heap_free(loader);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
+        void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+    struct dwrite_inmemory_filestream *stream;
+    DWORD index;
+
+    TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
+
+    *ret = NULL;
+
+    if (key_size != sizeof(DWORD))
+        return E_INVALIDARG;
+
+    index = *(DWORD *)key;
+
+    if (index >= loader->filecount)
+        return E_INVALIDARG;
+
+    if (!(stream = heap_alloc(sizeof(*stream))))
+        return E_OUTOFMEMORY;
+
+    stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
+    stream->ref = 1;
+    stream->data = loader->streams[index];
+    InterlockedIncrement(&stream->data->ref);
+
+    *ret = &stream->IDWriteFontFileStream_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
+        IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+    struct dwrite_inmemory_stream_data *stream;
+    DWORD key;
+
+    TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
+
+    *fontfile = NULL;
+
+    if (loader->filecount == loader->capacity) {
+        if (loader->streams) {
+            struct dwrite_inmemory_stream_data **ptr;
+
+            if (!(ptr = heap_realloc(loader->streams, 2 * loader->capacity * sizeof(*loader->streams))))
+                return E_OUTOFMEMORY;
+
+            loader->streams = ptr;
+            loader->capacity *= 2;
+        }
+        else {
+            loader->capacity = 16;
+            loader->streams = heap_alloc(loader->capacity * sizeof(*loader->streams));
+        }
+    }
+
+    if (!(stream = heap_alloc(sizeof(*stream))))
+        return E_OUTOFMEMORY;
+
+    stream->ref = 1;
+    stream->size = data_size;
+    stream->owner = owner;
+    if (stream->owner) {
+        IUnknown_AddRef(stream->owner);
+        stream->data = (void *)data;
+    }
+    else {
+        if (!(stream->data = heap_alloc(data_size))) {
+            heap_free(stream);
+            return E_OUTOFMEMORY;
+        }
+        memcpy(stream->data, data, data_size);
+    }
+
+    key = loader->filecount;
+    loader->streams[loader->filecount++] = stream;
+
+    return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
+            (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
+}
+
+static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
+{
+    struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
+
+    TRACE("(%p)\n", loader);
+
+    return loader->filecount;
+}
+
+static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
+{
+    inmemoryfontfileloader_QueryInterface,
+    inmemoryfontfileloader_AddRef,
+    inmemoryfontfileloader_Release,
+    inmemoryfontfileloader_CreateStreamFromKey,
+    inmemoryfontfileloader_CreateInMemoryFontFileReference,
+    inmemoryfontfileloader_GetFileCount,
+};
+
+HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
+{
+    struct dwrite_inmemory_fileloader *loader;
+
+    *ret = NULL;
+
+    loader = heap_alloc_zero(sizeof(*loader));
+    if (!loader)
+        return E_OUTOFMEMORY;
+
+    loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
+    loader->ref = 1;
+
+    *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
+
+    return S_OK;
+}
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index 6bf5b7310c..1cdcc7edb5 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -1617,9 +1617,9 @@ static HRESULT WINAPI dwritefactory5_CreateInMemoryFontFileLoader(IDWriteFactory
 {
     struct dwritefactory *This = impl_from_IDWriteFactory5(iface);
 
-    FIXME("(%p)->(%p): stub\n", This, loader);
+    TRACE("(%p)->(%p)\n", This, loader);
 
-    return E_NOTIMPL;
+    return create_inmemory_fileloader(loader);
 }
 
 static HRESULT WINAPI dwritefactory5_CreateHttpFontFileLoader(IDWriteFactory5 *iface, WCHAR const *referrer_url, WCHAR const *extra_headers,
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index a57806aeed..e97c4d133b 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -7644,14 +7644,15 @@ static void test_inmemory_file_loader(void)
     IDWriteFontFileLoader *loader, *loader2;
     IDWriteInMemoryFontFileLoader *inmemory;
     struct testowner_object ownerobject;
+    const void *key, *data, *frag_start;
+    UINT64 file_size, size, writetime;
     IDWriteFontFile *file, *file2;
     IDWriteFontFace *fontface;
     IDWriteFactory5 *factory5;
+    void *context, *context2;
     IDWriteFactory *factory;
-    const void *key, *data;
     UINT32 count, key_size;
-    UINT64 file_size;
-    void *context;
+    DWORD ref_key;
     HRESULT hr;
     ULONG ref;
 
@@ -7666,15 +7667,9 @@ static void test_inmemory_file_loader(void)
 
     EXPECT_REF(factory5, 1);
     hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory5, &loader);
-todo_wine
     ok(hr == S_OK, "got %#x\n", hr);
     EXPECT_REF(factory5, 1);
 
-    if (FAILED(hr)) {
-        IDWriteFactory5_Release(factory5);
-        return;
-    }
-
     testowner_init(&ownerobject);
     fontface = create_fontface((IDWriteFactory *)factory5);
 
@@ -7688,6 +7683,9 @@ todo_wine
     IDWriteFontFileLoader_Release(loader);
     EXPECT_REF(inmemory, 1);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(!count, "Unexpected file count %u.\n", count);
+
     /* Use whole font blob to construct in-memory file. */
     count = 1;
     hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
@@ -7715,6 +7713,9 @@ todo_wine
         file_size, NULL, &file);
     ok(hr == E_INVALIDARG, "got %#x\n", hr);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 1, "Unexpected file count %u.\n", count);
+
     hr = IDWriteFactory5_RegisterFontFileLoader(factory5, (IDWriteFontFileLoader *)inmemory);
     ok(hr == S_OK, "got %#x\n", hr);
     EXPECT_REF(inmemory, 2);
@@ -7726,6 +7727,9 @@ todo_wine
     EXPECT_REF(&ownerobject.IUnknown_iface, 2);
     EXPECT_REF(inmemory, 3);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 2, "Unexpected file count %u.\n", count);
+
     hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory5, data,
         file_size, &ownerobject.IUnknown_iface, &file2);
     ok(hr == S_OK, "got %#x\n", hr);
@@ -7733,6 +7737,9 @@ todo_wine
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
     EXPECT_REF(inmemory, 4);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 3, "Unexpected file count %u.\n", count);
+
     /* Check in-memory reference key format. */
     hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
     ok(hr == S_OK, "got %#x\n", hr);
@@ -7762,26 +7769,105 @@ todo_wine
 
     /* Release file at index 1, create new one to see if index is reused. */
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
-    IDWriteFontFile_Release(file);
+    ref = IDWriteFontFile_Release(file);
+    ok(ref == 0, "File object not released, %u.\n", ref);
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 3, "Unexpected file count %u.\n", count);
+
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
-    IDWriteFontFile_Release(file2);
+    ref = IDWriteFontFile_Release(file2);
+    ok(ref == 0, "File object not released, %u.\n", ref);
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
 
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 3, "Unexpected file count %u.\n", count);
+
     hr = IDWriteFactory5_UnregisterFontFileLoader(factory5, (IDWriteFontFileLoader *)inmemory);
     ok(hr == S_OK, "got %#x\n", hr);
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
 
-    IDWriteFontFileStream_ReleaseFileFragment(stream, context);
-    IDWriteFontFileStream_Release(stream);
-    IDWriteFontFace_Release(fontface);
-
     EXPECT_REF(&ownerobject.IUnknown_iface, 3);
     ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
     ok(ref == 0, "loader not released, %u.\n", ref);
     EXPECT_REF(&ownerobject.IUnknown_iface, 1);
 
+    /* Test reference key for first added file. */
+    hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory5, &loader);
+    ok(hr == S_OK, "Failed to create loader, hr %#x.\n", hr);
+
+    hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&inmemory);
+    ok(hr == S_OK, "Failed to get in-memory interface, hr %#x.\n", hr);
+    IDWriteFontFileLoader_Release(loader);
+
+    hr = IDWriteFactory5_RegisterFontFileLoader(factory5, (IDWriteFontFileLoader *)inmemory);
+    ok(hr == S_OK, "Failed to register loader, hr %#x.\n", hr);
+
+    ref_key = 0;
+    hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory5, data,
+        file_size, &ownerobject.IUnknown_iface, &file);
+    ok(hr == S_OK, "Failed to create in-memory file reference, hr %#x.\n", hr);
+
+    ref_key = 0;
+    hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
+    ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
+
+    context2 = (void *)0xdeadbeef;
+    hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
+    ok(hr == S_OK, "Failed to read a fragment, hr %#x.\n", hr);
+    ok(context == NULL, "Unexpected context %p.\n", context2);
+    ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
+
+    hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
+    ok(hr == S_OK, "Failed to get file size, hr %#x.\n", hr);
+    ok(size == file_size, "Unexpected file size.\n");
+
+    IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
+
+    writetime = 1;
+    hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
+    ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
+    ok(writetime == 0, "Unexpected writetime.\n");
+
+    IDWriteFontFileStream_Release(stream2);
+
+    ref_key = 0;
+    hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    ref_key = 0;
+    hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    ref_key = 0;
+    hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 1, "Unexpected file count %u.\n", count);
+
+    hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
+    ok(hr == S_OK, "Failed to get reference key, hr %#x.\n", hr);
+
+    ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
+    ok(key_size == 4, "Unexpected key size %u.\n", key_size);
+
+    IDWriteFontFile_Release(file);
+
+    count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
+    ok(count == 1, "Unexpected file count %u.\n", count);
+
+    hr = IDWriteFactory5_UnregisterFontFileLoader(factory5, (IDWriteFontFileLoader *)inmemory);
+    ok(hr == S_OK, "Failed to unregister loader, hr %#x.\n", hr);
+
+    IDWriteFontFileStream_ReleaseFileFragment(stream, context);
+    IDWriteFontFileStream_Release(stream);
+    IDWriteFontFace_Release(fontface);
+
     ref = IDWriteFactory5_Release(factory5);
     ok(ref == 0, "factory not released, %u\n", ref);
 }
-- 
2.14.2




More information about the wine-patches mailing list