dwrite: Use single per-process local file loader.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-09-25 00:08:40 +03:00 committed by Alexandre Julliard
parent 3b18054f25
commit 43c16a25eb
4 changed files with 122 additions and 78 deletions

View File

@ -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;

View File

@ -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)
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)

View File

@ -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;

View File

@ -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);
}