makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / dwrite / font.c
blobbd969a8fa6bbc28903ad8064d33e8b5e4ef0c6a5
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
31 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
33 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
34 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
44 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
45 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
46 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
48 static const WCHAR extraW[] = {'e','x','t','r','a',0};
49 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
50 static const WCHAR semiW[] = {'s','e','m','i',0};
51 static const WCHAR extW[] = {'e','x','t',0};
52 static const WCHAR thinW[] = {'t','h','i','n',0};
53 static const WCHAR lightW[] = {'l','i','g','h','t',0};
54 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
55 static const WCHAR blackW[] = {'b','l','a','c','k',0};
56 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
57 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
58 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
59 static const WCHAR boldW[] = {'B','o','l','d',0};
60 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
61 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
62 static const WCHAR demiW[] = {'d','e','m','i',0};
63 static const WCHAR spaceW[] = {' ',0};
64 static const WCHAR enusW[] = {'e','n','-','u','s',0};
66 struct dwrite_font_propvec {
67 FLOAT stretch;
68 FLOAT style;
69 FLOAT weight;
72 struct dwrite_font_data
74 LONG ref;
76 DWRITE_FONT_STYLE style;
77 DWRITE_FONT_STRETCH stretch;
78 DWRITE_FONT_WEIGHT weight;
79 DWRITE_PANOSE panose;
80 FONTSIGNATURE fontsig;
81 UINT32 flags; /* enum font_flags */
82 struct dwrite_font_propvec propvec;
83 /* Static axis for weight/width/italic. */
84 DWRITE_FONT_AXIS_VALUE axis[3];
86 DWRITE_FONT_METRICS1 metrics;
87 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
88 IDWriteLocalizedStrings *family_names;
89 IDWriteLocalizedStrings *names;
91 /* data needed to create fontface instance */
92 DWRITE_FONT_FACE_TYPE face_type;
93 IDWriteFontFile *file;
94 UINT32 face_index;
96 WCHAR *facename;
98 USHORT simulations;
100 LOGFONTW lf;
102 /* used to mark font as tested when scanning for simulation candidate */
103 BOOL bold_sim_tested : 1;
104 BOOL oblique_sim_tested : 1;
107 struct dwrite_fontfamily_data
109 LONG refcount;
111 IDWriteLocalizedStrings *familyname;
113 struct dwrite_font_data **fonts;
114 size_t size;
115 size_t count;
117 BOOL has_normal_face : 1;
118 BOOL has_oblique_face : 1;
119 BOOL has_italic_face : 1;
122 struct dwrite_fontcollection
124 IDWriteFontCollection3 IDWriteFontCollection3_iface;
125 LONG refcount;
127 IDWriteFactory7 *factory;
128 struct dwrite_fontfamily_data **family_data;
129 size_t size;
130 size_t count;
133 struct dwrite_fontfamily
135 IDWriteFontFamily2 IDWriteFontFamily2_iface;
136 IDWriteFontList2 IDWriteFontList2_iface;
137 LONG refcount;
139 struct dwrite_fontfamily_data *data;
140 struct dwrite_fontcollection *collection;
143 struct dwrite_fontlist
145 IDWriteFontList2 IDWriteFontList2_iface;
146 LONG refcount;
148 struct dwrite_font_data **fonts;
149 UINT32 font_count;
150 struct dwrite_fontfamily *family;
153 struct dwrite_font {
154 IDWriteFont3 IDWriteFont3_iface;
155 LONG ref;
157 DWRITE_FONT_STYLE style;
158 struct dwrite_font_data *data;
159 struct dwrite_fontfamily *family;
162 enum runanalysis_flags {
163 RUNANALYSIS_BOUNDS_READY = 1 << 0,
164 RUNANALYSIS_BITMAP_READY = 1 << 1,
165 RUNANALYSIS_USE_TRANSFORM = 1 << 2
168 struct dwrite_glyphrunanalysis {
169 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
170 LONG ref;
172 DWRITE_RENDERING_MODE1 rendering_mode;
173 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
174 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
175 DWRITE_MATRIX m;
176 UINT16 *glyphs;
177 D2D_POINT_2F *origins;
179 UINT8 flags;
180 RECT bounds;
181 BYTE *bitmap;
182 UINT32 max_glyph_bitmap_size;
185 struct dwrite_colorglyphenum
187 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
188 LONG refcount;
190 FLOAT origin_x; /* original run origin */
191 FLOAT origin_y;
193 IDWriteFontFace5 *fontface; /* for convenience */
194 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
195 DWRITE_GLYPH_RUN run; /* base run */
196 UINT32 palette; /* palette index to get layer color from */
197 FLOAT *advances; /* original or measured advances for base glyphs */
198 FLOAT *color_advances; /* returned color run points to this */
199 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
200 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
201 UINT16 *glyphindices; /* returned color run points to this */
202 struct dwrite_colorglyph *glyphs; /* current glyph color info */
203 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
204 UINT16 current_layer; /* enumerator position, updated with MoveNext */
205 UINT16 max_layer_num; /* max number of layers for this run */
206 struct dwrite_fonttable colr; /* used to access layers */
209 #define GLYPH_BLOCK_SHIFT 8
210 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
211 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
212 #define GLYPH_MAX 65536
214 struct dwrite_fontfile {
215 IDWriteFontFile IDWriteFontFile_iface;
216 LONG ref;
218 IDWriteFontFileLoader *loader;
219 void *reference_key;
220 UINT32 key_size;
221 IDWriteFontFileStream *stream;
224 struct dwrite_fontfacereference
226 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
227 LONG refcount;
229 IDWriteFontFile *file;
230 UINT32 index;
231 USHORT simulations;
232 DWRITE_FONT_AXIS_VALUE *axis_values;
233 UINT32 axis_values_count;
234 IDWriteFactory7 *factory;
237 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
239 struct dwrite_fontresource
241 IDWriteFontResource IDWriteFontResource_iface;
242 LONG refcount;
244 IDWriteFontFile *file;
245 UINT32 face_index;
246 IDWriteFactory7 *factory;
249 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
251 struct dwrite_fontface *fontface = context;
252 BOOL exists = FALSE;
254 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
255 size, data_context, &exists)) || !exists)
257 *data = NULL;
258 *size = 0;
259 *data_context = NULL;
263 static void dwrite_release_font_table(void *context, void *data_context)
265 struct dwrite_fontface *fontface = context;
266 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
269 static UINT16 dwrite_get_font_upem(void *context)
271 struct dwrite_fontface *fontface = context;
272 return fontface->metrics.designUnitsPerEm;
275 static const struct shaping_font_ops dwrite_font_ops =
277 dwrite_grab_font_table,
278 dwrite_release_font_table,
279 dwrite_get_font_upem,
282 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
284 if (fontface->shaping_cache)
285 return fontface->shaping_cache;
287 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
290 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
292 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
295 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
297 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
300 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
302 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
305 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
307 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
309 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
312 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
314 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
317 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
319 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
322 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
324 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
327 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
329 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
332 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
334 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
337 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
339 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
342 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
344 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
347 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
349 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
352 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
354 static const DWRITE_GLYPH_METRICS nil;
355 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
357 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
358 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
359 return S_OK;
362 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
364 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
366 if (!*block) {
367 /* start new block */
368 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
369 if (!*block)
370 return E_OUTOFMEMORY;
373 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
374 return S_OK;
377 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
379 HRESULT hr;
381 if (table->data || !table->exists)
382 return table->data;
384 table->exists = FALSE;
385 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
386 &table->exists);
387 if (FAILED(hr) || !table->exists) {
388 TRACE("Font does not have %s table\n", debugstr_tag(tag));
389 return NULL;
392 return table->data;
395 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
396 struct dwrite_font_propvec *vec)
398 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
399 vec->style = style * 7.0f;
400 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
403 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
405 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
408 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
410 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
413 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
415 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
416 return &fontface->vdmx;
419 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
421 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
422 return &fontface->gasp;
425 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
427 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
428 return &fontface->cpal;
431 static void addref_font_data(struct dwrite_font_data *data)
433 InterlockedIncrement(&data->ref);
436 static void release_font_data(struct dwrite_font_data *data)
438 int i;
440 if (InterlockedDecrement(&data->ref) > 0)
441 return;
443 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
445 if (data->info_strings[i])
446 IDWriteLocalizedStrings_Release(data->info_strings[i]);
448 if (data->names)
449 IDWriteLocalizedStrings_Release(data->names);
451 if (data->family_names)
452 IDWriteLocalizedStrings_Release(data->family_names);
454 IDWriteFontFile_Release(data->file);
455 heap_free(data->facename);
456 heap_free(data);
459 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
461 size_t i;
463 if (InterlockedDecrement(&data->refcount) > 0)
464 return;
466 for (i = 0; i < data->count; ++i)
467 release_font_data(data->fonts[i]);
468 heap_free(data->fonts);
469 IDWriteLocalizedStrings_Release(data->familyname);
470 heap_free(data);
473 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
475 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
476 fontface->cached = NULL;
479 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
481 UINT32 left_key_size, right_key_size;
482 const void *left_key, *right_key;
483 HRESULT hr;
485 if (left == right)
486 return TRUE;
488 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
489 if (FAILED(hr))
490 return FALSE;
492 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
493 if (FAILED(hr))
494 return FALSE;
496 if (left_key_size != right_key_size)
497 return FALSE;
499 return !memcmp(left_key, right_key, left_key_size);
502 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
504 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
506 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
508 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
509 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
510 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
511 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
512 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
513 IsEqualIID(riid, &IID_IDWriteFontFace) ||
514 IsEqualIID(riid, &IID_IUnknown))
516 *obj = iface;
518 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
519 *obj = &fontface->IDWriteFontFaceReference_iface;
520 else
521 *obj = NULL;
523 if (*obj)
525 if (InterlockedIncrement(&fontface->refcount) == 1)
527 InterlockedDecrement(&fontface->refcount);
528 *obj = NULL;
529 return E_FAIL;
531 return S_OK;
534 WARN("%s not implemented.\n", debugstr_guid(riid));
536 return E_NOINTERFACE;
539 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
541 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
542 ULONG refcount = InterlockedIncrement(&fontface->refcount);
544 TRACE("%p, refcount %u.\n", iface, refcount);
546 return refcount;
549 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
551 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
552 ULONG refcount = InterlockedDecrement(&fontface->refcount);
554 TRACE("%p, refcount %u.\n", iface, refcount);
556 if (!refcount)
558 UINT32 i;
560 if (fontface->cached)
562 factory_lock(fontface->factory);
563 list_remove(&fontface->cached->entry);
564 factory_unlock(fontface->factory);
565 heap_free(fontface->cached);
567 release_scriptshaping_cache(fontface->shaping_cache);
568 if (fontface->cmap.context)
569 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cmap.context);
570 if (fontface->vdmx.context)
571 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
572 if (fontface->gasp.context)
573 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
574 if (fontface->cpal.context)
575 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
576 if (fontface->colr.context)
577 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
578 for (i = 0; i < fontface->file_count; i++)
580 if (fontface->files[i])
581 IDWriteFontFile_Release(fontface->files[i]);
583 if (fontface->stream)
584 IDWriteFontFileStream_Release(fontface->stream);
585 heap_free(fontface->files);
586 if (fontface->names)
587 IDWriteLocalizedStrings_Release(fontface->names);
588 if (fontface->family_names)
589 IDWriteLocalizedStrings_Release(fontface->family_names);
590 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
592 if (fontface->info_strings[i])
593 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
596 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
597 heap_free(fontface->glyphs[i]);
599 freetype_notify_cacheremove(iface);
601 IDWriteFactory7_Release(fontface->factory);
602 heap_free(fontface);
605 return refcount;
608 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
610 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
612 TRACE("%p.\n", iface);
614 return fontface->type;
617 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
618 IDWriteFontFile **fontfiles)
620 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
621 int i;
623 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
625 if (fontfiles == NULL)
627 *number_of_files = fontface->file_count;
628 return S_OK;
631 if (*number_of_files < fontface->file_count)
632 return E_INVALIDARG;
634 for (i = 0; i < fontface->file_count; i++)
636 IDWriteFontFile_AddRef(fontface->files[i]);
637 fontfiles[i] = fontface->files[i];
640 return S_OK;
643 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
645 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
647 TRACE("%p.\n", iface);
649 return fontface->index;
652 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
654 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
656 TRACE("%p.\n", iface);
658 return fontface->simulations;
661 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
663 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
665 TRACE("%p.\n", iface);
667 return !!(fontface->flags & FONT_IS_SYMBOL);
670 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
672 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
674 TRACE("%p, %p.\n", iface, metrics);
676 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
679 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
681 TRACE("%p.\n", iface);
683 return freetype_get_glyphcount(iface);
686 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
687 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
689 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
690 unsigned int i;
691 HRESULT hr;
693 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
695 if (!glyphs)
696 return E_INVALIDARG;
698 if (is_sideways)
699 FIXME("sideways metrics are not supported.\n");
701 for (i = 0; i < glyph_count; i++) {
702 DWRITE_GLYPH_METRICS metrics;
704 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
705 if (hr != S_OK) {
706 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
707 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
708 if (FAILED(hr))
709 return hr;
711 ret[i] = metrics;
714 return S_OK;
717 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
718 UINT32 count, UINT16 *glyphs)
720 if (!glyphs)
721 return E_INVALIDARG;
723 if (!codepoints) {
724 memset(glyphs, 0, count * sizeof(*glyphs));
725 return E_INVALIDARG;
728 freetype_get_glyphs(&fontface->IDWriteFontFace5_iface, fontface->charmap, codepoints, count, glyphs);
729 return S_OK;
732 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
733 UINT32 count, UINT16 *glyphs)
735 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
737 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
739 return fontface_get_glyphs(fontface, codepoints, count, glyphs);
742 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
743 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
745 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
746 struct file_stream_desc stream_desc;
748 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
750 stream_desc.stream = fontface->stream;
751 stream_desc.face_type = fontface->type;
752 stream_desc.face_index = fontface->index;
753 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
756 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
758 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
760 TRACE("%p, %p.\n", iface, table_context);
762 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
765 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
766 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
767 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
769 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
770 count, is_sideways, is_rtl, sink);
772 if (!glyphs || !sink)
773 return E_INVALIDARG;
775 if (is_sideways)
776 FIXME("sideways mode is not supported.\n");
778 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
781 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
782 float ppem, unsigned int gasp)
784 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
786 switch (measuring)
788 case DWRITE_MEASURING_MODE_NATURAL:
790 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
791 mode = DWRITE_RENDERING_MODE_NATURAL;
792 else
793 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
794 break;
796 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
797 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
798 break;
799 case DWRITE_MEASURING_MODE_GDI_NATURAL:
800 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
801 break;
802 default:
806 return mode;
809 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
810 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
812 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
813 unsigned int flags;
814 FLOAT ppem;
816 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
818 if (!params) {
819 *mode = DWRITE_RENDERING_MODE_DEFAULT;
820 return E_INVALIDARG;
823 *mode = IDWriteRenderingParams_GetRenderingMode(params);
824 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
825 return S_OK;
827 ppem = emSize * ppdip;
829 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
830 *mode = DWRITE_RENDERING_MODE_OUTLINE;
831 return S_OK;
834 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
835 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
836 return S_OK;
839 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
840 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
842 DWRITE_FONT_METRICS1 metrics1;
843 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
844 memcpy(metrics, &metrics1, sizeof(*metrics));
845 return hr;
848 static inline int round_metric(FLOAT metric)
850 return (int)floorf(metric + 0.5f);
853 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
855 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
856 return 0;
858 return (fontface->metrics.designUnitsPerEm + 49) / 50;
861 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
862 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
863 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
865 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
866 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
867 DWRITE_MEASURING_MODE mode;
868 FLOAT scale, size;
869 HRESULT hr;
870 UINT32 i;
872 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
873 glyph_count, metrics, is_sideways);
875 if (m && memcmp(m, &identity, sizeof(*m)))
876 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
878 size = emSize * ppdip;
879 scale = size / fontface->metrics.designUnitsPerEm;
880 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
882 for (i = 0; i < glyph_count; i++) {
883 DWRITE_GLYPH_METRICS *ret = metrics + i;
884 DWRITE_GLYPH_METRICS design;
885 BOOL has_contours;
887 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
888 if (FAILED(hr))
889 return hr;
891 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
892 if (has_contours)
893 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
894 else
895 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
897 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
898 SCALE_METRIC(leftSideBearing);
899 SCALE_METRIC(rightSideBearing);
900 SCALE_METRIC(topSideBearing);
901 SCALE_METRIC(advanceHeight);
902 SCALE_METRIC(bottomSideBearing);
903 SCALE_METRIC(verticalOriginY);
904 #undef SCALE_METRIC
907 return S_OK;
910 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
912 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
914 TRACE("%p, %p.\n", iface, metrics);
916 *metrics = fontface->metrics;
919 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
920 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
922 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
923 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
924 UINT16 ascent, descent;
925 FLOAT scale;
927 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
929 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
930 memset(metrics, 0, sizeof(*metrics));
931 return E_INVALIDARG;
934 em_size *= pixels_per_dip;
935 if (m && m->m22 != 0.0f)
936 em_size *= fabs(m->m22);
938 scale = em_size / design->designUnitsPerEm;
939 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
941 ascent = round_metric(design->ascent * scale);
942 descent = round_metric(design->descent * scale);
945 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
946 metrics->designUnitsPerEm = design->designUnitsPerEm;
947 metrics->ascent = round_metric(ascent / scale);
948 metrics->descent = round_metric(descent / scale);
950 SCALE_METRIC(lineGap);
951 SCALE_METRIC(capHeight);
952 SCALE_METRIC(xHeight);
953 SCALE_METRIC(underlinePosition);
954 SCALE_METRIC(underlineThickness);
955 SCALE_METRIC(strikethroughPosition);
956 SCALE_METRIC(strikethroughThickness);
957 SCALE_METRIC(glyphBoxLeft);
958 SCALE_METRIC(glyphBoxTop);
959 SCALE_METRIC(glyphBoxRight);
960 SCALE_METRIC(glyphBoxBottom);
961 SCALE_METRIC(subscriptPositionX);
962 SCALE_METRIC(subscriptPositionY);
963 SCALE_METRIC(subscriptSizeX);
964 SCALE_METRIC(subscriptSizeY);
965 SCALE_METRIC(superscriptPositionX);
966 SCALE_METRIC(superscriptPositionY);
967 SCALE_METRIC(superscriptSizeX);
968 SCALE_METRIC(superscriptSizeY);
970 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
971 #undef SCALE_METRIC
973 return S_OK;
976 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
978 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
980 TRACE("%p, %p.\n", iface, metrics);
982 *metrics = fontface->caret;
985 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
986 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
988 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
989 struct file_stream_desc stream_desc;
991 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
993 *count = 0;
994 if (max_count && !ranges)
995 return E_INVALIDARG;
997 stream_desc.stream = fontface->stream;
998 stream_desc.face_index = fontface->index;
999 stream_desc.face_type = fontface->type;
1000 return opentype_cmap_get_unicode_ranges(&stream_desc, max_count, ranges, count);
1003 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1005 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1007 TRACE("%p.\n", iface);
1009 return !!(fontface->flags & FONT_IS_MONOSPACED);
1012 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1013 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1015 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1016 BOOL has_contours;
1017 int advance;
1019 if (is_sideways)
1020 FIXME("Sideways mode is not supported.\n");
1022 switch (measuring_mode)
1024 case DWRITE_MEASURING_MODE_NATURAL:
1025 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1026 glyph, measuring_mode, &has_contours);
1027 if (has_contours)
1028 advance += adjustment;
1030 return advance;
1031 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1032 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1033 emsize *= ppdip;
1034 if (emsize == 0.0f)
1035 return 0.0f;
1037 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1038 FIXME("Transform is not supported.\n");
1040 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1041 &has_contours);
1042 if (has_contours)
1043 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1044 else
1045 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1047 return advance;
1048 default:
1049 WARN("Unknown measuring mode %u.\n", measuring_mode);
1050 return 0;
1054 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1055 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1057 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1058 unsigned int i;
1060 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1062 if (is_sideways)
1063 FIXME("sideways mode not supported\n");
1065 for (i = 0; i < glyph_count; ++i)
1067 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1068 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1071 return S_OK;
1074 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1075 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1076 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1078 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1079 DWRITE_MEASURING_MODE measuring_mode;
1080 UINT32 i;
1082 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1083 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1085 if (em_size < 0.0f || ppdip <= 0.0f) {
1086 memset(advances, 0, sizeof(*advances) * glyph_count);
1087 return E_INVALIDARG;
1090 if (em_size == 0.0f) {
1091 memset(advances, 0, sizeof(*advances) * glyph_count);
1092 return S_OK;
1095 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1096 for (i = 0; i < glyph_count; ++i)
1098 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1099 glyphs[i], is_sideways);
1102 return S_OK;
1105 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1106 const UINT16 *indices, INT32 *adjustments)
1108 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1109 UINT32 i;
1111 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1113 if (!(indices || adjustments) || !count)
1114 return E_INVALIDARG;
1116 if (!indices || count == 1) {
1117 memset(adjustments, 0, count*sizeof(INT32));
1118 return E_INVALIDARG;
1121 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1123 memset(adjustments, 0, count*sizeof(INT32));
1124 return S_OK;
1127 for (i = 0; i < count-1; i++)
1128 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1129 adjustments[count-1] = 0;
1131 return S_OK;
1134 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1136 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1138 TRACE("%p.\n", iface);
1140 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1143 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1144 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1145 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1147 DWRITE_GRID_FIT_MODE gridfitmode;
1148 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1149 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1152 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1153 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1155 FIXME("%p, %u, %p, %p: stub\n", iface, glyph_count, nominal_indices, vertical_indices);
1157 return E_NOTIMPL;
1160 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1162 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1164 TRACE("%p.\n", iface);
1166 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1169 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1171 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1173 TRACE("%p.\n", iface);
1175 return !!(fontface->flags & FONT_IS_COLORED);
1178 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1180 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1182 TRACE("%p.\n", iface);
1184 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1187 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1189 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1191 TRACE("%p.\n", iface);
1193 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1196 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1197 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1199 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1201 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1203 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1206 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1207 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1208 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1209 DWRITE_GRID_FIT_MODE *gridfitmode)
1211 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1212 unsigned int flags;
1213 FLOAT emthreshold;
1215 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1216 measuringmode, params, renderingmode, gridfitmode);
1218 if (m)
1219 FIXME("transform not supported %s\n", debugstr_matrix(m));
1221 if (is_sideways)
1222 FIXME("sideways mode not supported\n");
1224 emSize *= max(dpiX, dpiY) / 96.0f;
1226 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1227 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1228 if (params) {
1229 IDWriteRenderingParams2 *params2;
1230 HRESULT hr;
1232 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1233 if (hr == S_OK) {
1234 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1235 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1236 IDWriteRenderingParams2_Release(params2);
1238 else
1239 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1242 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1244 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1246 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1247 if (emSize >= emthreshold)
1248 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1249 else
1250 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1253 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1254 if (emSize >= emthreshold)
1255 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1256 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1257 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1258 else
1259 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1260 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1263 return S_OK;
1266 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1267 IDWriteFontFaceReference **reference)
1269 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1271 TRACE("%p, %p.\n", iface, reference);
1273 *reference = &fontface->IDWriteFontFaceReference_iface;
1274 IDWriteFontFaceReference_AddRef(*reference);
1276 return S_OK;
1279 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1281 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1283 TRACE("%p, %p.\n", iface, panose);
1285 *panose = fontface->panose;
1288 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1290 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1292 TRACE("%p.\n", iface);
1294 return fontface->weight;
1297 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1299 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1301 TRACE("%p.\n", iface);
1303 return fontface->stretch;
1306 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1308 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1310 TRACE("%p.\n", iface);
1312 return fontface->style;
1315 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1317 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1319 TRACE("%p, %p.\n", iface, names);
1321 return clone_localizedstrings(fontface->family_names, names);
1324 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1326 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1328 TRACE("%p, %p.\n", iface, names);
1330 return clone_localizedstrings(fontface->names, names);
1333 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1334 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1335 IDWriteLocalizedStrings **ret, BOOL *exists)
1337 HRESULT hr = S_OK;
1339 *exists = FALSE;
1340 *ret = NULL;
1342 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1343 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1345 return S_OK;
1348 if (!strings_cache[stringid])
1350 struct file_stream_desc desc = *stream_desc;
1352 if (!desc.stream)
1353 hr = get_filestream_from_file(file, &desc.stream);
1354 if (SUCCEEDED(hr))
1355 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1357 if (!stream_desc->stream && desc.stream)
1358 IDWriteFontFileStream_Release(desc.stream);
1361 if (SUCCEEDED(hr) && strings_cache[stringid])
1363 hr = clone_localizedstrings(strings_cache[stringid], ret);
1364 if (SUCCEEDED(hr))
1365 *exists = TRUE;
1368 return hr;
1371 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1372 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1374 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1375 struct file_stream_desc stream_desc;
1377 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1379 stream_desc.stream = fontface->stream;
1380 stream_desc.face_index = fontface->index;
1381 stream_desc.face_type = fontface->type;
1382 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1385 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1387 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1388 UINT16 index;
1390 TRACE("%p, %#x.\n", iface, ch);
1392 index = 0;
1393 if (FAILED(fontface_get_glyphs(fontface, &ch, 1, &index)))
1394 return FALSE;
1396 return index != 0;
1399 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1400 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1401 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1403 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1404 unsigned int flags;
1405 FLOAT emthreshold;
1407 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1408 measuring_mode, params, rendering_mode, gridfit_mode);
1410 if (m)
1411 FIXME("transform not supported %s\n", debugstr_matrix(m));
1413 if (is_sideways)
1414 FIXME("sideways mode not supported\n");
1416 emSize *= max(dpiX, dpiY) / 96.0f;
1418 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1419 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1420 if (params) {
1421 IDWriteRenderingParams3 *params3;
1422 HRESULT hr;
1424 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1425 if (hr == S_OK) {
1426 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1427 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1428 IDWriteRenderingParams3_Release(params3);
1430 else
1431 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1434 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1436 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1438 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1439 if (emSize >= emthreshold)
1440 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1441 else
1442 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1445 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1446 if (emSize >= emthreshold)
1447 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1448 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1449 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1450 else
1451 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1452 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1455 return S_OK;
1458 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1460 FIXME("%p, %#x: stub\n", iface, ch);
1462 return FALSE;
1465 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1467 FIXME("%p, %u: stub\n", iface, glyph);
1469 return FALSE;
1472 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1473 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1475 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1477 return E_NOTIMPL;
1480 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1481 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1483 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1485 return E_NOTIMPL;
1488 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1489 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1491 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1493 return E_NOTIMPL;
1496 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1498 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1500 TRACE("%p.\n", iface);
1502 return fontface->glyph_image_formats;
1505 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1506 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1508 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1510 return E_NOTIMPL;
1513 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1515 FIXME("%p, %p: stub\n", iface, context);
1518 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1520 FIXME("%p: stub\n", iface);
1522 return 0;
1525 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1526 UINT32 value_count)
1528 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1530 return E_NOTIMPL;
1533 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1535 FIXME("%p: stub\n", iface);
1537 return FALSE;
1540 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1542 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1544 TRACE("%p, %p.\n", iface, resource);
1546 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1549 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1551 dwritefontface_QueryInterface,
1552 dwritefontface_AddRef,
1553 dwritefontface_Release,
1554 dwritefontface_GetType,
1555 dwritefontface_GetFiles,
1556 dwritefontface_GetIndex,
1557 dwritefontface_GetSimulations,
1558 dwritefontface_IsSymbolFont,
1559 dwritefontface_GetMetrics,
1560 dwritefontface_GetGlyphCount,
1561 dwritefontface_GetDesignGlyphMetrics,
1562 dwritefontface_GetGlyphIndices,
1563 dwritefontface_TryGetFontTable,
1564 dwritefontface_ReleaseFontTable,
1565 dwritefontface_GetGlyphRunOutline,
1566 dwritefontface_GetRecommendedRenderingMode,
1567 dwritefontface_GetGdiCompatibleMetrics,
1568 dwritefontface_GetGdiCompatibleGlyphMetrics,
1569 dwritefontface1_GetMetrics,
1570 dwritefontface1_GetGdiCompatibleMetrics,
1571 dwritefontface1_GetCaretMetrics,
1572 dwritefontface1_GetUnicodeRanges,
1573 dwritefontface1_IsMonospacedFont,
1574 dwritefontface1_GetDesignGlyphAdvances,
1575 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1576 dwritefontface1_GetKerningPairAdjustments,
1577 dwritefontface1_HasKerningPairs,
1578 dwritefontface1_GetRecommendedRenderingMode,
1579 dwritefontface1_GetVerticalGlyphVariants,
1580 dwritefontface1_HasVerticalGlyphVariants,
1581 dwritefontface2_IsColorFont,
1582 dwritefontface2_GetColorPaletteCount,
1583 dwritefontface2_GetPaletteEntryCount,
1584 dwritefontface2_GetPaletteEntries,
1585 dwritefontface2_GetRecommendedRenderingMode,
1586 dwritefontface3_GetFontFaceReference,
1587 dwritefontface3_GetPanose,
1588 dwritefontface3_GetWeight,
1589 dwritefontface3_GetStretch,
1590 dwritefontface3_GetStyle,
1591 dwritefontface3_GetFamilyNames,
1592 dwritefontface3_GetFaceNames,
1593 dwritefontface3_GetInformationalStrings,
1594 dwritefontface3_HasCharacter,
1595 dwritefontface3_GetRecommendedRenderingMode,
1596 dwritefontface3_IsCharacterLocal,
1597 dwritefontface3_IsGlyphLocal,
1598 dwritefontface3_AreCharactersLocal,
1599 dwritefontface3_AreGlyphsLocal,
1600 dwritefontface4_GetGlyphImageFormats_,
1601 dwritefontface4_GetGlyphImageFormats,
1602 dwritefontface4_GetGlyphImageData,
1603 dwritefontface4_ReleaseGlyphImageData,
1604 dwritefontface5_GetFontAxisValueCount,
1605 dwritefontface5_GetFontAxisValues,
1606 dwritefontface5_HasVariations,
1607 dwritefontface5_GetFontResource,
1610 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1612 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1613 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1616 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1618 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1619 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1622 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1624 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1625 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1628 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1629 IDWriteFontFace3 **ret)
1631 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1633 TRACE("%p, %p.\n", iface, ret);
1635 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1636 IDWriteFontFace3_AddRef(*ret);
1638 return S_OK;
1641 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1642 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1644 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1645 DWRITE_FONT_FILE_TYPE file_type;
1646 DWRITE_FONT_FACE_TYPE face_type;
1647 IDWriteFontFace *face;
1648 BOOL is_supported;
1649 UINT32 face_num;
1650 HRESULT hr;
1652 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1654 hr = IDWriteFontFile_Analyze(fontface->files[0], &is_supported, &file_type, &face_type, &face_num);
1655 if (FAILED(hr))
1656 return hr;
1658 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, fontface->files, fontface->index,
1659 simulations, &face);
1660 if (SUCCEEDED(hr))
1662 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1663 IDWriteFontFace_Release(face);
1666 return hr;
1669 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1671 FIXME("%p, %p.\n", iface, ref);
1673 return E_NOTIMPL;
1676 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1678 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1680 TRACE("%p.\n", iface);
1682 return fontface->index;
1685 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1687 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1689 TRACE("%p.\n", iface);
1691 return fontface->simulations;
1694 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1696 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1698 TRACE("%p, %p.\n", iface, file);
1700 *file = fontface->files[0];
1701 IDWriteFontFile_AddRef(*file);
1703 return S_OK;
1706 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1708 FIXME("%p.\n", iface);
1710 return 0;
1713 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1715 FIXME("%p.\n", iface);
1717 return 0;
1720 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1722 FIXME("%p, %p.\n", iface, writetime);
1724 return E_NOTIMPL;
1727 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1729 FIXME("%p.\n", iface);
1731 return DWRITE_LOCALITY_LOCAL;
1734 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1736 FIXME("%p.\n", iface);
1738 return E_NOTIMPL;
1741 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1742 WCHAR const *chars, UINT32 count)
1744 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1746 return E_NOTIMPL;
1749 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1750 UINT16 const *glyphs, UINT32 count)
1752 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1754 return E_NOTIMPL;
1757 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1758 UINT64 offset, UINT64 size)
1760 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1762 return E_NOTIMPL;
1765 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1767 dwritefontface_reference_QueryInterface,
1768 dwritefontface_reference_AddRef,
1769 dwritefontface_reference_Release,
1770 dwritefontface_reference_CreateFontFace,
1771 dwritefontface_reference_CreateFontFaceWithSimulations,
1772 dwritefontface_reference_Equals,
1773 dwritefontface_reference_GetFontFaceIndex,
1774 dwritefontface_reference_GetSimulations,
1775 dwritefontface_reference_GetFontFile,
1776 dwritefontface_reference_GetLocalFileSize,
1777 dwritefontface_reference_GetFileSize,
1778 dwritefontface_reference_GetFileTime,
1779 dwritefontface_reference_GetLocality,
1780 dwritefontface_reference_EnqueueFontDownloadRequest,
1781 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1782 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1783 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1786 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1788 struct dwrite_font_data *data = font->data;
1789 struct fontface_desc desc;
1790 struct list *cached_list;
1791 HRESULT hr;
1793 *fontface = NULL;
1795 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1796 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1797 if (hr == S_OK)
1798 return hr;
1800 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1801 return hr;
1803 desc.factory = font->family->collection->factory;
1804 desc.face_type = data->face_type;
1805 desc.files = &data->file;
1806 desc.files_number = 1;
1807 desc.index = data->face_index;
1808 desc.simulations = data->simulations;
1809 desc.font_data = data;
1810 hr = create_fontface(&desc, cached_list, fontface);
1812 IDWriteFontFileStream_Release(desc.stream);
1813 return hr;
1816 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1818 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1820 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1822 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1823 IsEqualIID(riid, &IID_IDWriteFont2) ||
1824 IsEqualIID(riid, &IID_IDWriteFont1) ||
1825 IsEqualIID(riid, &IID_IDWriteFont) ||
1826 IsEqualIID(riid, &IID_IUnknown))
1828 *obj = iface;
1829 IDWriteFont3_AddRef(iface);
1830 return S_OK;
1833 WARN("%s not implemented.\n", debugstr_guid(riid));
1835 *obj = NULL;
1836 return E_NOINTERFACE;
1839 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1841 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1842 ULONG ref = InterlockedIncrement(&This->ref);
1843 TRACE("(%p)->(%d)\n", This, ref);
1844 return ref;
1847 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1849 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1850 ULONG ref = InterlockedDecrement(&This->ref);
1852 TRACE("(%p)->(%d)\n", This, ref);
1854 if (!ref) {
1855 IDWriteFontFamily2_Release(&This->family->IDWriteFontFamily2_iface);
1856 release_font_data(This->data);
1857 heap_free(This);
1860 return ref;
1863 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1865 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1866 TRACE("(%p)->(%p)\n", This, family);
1868 *family = (IDWriteFontFamily*)This->family;
1869 IDWriteFontFamily_AddRef(*family);
1870 return S_OK;
1873 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1875 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1876 TRACE("(%p)\n", This);
1877 return This->data->weight;
1880 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1882 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1883 TRACE("(%p)\n", This);
1884 return This->data->stretch;
1887 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1889 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1890 TRACE("(%p)\n", This);
1891 return This->style;
1894 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1896 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1898 TRACE("%p.\n", iface);
1900 return !!(font->data->flags & FONT_IS_SYMBOL);
1903 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1905 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1907 TRACE("%p, %p.\n", iface, names);
1909 return clone_localizedstrings(font->data->names, names);
1912 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1913 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1915 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1916 struct dwrite_font_data *data = font->data;
1917 struct file_stream_desc stream_desc;
1919 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1921 /* Stream will be created if necessary. */
1922 stream_desc.stream = NULL;
1923 stream_desc.face_index = data->face_index;
1924 stream_desc.face_type = data->face_type;
1925 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1928 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1930 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1931 TRACE("(%p)\n", This);
1932 return This->data->simulations;
1935 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1937 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1939 TRACE("(%p)->(%p)\n", This, metrics);
1940 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1943 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1945 IDWriteFontFace5 *fontface;
1946 UINT16 index;
1947 HRESULT hr;
1949 *exists = FALSE;
1951 hr = get_fontface_from_font(font, &fontface);
1952 if (FAILED(hr))
1953 return hr;
1955 index = 0;
1956 hr = IDWriteFontFace5_GetGlyphIndices(fontface, &ch, 1, &index);
1957 IDWriteFontFace5_Release(fontface);
1958 if (FAILED(hr))
1959 return hr;
1961 *exists = index != 0;
1962 return S_OK;
1965 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1967 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1969 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1971 return font_has_character(This, ch, exists);
1974 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1976 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1978 TRACE("%p, %p.\n", iface, fontface);
1980 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
1983 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1985 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1986 TRACE("(%p)->(%p)\n", This, metrics);
1987 *metrics = This->data->metrics;
1990 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1992 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1993 TRACE("(%p)->(%p)\n", This, panose);
1994 *panose = This->data->panose;
1997 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
1998 UINT32 *count)
2000 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2001 struct file_stream_desc stream_desc;
2002 HRESULT hr;
2004 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2006 *count = 0;
2007 if (max_count && !ranges)
2008 return E_INVALIDARG;
2010 if (FAILED(hr = get_filestream_from_file(font->data->file, &stream_desc.stream)))
2011 return hr;
2012 stream_desc.face_index = font->data->face_index;
2013 stream_desc.face_type = font->data->face_type;
2014 hr = opentype_cmap_get_unicode_ranges(&stream_desc, max_count, ranges, count);
2015 IDWriteFontFileStream_Release(stream_desc.stream);
2016 return hr;
2019 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2021 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2023 TRACE("%p.\n", iface);
2025 return !!(font->data->flags & FONT_IS_MONOSPACED);
2028 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2030 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2032 TRACE("%p.\n", iface);
2034 return !!(font->data->flags & FONT_IS_COLORED);
2037 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2039 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2041 TRACE("%p, %p.\n", iface, fontface);
2043 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2046 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2048 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2050 TRACE("%p, %p.\n", iface, other);
2052 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2053 return FALSE;
2055 return font->data->face_index == other_font->data->face_index
2056 && font->data->simulations == other_font->data->simulations
2057 && is_same_fontfile(font->data->file, other_font->data->file);
2060 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2062 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2064 TRACE("%p, %p.\n", iface, reference);
2066 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2067 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2068 (IDWriteFontFaceReference1 **)reference);
2071 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2073 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
2074 BOOL ret;
2076 TRACE("(%p)->(%#x)\n", This, ch);
2078 return font_has_character(This, ch, &ret) == S_OK && ret;
2081 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2083 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
2084 FIXME("(%p): stub\n", This);
2085 return DWRITE_LOCALITY_LOCAL;
2088 static const IDWriteFont3Vtbl dwritefontvtbl = {
2089 dwritefont_QueryInterface,
2090 dwritefont_AddRef,
2091 dwritefont_Release,
2092 dwritefont_GetFontFamily,
2093 dwritefont_GetWeight,
2094 dwritefont_GetStretch,
2095 dwritefont_GetStyle,
2096 dwritefont_IsSymbolFont,
2097 dwritefont_GetFaceNames,
2098 dwritefont_GetInformationalStrings,
2099 dwritefont_GetSimulations,
2100 dwritefont_GetMetrics,
2101 dwritefont_HasCharacter,
2102 dwritefont_CreateFontFace,
2103 dwritefont1_GetMetrics,
2104 dwritefont1_GetPanose,
2105 dwritefont1_GetUnicodeRanges,
2106 dwritefont1_IsMonospacedFont,
2107 dwritefont2_IsColorFont,
2108 dwritefont3_CreateFontFace,
2109 dwritefont3_Equals,
2110 dwritefont3_GetFontFaceReference,
2111 dwritefont3_HasCharacter,
2112 dwritefont3_GetLocality
2115 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2117 if (!iface)
2118 return NULL;
2119 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2120 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2123 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2125 if (!iface)
2126 return NULL;
2127 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2128 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2131 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2133 if (!iface)
2134 return NULL;
2135 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2136 return NULL;
2137 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2138 IDWriteFontFaceReference1_iface);
2141 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2143 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2144 *lf = font->data->lf;
2147 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2149 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2150 *lf = fontface->lf;
2153 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2155 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2156 *fontsig = font->data->fontsig;
2157 return S_OK;
2160 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2162 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2163 *fontsig = fontface->fontsig;
2164 return S_OK;
2167 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2169 struct dwrite_font *This;
2171 *font = NULL;
2173 This = heap_alloc(sizeof(*This));
2174 if (!This)
2175 return E_OUTOFMEMORY;
2177 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2178 This->ref = 1;
2179 This->family = family;
2180 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2181 This->data = family->data->fonts[index];
2182 This->style = This->data->style;
2183 addref_font_data(This->data);
2185 *font = &This->IDWriteFont3_iface;
2187 return S_OK;
2190 /* IDWriteFontList2 */
2191 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2193 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2195 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2196 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2197 IsEqualIID(riid, &IID_IDWriteFontList) ||
2198 IsEqualIID(riid, &IID_IUnknown))
2200 *obj = iface;
2201 IDWriteFontList2_AddRef(iface);
2202 return S_OK;
2205 WARN("%s not implemented.\n", debugstr_guid(riid));
2207 *obj = NULL;
2208 return E_NOINTERFACE;
2211 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2213 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2214 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2216 TRACE("%p, refcount %u.\n", iface, refcount);
2218 return refcount;
2221 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2223 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2224 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2226 TRACE("%p, refcount %u.\n", iface, refcount);
2228 if (!refcount)
2230 UINT32 i;
2232 for (i = 0; i < fontlist->font_count; i++)
2233 release_font_data(fontlist->fonts[i]);
2234 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2235 heap_free(fontlist->fonts);
2236 heap_free(fontlist);
2239 return refcount;
2242 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2244 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2245 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2248 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2250 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2252 TRACE("%p.\n", iface);
2254 return fontlist->font_count;
2257 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2259 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2261 TRACE("%p, %u, %p.\n", iface, index, font);
2263 *font = NULL;
2265 if (fontlist->font_count == 0)
2266 return S_FALSE;
2268 if (index >= fontlist->font_count)
2269 return E_INVALIDARG;
2271 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2274 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2276 FIXME("%p, %u.\n", iface, index);
2278 return DWRITE_LOCALITY_LOCAL;
2281 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2283 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2285 TRACE("%p, %u, %p.\n", iface, index, font);
2287 *font = NULL;
2289 if (fontlist->font_count == 0)
2290 return S_FALSE;
2292 if (index >= fontlist->font_count)
2293 return E_FAIL;
2295 return create_font(fontlist->family, index, font);
2298 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2299 IDWriteFontFaceReference **reference)
2301 IDWriteFont3 *font;
2302 HRESULT hr;
2304 TRACE("%p, %u, %p.\n", iface, index, reference);
2306 *reference = NULL;
2308 hr = IDWriteFontList2_GetFont(iface, index, &font);
2309 if (FAILED(hr))
2310 return hr;
2312 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2313 IDWriteFont3_Release(font);
2315 return hr;
2318 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2320 FIXME("%p, %p.\n", iface, fontset);
2322 return E_NOTIMPL;
2325 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2327 dwritefontlist_QueryInterface,
2328 dwritefontlist_AddRef,
2329 dwritefontlist_Release,
2330 dwritefontlist_GetFontCollection,
2331 dwritefontlist_GetFontCount,
2332 dwritefontlist_GetFont,
2333 dwritefontlist1_GetFontLocality,
2334 dwritefontlist1_GetFont,
2335 dwritefontlist1_GetFontFaceReference,
2336 dwritefontlist2_GetFontSet,
2339 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2341 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2343 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2345 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2346 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2347 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2348 IsEqualIID(riid, &IID_IUnknown))
2350 *obj = iface;
2352 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2353 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2354 IsEqualIID(riid, &IID_IDWriteFontList))
2356 *obj = &family->IDWriteFontList2_iface;
2358 else
2360 WARN("%s not implemented.\n", debugstr_guid(riid));
2361 *obj = NULL;
2362 return E_NOINTERFACE;
2365 IUnknown_AddRef((IUnknown *)*obj);
2366 return S_OK;
2369 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2371 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2372 ULONG refcount = InterlockedIncrement(&family->refcount);
2374 TRACE("%p, %u.\n", iface, refcount);
2376 return refcount;
2379 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2381 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2382 ULONG refcount = InterlockedDecrement(&family->refcount);
2384 TRACE("%p, %u.\n", iface, refcount);
2386 if (!refcount)
2388 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2389 release_fontfamily_data(family->data);
2390 heap_free(family);
2393 return refcount;
2396 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2398 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2400 TRACE("%p, %p.\n", iface, collection);
2402 *collection = (IDWriteFontCollection *)family->collection;
2403 IDWriteFontCollection_AddRef(*collection);
2404 return S_OK;
2407 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2409 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2411 TRACE("%p.\n", iface);
2413 return family->data->count;
2416 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2418 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2420 TRACE("%p, %u, %p.\n", iface, index, font);
2422 *font = NULL;
2424 if (!family->data->count)
2425 return S_FALSE;
2427 if (index >= family->data->count)
2428 return E_INVALIDARG;
2430 return create_font(family, index, (IDWriteFont3 **)font);
2433 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2435 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2437 TRACE("%p, %p.\n", iface, names);
2439 return clone_localizedstrings(family->data->familyname, names);
2442 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2443 const struct dwrite_font_propvec *req)
2445 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2446 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2447 FLOAT cur_req_prod, next_req_prod;
2449 if (next_to_req < cur_to_req)
2450 return TRUE;
2452 if (next_to_req > cur_to_req)
2453 return FALSE;
2455 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2456 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2458 if (next_req_prod > cur_req_prod)
2459 return TRUE;
2461 if (next_req_prod < cur_req_prod)
2462 return FALSE;
2464 if (next->stretch > cur->stretch)
2465 return TRUE;
2466 if (next->stretch < cur->stretch)
2467 return FALSE;
2469 if (next->style > cur->style)
2470 return TRUE;
2471 if (next->style < cur->style)
2472 return FALSE;
2474 if (next->weight > cur->weight)
2475 return TRUE;
2476 if (next->weight < cur->weight)
2477 return FALSE;
2479 /* full match, no reason to prefer new variant */
2480 return FALSE;
2483 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2484 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2486 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2487 struct dwrite_font_propvec req;
2488 size_t i, match;
2490 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2492 if (!family->data->count)
2494 *font = NULL;
2495 return DWRITE_E_NOFONT;
2498 init_font_prop_vec(weight, stretch, style, &req);
2499 match = 0;
2501 for (i = 1; i < family->data->count; ++i)
2503 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2504 match = i;
2507 return create_font(family, match, (IDWriteFont3 **)font);
2510 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2512 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2514 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2517 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2519 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2522 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2524 UINT32 b = fonts->font_count - 1, j, t;
2526 while (1) {
2527 t = b;
2529 for (j = 0; j < b; j++) {
2530 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2531 struct dwrite_font_data *s = fonts->fonts[j];
2532 fonts->fonts[j] = fonts->fonts[j+1];
2533 fonts->fonts[j+1] = s;
2534 t = j;
2538 if (t == b)
2539 break;
2540 b = t;
2544 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2545 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2547 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2548 matching_filter_func func = NULL;
2549 struct dwrite_font_propvec req;
2550 struct dwrite_fontlist *fonts;
2551 size_t i;
2553 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2555 *ret = NULL;
2557 fonts = heap_alloc(sizeof(*fonts));
2558 if (!fonts)
2559 return E_OUTOFMEMORY;
2561 /* Allocate as many as family has, not all of them will be necessary used. */
2562 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2563 if (!fonts->fonts) {
2564 heap_free(fonts);
2565 return E_OUTOFMEMORY;
2568 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2569 fonts->refcount = 1;
2570 fonts->family = family;
2571 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2572 fonts->font_count = 0;
2574 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2575 if (style == DWRITE_FONT_STYLE_NORMAL) {
2576 if (family->data->has_normal_face || family->data->has_italic_face)
2577 func = is_font_acceptable_for_normal;
2579 else /* requested oblique or italic */ {
2580 if (family->data->has_oblique_face || family->data->has_italic_face)
2581 func = is_font_acceptable_for_oblique_italic;
2584 for (i = 0; i < family->data->count; ++i)
2586 if (!func || func(family->data->fonts[i]))
2588 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2589 addref_font_data(family->data->fonts[i]);
2590 fonts->font_count++;
2594 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2595 init_font_prop_vec(weight, stretch, style, &req);
2596 matchingfonts_sort(fonts, &req);
2598 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2599 return S_OK;
2602 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2604 FIXME("%p, %u.\n", iface, index);
2606 return DWRITE_LOCALITY_LOCAL;
2609 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2611 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2613 TRACE("%p, %u, %p.\n", iface, index, font);
2615 *font = NULL;
2617 if (!family->data->count)
2618 return S_FALSE;
2620 if (index >= family->data->count)
2621 return E_FAIL;
2623 return create_font(family, index, font);
2626 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2627 IDWriteFontFaceReference **reference)
2629 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2630 const struct dwrite_font_data *font;
2632 TRACE("%p, %u, %p.\n", iface, index, reference);
2634 *reference = NULL;
2636 if (index >= family->data->count)
2637 return E_FAIL;
2639 font = family->data->fonts[index];
2640 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2641 font->file, font->face_index, font->simulations, reference);
2644 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2645 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2647 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2649 return E_NOTIMPL;
2652 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2654 FIXME("%p, %p.\n", iface, fontset);
2656 return E_NOTIMPL;
2659 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2661 dwritefontfamily_QueryInterface,
2662 dwritefontfamily_AddRef,
2663 dwritefontfamily_Release,
2664 dwritefontfamily_GetFontCollection,
2665 dwritefontfamily_GetFontCount,
2666 dwritefontfamily_GetFont,
2667 dwritefontfamily_GetFamilyNames,
2668 dwritefontfamily_GetFirstMatchingFont,
2669 dwritefontfamily_GetMatchingFonts,
2670 dwritefontfamily1_GetFontLocality,
2671 dwritefontfamily1_GetFont,
2672 dwritefontfamily1_GetFontFaceReference,
2673 dwritefontfamily2_GetMatchingFonts,
2674 dwritefontfamily2_GetFontSet,
2677 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2679 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2680 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2683 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2685 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2686 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2689 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2691 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2692 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2695 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2696 IDWriteFontCollection **collection)
2698 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2699 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2702 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2704 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2705 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2708 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2710 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2711 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2714 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2716 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2717 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2720 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2722 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2723 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2726 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2727 IDWriteFontFaceReference **reference)
2729 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2730 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2733 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2735 FIXME("%p, %p.\n", iface, fontset);
2737 return E_NOTIMPL;
2740 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2742 dwritefontfamilylist_QueryInterface,
2743 dwritefontfamilylist_AddRef,
2744 dwritefontfamilylist_Release,
2745 dwritefontfamilylist_GetFontCollection,
2746 dwritefontfamilylist_GetFontCount,
2747 dwritefontfamilylist_GetFont,
2748 dwritefontfamilylist1_GetFontLocality,
2749 dwritefontfamilylist1_GetFont,
2750 dwritefontfamilylist1_GetFontFaceReference,
2751 dwritefontfamilylist2_GetFontSet,
2754 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2755 struct dwrite_fontfamily **family)
2757 struct dwrite_fontfamily *object;
2759 *family = NULL;
2761 object = heap_alloc(sizeof(*object));
2762 if (!object)
2763 return E_OUTOFMEMORY;
2765 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2766 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2767 object->refcount = 1;
2768 object->collection = collection;
2769 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2770 object->data = collection->family_data[index];
2771 InterlockedIncrement(&object->data->refcount);
2773 *family = object;
2775 return S_OK;
2778 BOOL is_system_collection(IDWriteFontCollection *collection)
2780 void *obj;
2781 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2784 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2786 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2788 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2790 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2791 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2792 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2793 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2794 IsEqualIID(riid, &IID_IUnknown))
2796 *obj = iface;
2797 IDWriteFontCollection3_AddRef(iface);
2798 return S_OK;
2801 *obj = NULL;
2803 if (IsEqualIID(riid, &IID_issystemcollection))
2804 return S_OK;
2806 WARN("%s not implemented.\n", debugstr_guid(riid));
2808 return E_NOINTERFACE;
2811 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2813 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2815 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2816 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2817 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2818 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2819 IsEqualIID(riid, &IID_IUnknown))
2821 *obj = iface;
2822 IDWriteFontCollection3_AddRef(iface);
2823 return S_OK;
2826 WARN("%s not implemented.\n", debugstr_guid(riid));
2828 *obj = NULL;
2830 return E_NOINTERFACE;
2833 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2835 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2836 ULONG refcount = InterlockedIncrement(&collection->refcount);
2838 TRACE("%p, refcount %d.\n", collection, refcount);
2840 return refcount;
2843 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2845 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2846 ULONG refcount = InterlockedDecrement(&collection->refcount);
2847 size_t i;
2849 TRACE("%p, refcount %d.\n", iface, refcount);
2851 if (!refcount)
2853 factory_detach_fontcollection(collection->factory, iface);
2854 for (i = 0; i < collection->count; ++i)
2855 release_fontfamily_data(collection->family_data[i]);
2856 heap_free(collection->family_data);
2857 heap_free(collection);
2860 return refcount;
2863 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2865 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2867 TRACE("%p.\n", iface);
2869 return collection->count;
2872 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2873 IDWriteFontFamily **ret)
2875 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2876 struct dwrite_fontfamily *family;
2877 HRESULT hr;
2879 TRACE("%p, %u, %p.\n", iface, index, ret);
2881 *ret = NULL;
2883 if (index >= collection->count)
2884 return E_FAIL;
2886 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2887 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2889 return hr;
2892 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2894 size_t i;
2896 for (i = 0; i < collection->count; ++i)
2898 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2899 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2900 HRESULT hr;
2902 for (j = 0; j < count; j++) {
2903 WCHAR buffer[255];
2904 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2905 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2906 return i;
2910 return ~0u;
2913 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2914 UINT32 *index, BOOL *exists)
2916 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2918 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2920 *index = collection_find_family(collection, name);
2921 *exists = *index != ~0u;
2922 return S_OK;
2925 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2926 IDWriteFont **font)
2928 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2929 struct dwrite_fontfamily *family;
2930 BOOL found_font = FALSE;
2931 IDWriteFontFile *file;
2932 UINT32 face_index, count;
2933 size_t i, j;
2934 HRESULT hr;
2936 TRACE("%p, %p, %p.\n", iface, face, font);
2938 *font = NULL;
2940 if (!face)
2941 return E_INVALIDARG;
2943 count = 1;
2944 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2945 if (FAILED(hr))
2946 return hr;
2947 face_index = IDWriteFontFace_GetIndex(face);
2949 found_font = FALSE;
2950 for (i = 0; i < collection->count; ++i)
2952 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2954 for (j = 0; j < family_data->count; ++j)
2956 struct dwrite_font_data *font_data = family_data->fonts[j];
2958 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2959 found_font = TRUE;
2960 break;
2964 if (found_font)
2965 break;
2967 IDWriteFontFile_Release(file);
2969 if (!found_font)
2970 return DWRITE_E_NOFONT;
2972 hr = create_fontfamily(collection, i, &family);
2973 if (FAILED(hr))
2974 return hr;
2976 hr = create_font(family, j, (IDWriteFont3 **)font);
2977 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
2978 return hr;
2981 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
2983 FIXME("%p, %p.\n", iface, fontset);
2985 return E_NOTIMPL;
2988 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2989 IDWriteFontFamily1 **ret)
2991 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2992 struct dwrite_fontfamily *family;
2993 HRESULT hr;
2995 TRACE("%p, %u, %p.\n", iface, index, ret);
2997 *ret = NULL;
2999 if (index >= collection->count)
3000 return E_FAIL;
3002 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3003 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3005 return hr;
3008 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3009 UINT32 index, IDWriteFontFamily2 **family)
3011 FIXME("%p, %u, %p.\n", iface, index, family);
3013 return E_NOTIMPL;
3016 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3017 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3018 IDWriteFontList2 **fontlist)
3020 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3022 return E_NOTIMPL;
3025 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3027 FIXME("%p.\n", iface);
3029 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3032 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3034 FIXME("%p, %p.\n", iface, fontset);
3036 return E_NOTIMPL;
3039 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3041 FIXME("%p.\n", iface);
3043 return NULL;
3046 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3048 dwritefontcollection_QueryInterface,
3049 dwritefontcollection_AddRef,
3050 dwritefontcollection_Release,
3051 dwritefontcollection_GetFontFamilyCount,
3052 dwritefontcollection_GetFontFamily,
3053 dwritefontcollection_FindFamilyName,
3054 dwritefontcollection_GetFontFromFontFace,
3055 dwritefontcollection1_GetFontSet,
3056 dwritefontcollection1_GetFontFamily,
3057 dwritefontcollection2_GetFontFamily,
3058 dwritefontcollection2_GetMatchingFonts,
3059 dwritefontcollection2_GetFontFamilyModel,
3060 dwritefontcollection2_GetFontSet,
3061 dwritefontcollection3_GetExpirationEvent,
3064 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3066 dwritesystemfontcollection_QueryInterface,
3067 dwritefontcollection_AddRef,
3068 dwritefontcollection_Release,
3069 dwritefontcollection_GetFontFamilyCount,
3070 dwritefontcollection_GetFontFamily,
3071 dwritefontcollection_FindFamilyName,
3072 dwritefontcollection_GetFontFromFontFace,
3073 dwritefontcollection1_GetFontSet,
3074 dwritefontcollection1_GetFontFamily,
3075 dwritefontcollection2_GetFontFamily,
3076 dwritefontcollection2_GetMatchingFonts,
3077 dwritefontcollection2_GetFontFamilyModel,
3078 dwritefontcollection2_GetFontSet,
3079 dwritefontcollection3_GetExpirationEvent,
3082 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3084 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3085 sizeof(*family_data->fonts)))
3087 return E_OUTOFMEMORY;
3090 family_data->fonts[family_data->count++] = font_data;
3091 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3092 family_data->has_normal_face = 1;
3093 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3094 family_data->has_oblique_face = 1;
3095 else
3096 family_data->has_italic_face = 1;
3097 return S_OK;
3100 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3101 struct dwrite_fontfamily_data *family)
3103 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3104 sizeof(*collection->family_data)))
3106 return E_OUTOFMEMORY;
3109 collection->family_data[collection->count++] = family;
3110 return S_OK;
3113 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3115 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3116 collection->refcount = 1;
3117 collection->count = 0;
3118 collection->size = 0;
3119 collection->family_data = NULL;
3121 return S_OK;
3124 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3126 IDWriteFontFileLoader *loader;
3127 const void *key;
3128 UINT32 key_size;
3129 HRESULT hr;
3131 *stream = NULL;
3133 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3134 if (FAILED(hr))
3135 return hr;
3137 hr = IDWriteFontFile_GetLoader(file, &loader);
3138 if (FAILED(hr))
3139 return hr;
3141 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3142 IDWriteFontFileLoader_Release(loader);
3143 if (FAILED(hr))
3144 return hr;
3146 return hr;
3149 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3151 BOOL exists = FALSE;
3152 UINT32 index;
3153 HRESULT hr;
3155 buffer[0] = 0;
3156 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3157 if (FAILED(hr) || !exists)
3158 return;
3160 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3163 static int trim_spaces(WCHAR *in, WCHAR *ret)
3165 int len;
3167 while (isspaceW(*in))
3168 in++;
3170 ret[0] = 0;
3171 if (!(len = strlenW(in)))
3172 return 0;
3174 while (isspaceW(in[len-1]))
3175 len--;
3177 memcpy(ret, in, len*sizeof(WCHAR));
3178 ret[len] = 0;
3180 return len;
3183 struct name_token {
3184 struct list entry;
3185 const WCHAR *ptr;
3186 INT len; /* token length */
3187 INT fulllen; /* full length including following separators */
3190 static inline BOOL is_name_separator_char(WCHAR ch)
3192 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3195 struct name_pattern {
3196 const WCHAR *part1; /* NULL indicates end of list */
3197 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3200 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3202 const struct name_pattern *pattern;
3203 struct name_token *token;
3204 int i = 0;
3206 while ((pattern = &patterns[i++])->part1) {
3207 int len_part1 = strlenW(pattern->part1);
3208 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3210 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3211 if (len_part2 == 0) {
3212 /* simple case with single part pattern */
3213 if (token->len != len_part1)
3214 continue;
3216 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3217 if (match) *match = *token;
3218 list_remove(&token->entry);
3219 heap_free(token);
3220 return TRUE;
3223 else {
3224 struct name_token *next_token;
3225 struct list *next_entry;
3227 /* pattern parts are stored in reading order, tokens list is reversed */
3228 if (token->len < len_part2)
3229 continue;
3231 /* it's possible to have combined string as a token, like ExtraCondensed */
3232 if (token->len == len_part1 + len_part2) {
3233 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3234 continue;
3236 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3237 continue;
3239 /* combined string match */
3240 if (match) *match = *token;
3241 list_remove(&token->entry);
3242 heap_free(token);
3243 return TRUE;
3246 /* now it's only possible to have two tokens matched to respective pattern parts */
3247 if (token->len != len_part2)
3248 continue;
3250 next_entry = list_next(tokens, &token->entry);
3251 if (next_entry) {
3252 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3253 if (next_token->len != len_part1)
3254 continue;
3256 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3257 continue;
3259 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3260 continue;
3262 /* both parts matched, remove tokens */
3263 if (match) {
3264 match->ptr = next_token->ptr;
3265 match->len = (token->ptr - next_token->ptr) + token->len;
3267 list_remove(&token->entry);
3268 list_remove(&next_token->entry);
3269 heap_free(next_token);
3270 heap_free(token);
3271 return TRUE;
3277 if (match) {
3278 match->ptr = NULL;
3279 match->len = 0;
3281 return FALSE;
3284 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3286 static const WCHAR itaW[] = {'i','t','a',0};
3287 static const WCHAR italW[] = {'i','t','a','l',0};
3288 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3289 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3291 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3292 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3293 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3294 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3296 static const struct name_pattern italic_patterns[] = {
3297 { itaW },
3298 { italW },
3299 { italicW },
3300 { cursiveW },
3301 { kursivW },
3302 { NULL }
3305 static const struct name_pattern oblique_patterns[] = {
3306 { inclinedW },
3307 { obliqueW },
3308 { backslantedW },
3309 { backslantW },
3310 { slantedW },
3311 { NULL }
3314 /* italic patterns first */
3315 if (match_pattern_list(tokens, italic_patterns, match))
3316 return DWRITE_FONT_STYLE_ITALIC;
3318 /* oblique patterns */
3319 if (match_pattern_list(tokens, oblique_patterns, match))
3320 return DWRITE_FONT_STYLE_OBLIQUE;
3322 return style;
3325 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3326 struct name_token *match)
3328 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3329 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3330 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3331 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3332 static const WCHAR wideW[] = {'w','i','d','e',0};
3333 static const WCHAR condW[] = {'c','o','n','d',0};
3335 static const struct name_pattern ultracondensed_patterns[] = {
3336 { extraW, compressedW },
3337 { extW, compressedW },
3338 { ultraW, compressedW },
3339 { ultraW, condensedW },
3340 { ultraW, condW },
3341 { NULL }
3344 static const struct name_pattern extracondensed_patterns[] = {
3345 { compressedW },
3346 { extraW, condensedW },
3347 { extW, condensedW },
3348 { extraW, condW },
3349 { extW, condW },
3350 { NULL }
3353 static const struct name_pattern semicondensed_patterns[] = {
3354 { narrowW },
3355 { compactW },
3356 { semiW, condensedW },
3357 { semiW, condW },
3358 { NULL }
3361 static const struct name_pattern semiexpanded_patterns[] = {
3362 { wideW },
3363 { semiW, expandedW },
3364 { semiW, extendedW },
3365 { NULL }
3368 static const struct name_pattern extraexpanded_patterns[] = {
3369 { extraW, expandedW },
3370 { extW, expandedW },
3371 { extraW, extendedW },
3372 { extW, extendedW },
3373 { NULL }
3376 static const struct name_pattern ultraexpanded_patterns[] = {
3377 { ultraW, expandedW },
3378 { ultraW, extendedW },
3379 { NULL }
3382 static const struct name_pattern condensed_patterns[] = {
3383 { condensedW },
3384 { condW },
3385 { NULL }
3388 static const struct name_pattern expanded_patterns[] = {
3389 { expandedW },
3390 { extendedW },
3391 { NULL }
3394 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3395 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3397 if (match_pattern_list(tokens, extracondensed_patterns, match))
3398 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3400 if (match_pattern_list(tokens, semicondensed_patterns, match))
3401 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3403 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3404 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3406 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3407 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3409 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3410 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3412 if (match_pattern_list(tokens, condensed_patterns, match))
3413 return DWRITE_FONT_STRETCH_CONDENSED;
3415 if (match_pattern_list(tokens, expanded_patterns, match))
3416 return DWRITE_FONT_STRETCH_EXPANDED;
3418 return stretch;
3421 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3422 struct name_token *match)
3424 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3425 static const WCHAR nordW[] = {'n','o','r','d',0};
3427 static const struct name_pattern thin_patterns[] = {
3428 { extraW, thinW },
3429 { extW, thinW },
3430 { ultraW, thinW },
3431 { NULL }
3434 static const struct name_pattern extralight_patterns[] = {
3435 { extraW, lightW },
3436 { extW, lightW },
3437 { ultraW, lightW },
3438 { NULL }
3441 static const struct name_pattern semilight_patterns[] = {
3442 { semiW, lightW },
3443 { NULL }
3446 static const struct name_pattern demibold_patterns[] = {
3447 { semiW, boldW },
3448 { demiW, boldW },
3449 { NULL }
3452 static const struct name_pattern extrabold_patterns[] = {
3453 { extraW, boldW },
3454 { extW, boldW },
3455 { ultraW, boldW },
3456 { NULL }
3459 static const struct name_pattern extrablack_patterns[] = {
3460 { extraW, blackW },
3461 { extW, blackW },
3462 { ultraW, blackW },
3463 { NULL }
3466 static const struct name_pattern bold_patterns[] = {
3467 { boldW },
3468 { NULL }
3471 static const struct name_pattern thin2_patterns[] = {
3472 { thinW },
3473 { NULL }
3476 static const struct name_pattern light_patterns[] = {
3477 { lightW },
3478 { NULL }
3481 static const struct name_pattern medium_patterns[] = {
3482 { mediumW },
3483 { NULL }
3486 static const struct name_pattern black_patterns[] = {
3487 { blackW },
3488 { heavyW },
3489 { nordW },
3490 { NULL }
3493 static const struct name_pattern demibold2_patterns[] = {
3494 { demiW },
3495 { NULL }
3498 static const struct name_pattern extrabold2_patterns[] = {
3499 { ultraW },
3500 { NULL }
3503 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3504 matching pattern. */
3506 if (match_pattern_list(tokens, thin_patterns, match))
3507 return DWRITE_FONT_WEIGHT_THIN;
3509 if (match_pattern_list(tokens, extralight_patterns, match))
3510 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3512 if (match_pattern_list(tokens, semilight_patterns, match))
3513 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3515 if (match_pattern_list(tokens, demibold_patterns, match))
3516 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3518 if (match_pattern_list(tokens, extrabold_patterns, match))
3519 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3521 if (match_pattern_list(tokens, extrablack_patterns, match))
3522 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3524 if (match_pattern_list(tokens, bold_patterns, match))
3525 return DWRITE_FONT_WEIGHT_BOLD;
3527 if (match_pattern_list(tokens, thin2_patterns, match))
3528 return DWRITE_FONT_WEIGHT_THIN;
3530 if (match_pattern_list(tokens, light_patterns, match))
3531 return DWRITE_FONT_WEIGHT_LIGHT;
3533 if (match_pattern_list(tokens, medium_patterns, match))
3534 return DWRITE_FONT_WEIGHT_MEDIUM;
3536 if (match_pattern_list(tokens, black_patterns, match))
3537 return DWRITE_FONT_WEIGHT_BLACK;
3539 if (match_pattern_list(tokens, black_patterns, match))
3540 return DWRITE_FONT_WEIGHT_BLACK;
3542 if (match_pattern_list(tokens, demibold2_patterns, match))
3543 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3545 if (match_pattern_list(tokens, extrabold2_patterns, match))
3546 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3548 /* FIXME: use abbreviated names to extract weight */
3550 return weight;
3553 struct knownweight_entry {
3554 const WCHAR *nameW;
3555 DWRITE_FONT_WEIGHT weight;
3558 static int compare_knownweights(const void *a, const void* b)
3560 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3561 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3562 int ret = 0;
3564 if (target > entry->weight)
3565 ret = 1;
3566 else if (target < entry->weight)
3567 ret = -1;
3569 return ret;
3572 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3574 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3575 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3576 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3577 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3578 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3579 const struct knownweight_entry *ptr;
3581 static const struct knownweight_entry knownweights[] = {
3582 { thinW, DWRITE_FONT_WEIGHT_THIN },
3583 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3584 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3585 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3586 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3587 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3588 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3589 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3590 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3591 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3594 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3595 compare_knownweights);
3596 if (!ptr) {
3597 nameW[0] = 0;
3598 return FALSE;
3601 strcpyW(nameW, ptr->nameW);
3602 return TRUE;
3605 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3607 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3608 strW[name->len] = 0;
3611 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3612 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3614 static const WCHAR bookW[] = {'B','o','o','k',0};
3615 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3616 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3617 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3618 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3620 static const WCHAR *regular_patterns[] = {
3621 bookW,
3622 normalW,
3623 regularW,
3624 romanW,
3625 uprightW,
3626 NULL
3629 const WCHAR *regular_ptr = NULL, *ptr;
3630 int i = 0;
3632 if (len == -1)
3633 len = strlenW(facenameW);
3635 /* remove rightmost regular variant from face name */
3636 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3637 int pattern_len = strlenW(ptr);
3638 WCHAR *src;
3640 if (pattern_len > len)
3641 continue;
3643 src = facenameW + len - pattern_len;
3644 while (src >= facenameW) {
3645 if (!strncmpiW(src, ptr, pattern_len)) {
3646 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3647 len = strlenW(facenameW);
3648 regular_ptr = ptr;
3649 break;
3651 else
3652 src--;
3656 return regular_ptr;
3659 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3661 const WCHAR *ptr;
3663 list_init(tokens);
3664 ptr = nameW;
3666 while (*ptr) {
3667 struct name_token *token = heap_alloc(sizeof(*token));
3668 token->ptr = ptr;
3669 token->len = 0;
3670 token->fulllen = 0;
3672 while (*ptr && !is_name_separator_char(*ptr)) {
3673 token->len++;
3674 token->fulllen++;
3675 ptr++;
3678 /* skip separators */
3679 while (is_name_separator_char(*ptr)) {
3680 token->fulllen++;
3681 ptr++;
3684 list_add_head(tokens, &token->entry);
3688 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3690 struct name_token *token, *token2;
3691 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3692 int len;
3694 list_remove(&token->entry);
3696 /* don't include last separator */
3697 len = list_empty(tokens) ? token->len : token->fulllen;
3698 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3699 nameW += len;
3701 heap_free(token);
3703 *nameW = 0;
3706 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3708 struct name_token stretch_name, weight_name, style_name;
3709 WCHAR familynameW[255], facenameW[255], finalW[255];
3710 WCHAR weightW[32], stretchW[32], styleW[32];
3711 const WCHAR *regular_ptr = NULL;
3712 DWRITE_FONT_STRETCH stretch;
3713 DWRITE_FONT_WEIGHT weight;
3714 struct list tokens;
3715 int len;
3717 /* remove leading and trailing spaces from family and face name */
3718 trim_spaces(familyW, familynameW);
3719 len = trim_spaces(faceW, facenameW);
3721 /* remove rightmost regular variant from face name */
3722 regular_ptr = facename_remove_regular_term(facenameW, len);
3724 /* append face name to family name, FIXME check if face name is a substring of family name */
3725 if (*facenameW) {
3726 strcatW(familynameW, spaceW);
3727 strcatW(familynameW, facenameW);
3730 /* tokenize with " .-_" */
3731 fontname_tokenize(&tokens, familynameW);
3733 /* extract and resolve style */
3734 font->style = font_extract_style(&tokens, font->style, &style_name);
3736 /* extract stretch */
3737 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3739 /* extract weight */
3740 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3742 /* resolve weight */
3743 if (weight != font->weight) {
3744 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3745 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3746 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3747 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3748 !(abs(weight - font->weight) <= 150 &&
3749 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3750 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3751 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3753 font->weight = weight;
3757 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3758 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3759 stretch itself is normal (extracted stretch is never normal). */
3760 if (stretch != font->stretch) {
3761 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3762 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3763 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3765 font->stretch = stretch;
3769 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3771 /* get final combined string from what's left in token list, list is released */
3772 fontname_tokens_to_str(&tokens, finalW);
3774 if (!strcmpW(familyW, finalW))
3775 return FALSE;
3777 /* construct face name */
3778 strcpyW(familyW, finalW);
3780 /* resolved weight name */
3781 if (weight_name.ptr)
3782 font_name_token_to_str(&weight_name, weightW);
3783 /* ignore normal weight */
3784 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3785 weightW[0] = 0;
3786 /* for known weight values use appropriate names */
3787 else if (is_known_weight_value(font->weight, weightW)) {
3789 /* use Wnnn format as a fallback in case weight is not one of known values */
3790 else {
3791 static const WCHAR fmtW[] = {'W','%','d',0};
3792 sprintfW(weightW, fmtW, font->weight);
3795 /* resolved stretch name */
3796 if (stretch_name.ptr)
3797 font_name_token_to_str(&stretch_name, stretchW);
3798 /* ignore normal stretch */
3799 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3800 stretchW[0] = 0;
3801 /* use predefined stretch names */
3802 else {
3803 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3804 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3805 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3806 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3807 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3808 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3810 static const WCHAR *stretchnamesW[] = {
3811 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3812 ultracondensedW,
3813 extracondensedW,
3814 condensedW,
3815 semicondensedW,
3816 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3817 semiexpandedW,
3818 expandedW,
3819 extraexpandedW,
3820 ultraexpandedW
3822 strcpyW(stretchW, stretchnamesW[font->stretch]);
3825 /* resolved style name */
3826 if (style_name.ptr)
3827 font_name_token_to_str(&style_name, styleW);
3828 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3829 styleW[0] = 0;
3830 /* use predefined names */
3831 else {
3832 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3833 strcpyW(styleW, italicW);
3834 else
3835 strcpyW(styleW, obliqueW);
3838 /* use Regular match if it was found initially */
3839 if (!*weightW && !*stretchW && !*styleW)
3840 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3841 else {
3842 faceW[0] = 0;
3843 if (*stretchW)
3844 strcpyW(faceW, stretchW);
3845 if (*weightW) {
3846 if (*faceW)
3847 strcatW(faceW, spaceW);
3848 strcatW(faceW, weightW);
3850 if (*styleW) {
3851 if (*faceW)
3852 strcatW(faceW, spaceW);
3853 strcatW(faceW, styleW);
3857 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3858 return TRUE;
3861 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3863 static const float width_axis_values[] =
3865 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3866 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3867 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3868 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3869 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3870 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3871 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3872 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3873 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3874 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3877 struct file_stream_desc stream_desc;
3878 struct dwrite_font_props props;
3879 struct dwrite_font_data *data;
3880 WCHAR familyW[255], faceW[255];
3881 HRESULT hr;
3883 *ret = NULL;
3885 data = heap_alloc_zero(sizeof(*data));
3886 if (!data)
3887 return E_OUTOFMEMORY;
3889 data->ref = 1;
3890 data->file = desc->files[0];
3891 data->face_index = desc->index;
3892 data->face_type = desc->face_type;
3893 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3894 data->bold_sim_tested = 0;
3895 data->oblique_sim_tested = 0;
3896 IDWriteFontFile_AddRef(data->file);
3898 stream_desc.stream = desc->stream;
3899 stream_desc.face_type = desc->face_type;
3900 stream_desc.face_index = desc->index;
3901 opentype_get_font_properties(&stream_desc, &props);
3902 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3903 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3905 /* get family name from font file */
3906 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3907 if (FAILED(hr)) {
3908 WARN("unable to get family name from font\n");
3909 release_font_data(data);
3910 return hr;
3913 data->style = props.style;
3914 data->stretch = props.stretch;
3915 data->weight = props.weight;
3916 data->panose = props.panose;
3917 data->fontsig = props.fontsig;
3918 data->lf = props.lf;
3919 data->flags = props.flags;
3921 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3922 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3923 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3924 set_en_localizedstring(data->family_names, familyW);
3925 set_en_localizedstring(data->names, faceW);
3928 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3930 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
3931 data->axis[0].value = props.weight;
3932 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
3933 data->axis[1].value = width_axis_values[props.stretch];
3934 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
3935 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
3937 *ret = data;
3938 return S_OK;
3941 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3942 const WCHAR *facenameW, struct dwrite_font_data **ret)
3944 struct dwrite_font_data *data;
3946 *ret = NULL;
3948 data = heap_alloc_zero(sizeof(*data));
3949 if (!data)
3950 return E_OUTOFMEMORY;
3952 *data = *src;
3953 data->ref = 1;
3954 data->simulations |= sim;
3955 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3956 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3957 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3958 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3959 memset(data->info_strings, 0, sizeof(data->info_strings));
3960 data->names = NULL;
3961 IDWriteFontFile_AddRef(data->file);
3962 IDWriteLocalizedStrings_AddRef(data->family_names);
3964 create_localizedstrings(&data->names);
3965 add_localizedstring(data->names, enusW, facenameW);
3967 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3969 *ret = data;
3970 return S_OK;
3973 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3975 struct dwrite_fontfamily_data *data;
3977 data = heap_alloc_zero(sizeof(*data));
3978 if (!data)
3979 return E_OUTOFMEMORY;
3981 data->refcount = 1;
3982 data->familyname = familyname;
3983 IDWriteLocalizedStrings_AddRef(familyname);
3985 *ret = data;
3987 return S_OK;
3990 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3992 size_t i, j, heaviest;
3994 for (i = 0; i < family->count; ++i)
3996 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3997 heaviest = i;
3999 if (family->fonts[i]->bold_sim_tested)
4000 continue;
4002 family->fonts[i]->bold_sim_tested = 1;
4003 for (j = i; j < family->count; ++j)
4005 if (family->fonts[j]->bold_sim_tested)
4006 continue;
4008 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4009 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4010 if (family->fonts[j]->weight > weight) {
4011 weight = family->fonts[j]->weight;
4012 heaviest = j;
4014 family->fonts[j]->bold_sim_tested = 1;
4018 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4019 static const struct name_pattern weightsim_patterns[] = {
4020 { extraW, lightW },
4021 { extW, lightW },
4022 { ultraW, lightW },
4023 { semiW, lightW },
4024 { semiW, boldW },
4025 { demiW, boldW },
4026 { boldW },
4027 { thinW },
4028 { lightW },
4029 { mediumW },
4030 { demiW },
4031 { NULL }
4034 WCHAR facenameW[255], initialW[255];
4035 struct dwrite_font_data *boldface;
4036 struct list tokens;
4038 /* add Bold simulation based on heaviest face data */
4040 /* Simulated face name should only contain Bold as weight term,
4041 so remove existing regular and weight terms. */
4042 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4043 facename_remove_regular_term(initialW, -1);
4045 /* remove current weight pattern */
4046 fontname_tokenize(&tokens, initialW);
4047 match_pattern_list(&tokens, weightsim_patterns, NULL);
4048 fontname_tokens_to_str(&tokens, facenameW);
4050 /* Bold suffix for new name */
4051 if (*facenameW)
4052 strcatW(facenameW, spaceW);
4053 strcatW(facenameW, boldW);
4055 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4056 boldface->bold_sim_tested = 1;
4057 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4058 fontfamily_add_font(family, boldface);
4064 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4066 size_t i, j;
4068 for (i = 0; i < family->count; ++i)
4070 UINT32 regular = ~0u, oblique = ~0u;
4071 struct dwrite_font_data *obliqueface;
4072 WCHAR facenameW[255];
4074 if (family->fonts[i]->oblique_sim_tested)
4075 continue;
4077 family->fonts[i]->oblique_sim_tested = 1;
4078 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4079 regular = i;
4080 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4081 oblique = i;
4083 /* find regular style with same weight/stretch values */
4084 for (j = i; j < family->count; ++j)
4086 if (family->fonts[j]->oblique_sim_tested)
4087 continue;
4089 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4090 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4092 family->fonts[j]->oblique_sim_tested = 1;
4093 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4094 regular = j;
4096 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4097 oblique = j;
4100 if (regular != ~0u && oblique != ~0u)
4101 break;
4104 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4105 if (regular == ~0u)
4106 continue;
4108 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4109 if (oblique != ~0u)
4110 continue;
4112 /* add oblique simulation based on this regular face */
4114 /* remove regular term if any, append 'Oblique' */
4115 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4116 facename_remove_regular_term(facenameW, -1);
4118 if (*facenameW)
4119 strcatW(facenameW, spaceW);
4120 strcatW(facenameW, obliqueW);
4122 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4123 obliqueface->oblique_sim_tested = 1;
4124 obliqueface->lf.lfItalic = 1;
4125 fontfamily_add_font(family, obliqueface);
4130 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4131 const WCHAR *replacement_name)
4133 UINT32 i = collection_find_family(collection, replacement_name);
4134 struct dwrite_fontfamily_data *target;
4135 IDWriteLocalizedStrings *strings;
4136 HRESULT hr;
4138 /* replacement does not exist */
4139 if (i == ~0u)
4140 return FALSE;
4142 hr = create_localizedstrings(&strings);
4143 if (FAILED(hr))
4144 return FALSE;
4146 /* add a new family with target name, reuse font data from replacement */
4147 add_localizedstring(strings, enusW, target_name);
4148 hr = init_fontfamily_data(strings, &target);
4149 if (hr == S_OK) {
4150 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4151 WCHAR nameW[255];
4153 for (i = 0; i < replacement->count; ++i)
4155 fontfamily_add_font(target, replacement->fonts[i]);
4156 addref_font_data(replacement->fonts[i]);
4159 fontcollection_add_family(collection, target);
4160 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4161 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4163 IDWriteLocalizedStrings_Release(strings);
4164 return TRUE;
4167 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4168 system font collections. */
4169 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4171 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4172 WCHAR *name;
4173 void *data;
4174 HKEY hkey;
4176 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4177 return;
4179 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4180 RegCloseKey(hkey);
4181 return;
4184 max_namelen++; /* returned value doesn't include room for '\0' */
4185 name = heap_alloc(max_namelen * sizeof(WCHAR));
4186 data = heap_alloc(max_datalen);
4188 datalen = max_datalen;
4189 namelen = max_namelen;
4190 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4191 if (collection_find_family(collection, name) == ~0u) {
4192 if (type == REG_MULTI_SZ) {
4193 WCHAR *replacement = data;
4194 while (*replacement) {
4195 if (fontcollection_add_replacement(collection, name, replacement))
4196 break;
4197 replacement += strlenW(replacement) + 1;
4200 else if (type == REG_SZ)
4201 fontcollection_add_replacement(collection, name, data);
4203 else
4204 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4206 datalen = max_datalen;
4207 namelen = max_namelen;
4210 heap_free(data);
4211 heap_free(name);
4212 RegCloseKey(hkey);
4215 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4216 IDWriteFontCollection3 **ret)
4218 struct fontfile_enum {
4219 struct list entry;
4220 IDWriteFontFile *file;
4222 struct fontfile_enum *fileenum, *fileenum2;
4223 struct dwrite_fontcollection *collection;
4224 struct list scannedfiles;
4225 BOOL current = FALSE;
4226 HRESULT hr = S_OK;
4227 size_t i;
4229 *ret = NULL;
4231 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4232 if (!collection) return E_OUTOFMEMORY;
4234 hr = init_font_collection(collection, is_system);
4235 if (FAILED(hr)) {
4236 heap_free(collection);
4237 return hr;
4240 *ret = &collection->IDWriteFontCollection3_iface;
4242 TRACE("building font collection:\n");
4244 list_init(&scannedfiles);
4245 while (hr == S_OK) {
4246 DWRITE_FONT_FACE_TYPE face_type;
4247 DWRITE_FONT_FILE_TYPE file_type;
4248 BOOL supported, same = FALSE;
4249 IDWriteFontFileStream *stream;
4250 IDWriteFontFile *file;
4251 UINT32 face_count;
4253 current = FALSE;
4254 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4255 if (FAILED(hr) || !current)
4256 break;
4258 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4259 if (FAILED(hr))
4260 break;
4262 /* check if we've scanned this file already */
4263 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4264 if ((same = is_same_fontfile(fileenum->file, file)))
4265 break;
4268 if (same) {
4269 IDWriteFontFile_Release(file);
4270 continue;
4273 if (FAILED(get_filestream_from_file(file, &stream))) {
4274 IDWriteFontFile_Release(file);
4275 continue;
4278 /* Unsupported formats are skipped. */
4279 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4280 if (FAILED(hr) || !supported || face_count == 0) {
4281 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4282 IDWriteFontFileStream_Release(stream);
4283 IDWriteFontFile_Release(file);
4284 hr = S_OK;
4285 continue;
4288 /* add to scanned list */
4289 fileenum = heap_alloc(sizeof(*fileenum));
4290 fileenum->file = file;
4291 list_add_tail(&scannedfiles, &fileenum->entry);
4293 for (i = 0; i < face_count; ++i)
4295 struct dwrite_font_data *font_data;
4296 struct fontface_desc desc;
4297 WCHAR familyW[255];
4298 UINT32 index;
4300 desc.factory = factory;
4301 desc.face_type = face_type;
4302 desc.files = &file;
4303 desc.stream = stream;
4304 desc.files_number = 1;
4305 desc.index = i;
4306 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4307 desc.font_data = NULL;
4309 /* Allocate an initialize new font data structure. */
4310 hr = init_font_data(&desc, &font_data);
4311 if (FAILED(hr))
4313 /* move to next one */
4314 hr = S_OK;
4315 continue;
4318 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4320 /* ignore dot named faces */
4321 if (familyW[0] == '.')
4323 WARN("Ignoring face %s\n", debugstr_w(familyW));
4324 release_font_data(font_data);
4325 continue;
4328 index = collection_find_family(collection, familyW);
4329 if (index != ~0u)
4330 hr = fontfamily_add_font(collection->family_data[index], font_data);
4331 else {
4332 struct dwrite_fontfamily_data *family_data;
4334 /* create and init new family */
4335 hr = init_fontfamily_data(font_data->family_names, &family_data);
4336 if (hr == S_OK) {
4337 /* add font to family, family - to collection */
4338 hr = fontfamily_add_font(family_data, font_data);
4339 if (hr == S_OK)
4340 hr = fontcollection_add_family(collection, family_data);
4342 if (FAILED(hr))
4343 release_fontfamily_data(family_data);
4347 if (FAILED(hr))
4348 break;
4351 IDWriteFontFileStream_Release(stream);
4354 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4355 IDWriteFontFile_Release(fileenum->file);
4356 list_remove(&fileenum->entry);
4357 heap_free(fileenum);
4360 for (i = 0; i < collection->count; ++i)
4362 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4363 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4366 if (is_system)
4367 fontcollection_add_replacements(collection);
4369 collection->factory = factory;
4370 IDWriteFactory7_AddRef(factory);
4372 return hr;
4375 struct system_fontfile_enumerator
4377 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4378 LONG ref;
4380 IDWriteFactory7 *factory;
4381 HKEY hkey;
4382 int index;
4384 WCHAR *filename;
4385 DWORD filename_size;
4388 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4390 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4393 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4395 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4396 IDWriteFontFileEnumerator_AddRef(iface);
4397 *obj = iface;
4398 return S_OK;
4401 WARN("%s not implemented.\n", debugstr_guid(riid));
4403 *obj = NULL;
4405 return E_NOINTERFACE;
4408 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4410 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4411 return InterlockedIncrement(&enumerator->ref);
4414 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4416 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4417 ULONG ref = InterlockedDecrement(&enumerator->ref);
4419 if (!ref)
4421 IDWriteFactory7_Release(enumerator->factory);
4422 RegCloseKey(enumerator->hkey);
4423 heap_free(enumerator->filename);
4424 heap_free(enumerator);
4427 return ref;
4430 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4432 HRESULT hr;
4434 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4435 if (!strchrW(filename, '\\')) {
4436 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4437 WCHAR fullpathW[MAX_PATH];
4439 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4440 strcatW(fullpathW, fontsW);
4441 strcatW(fullpathW, filename);
4443 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4445 else
4446 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4448 return hr;
4451 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4453 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4455 *file = NULL;
4457 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4458 return E_FAIL;
4460 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4463 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4465 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4466 WCHAR name_buf[256], *name = name_buf;
4467 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4468 HRESULT hr = S_OK;
4469 LONG r;
4471 *current = FALSE;
4472 enumerator->index++;
4474 /* iterate until we find next string value */
4475 for (;;) {
4476 do {
4477 name_count = max_name_count;
4478 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4480 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4481 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4482 if (r == ERROR_MORE_DATA) {
4483 if (name_count >= max_name_count) {
4484 if (name != name_buf) heap_free(name);
4485 max_name_count *= 2;
4486 name = heap_alloc(max_name_count * sizeof(*name));
4487 if (!name) return E_OUTOFMEMORY;
4489 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4490 heap_free(enumerator->filename);
4491 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4492 enumerator->filename = heap_alloc(enumerator->filename_size);
4493 if (!enumerator->filename) {
4494 hr = E_OUTOFMEMORY;
4495 goto err;
4499 } while (r == ERROR_MORE_DATA);
4501 if (r != ERROR_SUCCESS) {
4502 enumerator->filename[0] = 0;
4503 break;
4505 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4506 if (type == REG_SZ && *name != '@') {
4507 *current = TRUE;
4508 break;
4510 enumerator->index++;
4512 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4514 err:
4515 if (name != name_buf) heap_free(name);
4516 return hr;
4519 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4521 systemfontfileenumerator_QueryInterface,
4522 systemfontfileenumerator_AddRef,
4523 systemfontfileenumerator_Release,
4524 systemfontfileenumerator_MoveNext,
4525 systemfontfileenumerator_GetCurrentFontFile
4528 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4530 struct system_fontfile_enumerator *enumerator;
4531 static const WCHAR fontslistW[] = {
4532 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4533 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4534 'F','o','n','t','s',0
4537 *ret = NULL;
4539 enumerator = heap_alloc(sizeof(*enumerator));
4540 if (!enumerator)
4541 return E_OUTOFMEMORY;
4543 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4544 enumerator->ref = 1;
4545 enumerator->factory = factory;
4546 enumerator->index = -1;
4547 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4548 enumerator->filename = heap_alloc(enumerator->filename_size);
4549 if (!enumerator->filename) {
4550 heap_free(enumerator);
4551 return E_OUTOFMEMORY;
4554 IDWriteFactory7_AddRef(factory);
4556 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4558 ERR("failed to open fonts list key\n");
4559 IDWriteFactory7_Release(factory);
4560 heap_free(enumerator->filename);
4561 heap_free(enumerator);
4562 return E_FAIL;
4565 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4567 return S_OK;
4570 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4572 IDWriteFontFileEnumerator *enumerator;
4573 HRESULT hr;
4575 *collection = NULL;
4577 hr = create_system_fontfile_enumerator(factory, &enumerator);
4578 if (FAILED(hr))
4579 return hr;
4581 TRACE("building system font collection for factory %p\n", factory);
4582 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4583 IDWriteFontFileEnumerator_Release(enumerator);
4584 return hr;
4587 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4588 const WCHAR *keynameW, const WCHAR *pathW)
4590 static const WCHAR defaultfontW[] = {'S','y','s','t','e','m','D','e','f','a','u','l','t','E','U','D','C','F','o','n','t',0};
4591 static const WCHAR emptyW[] = {0};
4592 struct dwrite_fontfamily_data *family_data;
4593 IDWriteLocalizedStrings *names;
4594 DWRITE_FONT_FACE_TYPE face_type;
4595 DWRITE_FONT_FILE_TYPE file_type;
4596 IDWriteFontFileStream *stream;
4597 IDWriteFontFile *file;
4598 UINT32 face_count, i;
4599 BOOL supported;
4600 HRESULT hr;
4602 /* create font file from this path */
4603 hr = create_local_file_reference(factory, pathW, &file);
4604 if (FAILED(hr))
4605 return S_FALSE;
4607 if (FAILED(get_filestream_from_file(file, &stream))) {
4608 IDWriteFontFile_Release(file);
4609 return S_FALSE;
4612 /* Unsupported formats are skipped. */
4613 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4614 if (FAILED(hr) || !supported || face_count == 0) {
4615 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4616 IDWriteFontFileStream_Release(stream);
4617 IDWriteFontFile_Release(file);
4618 return S_FALSE;
4621 /* create and init new family */
4623 /* Family names are added for non-specific locale, represented with empty string.
4624 Default family appears with empty family name. */
4625 create_localizedstrings(&names);
4626 if (!strcmpiW(keynameW, defaultfontW))
4627 add_localizedstring(names, emptyW, emptyW);
4628 else
4629 add_localizedstring(names, emptyW, keynameW);
4631 hr = init_fontfamily_data(names, &family_data);
4632 IDWriteLocalizedStrings_Release(names);
4633 if (hr != S_OK) {
4634 IDWriteFontFile_Release(file);
4635 return hr;
4638 /* fill with faces */
4639 for (i = 0; i < face_count; i++) {
4640 struct dwrite_font_data *font_data;
4641 struct fontface_desc desc;
4643 /* alloc and init new font data structure */
4644 desc.factory = factory;
4645 desc.face_type = face_type;
4646 desc.index = i;
4647 desc.files = &file;
4648 desc.stream = stream;
4649 desc.files_number = 1;
4650 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4651 desc.font_data = NULL;
4653 hr = init_font_data(&desc, &font_data);
4654 if (FAILED(hr))
4655 continue;
4657 /* add font to family */
4658 hr = fontfamily_add_font(family_data, font_data);
4659 if (hr != S_OK)
4660 release_font_data(font_data);
4663 /* add family to collection */
4664 hr = fontcollection_add_family(collection, family_data);
4665 if (FAILED(hr))
4666 release_fontfamily_data(family_data);
4667 IDWriteFontFileStream_Release(stream);
4668 IDWriteFontFile_Release(file);
4670 return hr;
4673 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4675 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4676 struct dwrite_fontcollection *collection;
4677 static const WCHAR emptyW[] = {0};
4678 WCHAR eudckeypathW[16];
4679 HKEY eudckey;
4680 DWORD index;
4681 BOOL exists;
4682 LONG retval;
4683 HRESULT hr;
4684 size_t i;
4686 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4688 *ret = NULL;
4690 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4691 if (!collection) return E_OUTOFMEMORY;
4693 hr = init_font_collection(collection, FALSE);
4694 if (FAILED(hr)) {
4695 heap_free(collection);
4696 return hr;
4699 *ret = &collection->IDWriteFontCollection3_iface;
4700 collection->factory = factory;
4701 IDWriteFactory7_AddRef(factory);
4703 /* return empty collection if EUDC fonts are not configured */
4704 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4705 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4706 return S_OK;
4708 retval = ERROR_SUCCESS;
4709 index = 0;
4710 while (retval != ERROR_NO_MORE_ITEMS) {
4711 WCHAR keynameW[64], pathW[MAX_PATH];
4712 DWORD type, path_len, name_len;
4714 path_len = ARRAY_SIZE(pathW);
4715 name_len = ARRAY_SIZE(keynameW);
4716 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4717 if (retval || type != REG_SZ)
4718 continue;
4720 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4721 if (hr != S_OK)
4722 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4724 RegCloseKey(eudckey);
4726 /* try to add global default if not defined for specific codepage */
4727 exists = FALSE;
4728 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4729 &index, &exists);
4730 if (FAILED(hr) || !exists) {
4731 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4732 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4733 if (hr != S_OK)
4734 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4737 /* EUDC collection offers simulated faces too */
4738 for (i = 0; i < collection->count; ++i)
4740 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4741 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4744 return S_OK;
4747 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4749 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4751 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4753 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4755 *obj = iface;
4756 IDWriteFontFile_AddRef(iface);
4757 return S_OK;
4760 WARN("%s not implemented.\n", debugstr_guid(riid));
4762 *obj = NULL;
4763 return E_NOINTERFACE;
4766 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4768 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4769 ULONG ref = InterlockedIncrement(&This->ref);
4770 TRACE("(%p)->(%d)\n", This, ref);
4771 return ref;
4774 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4776 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4777 ULONG ref = InterlockedDecrement(&This->ref);
4779 TRACE("(%p)->(%d)\n", This, ref);
4781 if (!ref)
4783 IDWriteFontFileLoader_Release(This->loader);
4784 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4785 heap_free(This->reference_key);
4786 heap_free(This);
4789 return ref;
4792 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4794 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4795 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4796 *fontFileReferenceKey = This->reference_key;
4797 *fontFileReferenceKeySize = This->key_size;
4799 return S_OK;
4802 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4804 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4805 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4806 *fontFileLoader = This->loader;
4807 IDWriteFontFileLoader_AddRef(This->loader);
4809 return S_OK;
4812 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4813 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4815 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4816 IDWriteFontFileStream *stream;
4817 HRESULT hr;
4819 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4821 *is_supported = FALSE;
4822 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4823 if (face_type)
4824 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4825 *face_count = 0;
4827 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4828 if (FAILED(hr))
4829 return hr;
4831 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4833 /* TODO: Further Analysis */
4834 IDWriteFontFileStream_Release(stream);
4835 return S_OK;
4838 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4839 dwritefontfile_QueryInterface,
4840 dwritefontfile_AddRef,
4841 dwritefontfile_Release,
4842 dwritefontfile_GetReferenceKey,
4843 dwritefontfile_GetLoader,
4844 dwritefontfile_Analyze,
4847 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4848 IDWriteFontFile **ret)
4850 struct dwrite_fontfile *file;
4851 void *key;
4853 *ret = NULL;
4855 file = heap_alloc(sizeof(*file));
4856 key = heap_alloc(key_size);
4857 if (!file || !key) {
4858 heap_free(file);
4859 heap_free(key);
4860 return E_OUTOFMEMORY;
4863 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4864 file->ref = 1;
4865 IDWriteFontFileLoader_AddRef(loader);
4866 file->loader = loader;
4867 file->stream = NULL;
4868 file->reference_key = key;
4869 memcpy(file->reference_key, reference_key, key_size);
4870 file->key_size = key_size;
4872 *ret = &file->IDWriteFontFile_iface;
4874 return S_OK;
4877 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4879 struct file_stream_desc stream_desc;
4880 struct dwrite_font_data *font_data;
4881 struct dwrite_fontface *fontface;
4882 HRESULT hr;
4883 int i;
4885 *ret = NULL;
4887 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4888 if (!fontface)
4889 return E_OUTOFMEMORY;
4891 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4892 if (!fontface->files) {
4893 heap_free(fontface);
4894 return E_OUTOFMEMORY;
4897 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4898 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
4899 fontface->refcount = 1;
4900 fontface->type = desc->face_type;
4901 fontface->file_count = desc->files_number;
4902 fontface->cmap.exists = TRUE;
4903 fontface->vdmx.exists = TRUE;
4904 fontface->gasp.exists = TRUE;
4905 fontface->cpal.exists = TRUE;
4906 fontface->colr.exists = TRUE;
4907 fontface->index = desc->index;
4908 fontface->simulations = desc->simulations;
4909 fontface->factory = desc->factory;
4910 IDWriteFactory7_AddRef(fontface->factory);
4912 for (i = 0; i < fontface->file_count; i++) {
4913 fontface->files[i] = desc->files[i];
4914 IDWriteFontFile_AddRef(fontface->files[i]);
4916 fontface->stream = desc->stream;
4917 IDWriteFontFileStream_AddRef(fontface->stream);
4919 stream_desc.stream = fontface->stream;
4920 stream_desc.face_type = desc->face_type;
4921 stream_desc.face_index = desc->index;
4922 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4923 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4924 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4925 /* TODO: test what happens if caret is already slanted */
4926 if (fontface->caret.slopeRise == 1) {
4927 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4928 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4932 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace5_iface);
4933 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4934 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4935 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace5_iface))
4936 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4937 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4939 /* Font properties are reused from font object when 'normal' face creation path is used:
4940 collection -> family -> matching font -> fontface.
4942 If face is created directly from factory we have to go through properties resolution.
4944 if (desc->font_data)
4946 font_data = desc->font_data;
4947 addref_font_data(font_data);
4949 else
4951 hr = init_font_data(desc, &font_data);
4952 if (FAILED(hr))
4954 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
4955 return hr;
4959 fontface->weight = font_data->weight;
4960 fontface->style = font_data->style;
4961 fontface->stretch = font_data->stretch;
4962 fontface->panose = font_data->panose;
4963 fontface->fontsig = font_data->fontsig;
4964 fontface->lf = font_data->lf;
4965 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
4966 fontface->names = font_data->names;
4967 if (fontface->names)
4968 IDWriteLocalizedStrings_AddRef(fontface->names);
4969 fontface->family_names = font_data->family_names;
4970 if (fontface->family_names)
4971 IDWriteLocalizedStrings_AddRef(fontface->family_names);
4972 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
4973 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
4975 if (fontface->info_strings[i])
4976 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
4978 release_font_data(font_data);
4980 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
4982 *ret = &fontface->IDWriteFontFace5_iface;
4984 return S_OK;
4987 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4988 struct local_refkey
4990 FILETIME writetime;
4991 WCHAR name[1];
4994 struct local_cached_stream
4996 struct list entry;
4997 IDWriteFontFileStream *stream;
4998 struct local_refkey *key;
4999 UINT32 key_size;
5002 struct dwrite_localfontfilestream
5004 IDWriteFontFileStream IDWriteFontFileStream_iface;
5005 LONG ref;
5007 struct local_cached_stream *entry;
5008 const void *file_ptr;
5009 UINT64 size;
5012 struct dwrite_localfontfileloader {
5013 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5014 LONG ref;
5016 struct list streams;
5017 CRITICAL_SECTION cs;
5020 static struct dwrite_localfontfileloader local_fontfile_loader;
5022 struct dwrite_inmemory_stream_data
5024 LONG ref;
5025 IUnknown *owner;
5026 void *data;
5027 UINT32 size;
5030 struct dwrite_inmemory_filestream
5032 IDWriteFontFileStream IDWriteFontFileStream_iface;
5033 LONG ref;
5035 struct dwrite_inmemory_stream_data *data;
5038 struct dwrite_inmemory_fileloader
5040 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5041 LONG ref;
5043 struct dwrite_inmemory_stream_data **streams;
5044 size_t size;
5045 size_t count;
5048 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5050 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5053 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5055 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5058 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5060 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5063 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5065 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5068 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5070 if (InterlockedDecrement(&stream->ref) == 0) {
5071 if (stream->owner)
5072 IUnknown_Release(stream->owner);
5073 else
5074 heap_free(stream->data);
5075 heap_free(stream);
5079 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5081 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5083 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5085 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5086 IsEqualIID(riid, &IID_IUnknown))
5088 *obj = iface;
5089 if (InterlockedIncrement(&This->ref) == 1) {
5090 InterlockedDecrement(&This->ref);
5091 *obj = NULL;
5092 return E_FAIL;
5094 return S_OK;
5097 WARN("%s not implemented.\n", debugstr_guid(riid));
5099 *obj = NULL;
5100 return E_NOINTERFACE;
5103 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5105 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5106 ULONG ref = InterlockedIncrement(&This->ref);
5107 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5108 return ref;
5111 static inline void release_cached_stream(struct local_cached_stream *stream)
5113 list_remove(&stream->entry);
5114 heap_free(stream->key);
5115 heap_free(stream);
5118 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5120 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5121 ULONG ref = InterlockedDecrement(&This->ref);
5123 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5125 if (!ref) {
5126 UnmapViewOfFile(This->file_ptr);
5128 EnterCriticalSection(&local_fontfile_loader.cs);
5129 release_cached_stream(This->entry);
5130 LeaveCriticalSection(&local_fontfile_loader.cs);
5132 heap_free(This);
5135 return ref;
5138 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5139 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5141 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5143 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
5144 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5146 *fragment_context = NULL;
5148 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
5149 *fragment_start = NULL;
5150 return E_FAIL;
5153 *fragment_start = (char*)This->file_ptr + offset;
5154 return S_OK;
5157 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5159 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5160 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
5163 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5165 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5166 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
5167 *size = This->size;
5168 return S_OK;
5171 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5173 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5174 ULARGE_INTEGER li;
5176 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
5178 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
5179 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
5180 *last_writetime = li.QuadPart;
5182 return S_OK;
5185 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5187 localfontfilestream_QueryInterface,
5188 localfontfilestream_AddRef,
5189 localfontfilestream_Release,
5190 localfontfilestream_ReadFileFragment,
5191 localfontfilestream_ReleaseFileFragment,
5192 localfontfilestream_GetFileSize,
5193 localfontfilestream_GetLastWriteTime
5196 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
5198 struct dwrite_localfontfilestream *This;
5200 *ret = NULL;
5202 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
5203 if (!This)
5204 return E_OUTOFMEMORY;
5206 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5207 This->ref = 1;
5209 This->file_ptr = file_ptr;
5210 This->size = size;
5211 This->entry = entry;
5213 *ret = &This->IDWriteFontFileStream_iface;
5214 return S_OK;
5217 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5219 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5221 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5223 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5224 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5225 IsEqualIID(riid, &IID_IUnknown))
5227 *obj = iface;
5228 IDWriteLocalFontFileLoader_AddRef(iface);
5229 return S_OK;
5232 WARN("%s not implemented.\n", debugstr_guid(riid));
5234 *obj = NULL;
5235 return E_NOINTERFACE;
5238 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5240 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5241 ULONG ref = InterlockedIncrement(&This->ref);
5242 TRACE("(%p)->(%d)\n", This, ref);
5243 return ref;
5246 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5248 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5249 ULONG ref = InterlockedDecrement(&This->ref);
5251 TRACE("(%p)->(%d)\n", This, ref);
5253 return ref;
5256 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5258 const struct local_refkey *refkey = key;
5259 struct local_cached_stream *stream;
5260 IDWriteFontFileStream *filestream;
5261 HANDLE file, mapping;
5262 LARGE_INTEGER size;
5263 void *file_ptr;
5264 HRESULT hr = S_OK;
5266 *ret = NULL;
5268 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5269 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5270 if (file == INVALID_HANDLE_VALUE) {
5271 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5272 return E_FAIL;
5275 GetFileSizeEx(file, &size);
5276 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5277 CloseHandle(file);
5278 if (!mapping)
5279 return E_FAIL;
5281 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5282 CloseHandle(mapping);
5283 if (!file_ptr) {
5284 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5285 return E_FAIL;
5288 stream = heap_alloc(sizeof(*stream));
5289 if (!stream) {
5290 UnmapViewOfFile(file_ptr);
5291 return E_OUTOFMEMORY;
5294 stream->key = heap_alloc(key_size);
5295 if (!stream->key) {
5296 UnmapViewOfFile(file_ptr);
5297 heap_free(stream);
5298 return E_OUTOFMEMORY;
5301 stream->key_size = key_size;
5302 memcpy(stream->key, key, key_size);
5304 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5305 if (FAILED(hr)) {
5306 UnmapViewOfFile(file_ptr);
5307 heap_free(stream->key);
5308 heap_free(stream);
5309 return hr;
5312 stream->stream = filestream;
5314 *ret = stream;
5316 return S_OK;
5319 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5320 UINT32 key_size, IDWriteFontFileStream **ret)
5322 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5323 const struct local_refkey *refkey = key;
5324 struct local_cached_stream *stream;
5325 HRESULT hr = S_OK;
5327 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
5328 TRACE("name: %s\n", debugstr_w(refkey->name));
5330 EnterCriticalSection(&This->cs);
5332 *ret = NULL;
5334 /* search cache first */
5335 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
5336 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5337 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5338 break;
5342 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
5343 list_add_head(&This->streams, &stream->entry);
5344 *ret = stream->stream;
5347 LeaveCriticalSection(&This->cs);
5349 return hr;
5352 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
5354 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5355 const struct local_refkey *refkey = key;
5357 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
5359 *length = strlenW(refkey->name);
5360 return S_OK;
5363 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
5365 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5366 const struct local_refkey *refkey = key;
5368 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
5370 if (length < strlenW(refkey->name))
5371 return E_INVALIDARG;
5373 strcpyW(path, refkey->name);
5374 return S_OK;
5377 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5378 UINT32 key_size, FILETIME *writetime)
5380 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5381 const struct local_refkey *refkey = key;
5383 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
5385 *writetime = refkey->writetime;
5386 return S_OK;
5389 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
5390 localfontfileloader_QueryInterface,
5391 localfontfileloader_AddRef,
5392 localfontfileloader_Release,
5393 localfontfileloader_CreateStreamFromKey,
5394 localfontfileloader_GetFilePathLengthFromKey,
5395 localfontfileloader_GetFilePathFromKey,
5396 localfontfileloader_GetLastWriteTimeFromKey
5399 void init_local_fontfile_loader(void)
5401 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5402 local_fontfile_loader.ref = 1;
5403 list_init(&local_fontfile_loader.streams);
5404 InitializeCriticalSection(&local_fontfile_loader.cs);
5405 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5408 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5410 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5413 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5415 struct local_refkey *refkey;
5417 if (!path)
5418 return E_INVALIDARG;
5420 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5421 *key = NULL;
5423 refkey = heap_alloc(*size);
5424 if (!refkey)
5425 return E_OUTOFMEMORY;
5427 if (writetime)
5428 refkey->writetime = *writetime;
5429 else {
5430 WIN32_FILE_ATTRIBUTE_DATA info;
5432 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5433 refkey->writetime = info.ftLastWriteTime;
5434 else
5435 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5437 strcpyW(refkey->name, path);
5439 *key = refkey;
5441 return S_OK;
5444 /* IDWriteGlyphRunAnalysis */
5445 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5447 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5449 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5451 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5452 IsEqualIID(riid, &IID_IUnknown))
5454 *ppv = iface;
5455 IDWriteGlyphRunAnalysis_AddRef(iface);
5456 return S_OK;
5459 WARN("%s not implemented.\n", debugstr_guid(riid));
5461 *ppv = NULL;
5462 return E_NOINTERFACE;
5465 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5467 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5468 ULONG ref = InterlockedIncrement(&This->ref);
5469 TRACE("(%p)->(%u)\n", This, ref);
5470 return ref;
5473 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5475 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5476 ULONG ref = InterlockedDecrement(&This->ref);
5478 TRACE("(%p)->(%u)\n", This, ref);
5480 if (!ref) {
5481 if (This->run.fontFace)
5482 IDWriteFontFace_Release(This->run.fontFace);
5483 heap_free(This->glyphs);
5484 heap_free(This->origins);
5485 heap_free(This->bitmap);
5486 heap_free(This);
5489 return ref;
5492 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5494 switch (mode)
5496 case DWRITE_RENDERING_MODE1_NATURAL:
5497 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5498 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5499 return TRUE;
5500 default:
5501 return FALSE;
5505 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5507 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5510 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5512 struct dwrite_glyphbitmap glyph_bitmap;
5513 IDWriteFontFace4 *fontface;
5514 HRESULT hr;
5515 UINT32 i;
5517 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5518 *bounds = analysis->bounds;
5519 return;
5522 if (analysis->run.isSideways)
5523 FIXME("sideways runs are not supported.\n");
5525 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5526 if (FAILED(hr))
5527 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5529 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5530 glyph_bitmap.fontface = fontface;
5531 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5532 glyph_bitmap.emsize = analysis->run.fontEmSize;
5533 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5534 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5535 glyph_bitmap.m = &analysis->m;
5537 for (i = 0; i < analysis->run.glyphCount; i++) {
5538 RECT *bbox = &glyph_bitmap.bbox;
5539 UINT32 bitmap_size;
5541 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5542 freetype_get_glyph_bbox(&glyph_bitmap);
5544 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5545 (bbox->bottom - bbox->top);
5546 if (bitmap_size > analysis->max_glyph_bitmap_size)
5547 analysis->max_glyph_bitmap_size = bitmap_size;
5549 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5550 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5553 IDWriteFontFace4_Release(fontface);
5555 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5556 *bounds = analysis->bounds;
5559 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5561 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5563 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5565 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5566 SetRectEmpty(bounds);
5567 return E_INVALIDARG;
5570 if (type != This->texture_type) {
5571 SetRectEmpty(bounds);
5572 return S_OK;
5575 glyphrunanalysis_get_texturebounds(This, bounds);
5576 return S_OK;
5579 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5581 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5582 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5583 (runbounds->left - bounds->left) * 3;
5584 else
5585 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5586 runbounds->left - bounds->left;
5589 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5591 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5592 struct dwrite_glyphbitmap glyph_bitmap;
5593 IDWriteFontFace4 *fontface;
5594 D2D_POINT_2F origin;
5595 UINT32 i, size;
5596 HRESULT hr;
5597 RECT *bbox;
5599 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5600 if (FAILED(hr)) {
5601 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5602 return hr;
5605 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5606 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5607 size *= 3;
5608 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5609 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5610 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5611 IDWriteFontFace4_Release(fontface);
5612 return E_OUTOFMEMORY;
5615 origin.x = origin.y = 0.0f;
5617 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5618 glyph_bitmap.fontface = fontface;
5619 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5620 glyph_bitmap.emsize = analysis->run.fontEmSize;
5621 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5622 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5623 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5624 glyph_bitmap.m = &analysis->m;
5625 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5626 IDWriteFontFace4_Release(fontface);
5627 return E_OUTOFMEMORY;
5630 bbox = &glyph_bitmap.bbox;
5632 for (i = 0; i < analysis->run.glyphCount; i++) {
5633 BYTE *src = glyph_bitmap.buf, *dst;
5634 int x, y, width, height;
5635 BOOL is_1bpp;
5637 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5638 freetype_get_glyph_bbox(&glyph_bitmap);
5640 if (IsRectEmpty(bbox))
5641 continue;
5643 width = bbox->right - bbox->left;
5644 height = bbox->bottom - bbox->top;
5646 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5647 memset(src, 0, height * glyph_bitmap.pitch);
5648 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5650 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5652 /* blit to analysis bitmap */
5653 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5655 if (is_1bpp) {
5656 /* convert 1bpp to 8bpp/24bpp */
5657 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5658 for (y = 0; y < height; y++) {
5659 for (x = 0; x < width; x++)
5660 if (src[x / 8] & masks[x % 8])
5661 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5662 src += glyph_bitmap.pitch;
5663 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5666 else {
5667 for (y = 0; y < height; y++) {
5668 for (x = 0; x < width; x++)
5669 if (src[x / 8] & masks[x % 8])
5670 dst[x] = DWRITE_ALPHA_MAX;
5671 src += glyph_bitmap.pitch;
5672 dst += analysis->bounds.right - analysis->bounds.left;
5676 else {
5677 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5678 for (y = 0; y < height; y++) {
5679 for (x = 0; x < width; x++)
5680 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5681 src += glyph_bitmap.pitch;
5682 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5685 else {
5686 for (y = 0; y < height; y++) {
5687 for (x = 0; x < width; x++)
5688 dst[x] |= src[x];
5689 src += glyph_bitmap.pitch;
5690 dst += analysis->bounds.right - analysis->bounds.left;
5695 heap_free(glyph_bitmap.buf);
5697 IDWriteFontFace4_Release(fontface);
5699 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5701 /* we don't need this anymore */
5702 heap_free(analysis->glyphs);
5703 heap_free(analysis->origins);
5704 IDWriteFontFace_Release(analysis->run.fontFace);
5706 analysis->glyphs = NULL;
5707 analysis->origins = NULL;
5708 analysis->run.glyphIndices = NULL;
5709 analysis->run.fontFace = NULL;
5711 return S_OK;
5714 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5715 RECT const *bounds, BYTE *bitmap, UINT32 size)
5717 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5718 UINT32 required;
5719 RECT runbounds;
5721 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5723 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5724 return E_INVALIDARG;
5726 /* make sure buffer is large enough for requested texture type */
5727 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5728 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5729 required *= 3;
5731 if (size < required)
5732 return E_NOT_SUFFICIENT_BUFFER;
5734 /* validate requested texture type */
5735 if (This->texture_type != type)
5736 return DWRITE_E_UNSUPPORTEDOPERATION;
5738 memset(bitmap, 0, size);
5739 glyphrunanalysis_get_texturebounds(This, &runbounds);
5740 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5741 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5742 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5743 int dst_width = (bounds->right - bounds->left) * pixel_size;
5744 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5745 BYTE *src, *dst;
5746 int y;
5748 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5749 HRESULT hr;
5751 if (FAILED(hr = glyphrunanalysis_render(This)))
5752 return hr;
5755 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5756 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5758 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5759 memcpy(dst, src, draw_width);
5760 src += src_width;
5761 dst += dst_width;
5765 return S_OK;
5768 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5769 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5771 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5773 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5775 if (!params)
5776 return E_INVALIDARG;
5778 switch (This->rendering_mode)
5780 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5781 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5783 UINT value = 0;
5784 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5785 *gamma = (FLOAT)value / 1000.0f;
5786 *contrast = 0.0f;
5787 *cleartypelevel = 1.0f;
5788 break;
5790 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5791 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5792 /* fallthrough */
5793 case DWRITE_RENDERING_MODE1_ALIASED:
5794 case DWRITE_RENDERING_MODE1_NATURAL:
5795 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5796 *gamma = IDWriteRenderingParams_GetGamma(params);
5797 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5798 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5799 break;
5800 default:
5804 return S_OK;
5807 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5808 glyphrunanalysis_QueryInterface,
5809 glyphrunanalysis_AddRef,
5810 glyphrunanalysis_Release,
5811 glyphrunanalysis_GetAlphaTextureBounds,
5812 glyphrunanalysis_CreateAlphaTexture,
5813 glyphrunanalysis_GetAlphaBlendParams
5816 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5818 D2D_POINT_2F ret;
5819 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5820 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5821 *point = ret;
5824 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5825 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5827 unsigned int upem = fontface->metrics.designUnitsPerEm;
5828 int advance;
5830 if (is_sideways)
5831 FIXME("Sideways mode is not supported.\n");
5833 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5835 switch (measuring_mode)
5837 case DWRITE_MEASURING_MODE_NATURAL:
5838 return (float)advance * emsize / (float)upem;
5839 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5840 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5841 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5842 default:
5843 WARN("Unknown measuring mode %u.\n", measuring_mode);
5844 return 0.0f;
5848 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5850 struct dwrite_glyphrunanalysis *analysis;
5851 struct dwrite_fontface *fontface;
5852 D2D_POINT_2F origin;
5853 FLOAT rtl_factor;
5854 UINT32 i;
5856 *ret = NULL;
5858 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5859 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5860 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5861 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5862 return E_INVALIDARG;
5864 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5865 return E_INVALIDARG;
5867 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5868 return E_INVALIDARG;
5870 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5871 return E_INVALIDARG;
5873 analysis = heap_alloc(sizeof(*analysis));
5874 if (!analysis)
5875 return E_OUTOFMEMORY;
5877 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5878 analysis->ref = 1;
5879 analysis->rendering_mode = desc->rendering_mode;
5881 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5882 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5883 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5884 else
5885 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5887 analysis->flags = 0;
5888 analysis->bitmap = NULL;
5889 analysis->max_glyph_bitmap_size = 0;
5890 SetRectEmpty(&analysis->bounds);
5891 analysis->run = *desc->run;
5892 IDWriteFontFace_AddRef(analysis->run.fontFace);
5893 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5894 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5896 if (!analysis->glyphs || !analysis->origins) {
5897 heap_free(analysis->glyphs);
5898 heap_free(analysis->origins);
5900 analysis->glyphs = NULL;
5901 analysis->origins = NULL;
5903 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5904 return E_OUTOFMEMORY;
5907 /* check if transform is usable */
5908 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5909 analysis->m = *desc->transform;
5910 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5912 else
5913 memset(&analysis->m, 0, sizeof(analysis->m));
5915 analysis->run.glyphIndices = analysis->glyphs;
5916 analysis->run.glyphAdvances = NULL;
5917 analysis->run.glyphOffsets = NULL;
5919 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5921 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5923 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5925 origin.x = desc->origin.x;
5926 origin.y = desc->origin.y;
5927 for (i = 0; i < desc->run->glyphCount; ++i)
5929 float advance;
5931 /* Use nominal advances if not provided by caller. */
5932 if (desc->run->glyphAdvances)
5933 advance = rtl_factor * desc->run->glyphAdvances[i];
5934 else
5935 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5936 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5938 analysis->origins[i] = origin;
5939 if (desc->run->bidiLevel & 1)
5941 if (desc->run->isSideways)
5942 analysis->origins[i].y += advance;
5943 else
5944 analysis->origins[i].x += advance;
5947 /* Offsets are optional, appled to pre-transformed origin. */
5948 if (desc->run->glyphOffsets) {
5949 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5950 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5952 if (desc->run->isSideways) {
5953 analysis->origins[i].x += ascenderoffset;
5954 analysis->origins[i].y += advanceoffset;
5956 else {
5957 analysis->origins[i].x += advanceoffset;
5958 analysis->origins[i].y += ascenderoffset;
5962 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5963 transform_point(analysis->origins + i, &analysis->m);
5965 if (desc->run->isSideways)
5966 origin.y += advance;
5967 else
5968 origin.x += advance;
5971 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5972 return S_OK;
5975 /* IDWriteColorGlyphRunEnumerator1 */
5976 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
5978 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5980 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
5981 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5982 IsEqualIID(riid, &IID_IUnknown))
5984 *ppv = iface;
5985 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
5986 return S_OK;
5989 WARN("%s not implemented.\n", debugstr_guid(riid));
5991 *ppv = NULL;
5992 return E_NOINTERFACE;
5995 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
5997 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5998 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6000 TRACE("%p, refcount %u.\n", iface, refcount);
6002 return refcount;
6005 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6007 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6008 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6010 TRACE("%p, refcount %u.\n", iface, refcount);
6012 if (!refcount)
6014 heap_free(glyphenum->advances);
6015 heap_free(glyphenum->color_advances);
6016 heap_free(glyphenum->offsets);
6017 heap_free(glyphenum->color_offsets);
6018 heap_free(glyphenum->glyphindices);
6019 heap_free(glyphenum->glyphs);
6020 if (glyphenum->colr.context)
6021 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6022 IDWriteFontFace5_Release(glyphenum->fontface);
6023 heap_free(glyphenum);
6026 return refcount;
6029 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6031 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6032 FLOAT origin = 0.0f;
6034 if (g == 0)
6035 return 0.0f;
6037 while (g--)
6038 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6039 return origin;
6042 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6044 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6045 FLOAT advance_adj = 0.0f;
6046 BOOL got_palette_index;
6047 UINT32 g;
6049 /* start with regular glyphs */
6050 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6051 UINT32 first_glyph = 0;
6053 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6054 if (glyphenum->glyphs[g].num_layers == 0) {
6055 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6056 first_glyph = min(first_glyph, g);
6058 else
6059 glyphenum->glyphindices[g] = 1;
6060 glyphenum->color_advances[g] = glyphenum->advances[g];
6061 if (glyphenum->color_offsets)
6062 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6065 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6066 colorrun->baselineOriginY = glyphenum->origin_y;
6067 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6068 colorrun->paletteIndex = 0xffff;
6069 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6070 glyphenum->has_regular_glyphs = FALSE;
6071 return TRUE;
6073 else {
6074 colorrun->glyphRun.glyphCount = 0;
6075 got_palette_index = FALSE;
6078 advance_adj = 0.0f;
6079 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6081 glyphenum->glyphindices[g] = 1;
6083 /* all glyph layers were returned */
6084 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6085 advance_adj += glyphenum->advances[g];
6086 continue;
6089 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6090 UINT32 index = colorrun->glyphRun.glyphCount;
6091 if (!got_palette_index) {
6092 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6093 /* use foreground color or request one from the font */
6094 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6095 if (colorrun->paletteIndex != 0xffff)
6097 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6098 colorrun->paletteIndex, 1, &colorrun->runColor);
6099 if (FAILED(hr))
6100 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6101 glyphenum->palette, colorrun->paletteIndex, hr);
6103 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6104 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6105 colorrun->baselineOriginY = glyphenum->origin_y;
6106 glyphenum->color_advances[index] = glyphenum->advances[g];
6107 got_palette_index = TRUE;
6110 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6111 /* offsets are relative to glyph origin, nothing to fix up */
6112 if (glyphenum->color_offsets)
6113 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6114 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6115 if (index)
6116 glyphenum->color_advances[index-1] += advance_adj;
6117 colorrun->glyphRun.glyphCount++;
6118 advance_adj = 0.0f;
6120 else
6121 advance_adj += glyphenum->advances[g];
6124 /* reset last advance */
6125 if (colorrun->glyphRun.glyphCount)
6126 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6128 return colorrun->glyphRun.glyphCount > 0;
6131 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6133 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6135 TRACE("%p, %p.\n", iface, has_run);
6137 *has_run = FALSE;
6139 glyphenum->colorrun.glyphRun.glyphCount = 0;
6140 while (glyphenum->current_layer < glyphenum->max_layer_num)
6142 if (colorglyphenum_build_color_run(glyphenum))
6143 break;
6144 else
6145 glyphenum->current_layer++;
6148 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6150 return S_OK;
6153 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6154 DWRITE_COLOR_GLYPH_RUN1 const **run)
6156 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6158 *run = NULL;
6159 return E_NOT_VALID_STATE;
6162 *run = &glyphenum->colorrun;
6163 return S_OK;
6166 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6167 DWRITE_COLOR_GLYPH_RUN const **run)
6169 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6171 TRACE("%p, %p.\n", iface, run);
6173 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6176 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6177 DWRITE_COLOR_GLYPH_RUN1 const **run)
6179 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6181 TRACE("%p, %p.\n", iface, run);
6183 return colorglyphenum_get_current_run(glyphenum, run);
6186 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6188 colorglyphenum_QueryInterface,
6189 colorglyphenum_AddRef,
6190 colorglyphenum_Release,
6191 colorglyphenum_MoveNext,
6192 colorglyphenum_GetCurrentRun,
6193 colorglyphenum1_GetCurrentRun,
6196 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6197 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6198 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6200 struct dwrite_colorglyphenum *colorglyphenum;
6201 BOOL colorfont, has_colored_glyph;
6202 struct dwrite_fontface *fontface;
6203 unsigned int i;
6205 *ret = NULL;
6207 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6209 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6210 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6211 if (!colorfont)
6212 return DWRITE_E_NOCOLOR;
6214 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6215 if (!colorglyphenum)
6216 return E_OUTOFMEMORY;
6218 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6219 colorglyphenum->refcount = 1;
6220 colorglyphenum->origin_x = originX;
6221 colorglyphenum->origin_y = originY;
6222 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6223 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6224 colorglyphenum->glyphs = NULL;
6225 colorglyphenum->run = *run;
6226 colorglyphenum->run.glyphIndices = NULL;
6227 colorglyphenum->run.glyphAdvances = NULL;
6228 colorglyphenum->run.glyphOffsets = NULL;
6229 colorglyphenum->palette = palette;
6230 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6231 colorglyphenum->colr.exists = TRUE;
6232 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6233 colorglyphenum->current_layer = 0;
6234 colorglyphenum->max_layer_num = 0;
6236 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6238 has_colored_glyph = FALSE;
6239 colorglyphenum->has_regular_glyphs = FALSE;
6240 for (i = 0; i < run->glyphCount; i++) {
6241 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6242 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6243 has_colored_glyph = TRUE;
6245 if (colorglyphenum->glyphs[i].num_layers == 0)
6246 colorglyphenum->has_regular_glyphs = TRUE;
6249 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6250 is supposed to proceed normally, like if font had no color info at all. */
6251 if (!has_colored_glyph) {
6252 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6253 return DWRITE_E_NOCOLOR;
6256 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6257 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6258 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6259 if (run->glyphOffsets) {
6260 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6261 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6262 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6265 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6266 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6267 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6268 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6269 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6270 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6271 colorglyphenum->colorrun.measuringMode = measuring_mode;
6272 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6274 if (run->glyphAdvances)
6275 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6276 else
6278 for (i = 0; i < run->glyphCount; ++i)
6279 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6280 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6283 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6285 return S_OK;
6288 /* IDWriteFontFaceReference */
6289 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6291 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6293 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6294 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6295 IsEqualIID(riid, &IID_IUnknown))
6297 *obj = iface;
6298 IDWriteFontFaceReference1_AddRef(iface);
6299 return S_OK;
6302 WARN("%s not implemented.\n", debugstr_guid(riid));
6304 *obj = NULL;
6306 return E_NOINTERFACE;
6309 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6311 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6312 ULONG refcount = InterlockedIncrement(&reference->refcount);
6314 TRACE("%p, refcount %u.\n", iface, refcount);
6316 return refcount;
6319 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6321 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6322 ULONG refcount = InterlockedDecrement(&reference->refcount);
6324 TRACE("%p, refcount %u.\n", iface, refcount);
6326 if (!refcount)
6328 IDWriteFontFile_Release(reference->file);
6329 IDWriteFactory7_Release(reference->factory);
6330 heap_free(reference->axis_values);
6331 heap_free(reference);
6334 return refcount;
6337 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6339 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6341 TRACE("%p, %p.\n", iface, fontface);
6343 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6346 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6347 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6349 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6350 DWRITE_FONT_FILE_TYPE file_type;
6351 DWRITE_FONT_FACE_TYPE face_type;
6352 IDWriteFontFace *fontface;
6353 BOOL is_supported;
6354 UINT32 face_num;
6355 HRESULT hr;
6357 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6359 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6360 if (FAILED(hr))
6361 return hr;
6363 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6364 simulations, &fontface);
6365 if (SUCCEEDED(hr))
6367 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6368 IDWriteFontFace_Release(fontface);
6371 return hr;
6374 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6376 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6377 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6378 BOOL ret;
6380 TRACE("%p, %p.\n", iface, ref);
6382 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6383 reference->simulations == other->simulations;
6384 if (reference->axis_values_count)
6386 ret &= reference->axis_values_count == other->axis_values_count &&
6387 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6390 return ret;
6393 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6395 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6397 TRACE("%p.\n", iface);
6399 return reference->index;
6402 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6404 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6406 TRACE("%p.\n", iface);
6408 return reference->simulations;
6411 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6413 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6414 IDWriteFontFileLoader *loader;
6415 const void *key;
6416 UINT32 key_size;
6417 HRESULT hr;
6419 TRACE("%p, %p.\n", iface, file);
6421 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6422 if (FAILED(hr))
6423 return hr;
6425 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6426 if (FAILED(hr))
6427 return hr;
6429 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6430 IDWriteFontFileLoader_Release(loader);
6432 return hr;
6435 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6437 FIXME("%p.\n", iface);
6439 return 0;
6442 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6444 FIXME("%p.\n", iface);
6446 return 0;
6449 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6451 FIXME("%p, %p.\n", iface, writetime);
6453 return E_NOTIMPL;
6456 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6458 FIXME("%p.\n", iface);
6460 return DWRITE_LOCALITY_LOCAL;
6463 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6465 FIXME("%p.\n", iface);
6467 return E_NOTIMPL;
6470 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6471 WCHAR const *chars, UINT32 count)
6473 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6475 return E_NOTIMPL;
6478 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6479 UINT16 const *glyphs, UINT32 count)
6481 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6483 return E_NOTIMPL;
6486 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6487 UINT64 offset, UINT64 size)
6489 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6491 return E_NOTIMPL;
6494 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6496 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6497 IDWriteFontFace3 *fontface3;
6498 HRESULT hr;
6500 TRACE("%p, %p.\n", iface, fontface);
6502 /* FIXME: created instance should likely respect given axis. */
6503 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6504 &fontface3)))
6506 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6507 IDWriteFontFace3_Release(fontface3);
6510 return hr;
6513 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6515 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6517 TRACE("%p.\n", iface);
6519 return reference->axis_values_count;
6522 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6523 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6525 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6527 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6529 if (value_count < reference->axis_values_count)
6530 return E_NOT_SUFFICIENT_BUFFER;
6532 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6534 return S_OK;
6537 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6539 fontfacereference_QueryInterface,
6540 fontfacereference_AddRef,
6541 fontfacereference_Release,
6542 fontfacereference_CreateFontFace,
6543 fontfacereference_CreateFontFaceWithSimulations,
6544 fontfacereference_Equals,
6545 fontfacereference_GetFontFaceIndex,
6546 fontfacereference_GetSimulations,
6547 fontfacereference_GetFontFile,
6548 fontfacereference_GetLocalFileSize,
6549 fontfacereference_GetFileSize,
6550 fontfacereference_GetFileTime,
6551 fontfacereference_GetLocality,
6552 fontfacereference_EnqueueFontDownloadRequest,
6553 fontfacereference_EnqueueCharacterDownloadRequest,
6554 fontfacereference_EnqueueGlyphDownloadRequest,
6555 fontfacereference_EnqueueFileFragmentDownloadRequest,
6556 fontfacereference1_CreateFontFace,
6557 fontfacereference1_GetFontAxisValueCount,
6558 fontfacereference1_GetFontAxisValues,
6561 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6562 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6563 IDWriteFontFaceReference1 **ret)
6565 struct dwrite_fontfacereference *object;
6567 *ret = NULL;
6569 if (!is_simulation_valid(simulations))
6570 return E_INVALIDARG;
6572 object = heap_alloc_zero(sizeof(*object));
6573 if (!object)
6574 return E_OUTOFMEMORY;
6576 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6577 object->refcount = 1;
6579 object->factory = factory;
6580 IDWriteFactory7_AddRef(object->factory);
6581 object->file = file;
6582 IDWriteFontFile_AddRef(object->file);
6583 object->index = index;
6584 object->simulations = simulations;
6585 if (axis_values_count)
6587 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6589 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6590 return E_OUTOFMEMORY;
6592 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6593 object->axis_values_count = axis_values_count;
6596 *ret = &object->IDWriteFontFaceReference1_iface;
6598 return S_OK;
6601 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6603 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6605 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6607 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6608 *obj = iface;
6609 IDWriteFontFileStream_AddRef(iface);
6610 return S_OK;
6613 *obj = NULL;
6615 WARN("%s not implemented.\n", debugstr_guid(riid));
6616 return E_NOINTERFACE;
6619 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6621 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6622 ULONG ref = InterlockedIncrement(&stream->ref);
6623 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6624 return ref;
6627 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6629 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6630 ULONG ref = InterlockedDecrement(&stream->ref);
6632 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6634 if (!ref) {
6635 release_inmemory_stream(stream->data);
6636 heap_free(stream);
6639 return ref;
6642 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6643 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6645 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6647 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6648 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6650 *fragment_context = NULL;
6652 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6653 *fragment_start = NULL;
6654 return E_FAIL;
6657 *fragment_start = (char *)stream->data->data + offset;
6658 return S_OK;
6661 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6663 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6665 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6668 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6670 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6672 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6674 *size = stream->data->size;
6676 return S_OK;
6679 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6681 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6683 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6685 *last_writetime = 0;
6687 return E_NOTIMPL;
6690 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6691 inmemoryfilestream_QueryInterface,
6692 inmemoryfilestream_AddRef,
6693 inmemoryfilestream_Release,
6694 inmemoryfilestream_ReadFileFragment,
6695 inmemoryfilestream_ReleaseFileFragment,
6696 inmemoryfilestream_GetFileSize,
6697 inmemoryfilestream_GetLastWriteTime,
6700 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6701 REFIID riid, void **obj)
6703 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6705 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6707 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6708 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6709 IsEqualIID(riid, &IID_IUnknown))
6711 *obj = iface;
6712 IDWriteInMemoryFontFileLoader_AddRef(iface);
6713 return S_OK;
6716 WARN("%s not implemented.\n", debugstr_guid(riid));
6718 *obj = NULL;
6720 return E_NOINTERFACE;
6723 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6725 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6726 ULONG ref = InterlockedIncrement(&loader->ref);
6727 TRACE("(%p)->(%u)\n", loader, ref);
6728 return ref;
6731 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6733 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6734 ULONG ref = InterlockedDecrement(&loader->ref);
6735 size_t i;
6737 TRACE("(%p)->(%u)\n", loader, ref);
6739 if (!ref) {
6740 for (i = 0; i < loader->count; ++i)
6741 release_inmemory_stream(loader->streams[i]);
6742 heap_free(loader->streams);
6743 heap_free(loader);
6746 return ref;
6749 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6750 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6752 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6753 struct dwrite_inmemory_filestream *stream;
6754 DWORD index;
6756 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6758 *ret = NULL;
6760 if (key_size != sizeof(DWORD))
6761 return E_INVALIDARG;
6763 index = *(DWORD *)key;
6765 if (index >= loader->count)
6766 return E_INVALIDARG;
6768 if (!(stream = heap_alloc(sizeof(*stream))))
6769 return E_OUTOFMEMORY;
6771 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6772 stream->ref = 1;
6773 stream->data = loader->streams[index];
6774 InterlockedIncrement(&stream->data->ref);
6776 *ret = &stream->IDWriteFontFileStream_iface;
6778 return S_OK;
6781 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6782 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6784 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6785 struct dwrite_inmemory_stream_data *stream;
6786 DWORD key;
6788 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6790 *fontfile = NULL;
6792 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6793 return E_OUTOFMEMORY;
6795 if (!(stream = heap_alloc(sizeof(*stream))))
6796 return E_OUTOFMEMORY;
6798 stream->ref = 1;
6799 stream->size = data_size;
6800 stream->owner = owner;
6801 if (stream->owner) {
6802 IUnknown_AddRef(stream->owner);
6803 stream->data = (void *)data;
6805 else {
6806 if (!(stream->data = heap_alloc(data_size))) {
6807 heap_free(stream);
6808 return E_OUTOFMEMORY;
6810 memcpy(stream->data, data, data_size);
6813 key = loader->count;
6814 loader->streams[loader->count++] = stream;
6816 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6817 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6820 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6822 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6824 TRACE("%p.\n", iface);
6826 return loader->count;
6829 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6831 inmemoryfontfileloader_QueryInterface,
6832 inmemoryfontfileloader_AddRef,
6833 inmemoryfontfileloader_Release,
6834 inmemoryfontfileloader_CreateStreamFromKey,
6835 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6836 inmemoryfontfileloader_GetFileCount,
6839 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6841 struct dwrite_inmemory_fileloader *loader;
6843 *ret = NULL;
6845 loader = heap_alloc_zero(sizeof(*loader));
6846 if (!loader)
6847 return E_OUTOFMEMORY;
6849 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6850 loader->ref = 1;
6852 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6854 return S_OK;
6857 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6859 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6861 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6862 IsEqualIID(riid, &IID_IUnknown))
6864 *obj = iface;
6865 IDWriteFontResource_AddRef(iface);
6866 return S_OK;
6869 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6871 return E_NOINTERFACE;
6874 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6876 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6877 ULONG refcount = InterlockedIncrement(&resource->refcount);
6879 TRACE("%p, refcount %u.\n", iface, refcount);
6881 return refcount;
6884 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6886 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6887 ULONG refcount = InterlockedDecrement(&resource->refcount);
6889 TRACE("%p, refcount %u.\n", iface, refcount);
6891 if (!refcount)
6893 IDWriteFactory7_Release(resource->factory);
6894 IDWriteFontFile_Release(resource->file);
6895 heap_free(resource);
6898 return refcount;
6901 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6903 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6905 TRACE("%p, %p.\n", iface, fontfile);
6907 *fontfile = resource->file;
6908 IDWriteFontFile_AddRef(*fontfile);
6910 return S_OK;
6913 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6915 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6917 TRACE("%p.\n", iface);
6919 return resource->face_index;
6922 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6924 FIXME("%p.\n", iface);
6926 return 0;
6929 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6930 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6932 FIXME("%p, %p, %u.\n", iface, values, num_values);
6934 return E_NOTIMPL;
6937 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6938 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
6940 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
6942 return E_NOTIMPL;
6945 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
6946 UINT32 axis)
6948 FIXME("%p, %u.\n", iface, axis);
6950 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
6953 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
6954 IDWriteLocalizedStrings **names)
6956 FIXME("%p, %u, %p.\n", iface, axis, names);
6958 return E_NOTIMPL;
6961 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
6963 FIXME("%p, %u.\n", iface, axis);
6965 return 0;
6968 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
6969 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
6971 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
6973 return E_NOTIMPL;
6976 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
6978 FIXME("%p.\n", iface);
6980 return FALSE;
6983 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
6984 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
6985 IDWriteFontFace5 **fontface)
6987 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6988 IDWriteFontFaceReference1 *reference;
6989 HRESULT hr;
6991 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
6993 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
6994 simulations, axis_values, num_values, &reference);
6995 if (SUCCEEDED(hr))
6997 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
6998 IDWriteFontFaceReference1_Release(reference);
7001 return hr;
7004 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7005 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7006 IDWriteFontFaceReference1 **reference)
7008 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7010 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7012 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7013 simulations, axis_values, num_values, reference);
7016 static const IDWriteFontResourceVtbl fontresourcevtbl =
7018 dwritefontresource_QueryInterface,
7019 dwritefontresource_AddRef,
7020 dwritefontresource_Release,
7021 dwritefontresource_GetFontFile,
7022 dwritefontresource_GetFontFaceIndex,
7023 dwritefontresource_GetFontAxisCount,
7024 dwritefontresource_GetDefaultFontAxisValues,
7025 dwritefontresource_GetFontAxisRanges,
7026 dwritefontresource_GetFontAxisAttributes,
7027 dwritefontresource_GetAxisNames,
7028 dwritefontresource_GetAxisValueNameCount,
7029 dwritefontresource_GetAxisValueNames,
7030 dwritefontresource_HasVariations,
7031 dwritefontresource_CreateFontFace,
7032 dwritefontresource_CreateFontFaceReference,
7035 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7036 IDWriteFontResource **ret)
7038 struct dwrite_fontresource *resource;
7040 *ret = NULL;
7042 resource = heap_alloc_zero(sizeof(*resource));
7043 if (!resource)
7044 return E_OUTOFMEMORY;
7046 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7047 resource->refcount = 1;
7048 resource->face_index = face_index;
7049 resource->file = file;
7050 IDWriteFontFile_AddRef(resource->file);
7051 resource->factory = factory;
7052 IDWriteFactory7_AddRef(resource->factory);
7054 *ret = &resource->IDWriteFontResource_iface;
7056 return S_OK;