[PATCH] dwrite: Use single per-process local file loader

Nikolay Sivov nsivov at codeweavers.com
Sun Sep 24 16:08:40 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/dwrite_private.h |   3 +-
 dlls/dwrite/font.c           | 126 +++++++++++++++++++++++++------------------
 dlls/dwrite/main.c           |  31 +++--------
 dlls/dwrite/tests/font.c     |  40 +++++++++++++-
 4 files changed, 122 insertions(+), 78 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 676d85974a..9001420290 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -177,7 +177,8 @@ extern HRESULT get_system_fontcollection(IDWriteFactory5*,IDWriteFontCollection1
 extern HRESULT get_eudc_fontcollection(IDWriteFactory5*,IDWriteFontCollection1**) DECLSPEC_HIDDEN;
 extern IDWriteTextAnalyzer *get_text_analyzer(void) DECLSPEC_HIDDEN;
 extern HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file) DECLSPEC_HIDDEN;
-extern HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) DECLSPEC_HIDDEN;
+extern void    init_local_fontfile_loader(void) DECLSPEC_HIDDEN;
+extern IDWriteFontFileLoader *get_local_fontfile_loader(void) DECLSPEC_HIDDEN;
 extern HRESULT create_fontface(const struct fontface_desc*,struct list*,IDWriteFontFace4**) DECLSPEC_HIDDEN;
 extern HRESULT create_font_collection(IDWriteFactory5*,IDWriteFontFileEnumerator*,BOOL,IDWriteFontCollection1**) DECLSPEC_HIDDEN;
 extern HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc*,IDWriteGlyphRunAnalysis**) DECLSPEC_HIDDEN;
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 16bff9bbe1..81d1624509 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -497,10 +497,10 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
     if (!ref) {
         UINT32 i;
 
-        factory_lock(This->factory);
-
         if (This->cached) {
+            factory_lock(This->factory);
             list_remove(&This->cached->entry);
+            factory_unlock(This->factory);
             heap_free(This->cached);
         }
 
@@ -528,7 +528,6 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
 
         freetype_notify_cacheremove(iface);
 
-        factory_unlock(This->factory);
         IDWriteFactory5_Release(This->factory);
         heap_free(This);
     }
@@ -4476,8 +4475,11 @@ struct dwrite_localfontfileloader {
     LONG ref;
 
     struct list streams;
+    CRITICAL_SECTION cs;
 };
 
+static struct dwrite_localfontfileloader local_fontfile_loader;
+
 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
 {
     return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
@@ -4491,11 +4493,18 @@ static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream
 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
 {
     struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
+
     TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
-    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
+
+    if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
+        IsEqualIID(riid, &IID_IUnknown))
     {
         *obj = iface;
-        IDWriteFontFileStream_AddRef(iface);
+        if (InterlockedIncrement(&This->ref) == 1) {
+            InterlockedDecrement(&This->ref);
+            *obj = NULL;
+            return E_FAIL;
+        }
         return S_OK;
     }
 
@@ -4529,7 +4538,11 @@ static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
 
     if (!ref) {
         UnmapViewOfFile(This->file_ptr);
+
+        EnterCriticalSection(&local_fontfile_loader.cs);
         release_cached_stream(This->entry);
+        LeaveCriticalSection(&local_fontfile_loader.cs);
+
         heap_free(This);
     }
 
@@ -4621,7 +4634,9 @@ static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoa
 
     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
 
-    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
+    if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
+        IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
+        IsEqualIID(riid, &IID_IUnknown))
     {
         *obj = iface;
         IDWriteLocalFontFileLoader_AddRef(iface);
@@ -4649,49 +4664,27 @@ static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *ifac
 
     TRACE("(%p)->(%d)\n", This, 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 cache entry 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 **ret)
+static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
 {
-    struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
     const struct local_refkey *refkey = key;
     struct local_cached_stream *stream;
     IDWriteFontFileStream *filestream;
     HANDLE file, mapping;
     LARGE_INTEGER size;
     void *file_ptr;
-    HRESULT hr;
-
-    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;
-        }
-    }
+    HRESULT hr = S_OK;
 
     *ret = NULL;
 
     file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
-                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-    if (file == INVALID_HANDLE_VALUE)
+            NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (file == INVALID_HANDLE_VALUE) {
+        WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
         return E_FAIL;
+    }
 
     GetFileSizeEx(file, &size);
     mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
@@ -4731,13 +4724,45 @@ static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFi
     }
 
     stream->stream = filestream;
-    list_add_head(&This->streams, &stream->entry);
 
-    *ret = stream->stream;
+    *ret = stream;
 
     return S_OK;
 }
 
+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;
+    HRESULT hr = S_OK;
+
+    TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
+    TRACE("name: %s\n", debugstr_w(refkey->name));
+
+    EnterCriticalSection(&This->cs);
+
+    *ret = NULL;
+
+    /* 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)) {
+            IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
+            break;
+        }
+    }
+
+    if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
+        list_add_head(&This->streams, &stream->entry);
+        *ret = stream->stream;
+    }
+
+    LeaveCriticalSection(&This->cs);
+
+    return hr;
+}
+
 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
 {
     struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
@@ -4763,12 +4788,13 @@ static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFil
     return S_OK;
 }
 
-static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
+static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
+        UINT32 key_size, FILETIME *writetime)
 {
     struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
     const struct local_refkey *refkey = key;
 
-    TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
+    TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
 
     *writetime = refkey->writetime;
     return S_OK;
@@ -4784,22 +4810,18 @@ static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
     localfontfileloader_GetLastWriteTimeFromKey
 };
 
-HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
+void init_local_fontfile_loader(void)
 {
-    struct dwrite_localfontfileloader *This;
-
-    *ret = NULL;
-
-    This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
-    if (!This)
-        return E_OUTOFMEMORY;
-
-    This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
-    This->ref = 1;
-    list_init(&This->streams);
+    local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
+    local_fontfile_loader.ref = 1;
+    list_init(&local_fontfile_loader.streams);
+    InitializeCriticalSection(&local_fontfile_loader.cs);
+    local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
+}
 
-    *ret = &This->IDWriteLocalFontFileLoader_iface;
-    return S_OK;
+IDWriteFontFileLoader *get_local_fontfile_loader(void)
+{
+    return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
 }
 
 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c
index 059121ce65..6bf5b7310c 100644
--- a/dlls/dwrite/main.c
+++ b/dlls/dwrite/main.c
@@ -44,6 +44,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls( hinstDLL );
         init_freetype();
+        init_local_fontfile_loader();
         break;
     case DLL_PROCESS_DETACH:
         if (reserved) break;
@@ -542,7 +543,7 @@ struct dwritefactory {
     IDWriteGdiInterop1 *gdiinterop;
     IDWriteFontFallback *fallback;
 
-    IDWriteLocalFontFileLoader* localfontfileloader;
+    IDWriteFontFileLoader *localfontfileloader;
     struct list localfontfaces;
 
     struct list collection_loaders;
@@ -580,9 +581,6 @@ static void release_dwritefactory(struct dwritefactory *factory)
     struct fileloader *fileloader, *fileloader2;
     struct collectionloader *loader, *loader2;
 
-    if (factory->localfontfileloader)
-        IDWriteLocalFontFileLoader_Release(factory->localfontfileloader);
-
     EnterCriticalSection(&factory->cs);
     release_fontface_cache(&factory->localfontfaces);
     LeaveCriticalSection(&factory->cs);
@@ -806,19 +804,12 @@ static HRESULT WINAPI dwritefactory_CreateFontFileReference(IDWriteFactory5 *ifa
 
     *font_file = NULL;
 
-    if (!This->localfontfileloader)
-    {
-        hr = create_localfontfileloader(&This->localfontfileloader);
-        if (FAILED(hr))
-            return hr;
-    }
-
-    /* get a reference key used by local loader */
+    /* Get a reference key in local file loader format. */
     hr = get_local_refkey(path, writetime, &key, &key_size);
     if (FAILED(hr))
         return hr;
 
-    hr = create_font_file((IDWriteFontFileLoader*)This->localfontfileloader, key, key_size, font_file);
+    hr = create_font_file(This->localfontfileloader, key, key_size, font_file);
     heap_free(key);
 
     return hr;
@@ -833,9 +824,7 @@ static HRESULT WINAPI dwritefactory_CreateCustomFontFileReference(IDWriteFactory
 
     *font_file = NULL;
 
-    /* local loader is accepted as well */
-    if (!loader || !(factory_get_file_loader(This, loader) ||
-        (IDWriteFontFileLoader*)This->localfontfileloader == loader))
+    if (!loader || !(factory_get_file_loader(This, loader) || This->localfontfileloader == loader))
         return E_INVALIDARG;
 
     return create_font_file(loader, reference_key, key_size, font_file);
@@ -875,7 +864,7 @@ HRESULT factory_get_cached_fontface(IDWriteFactory5 *iface, IDWriteFontFile * co
     if (FAILED(hr))
         return hr;
 
-    if (loader == (IDWriteFontFileLoader*)factory->localfontfileloader) {
+    if (loader == factory->localfontfileloader) {
         fontfaces = &factory->localfontfaces;
         IDWriteFontFileLoader_Release(loader);
     }
@@ -1066,9 +1055,6 @@ static HRESULT WINAPI dwritefactory_RegisterFontFileLoader(IDWriteFactory5 *ifac
     if (!loader)
         return E_INVALIDARG;
 
-    if ((IDWriteFontFileLoader*)This->localfontfileloader == loader)
-        return S_OK;
-
     if (factory_get_file_loader(This, loader))
         return DWRITE_E_ALREADYREGISTERED;
 
@@ -1094,9 +1080,6 @@ static HRESULT WINAPI dwritefactory_UnregisterFontFileLoader(IDWriteFactory5 *if
     if (!loader)
         return E_INVALIDARG;
 
-    if ((IDWriteFontFileLoader*)This->localfontfileloader == loader)
-        return S_OK;
-
     found = factory_get_file_loader(This, loader);
     if (!found)
         return E_INVALIDARG;
@@ -1789,7 +1772,7 @@ static void init_dwritefactory(struct dwritefactory *factory, DWRITE_FACTORY_TYP
     factory->IDWriteFactory5_iface.lpVtbl = type == DWRITE_FACTORY_TYPE_SHARED ?
             &shareddwritefactoryvtbl : &dwritefactoryvtbl;
     factory->ref = 1;
-    factory->localfontfileloader = NULL;
+    factory->localfontfileloader = get_local_fontfile_loader();
     factory->system_collection = NULL;
     factory->eudc_collection = NULL;
     factory->gdiinterop = NULL;
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 813ce22abf..62d5884ce8 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -340,7 +340,7 @@ static IDWriteFactory *create_factory(void)
 {
     IDWriteFactory *factory;
     HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
-    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(hr == S_OK, "Failed to create factory, hr %#x.\n", hr);
     return factory;
 }
 
@@ -7964,6 +7964,43 @@ static void test_CreateCustomRenderingParams(void)
     ok(ref == 0, "factory not released, %u\n", ref);
 }
 
+static void test_localfontfileloader(void)
+{
+    IDWriteFontFileLoader *loader, *loader2;
+    IDWriteFactory *factory, *factory2;
+    IDWriteFontFile *file, *file2;
+    WCHAR *path;
+    HRESULT hr;
+    ULONG ref;
+
+    factory = create_factory();
+    factory2 = create_factory();
+
+    path = create_testfontfile(test_fontfile);
+
+    hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
+    ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
+
+    hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
+    ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
+    ok(file != file2, "Unexpected file instance.\n");
+
+    hr = IDWriteFontFile_GetLoader(file, &loader);
+    ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
+
+    hr = IDWriteFontFile_GetLoader(file2, &loader2);
+    ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
+    ok(loader == loader2, "Unexpected loader instance\n");
+
+    IDWriteFontFile_Release(file);
+    IDWriteFontFile_Release(file2);
+    IDWriteFontFileLoader_Release(loader);
+    IDWriteFontFileLoader_Release(loader2);
+    ref = IDWriteFactory_Release(factory);
+    ok(ref == 0, "factory not released, %u\n", ref);
+    DELETE_FONTFILE(path);
+}
+
 START_TEST(font)
 {
     IDWriteFactory *factory;
@@ -8028,6 +8065,7 @@ START_TEST(font)
     test_inmemory_file_loader();
     test_GetGlyphImageFormats();
     test_CreateCustomRenderingParams();
+    test_localfontfileloader();
 
     IDWriteFactory_Release(factory);
 }
-- 
2.14.1




More information about the wine-patches mailing list