From: Nikolay Sivov Subject: [PATCH 2/5] dwrite: Cache fontface instances at factory level Message-Id: <544A08F5.9020901@codeweavers.com> Date: Fri, 24 Oct 2014 12:08:21 +0400 --- From 8d98e4b06430f1f4358b626652105e22a40e76ee Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 24 Oct 2014 11:40:06 +0400 Subject: [PATCH 2/5] dwrite: Cache fontface instances at factory level --- dlls/dwrite/dwrite_private.h | 2 +- dlls/dwrite/font.c | 124 ++++++++++++++++++++-------------------- dlls/dwrite/main.c | 132 ++++++++++++++++++++++++++++++++++++++----- dlls/dwrite/tests/font.c | 14 +++-- 4 files changed, 189 insertions(+), 83 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 5ac0852..02601fb 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -105,7 +105,7 @@ extern HRESULT get_system_fontcollection(IDWriteFontCollection**) DECLSPEC_HIDDE extern HRESULT get_textanalyzer(IDWriteTextAnalyzer**) 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 HRESULT font_create_fontface(DWRITE_FONT_FACE_TYPE,UINT32,IDWriteFontFile* const*,UINT32,DWRITE_FONT_SIMULATIONS,IDWriteFontFace2 **) DECLSPEC_HIDDEN; +extern HRESULT create_fontface(DWRITE_FONT_FACE_TYPE,UINT32,IDWriteFontFile* const*,UINT32,DWRITE_FONT_SIMULATIONS,IDWriteFontFace2**) DECLSPEC_HIDDEN; /* Opentype font table functions */ extern HRESULT opentype_analyze_font(IDWriteFontFileStream*,UINT32*,DWRITE_FONT_FILE_TYPE*,DWRITE_FONT_FACE_TYPE*,BOOL*) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 2b67543..fcdfdb5 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -116,7 +116,13 @@ struct dwrite_fontface { IDWriteFontFace2 IDWriteFontFace2_iface; LONG ref; - struct dwrite_fontface_data *data; + IDWriteFontFile **files; + UINT32 file_count; + UINT32 index; + + DWRITE_FONT_SIMULATIONS simulations; + DWRITE_FONT_FACE_TYPE type; + struct dwrite_fonttable cmap; BOOL is_system; @@ -282,11 +288,13 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace2 *iface) TRACE("(%p)->(%d)\n", This, ref); - if (!ref) - { + if (!ref) { + UINT32 i; + if (This->cmap.context) IDWriteFontFace2_ReleaseFontTable(iface, This->cmap.context); - _free_fontface_data(This->data); + for (i = 0; i < This->file_count; i++) + IDWriteFontFile_Release(This->files[i]); heap_free(This); } @@ -297,7 +305,7 @@ static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace2 *ifa { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); TRACE("(%p)\n", This); - return This->data->type; + return This->type; } static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace2 *iface, UINT32 *number_of_files, @@ -309,16 +317,16 @@ static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace2 *iface, UINT32 *n TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles); if (fontfiles == NULL) { - *number_of_files = This->data->file_count; + *number_of_files = This->file_count; return S_OK; } - if (*number_of_files < This->data->file_count) + if (*number_of_files < This->file_count) return E_INVALIDARG; - for (i = 0; i < This->data->file_count; i++) + for (i = 0; i < This->file_count; i++) { - IDWriteFontFile_AddRef(This->data->files[i]); - fontfiles[i] = This->data->files[i]; + IDWriteFontFile_AddRef(This->files[i]); + fontfiles[i] = This->files[i]; } return S_OK; @@ -328,14 +336,14 @@ static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace2 *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); TRACE("(%p)\n", This); - return This->data->index; + return This->index; } static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace2 *iface) { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); TRACE("(%p)\n", This); - return This->data->simulations; + return This->simulations; } static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace2 *iface) @@ -438,15 +446,15 @@ static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace2 *iface, UI tablecontext->magic = DWRITE_FONTTABLE_MAGIC; *exists = FALSE; - for (i = 0; i < This->data->file_count && !(*exists); i++) + for (i = 0; i < This->file_count && !(*exists); i++) { IDWriteFontFileStream *stream; - hr = _dwritefontfile_GetFontFileStream(This->data->files[i], &stream); + hr = _dwritefontfile_GetFontFileStream(This->files[i], &stream); if (FAILED(hr)) continue; tablecontext->file_index = i; - hr = opentype_get_font_table(stream, This->data->type, This->data->index, table_tag, table_data, &tablecontext->context, table_size, exists); + hr = opentype_get_font_table(stream, This->type, This->index, table_tag, table_data, &tablecontext->context, table_size, exists); IDWriteFontFileStream_Release(stream); } @@ -472,7 +480,7 @@ static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace2 *iface, void return; } - hr = _dwritefontfile_GetFontFileStream(This->data->files[tablecontext->file_index], &stream); + hr = _dwritefontfile_GetFontFileStream(This->files[tablecontext->file_index], &stream); if (FAILED(hr)) return; IDWriteFontFileStream_ReleaseFileFragment(stream, tablecontext->context); @@ -702,20 +710,14 @@ static HRESULT create_system_fontface(struct dwrite_font *font, IDWriteFontFace2 This = heap_alloc(sizeof(struct dwrite_fontface)); if (!This) return E_OUTOFMEMORY; - This->data = heap_alloc(sizeof(struct dwrite_fontface_data)); - if (!This->data) - { - heap_free(This); - return E_OUTOFMEMORY; - } This->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl; This->ref = 1; - This->data->type = DWRITE_FONT_FACE_TYPE_UNKNOWN; - This->data->file_count = 0; - This->data->files = NULL; - This->data->index = 0; - This->data->simulations = DWRITE_FONT_SIMULATIONS_NONE; + This->type = DWRITE_FONT_FACE_TYPE_UNKNOWN; + This->file_count = 0; + This->files = NULL; + This->index = 0; + This->simulations = DWRITE_FONT_SIMULATIONS_NONE; This->cmap.data = NULL; This->cmap.context = NULL; This->cmap.size = 0; @@ -747,7 +749,7 @@ static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace2 if (!font->face) { HRESULT hr = font->is_system ? create_system_fontface(font, &font->face) : - font_create_fontface(font->data->face_data->type, font->data->face_data->file_count, font->data->face_data->files, + create_fontface(font->data->face_data->type, font->data->face_data->file_count, font->data->face_data->files, font->data->face_data->index, font->data->face_data->simulations, &font->face); if (FAILED(hr)) return hr; } @@ -1676,62 +1678,56 @@ HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_ke return S_OK; } -HRESULT font_create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index, DWRITE_FONT_SIMULATIONS sim_flags, IDWriteFontFace2 **font_face) +HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index, + DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace2 **ret) { - int i; - struct dwrite_fontface *This; + struct dwrite_fontface *fontface; HRESULT hr = S_OK; + int i; - *font_face = NULL; - - if (facetype != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION && index) - return E_INVALIDARG; + fontface = heap_alloc(sizeof(struct dwrite_fontface)); + if (!fontface) + return E_OUTOFMEMORY; - This = heap_alloc(sizeof(struct dwrite_fontface)); - if (!This) return E_OUTOFMEMORY; - This->data = heap_alloc(sizeof(struct dwrite_fontface_data)); - if (!This->data) - { - heap_free(This); + fontface->files = heap_alloc(sizeof(*fontface->files) * files_number); + if (!fontface->files) { + heap_free(fontface); return E_OUTOFMEMORY; } - This->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl; - This->ref = 1; - This->data->ref = 1; - This->data->type = facetype; - This->data->file_count = files_number; - This->data->files = heap_alloc(sizeof(*This->data->files) * files_number); - This->cmap.data = NULL; - This->cmap.context = NULL; - This->cmap.size = 0; + fontface->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl; + fontface->ref = 1; + fontface->type = facetype; + fontface->file_count = files_number; + fontface->cmap.data = NULL; + fontface->cmap.context = NULL; + fontface->cmap.size = 0; + /* Verify font file streams */ - for (i = 0; i < This->data->file_count && SUCCEEDED(hr); i++) + for (i = 0; i < fontface->file_count && SUCCEEDED(hr); i++) { IDWriteFontFileStream *stream; hr = _dwritefontfile_GetFontFileStream(font_files[i], &stream); if (SUCCEEDED(hr)) IDWriteFontFileStream_Release(stream); } - if (FAILED(hr)) - { - heap_free(This->data->files); - heap_free(This->data); - heap_free(This); + + if (FAILED(hr)) { + heap_free(fontface->files); + heap_free(fontface); return hr; } - for (i = 0; i < This->data->file_count; i++) - { - This->data->files[i] = font_files[i]; + + for (i = 0; i < fontface->file_count; i++) { + fontface->files[i] = font_files[i]; IDWriteFontFile_AddRef(font_files[i]); } - This->data->index = index; - This->data->simulations = sim_flags; - This->is_system = FALSE; - - *font_face = &This->IDWriteFontFace2_iface; + fontface->index = index; + fontface->simulations = simulations; + fontface->is_system = FALSE; + *ret = &fontface->IDWriteFontFace2_iface; return S_OK; } diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c index 3211ee3..57e0038 100644 --- a/dlls/dwrite/main.c +++ b/dlls/dwrite/main.c @@ -398,9 +398,16 @@ struct collectionloader IDWriteFontCollectionLoader *loader; }; +struct fontfacecached +{ + struct list entry; + IDWriteFontFace *fontface; +}; + struct fileloader { struct list entry; + struct list fontfaces; IDWriteFontFileLoader *loader; }; @@ -408,10 +415,12 @@ struct dwritefactory { IDWriteFactory IDWriteFactory_iface; LONG ref; - IDWriteLocalFontFileLoader* localfontfileloader; IDWriteFontCollection *system_collection; IDWriteGdiInterop *gdiinterop; + IDWriteLocalFontFileLoader* localfontfileloader; + struct list localfontfaces; + struct list collection_loaders; struct list file_loaders; }; @@ -421,6 +430,24 @@ static inline struct dwritefactory *impl_from_IDWriteFactory(IDWriteFactory *ifa return CONTAINING_RECORD(iface, struct dwritefactory, IDWriteFactory_iface); } +static void release_fontface_cache(struct list *fontfaces) +{ + struct fontfacecached *fontface, *fontface2; + LIST_FOR_EACH_ENTRY_SAFE(fontface, fontface2, fontfaces, struct fontfacecached, entry) { + list_remove(&fontface->entry); + IDWriteFontFace_Release(fontface->fontface); + heap_free(fontface); + } +} + +static void release_fileloader(struct fileloader *fileloader) +{ + list_remove(&fileloader->entry); + release_fontface_cache(&fileloader->fontfaces); + IDWriteFontFileLoader_Release(fileloader->loader); + heap_free(fileloader); +} + static void release_dwritefactory(struct dwritefactory *factory) { struct fileloader *fileloader, *fileloader2; @@ -428,6 +455,7 @@ static void release_dwritefactory(struct dwritefactory *factory) if (factory->localfontfileloader) IDWriteLocalFontFileLoader_Release(factory->localfontfileloader); + release_fontface_cache(&factory->localfontfaces); LIST_FOR_EACH_ENTRY_SAFE(loader, loader2, &factory->collection_loaders, struct collectionloader, entry) { list_remove(&loader->entry); @@ -435,11 +463,8 @@ static void release_dwritefactory(struct dwritefactory *factory) heap_free(loader); } - LIST_FOR_EACH_ENTRY_SAFE(fileloader, fileloader2, &factory->file_loaders, struct fileloader, entry) { - list_remove(&fileloader->entry); - IDWriteFontFileLoader_Release(fileloader->loader); - heap_free(fileloader); - } + LIST_FOR_EACH_ENTRY_SAFE(fileloader, fileloader2, &factory->file_loaders, struct fileloader, entry) + release_fileloader(fileloader); if (factory->system_collection) IDWriteFontCollection_Release(factory->system_collection); @@ -625,11 +650,93 @@ static HRESULT WINAPI dwritefactory_CreateCustomFontFileReference(IDWriteFactory static HRESULT WINAPI dwritefactory_CreateFontFace(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, - UINT32 index, DWRITE_FONT_SIMULATIONS sim_flags, IDWriteFontFace **font_face) + UINT32 index, DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace **font_face) { struct dwritefactory *This = impl_from_IDWriteFactory(iface); - TRACE("(%p)->(%d %u %p %u 0x%x %p)\n", This, facetype, files_number, font_files, index, sim_flags, font_face); - return font_create_fontface(facetype, files_number, font_files, index, sim_flags, (IDWriteFontFace2**)font_face); + IDWriteFontFileLoader *loader; + struct fontfacecached *cached; + struct list *fontfaces; + IDWriteFontFace2 *face; + const void *key; + UINT32 key_size; + HRESULT hr; + + TRACE("(%p)->(%d %u %p %u 0x%x %p)\n", This, facetype, files_number, font_files, index, simulations, font_face); + + *font_face = NULL; + + if (facetype != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION && index) + return E_INVALIDARG; + + hr = IDWriteFontFile_GetReferenceKey(*font_files, &key, &key_size); + if (FAILED(hr)) + return hr; + + hr = IDWriteFontFile_GetLoader(*font_files, &loader); + if (FAILED(hr)) + return hr; + + if (loader == (IDWriteFontFileLoader*)This->localfontfileloader) { + fontfaces = &This->localfontfaces; + IDWriteFontFileLoader_Release(loader); + } + else { + struct fileloader *fileloader = factory_get_file_loader(This, loader); + IDWriteFontFileLoader_Release(loader); + if (!fileloader) + return E_INVALIDARG; + fontfaces = &fileloader->fontfaces; + } + + /* search through cache list */ + LIST_FOR_EACH_ENTRY(cached, fontfaces, struct fontfacecached, entry) { + UINT32 cached_key_size, count = 1, cached_face_index; + DWRITE_FONT_SIMULATIONS cached_simulations; + const void *cached_key; + IDWriteFontFile *file; + + cached_face_index = IDWriteFontFace_GetIndex(cached->fontface); + cached_simulations = IDWriteFontFace_GetSimulations(cached->fontface); + + /* skip earlier */ + if (cached_face_index != index || cached_simulations != simulations) + continue; + + hr = IDWriteFontFace_GetFiles(cached->fontface, &count, &file); + if (FAILED(hr)) + return hr; + + hr = IDWriteFontFile_GetReferenceKey(file, &cached_key, &cached_key_size); + IDWriteFontFile_Release(file); + if (FAILED(hr)) + return hr; + + if (cached_key_size == key_size && !memcmp(cached_key, key, key_size)) { + TRACE("returning cached fontface %p\n", cached->fontface); + *font_face = cached->fontface; + IDWriteFontFace_AddRef(*font_face); + return S_OK; + } + } + + hr = create_fontface(facetype, files_number, font_files, index, simulations, &face); + if (FAILED(hr)) + return hr; + + /* new cache entry */ + cached = heap_alloc(sizeof(*cached)); + if (!cached) { + IDWriteFontFace2_Release(face); + return hr; + } + + cached->fontface = (IDWriteFontFace*)face; + list_add_tail(fontfaces, &cached->entry); + + *font_face = cached->fontface; + IDWriteFontFace_AddRef(*font_face); + + return S_OK; } static HRESULT WINAPI dwritefactory_CreateRenderingParams(IDWriteFactory *iface, IDWriteRenderingParams **params) @@ -687,6 +794,7 @@ static HRESULT WINAPI dwritefactory_RegisterFontFileLoader(IDWriteFactory *iface return E_OUTOFMEMORY; entry->loader = loader; + list_init(&entry->fontfaces); IDWriteFontFileLoader_AddRef(loader); list_add_tail(&This->file_loaders, &entry->entry); @@ -707,10 +815,7 @@ static HRESULT WINAPI dwritefactory_UnregisterFontFileLoader(IDWriteFactory *ifa if (!found) return E_INVALIDARG; - IDWriteFontFileLoader_Release(found->loader); - list_remove(&found->entry); - heap_free(found); - + release_fileloader(found); return S_OK; } @@ -893,6 +998,7 @@ static void init_dwritefactory(struct dwritefactory *factory, const struct IDWri list_init(&factory->collection_loaders); list_init(&factory->file_loaders); + list_init(&factory->localfontfaces); } HRESULT WINAPI DWriteCreateFactory(DWRITE_FACTORY_TYPE type, REFIID riid, IUnknown **ret) diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 469be88..baba6c2 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -1113,19 +1113,20 @@ static void test_CreateCustomFontFileReference(void) IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl }; IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl }; IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl }; + IDWriteFactory *factory, *factory2; IDWriteFontFile *file, *file2; BOOL support; DWRITE_FONT_FILE_TYPE file_type; DWRITE_FONT_FACE_TYPE face_type; UINT32 count; IDWriteFontFace *face, *face2; - IDWriteFactory *factory; HRESULT hr; HRSRC fontrsrc; UINT32 codePoints[1] = {0xa8}; UINT16 indices[1]; factory = create_factory(); + factory2 = create_factory(); hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL); ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); @@ -1194,11 +1195,14 @@ static void test_CreateCustomFontFileReference(void) hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine /* fontface instances are reused starting with win7 */ ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2); IDWriteFontFace_Release(face2); + /* file was created with different factory */ + hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + file2 = NULL; hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -1206,7 +1210,6 @@ todo_wine hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2); ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine /* fontface instances are reused starting with win7 */ ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2); IDWriteFontFace_Release(face2); @@ -1227,6 +1230,7 @@ todo_wine hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader); ok(hr == S_OK, "got 0x%08x\n", hr); + IDWriteFactory_Release(factory2); IDWriteFactory_Release(factory); } @@ -1268,8 +1272,8 @@ static void test_CreateFontFileReference(void) ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face); ok(count == 1, "got %i\n", count); - hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, 0, &fface); - ok(hr == S_OK, "got 0x%08x\n",hr); + hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface); + ok(hr == S_OK, "got 0x%08x\n", hr); IDWriteFontFace_Release(fface); IDWriteFontFile_Release(ffile); -- 2.1.1