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