dwrite: Implement IDWriteInMemoryFontFileLoader.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-10-06 12:45:20 +03:00 committed by Alexandre Julliard
parent b4c0b77b03
commit fb8226f639
4 changed files with 421 additions and 17 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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,

View File

@ -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);
}