Nikolay Sivov : dwrite: Reuse local file stream instances.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Nov 17 07:43:45 CST 2014
Module: wine
Branch: master
Commit: 8b769332e25face5d80d7568c838269c795440f9
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8b769332e25face5d80d7568c838269c795440f9
Author: Nikolay Sivov <nsivov at 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);
}
More information about the wine-cvs
mailing list