dwrite: Cache fontface instances at factory level.
[wine.git] / dlls / dwrite / main.c
blob57e00380ba647ed745f6dd8abf99f5abaae7e998
1 /*
2 * DWrite
4 * Copyright 2012 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
29 #include "initguid.h"
31 #include "dwrite_private.h"
32 #include "wine/debug.h"
33 #include "wine/list.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
37 static IDWriteFactory *shared_factory;
38 static void release_shared_factory(IDWriteFactory*);
40 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
42 switch (reason)
44 case DLL_WINE_PREATTACH:
45 return FALSE; /* prefer native version */
46 case DLL_PROCESS_ATTACH:
47 DisableThreadLibraryCalls( hinstDLL );
48 break;
49 case DLL_PROCESS_DETACH:
50 if (reserved) break;
51 release_shared_factory(shared_factory);
53 return TRUE;
56 struct renderingparams {
57 IDWriteRenderingParams IDWriteRenderingParams_iface;
58 LONG ref;
60 FLOAT gamma;
61 FLOAT enh_contrast;
62 FLOAT cleartype_level;
63 DWRITE_PIXEL_GEOMETRY geometry;
64 DWRITE_RENDERING_MODE mode;
67 static inline struct renderingparams *impl_from_IDWriteRenderingParams(IDWriteRenderingParams *iface)
69 return CONTAINING_RECORD(iface, struct renderingparams, IDWriteRenderingParams_iface);
72 static HRESULT WINAPI renderingparams_QueryInterface(IDWriteRenderingParams *iface, REFIID riid, void **obj)
74 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
76 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
78 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteRenderingParams))
80 *obj = iface;
81 IDWriteRenderingParams_AddRef(iface);
82 return S_OK;
85 *obj = NULL;
87 return E_NOINTERFACE;
90 static ULONG WINAPI renderingparams_AddRef(IDWriteRenderingParams *iface)
92 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
93 ULONG ref = InterlockedIncrement(&This->ref);
94 TRACE("(%p)->(%d)\n", This, ref);
95 return ref;
98 static ULONG WINAPI renderingparams_Release(IDWriteRenderingParams *iface)
100 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
101 ULONG ref = InterlockedDecrement(&This->ref);
103 TRACE("(%p)->(%d)\n", This, ref);
105 if (!ref)
106 heap_free(This);
108 return ref;
111 static FLOAT WINAPI renderingparams_GetGamma(IDWriteRenderingParams *iface)
113 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
114 TRACE("(%p)\n", This);
115 return This->gamma;
118 static FLOAT WINAPI renderingparams_GetEnhancedContrast(IDWriteRenderingParams *iface)
120 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
121 TRACE("(%p)\n", This);
122 return This->enh_contrast;
125 static FLOAT WINAPI renderingparams_GetClearTypeLevel(IDWriteRenderingParams *iface)
127 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
128 TRACE("(%p)\n", This);
129 return This->cleartype_level;
132 static DWRITE_PIXEL_GEOMETRY WINAPI renderingparams_GetPixelGeometry(IDWriteRenderingParams *iface)
134 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
135 TRACE("(%p)\n", This);
136 return This->geometry;
139 static DWRITE_RENDERING_MODE WINAPI renderingparams_GetRenderingMode(IDWriteRenderingParams *iface)
141 struct renderingparams *This = impl_from_IDWriteRenderingParams(iface);
142 TRACE("(%p)\n", This);
143 return This->mode;
146 static const struct IDWriteRenderingParamsVtbl renderingparamsvtbl = {
147 renderingparams_QueryInterface,
148 renderingparams_AddRef,
149 renderingparams_Release,
150 renderingparams_GetGamma,
151 renderingparams_GetEnhancedContrast,
152 renderingparams_GetClearTypeLevel,
153 renderingparams_GetPixelGeometry,
154 renderingparams_GetRenderingMode
157 static HRESULT create_renderingparams(FLOAT gamma, FLOAT enhancedContrast, FLOAT cleartype_level,
158 DWRITE_PIXEL_GEOMETRY geometry, DWRITE_RENDERING_MODE mode, IDWriteRenderingParams **params)
160 struct renderingparams *This;
162 *params = NULL;
164 This = heap_alloc(sizeof(struct renderingparams));
165 if (!This) return E_OUTOFMEMORY;
167 This->IDWriteRenderingParams_iface.lpVtbl = &renderingparamsvtbl;
168 This->ref = 1;
170 This->gamma = gamma;
171 This->enh_contrast = enhancedContrast;
172 This->cleartype_level = cleartype_level;
173 This->geometry = geometry;
174 This->mode = mode;
176 *params = &This->IDWriteRenderingParams_iface;
178 return S_OK;
181 struct localizedpair {
182 WCHAR *locale;
183 WCHAR *string;
186 struct localizedstrings {
187 IDWriteLocalizedStrings IDWriteLocalizedStrings_iface;
188 LONG ref;
190 struct localizedpair *data;
191 UINT32 count;
192 UINT32 alloc;
195 static inline struct localizedstrings *impl_from_IDWriteLocalizedStrings(IDWriteLocalizedStrings *iface)
197 return CONTAINING_RECORD(iface, struct localizedstrings, IDWriteLocalizedStrings_iface);
200 static HRESULT WINAPI localizedstrings_QueryInterface(IDWriteLocalizedStrings *iface, REFIID riid, void **obj)
202 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
204 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
206 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteLocalizedStrings))
208 *obj = iface;
209 IDWriteLocalizedStrings_AddRef(iface);
210 return S_OK;
213 *obj = NULL;
215 return E_NOINTERFACE;
218 static ULONG WINAPI localizedstrings_AddRef(IDWriteLocalizedStrings *iface)
220 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
221 ULONG ref = InterlockedIncrement(&This->ref);
222 TRACE("(%p)->(%d)\n", This, ref);
223 return ref;
226 static ULONG WINAPI localizedstrings_Release(IDWriteLocalizedStrings *iface)
228 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
229 ULONG ref = InterlockedDecrement(&This->ref);
231 TRACE("(%p)->(%d)\n", This, ref);
233 if (!ref) {
234 unsigned int i;
236 for (i = 0; i < This->count; i++) {
237 heap_free(This->data[i].locale);
238 heap_free(This->data[i].string);
241 heap_free(This->data);
242 heap_free(This);
245 return ref;
248 static UINT32 WINAPI localizedstrings_GetCount(IDWriteLocalizedStrings *iface)
250 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
251 TRACE("(%p)\n", This);
252 return This->count;
255 static HRESULT WINAPI localizedstrings_FindLocaleName(IDWriteLocalizedStrings *iface,
256 WCHAR const *locale_name, UINT32 *index, BOOL *exists)
258 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
259 FIXME("(%p)->(%s %p %p): stub\n", This, debugstr_w(locale_name), index, exists);
260 return E_NOTIMPL;
263 static HRESULT WINAPI localizedstrings_GetLocaleNameLength(IDWriteLocalizedStrings *iface, UINT32 index, UINT32 *length)
265 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
266 FIXME("(%p)->(%u %p): stub\n", This, index, length);
267 return E_NOTIMPL;
270 static HRESULT WINAPI localizedstrings_GetLocaleName(IDWriteLocalizedStrings *iface, UINT32 index, WCHAR *locale_name, UINT32 size)
272 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
273 FIXME("(%p)->(%u %p %u): stub\n", This, index, locale_name, size);
274 return E_NOTIMPL;
277 static HRESULT WINAPI localizedstrings_GetStringLength(IDWriteLocalizedStrings *iface, UINT32 index, UINT32 *length)
279 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
281 TRACE("(%p)->(%u %p)\n", This, index, length);
283 if (index >= This->count) {
284 *length = (UINT32)-1;
285 return E_FAIL;
288 *length = strlenW(This->data[index].string);
289 return S_OK;
292 static HRESULT WINAPI localizedstrings_GetString(IDWriteLocalizedStrings *iface, UINT32 index, WCHAR *buffer, UINT32 size)
294 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
296 TRACE("(%p)->(%u %p %u)\n", This, index, buffer, size);
298 if (index >= This->count) {
299 if (buffer) *buffer = 0;
300 return E_FAIL;
303 if (size < strlenW(This->data[index].string)+1) {
304 if (buffer) *buffer = 0;
305 return E_NOT_SUFFICIENT_BUFFER;
308 strcpyW(buffer, This->data[index].string);
309 return S_OK;
312 static const IDWriteLocalizedStringsVtbl localizedstringsvtbl = {
313 localizedstrings_QueryInterface,
314 localizedstrings_AddRef,
315 localizedstrings_Release,
316 localizedstrings_GetCount,
317 localizedstrings_FindLocaleName,
318 localizedstrings_GetLocaleNameLength,
319 localizedstrings_GetLocaleName,
320 localizedstrings_GetStringLength,
321 localizedstrings_GetString
324 HRESULT create_localizedstrings(IDWriteLocalizedStrings **strings)
326 struct localizedstrings *This;
328 *strings = NULL;
330 This = heap_alloc(sizeof(struct localizedstrings));
331 if (!This) return E_OUTOFMEMORY;
333 This->IDWriteLocalizedStrings_iface.lpVtbl = &localizedstringsvtbl;
334 This->ref = 1;
335 This->count = 0;
336 This->data = heap_alloc_zero(sizeof(struct localizedpair));
337 if (!This->data) {
338 heap_free(This);
339 return E_OUTOFMEMORY;
341 This->alloc = 1;
343 *strings = &This->IDWriteLocalizedStrings_iface;
345 return S_OK;
348 HRESULT add_localizedstring(IDWriteLocalizedStrings *iface, const WCHAR *locale, const WCHAR *string)
350 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
352 if (This->count == This->alloc) {
353 This->alloc *= 2;
354 This->data = heap_realloc(This->data, This->alloc*sizeof(struct localizedpair));
357 This->data[This->count].locale = heap_strdupW(locale);
358 This->data[This->count].string = heap_strdupW(string);
359 This->count++;
361 return S_OK;
364 HRESULT clone_localizedstring(IDWriteLocalizedStrings *iface, IDWriteLocalizedStrings **strings)
366 struct localizedstrings *This = impl_from_IDWriteLocalizedStrings(iface);
367 struct localizedstrings *New;
368 int i;
370 *strings = NULL;
372 New = heap_alloc(sizeof(struct localizedstrings));
373 if (!New) return E_OUTOFMEMORY;
375 New->IDWriteLocalizedStrings_iface.lpVtbl = &localizedstringsvtbl;
376 New->ref = 1;
377 New->count = This->count;
378 New->data = heap_alloc(sizeof(struct localizedpair) * New->count);
379 if (!New->data) {
380 heap_free(New);
381 return E_OUTOFMEMORY;
383 for (i = 0; i < New->count; i++)
385 New->data[i].locale = heap_strdupW(This->data[i].locale);
386 New->data[i].string = heap_strdupW(This->data[i].string);
388 New->alloc = New->count;
390 *strings = &New->IDWriteLocalizedStrings_iface;
392 return S_OK;
395 struct collectionloader
397 struct list entry;
398 IDWriteFontCollectionLoader *loader;
401 struct fontfacecached
403 struct list entry;
404 IDWriteFontFace *fontface;
407 struct fileloader
409 struct list entry;
410 struct list fontfaces;
411 IDWriteFontFileLoader *loader;
414 struct dwritefactory {
415 IDWriteFactory IDWriteFactory_iface;
416 LONG ref;
418 IDWriteFontCollection *system_collection;
419 IDWriteGdiInterop *gdiinterop;
421 IDWriteLocalFontFileLoader* localfontfileloader;
422 struct list localfontfaces;
424 struct list collection_loaders;
425 struct list file_loaders;
428 static inline struct dwritefactory *impl_from_IDWriteFactory(IDWriteFactory *iface)
430 return CONTAINING_RECORD(iface, struct dwritefactory, IDWriteFactory_iface);
433 static void release_fontface_cache(struct list *fontfaces)
435 struct fontfacecached *fontface, *fontface2;
436 LIST_FOR_EACH_ENTRY_SAFE(fontface, fontface2, fontfaces, struct fontfacecached, entry) {
437 list_remove(&fontface->entry);
438 IDWriteFontFace_Release(fontface->fontface);
439 heap_free(fontface);
443 static void release_fileloader(struct fileloader *fileloader)
445 list_remove(&fileloader->entry);
446 release_fontface_cache(&fileloader->fontfaces);
447 IDWriteFontFileLoader_Release(fileloader->loader);
448 heap_free(fileloader);
451 static void release_dwritefactory(struct dwritefactory *factory)
453 struct fileloader *fileloader, *fileloader2;
454 struct collectionloader *loader, *loader2;
456 if (factory->localfontfileloader)
457 IDWriteLocalFontFileLoader_Release(factory->localfontfileloader);
458 release_fontface_cache(&factory->localfontfaces);
460 LIST_FOR_EACH_ENTRY_SAFE(loader, loader2, &factory->collection_loaders, struct collectionloader, entry) {
461 list_remove(&loader->entry);
462 IDWriteFontCollectionLoader_Release(loader->loader);
463 heap_free(loader);
466 LIST_FOR_EACH_ENTRY_SAFE(fileloader, fileloader2, &factory->file_loaders, struct fileloader, entry)
467 release_fileloader(fileloader);
469 if (factory->system_collection)
470 IDWriteFontCollection_Release(factory->system_collection);
471 if (factory->gdiinterop)
472 release_gdiinterop(factory->gdiinterop);
473 heap_free(factory);
476 static void release_shared_factory(IDWriteFactory *iface)
478 struct dwritefactory *factory;
479 if (!iface) return;
480 factory = impl_from_IDWriteFactory(iface);
481 release_dwritefactory(factory);
484 static struct fileloader *factory_get_file_loader(struct dwritefactory *factory, IDWriteFontFileLoader *loader)
486 struct fileloader *entry, *found = NULL;
488 LIST_FOR_EACH_ENTRY(entry, &factory->file_loaders, struct fileloader, entry) {
489 if (entry->loader == loader) {
490 found = entry;
491 break;
495 return found;
498 static HRESULT WINAPI dwritefactory_QueryInterface(IDWriteFactory *iface, REFIID riid, void **obj)
500 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
502 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
504 if (IsEqualIID(riid, &IID_IUnknown) ||
505 IsEqualIID(riid, &IID_IDWriteFactory))
507 *obj = iface;
508 IDWriteFactory_AddRef(iface);
509 return S_OK;
512 *obj = NULL;
514 return E_NOINTERFACE;
517 static ULONG WINAPI dwritefactory_AddRef(IDWriteFactory *iface)
519 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
520 ULONG ref = InterlockedIncrement(&This->ref);
521 TRACE("(%p)->(%d)\n", This, ref);
522 return ref;
525 static ULONG WINAPI dwritefactory_Release(IDWriteFactory *iface)
527 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
528 ULONG ref = InterlockedDecrement(&This->ref);
530 TRACE("(%p)->(%d)\n", This, ref);
532 if (!ref)
533 release_dwritefactory(This);
535 return ref;
538 static HRESULT WINAPI dwritefactory_GetSystemFontCollection(IDWriteFactory *iface,
539 IDWriteFontCollection **collection, BOOL check_for_updates)
541 HRESULT hr = S_OK;
542 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
543 TRACE("(%p)->(%p %d)\n", This, collection, check_for_updates);
545 if (check_for_updates)
546 FIXME("checking for system font updates not implemented\n");
548 if (!This->system_collection)
549 hr = get_system_fontcollection(&This->system_collection);
551 if (SUCCEEDED(hr))
552 IDWriteFontCollection_AddRef(This->system_collection);
554 *collection = This->system_collection;
556 return hr;
559 static HRESULT WINAPI dwritefactory_CreateCustomFontCollection(IDWriteFactory *iface,
560 IDWriteFontCollectionLoader *loader, void const *key, UINT32 key_size, IDWriteFontCollection **collection)
562 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
563 FIXME("(%p)->(%p %p %u %p): stub\n", This, loader, key, key_size, collection);
564 return E_NOTIMPL;
567 static HRESULT WINAPI dwritefactory_RegisterFontCollectionLoader(IDWriteFactory *iface,
568 IDWriteFontCollectionLoader *loader)
570 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
571 struct collectionloader *entry;
573 TRACE("(%p)->(%p)\n", This, loader);
575 if (!loader)
576 return E_INVALIDARG;
578 LIST_FOR_EACH_ENTRY(entry, &This->collection_loaders, struct collectionloader, entry) {
579 if (entry->loader == loader)
580 return DWRITE_E_ALREADYREGISTERED;
583 entry = heap_alloc(sizeof(*entry));
584 if (!entry)
585 return E_OUTOFMEMORY;
587 entry->loader = loader;
588 IDWriteFontCollectionLoader_AddRef(loader);
589 list_add_tail(&This->collection_loaders, &entry->entry);
591 return S_OK;
594 static HRESULT WINAPI dwritefactory_UnregisterFontCollectionLoader(IDWriteFactory *iface,
595 IDWriteFontCollectionLoader *loader)
597 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
598 struct collectionloader *entry, *found = NULL;
600 TRACE("(%p)->(%p)\n", This, loader);
602 if (!loader)
603 return E_INVALIDARG;
605 LIST_FOR_EACH_ENTRY(entry, &This->collection_loaders, struct collectionloader, entry) {
606 if (entry->loader == loader) {
607 found = entry;
608 break;
612 if (!found)
613 return E_INVALIDARG;
615 IDWriteFontCollectionLoader_Release(found->loader);
616 list_remove(&found->entry);
617 heap_free(found);
619 return S_OK;
622 static HRESULT WINAPI dwritefactory_CreateFontFileReference(IDWriteFactory *iface,
623 WCHAR const *path, FILETIME const *writetime, IDWriteFontFile **font_file)
625 HRESULT hr;
626 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
627 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(path), writetime, font_file);
629 if (!This->localfontfileloader)
631 hr = create_localfontfileloader(&This->localfontfileloader);
632 if (FAILED(hr))
633 return hr;
635 return create_font_file((IDWriteFontFileLoader*)This->localfontfileloader, path, sizeof(WCHAR) * (strlenW(path)+1), font_file);
638 static HRESULT WINAPI dwritefactory_CreateCustomFontFileReference(IDWriteFactory *iface,
639 void const *reference_key, UINT32 key_size, IDWriteFontFileLoader *loader, IDWriteFontFile **font_file)
641 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
643 TRACE("(%p)->(%p %u %p %p)\n", This, reference_key, key_size, loader, font_file);
645 if (!loader || !factory_get_file_loader(This, loader))
646 return E_INVALIDARG;
648 return create_font_file(loader, reference_key, key_size, font_file);
651 static HRESULT WINAPI dwritefactory_CreateFontFace(IDWriteFactory *iface,
652 DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files,
653 UINT32 index, DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace **font_face)
655 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
656 IDWriteFontFileLoader *loader;
657 struct fontfacecached *cached;
658 struct list *fontfaces;
659 IDWriteFontFace2 *face;
660 const void *key;
661 UINT32 key_size;
662 HRESULT hr;
664 TRACE("(%p)->(%d %u %p %u 0x%x %p)\n", This, facetype, files_number, font_files, index, simulations, font_face);
666 *font_face = NULL;
668 if (facetype != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION && index)
669 return E_INVALIDARG;
671 hr = IDWriteFontFile_GetReferenceKey(*font_files, &key, &key_size);
672 if (FAILED(hr))
673 return hr;
675 hr = IDWriteFontFile_GetLoader(*font_files, &loader);
676 if (FAILED(hr))
677 return hr;
679 if (loader == (IDWriteFontFileLoader*)This->localfontfileloader) {
680 fontfaces = &This->localfontfaces;
681 IDWriteFontFileLoader_Release(loader);
683 else {
684 struct fileloader *fileloader = factory_get_file_loader(This, loader);
685 IDWriteFontFileLoader_Release(loader);
686 if (!fileloader)
687 return E_INVALIDARG;
688 fontfaces = &fileloader->fontfaces;
691 /* search through cache list */
692 LIST_FOR_EACH_ENTRY(cached, fontfaces, struct fontfacecached, entry) {
693 UINT32 cached_key_size, count = 1, cached_face_index;
694 DWRITE_FONT_SIMULATIONS cached_simulations;
695 const void *cached_key;
696 IDWriteFontFile *file;
698 cached_face_index = IDWriteFontFace_GetIndex(cached->fontface);
699 cached_simulations = IDWriteFontFace_GetSimulations(cached->fontface);
701 /* skip earlier */
702 if (cached_face_index != index || cached_simulations != simulations)
703 continue;
705 hr = IDWriteFontFace_GetFiles(cached->fontface, &count, &file);
706 if (FAILED(hr))
707 return hr;
709 hr = IDWriteFontFile_GetReferenceKey(file, &cached_key, &cached_key_size);
710 IDWriteFontFile_Release(file);
711 if (FAILED(hr))
712 return hr;
714 if (cached_key_size == key_size && !memcmp(cached_key, key, key_size)) {
715 TRACE("returning cached fontface %p\n", cached->fontface);
716 *font_face = cached->fontface;
717 IDWriteFontFace_AddRef(*font_face);
718 return S_OK;
722 hr = create_fontface(facetype, files_number, font_files, index, simulations, &face);
723 if (FAILED(hr))
724 return hr;
726 /* new cache entry */
727 cached = heap_alloc(sizeof(*cached));
728 if (!cached) {
729 IDWriteFontFace2_Release(face);
730 return hr;
733 cached->fontface = (IDWriteFontFace*)face;
734 list_add_tail(fontfaces, &cached->entry);
736 *font_face = cached->fontface;
737 IDWriteFontFace_AddRef(*font_face);
739 return S_OK;
742 static HRESULT WINAPI dwritefactory_CreateRenderingParams(IDWriteFactory *iface, IDWriteRenderingParams **params)
744 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
745 HMONITOR monitor;
746 POINT pt;
748 TRACE("(%p)->(%p)\n", This, params);
750 pt.x = pt.y = 0;
751 monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
752 return IDWriteFactory_CreateMonitorRenderingParams(iface, monitor, params);
755 static HRESULT WINAPI dwritefactory_CreateMonitorRenderingParams(IDWriteFactory *iface, HMONITOR monitor,
756 IDWriteRenderingParams **params)
758 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
759 static int fixme_once = 0;
761 TRACE("(%p)->(%p %p)\n", This, monitor, params);
763 if (!fixme_once++)
764 FIXME("(%p): monitor setting ignored\n", monitor);
765 return IDWriteFactory_CreateCustomRenderingParams(iface, 0.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
766 DWRITE_RENDERING_MODE_DEFAULT, params);
769 static HRESULT WINAPI dwritefactory_CreateCustomRenderingParams(IDWriteFactory *iface, FLOAT gamma, FLOAT enhancedContrast,
770 FLOAT cleartype_level, DWRITE_PIXEL_GEOMETRY geometry, DWRITE_RENDERING_MODE mode, IDWriteRenderingParams **params)
772 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
773 TRACE("(%p)->(%f %f %f %d %d %p)\n", This, gamma, enhancedContrast, cleartype_level, geometry, mode, params);
774 return create_renderingparams(gamma, enhancedContrast, cleartype_level, geometry, mode, params);
777 static HRESULT WINAPI dwritefactory_RegisterFontFileLoader(IDWriteFactory *iface, IDWriteFontFileLoader *loader)
779 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
780 struct fileloader *entry;
782 TRACE("(%p)->(%p)\n", This, loader);
784 if (!loader)
785 return E_INVALIDARG;
787 LIST_FOR_EACH_ENTRY(entry, &This->file_loaders, struct fileloader, entry) {
788 if (entry->loader == loader)
789 return DWRITE_E_ALREADYREGISTERED;
792 entry = heap_alloc(sizeof(*entry));
793 if (!entry)
794 return E_OUTOFMEMORY;
796 entry->loader = loader;
797 list_init(&entry->fontfaces);
798 IDWriteFontFileLoader_AddRef(loader);
799 list_add_tail(&This->file_loaders, &entry->entry);
801 return S_OK;
804 static HRESULT WINAPI dwritefactory_UnregisterFontFileLoader(IDWriteFactory *iface, IDWriteFontFileLoader *loader)
806 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
807 struct fileloader *found;
809 TRACE("(%p)->(%p)\n", This, loader);
811 if (!loader)
812 return E_INVALIDARG;
814 found = factory_get_file_loader(This, loader);
815 if (!found)
816 return E_INVALIDARG;
818 release_fileloader(found);
819 return S_OK;
822 static HRESULT WINAPI dwritefactory_CreateTextFormat(IDWriteFactory *iface, WCHAR const* family_name,
823 IDWriteFontCollection *collection, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style,
824 DWRITE_FONT_STRETCH stretch, FLOAT size, WCHAR const *locale, IDWriteTextFormat **format)
826 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
827 TRACE("(%p)->(%s %p %d %d %d %f %s %p)\n", This, debugstr_w(family_name), collection, weight, style, stretch,
828 size, debugstr_w(locale), format);
830 if (!collection)
832 HRESULT hr = IDWriteFactory_GetSystemFontCollection(iface, &collection, FALSE);
833 if (hr != S_OK)
834 return hr;
835 /* Our ref count is 1 too many, since we will add ref in create_textformat */
836 IDWriteFontCollection_Release(This->system_collection);
838 return create_textformat(family_name, collection, weight, style, stretch, size, locale, format);
841 static HRESULT WINAPI dwritefactory_CreateTypography(IDWriteFactory *iface, IDWriteTypography **typography)
843 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
844 TRACE("(%p)->(%p)\n", This, typography);
845 return create_typography(typography);
848 static HRESULT WINAPI dwritefactory_GetGdiInterop(IDWriteFactory *iface, IDWriteGdiInterop **gdi_interop)
850 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
852 TRACE("(%p)->(%p)\n", This, gdi_interop);
854 *gdi_interop = NULL;
856 if (!This->gdiinterop) {
857 HRESULT hr = create_gdiinterop(iface, &This->gdiinterop);
858 if (FAILED(hr))
859 return hr;
862 *gdi_interop = This->gdiinterop;
863 IDWriteGdiInterop_AddRef(*gdi_interop);
865 return S_OK;
868 static HRESULT WINAPI dwritefactory_CreateTextLayout(IDWriteFactory *iface, WCHAR const* string,
869 UINT32 len, IDWriteTextFormat *format, FLOAT max_width, FLOAT max_height, IDWriteTextLayout **layout)
871 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
872 TRACE("(%p)->(%s %u %p %f %f %p)\n", This, debugstr_w(string), len, format, max_width, max_height, layout);
874 if (!format) return E_INVALIDARG;
875 return create_textlayout(string, len, format, max_width, max_height, layout);
878 static HRESULT WINAPI dwritefactory_CreateGdiCompatibleTextLayout(IDWriteFactory *iface, WCHAR const* string,
879 UINT32 len, IDWriteTextFormat *format, FLOAT layout_width, FLOAT layout_height, FLOAT pixels_per_dip,
880 DWRITE_MATRIX const* transform, BOOL use_gdi_natural, IDWriteTextLayout **layout)
882 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
883 FIXME("(%p)->(%s:%u %p %f %f %f %p %d %p): semi-stub\n", This, debugstr_wn(string, len), len, format, layout_width, layout_height,
884 pixels_per_dip, transform, use_gdi_natural, layout);
886 if (!format) return E_INVALIDARG;
887 return create_textlayout(string, len, format, layout_width, layout_height, layout);
890 static HRESULT WINAPI dwritefactory_CreateEllipsisTrimmingSign(IDWriteFactory *iface, IDWriteTextFormat *format,
891 IDWriteInlineObject **trimming_sign)
893 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
894 FIXME("(%p)->(%p %p): semi-stub\n", This, format, trimming_sign);
895 return create_trimmingsign(trimming_sign);
898 static HRESULT WINAPI dwritefactory_CreateTextAnalyzer(IDWriteFactory *iface, IDWriteTextAnalyzer **analyzer)
900 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
901 TRACE("(%p)->(%p)\n", This, analyzer);
902 return get_textanalyzer(analyzer);
905 static HRESULT WINAPI dwritefactory_CreateNumberSubstitution(IDWriteFactory *iface, DWRITE_NUMBER_SUBSTITUTION_METHOD method,
906 WCHAR const* locale, BOOL ignore_user_override, IDWriteNumberSubstitution **substitution)
908 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
909 TRACE("(%p)->(%d %s %d %p)\n", This, method, debugstr_w(locale), ignore_user_override, substitution);
910 return create_numbersubstitution(method, locale, ignore_user_override, substitution);
913 static HRESULT WINAPI dwritefactory_CreateGlyphRunAnalysis(IDWriteFactory *iface, DWRITE_GLYPH_RUN const *glyph_run,
914 FLOAT pixels_per_dip, DWRITE_MATRIX const* transform, DWRITE_RENDERING_MODE rendering_mode,
915 DWRITE_MEASURING_MODE measuring_mode, FLOAT baseline_x, FLOAT baseline_y, IDWriteGlyphRunAnalysis **analysis)
917 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
918 FIXME("(%p)->(%p %f %p %d %d %f %f %p): stub\n", This, glyph_run, pixels_per_dip, transform, rendering_mode,
919 measuring_mode, baseline_x, baseline_y, analysis);
920 return E_NOTIMPL;
923 static const struct IDWriteFactoryVtbl dwritefactoryvtbl = {
924 dwritefactory_QueryInterface,
925 dwritefactory_AddRef,
926 dwritefactory_Release,
927 dwritefactory_GetSystemFontCollection,
928 dwritefactory_CreateCustomFontCollection,
929 dwritefactory_RegisterFontCollectionLoader,
930 dwritefactory_UnregisterFontCollectionLoader,
931 dwritefactory_CreateFontFileReference,
932 dwritefactory_CreateCustomFontFileReference,
933 dwritefactory_CreateFontFace,
934 dwritefactory_CreateRenderingParams,
935 dwritefactory_CreateMonitorRenderingParams,
936 dwritefactory_CreateCustomRenderingParams,
937 dwritefactory_RegisterFontFileLoader,
938 dwritefactory_UnregisterFontFileLoader,
939 dwritefactory_CreateTextFormat,
940 dwritefactory_CreateTypography,
941 dwritefactory_GetGdiInterop,
942 dwritefactory_CreateTextLayout,
943 dwritefactory_CreateGdiCompatibleTextLayout,
944 dwritefactory_CreateEllipsisTrimmingSign,
945 dwritefactory_CreateTextAnalyzer,
946 dwritefactory_CreateNumberSubstitution,
947 dwritefactory_CreateGlyphRunAnalysis
950 static ULONG WINAPI shareddwritefactory_AddRef(IDWriteFactory *iface)
952 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
953 TRACE("(%p)\n", This);
954 return 2;
957 static ULONG WINAPI shareddwritefactory_Release(IDWriteFactory *iface)
959 struct dwritefactory *This = impl_from_IDWriteFactory(iface);
960 TRACE("(%p)\n", This);
961 return 1;
964 static const struct IDWriteFactoryVtbl shareddwritefactoryvtbl = {
965 dwritefactory_QueryInterface,
966 shareddwritefactory_AddRef,
967 shareddwritefactory_Release,
968 dwritefactory_GetSystemFontCollection,
969 dwritefactory_CreateCustomFontCollection,
970 dwritefactory_RegisterFontCollectionLoader,
971 dwritefactory_UnregisterFontCollectionLoader,
972 dwritefactory_CreateFontFileReference,
973 dwritefactory_CreateCustomFontFileReference,
974 dwritefactory_CreateFontFace,
975 dwritefactory_CreateRenderingParams,
976 dwritefactory_CreateMonitorRenderingParams,
977 dwritefactory_CreateCustomRenderingParams,
978 dwritefactory_RegisterFontFileLoader,
979 dwritefactory_UnregisterFontFileLoader,
980 dwritefactory_CreateTextFormat,
981 dwritefactory_CreateTypography,
982 dwritefactory_GetGdiInterop,
983 dwritefactory_CreateTextLayout,
984 dwritefactory_CreateGdiCompatibleTextLayout,
985 dwritefactory_CreateEllipsisTrimmingSign,
986 dwritefactory_CreateTextAnalyzer,
987 dwritefactory_CreateNumberSubstitution,
988 dwritefactory_CreateGlyphRunAnalysis
991 static void init_dwritefactory(struct dwritefactory *factory, const struct IDWriteFactoryVtbl *vtbl)
993 factory->IDWriteFactory_iface.lpVtbl = vtbl;
994 factory->ref = 1;
995 factory->localfontfileloader = NULL;
996 factory->system_collection = NULL;
997 factory->gdiinterop = NULL;
999 list_init(&factory->collection_loaders);
1000 list_init(&factory->file_loaders);
1001 list_init(&factory->localfontfaces);
1004 HRESULT WINAPI DWriteCreateFactory(DWRITE_FACTORY_TYPE type, REFIID riid, IUnknown **ret)
1006 struct dwritefactory *factory;
1008 TRACE("(%d, %s, %p)\n", type, debugstr_guid(riid), ret);
1010 *ret = NULL;
1012 if (!IsEqualIID(riid, &IID_IDWriteFactory)) return E_FAIL;
1014 if (type == DWRITE_FACTORY_TYPE_SHARED && shared_factory) {
1015 *ret = (IUnknown*)shared_factory;
1016 IDWriteFactory_AddRef(shared_factory);
1017 return S_OK;
1020 factory = heap_alloc(sizeof(struct dwritefactory));
1021 if (!factory) return E_OUTOFMEMORY;
1023 init_dwritefactory(factory, type == DWRITE_FACTORY_TYPE_SHARED ? &shareddwritefactoryvtbl : &dwritefactoryvtbl);
1025 if (type == DWRITE_FACTORY_TYPE_SHARED)
1026 if (InterlockedCompareExchangePointer((void**)&shared_factory, factory, NULL)) {
1027 release_shared_factory(&factory->IDWriteFactory_iface);
1028 *ret = (IUnknown*)shared_factory;
1029 IDWriteFactory_AddRef(shared_factory);
1030 return S_OK;
1033 *ret = (IUnknown*)&factory->IDWriteFactory_iface;
1034 return S_OK;