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:
parent
3b18054f25
commit
43c16a25eb
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue