From 43c16a25ebfd2917af6fff24a29e91039b46f3c8 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 25 Sep 2017 00:08:40 +0300 Subject: [PATCH] dwrite: Use single per-process local file loader. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- 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 676d85974ae..90014202908 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 16bff9bbe13..81d16245090 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; + 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 = 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); - - *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 059121ce65c..6bf5b7310c2 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 813ce22abf3..62d5884ce82 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); }