[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