Module: wine Branch: master Commit: 8b769332e25face5d80d7568c838269c795440f9 URL: http://source.winehq.org/git/wine.git/?a=commit;h=8b769332e25face5d80d7568c8...
Author: Nikolay Sivov nsivov@codeweavers.com Date: Mon Nov 17 12:30:25 2014 +0300
dwrite: Reuse local file stream instances.
---
dlls/dwrite/font.c | 84 +++++++++++++++++++++++++++++++++++++++++++----- dlls/dwrite/tests/font.c | 51 +++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 8 deletions(-)
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index a83baa7..a8d1efe 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -21,6 +21,7 @@
#define COBJMACROS
+#include "wine/list.h" #include "dwrite_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dwrite); @@ -1975,12 +1976,20 @@ HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDW }
/* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */ +struct local_cached_stream +{ + struct list entry; + IDWriteFontFileStream *stream; + void *key; + UINT32 key_size; +};
struct dwrite_localfontfilestream { IDWriteFontFileStream IDWriteFontFileStream_iface; LONG ref;
+ struct local_cached_stream *entry; HANDLE handle; };
@@ -1993,6 +2002,8 @@ struct local_refkey struct dwrite_localfontfileloader { IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface; LONG ref; + + struct list streams; };
static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface) @@ -2028,6 +2039,13 @@ static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface) return ref; }
+static inline void release_cached_stream(struct local_cached_stream *stream) +{ + list_remove(&stream->entry); + heap_free(stream->key); + heap_free(stream); +} + static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface) { struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface); @@ -2035,10 +2053,10 @@ static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
TRACE("(%p)->(%d)\n", This, ref);
- if (!ref) - { + if (!ref) { if (This->handle != INVALID_HANDLE_VALUE) CloseHandle(This->handle); + release_cached_stream(This->entry); heap_free(This); }
@@ -2107,7 +2125,7 @@ static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl = localfontfilestream_GetLastWriteTime };
-static HRESULT create_localfontfilestream(HANDLE handle, IDWriteFontFileStream** iface) +static HRESULT create_localfontfilestream(HANDLE handle, struct local_cached_stream *entry, IDWriteFontFileStream** iface) { struct dwrite_localfontfilestream *This = heap_alloc(sizeof(struct dwrite_localfontfilestream)); if (!This) @@ -2116,6 +2134,7 @@ static HRESULT create_localfontfilestream(HANDLE handle, IDWriteFontFileStream** This->ref = 1; This->handle = handle; This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl; + This->entry = entry;
*iface = &This->IDWriteFontFileStream_iface; return S_OK; @@ -2153,28 +2172,76 @@ static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *ifac
TRACE("(%p)->(%d)\n", This, ref);
- if (!ref) + if (!ref) { + struct local_cached_stream *stream, *stream2; + + /* This will detach all entries from cache. Entries are released together with streams, + so stream controls its lifetime. */ + LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry) + list_init(&stream->entry); + heap_free(This); + }
return ref; }
-static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **fontFileStream) +static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret) { struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface); const struct local_refkey *refkey = key; + struct local_cached_stream *stream; + IDWriteFontFileStream *filestream; HANDLE handle; + HRESULT hr;
- TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, fontFileStream); + TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
TRACE("name: %s\n", debugstr_w(refkey->name)); + + /* search cache first */ + LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) { + if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) { + *ret = stream->stream; + IDWriteFontFileStream_AddRef(*ret); + return S_OK; + } + } + + *ret = NULL; + handle = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) return E_FAIL;
- return create_localfontfilestream(handle, fontFileStream); + stream = heap_alloc(sizeof(*stream)); + if (!stream) + return E_OUTOFMEMORY; + + stream->key = heap_alloc(key_size); + if (!stream->key) { + heap_free(stream); + return E_OUTOFMEMORY; + } + + stream->key_size = key_size; + memcpy(stream->key, key, key_size); + + hr = create_localfontfilestream(handle, stream, &filestream); + if (FAILED(hr)) { + heap_free(stream->key); + heap_free(stream); + return hr; + } + + stream->stream = filestream; + list_add_head(&This->streams, &stream->entry); + + *ret = stream->stream; + + return S_OK; }
static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length) @@ -2229,8 +2296,9 @@ HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) if (!This) return E_OUTOFMEMORY;
- This->ref = 1; This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl; + This->ref = 1; + list_init(&This->streams);
*iface = &This->IDWriteLocalFontFileLoader_iface; return S_OK; diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 1fdb8d0..b8ff22d 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -2355,6 +2355,56 @@ if (0) { /* crashes on native */ IDWriteFactory_Release(factory); }
+static void test_CreateStreamFromKey(void) +{ + IDWriteLocalFontFileLoader *localloader; + IDWriteFontFileStream *stream, *stream2; + IDWriteFontFileLoader *loader; + IDWriteFactory *factory; + IDWriteFontFile *file; + void *key; + UINT32 size; + HRESULT hr; + + factory = create_factory(); + + create_testfontfile(test_fontfile); + + hr = IDWriteFactory_CreateFontFileReference(factory, test_fontfile, NULL, &file); + ok(hr == S_OK, "got 0x%08x\n",hr); + + key = NULL; + size = 0; + hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(size != 0, "got %u\n", size); + + hr = IDWriteFontFile_GetLoader(file, &loader); + ok(hr == S_OK, "got 0x%08x\n", hr); + IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader); + IDWriteFontFileLoader_Release(loader); + + hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + EXPECT_REF(stream, 1); + + hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(stream == stream2, "got %p, %p\n", stream, stream2); + EXPECT_REF(stream, 2); + IDWriteFontFileStream_Release(stream); + IDWriteFontFileStream_Release(stream2); + + hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + EXPECT_REF(stream, 1); + IDWriteFontFileStream_Release(stream); + + IDWriteLocalFontFileLoader_Release(localloader); + IDWriteFactory_Release(factory); + DeleteFileW(test_fontfile); +} + START_TEST(font) { IDWriteFactory *factory; @@ -2386,6 +2436,7 @@ START_TEST(font) test_GetFaceNames(); test_TryGetFontTable(); test_ConvertFontToLOGFONT(); + test_CreateStreamFromKey();
IDWriteFactory_Release(factory); }