[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