winecoreaudio: Remove GetAudioSessionWrapper.
[wine.git] / dlls / dwrite / font.c
bloba73f82395875a335aa6a524068e63a8c04a17e87
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2022 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"
29 #include "unixlib.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
32 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
34 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
35 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
36 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
37 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
38 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
39 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
40 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
41 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
43 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
45 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
46 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
47 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
49 struct cache_key
51 float size;
52 unsigned short glyph;
53 unsigned short mode;
56 struct cache_entry
58 struct wine_rb_entry entry;
59 struct list mru;
60 struct cache_key key;
61 int advance;
62 RECT bbox;
63 BYTE *bitmap;
64 unsigned int bitmap_size;
65 unsigned int is_1bpp : 1;
66 unsigned int has_contours : 1;
67 unsigned int has_advance : 1;
68 unsigned int has_bbox : 1;
69 unsigned int has_bitmap : 1;
72 /* Ignore dx and dy because FreeType doesn't actually use it */
73 static inline void matrix_2x2_from_dwrite_matrix(MATRIX_2X2 *m1, const DWRITE_MATRIX *m2)
75 m1->m11 = m2->m11;
76 m1->m12 = m2->m12;
77 m1->m21 = m2->m21;
78 m1->m22 = m2->m22;
81 static void fontface_release_cache_entry(struct cache_entry *entry)
83 free(entry->bitmap);
84 free(entry);
87 static struct cache_entry * fontface_get_cache_entry(struct dwrite_fontface *fontface, size_t size,
88 const struct cache_key *key)
90 struct cache_entry *entry, *old_entry;
91 struct wine_rb_entry *e;
93 if (!(e = wine_rb_get(&fontface->cache.tree, key)))
95 if (!(entry = calloc(1, sizeof(*entry)))) return NULL;
96 entry->key = *key;
97 list_init(&entry->mru);
99 size += sizeof(*entry);
101 if ((fontface->cache.size + size > fontface->cache.max_size) && !list_empty(&fontface->cache.mru))
103 old_entry = LIST_ENTRY(list_tail(&fontface->cache.mru), struct cache_entry, mru);
104 fontface->cache.size -= (old_entry->bitmap_size + sizeof(*old_entry));
105 wine_rb_remove(&fontface->cache.tree, &old_entry->entry);
106 list_remove(&old_entry->mru);
107 fontface_release_cache_entry(old_entry);
110 if (wine_rb_put(&fontface->cache.tree, key, &entry->entry) == -1)
112 WARN("Failed to add cache entry.\n");
113 free(entry);
114 return NULL;
117 fontface->cache.size += size;
119 else
120 entry = WINE_RB_ENTRY_VALUE(e, struct cache_entry, entry);
122 list_remove(&entry->mru);
123 list_add_head(&fontface->cache.mru, &entry->mru);
125 return entry;
128 static int fontface_get_glyph_advance(struct dwrite_fontface *fontface, float fontsize, unsigned short glyph,
129 unsigned short mode, BOOL *has_contours)
131 struct cache_key key = { .size = fontsize, .glyph = glyph, .mode = mode };
132 struct get_glyph_advance_params params;
133 struct cache_entry *entry;
134 unsigned int value;
136 if (!(entry = fontface_get_cache_entry(fontface, 0, &key)))
137 return 0;
139 if (!entry->has_advance)
141 params.object = fontface->get_font_object(fontface);
142 params.glyph = glyph;
143 params.mode = mode;
144 params.emsize = fontsize;
145 params.advance = &entry->advance;
146 params.has_contours = &value;
148 UNIX_CALL(get_glyph_advance, &params);
150 entry->has_contours = !!value;
151 entry->has_advance = 1;
154 *has_contours = entry->has_contours;
155 return entry->advance;
158 void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *iface, struct dwrite_glyphbitmap *bitmap)
160 struct cache_key key = { .size = bitmap->emsize, .glyph = bitmap->glyph, .mode = DWRITE_MEASURING_MODE_NATURAL };
161 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
162 struct get_glyph_bbox_params params;
163 struct cache_entry *entry;
165 params.object = fontface->get_font_object(fontface);
166 params.simulations = bitmap->simulations;
167 params.glyph = bitmap->glyph;
168 params.emsize = bitmap->emsize;
169 matrix_2x2_from_dwrite_matrix(&params.m, bitmap->m ? bitmap->m : &identity);
171 EnterCriticalSection(&fontface->cs);
172 /* For now bypass cache for transformed cases. */
173 if (bitmap->m && memcmp(&params.m, &identity_2x2, sizeof(params.m)))
175 params.bbox = &bitmap->bbox;
176 UNIX_CALL(get_glyph_bbox, &params);
178 else if ((entry = fontface_get_cache_entry(fontface, 0, &key)))
180 if (!entry->has_bbox)
182 params.bbox = &entry->bbox;
183 UNIX_CALL(get_glyph_bbox, &params);
184 entry->has_bbox = 1;
186 bitmap->bbox = entry->bbox;
188 LeaveCriticalSection(&fontface->cs);
191 static unsigned int get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
193 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
196 static HRESULT dwrite_fontface_get_glyph_bitmap(struct dwrite_fontface *fontface, DWRITE_RENDERING_MODE rendering_mode,
197 unsigned int *is_1bpp, struct dwrite_glyphbitmap *bitmap)
199 struct cache_key key = { .size = bitmap->emsize, .glyph = bitmap->glyph, .mode = DWRITE_MEASURING_MODE_NATURAL };
200 struct get_glyph_bitmap_params params;
201 const RECT *bbox = &bitmap->bbox;
202 unsigned int bitmap_size, _1bpp;
203 struct cache_entry *entry;
204 HRESULT hr = S_OK;
206 bitmap_size = get_glyph_bitmap_pitch(rendering_mode, bbox->right - bbox->left) *
207 (bbox->bottom - bbox->top);
209 params.object = fontface->get_font_object(fontface);
210 params.simulations = fontface->simulations;
211 params.glyph = bitmap->glyph;
212 params.mode = rendering_mode;
213 params.emsize = bitmap->emsize;
214 params.bbox = bitmap->bbox;
215 params.pitch = bitmap->pitch;
216 params.bitmap = bitmap->buf;
217 params.is_1bpp = is_1bpp;
218 matrix_2x2_from_dwrite_matrix(&params.m, bitmap->m ? bitmap->m : &identity);
220 EnterCriticalSection(&fontface->cs);
221 /* For now bypass cache for transformed cases. */
222 if (bitmap->m && memcmp(&params.m, &identity_2x2, sizeof(params.m)))
224 UNIX_CALL(get_glyph_bitmap, &params);
226 else if ((entry = fontface_get_cache_entry(fontface, bitmap_size, &key)))
228 if (entry->has_bitmap)
230 memcpy(bitmap->buf, entry->bitmap, entry->bitmap_size);
232 else
234 params.is_1bpp = &_1bpp;
235 UNIX_CALL(get_glyph_bitmap, &params);
237 entry->bitmap_size = bitmap_size;
238 if ((entry->bitmap = malloc(entry->bitmap_size)))
239 memcpy(entry->bitmap, bitmap->buf, entry->bitmap_size);
240 entry->is_1bpp = !!_1bpp;
241 entry->has_bitmap = 1;
243 *is_1bpp = entry->is_1bpp;
245 else
246 hr = E_FAIL;
247 LeaveCriticalSection(&fontface->cs);
249 return hr;
252 static int fontface_cache_compare(const void *k, const struct wine_rb_entry *e)
254 const struct cache_entry *entry = WINE_RB_ENTRY_VALUE(e, const struct cache_entry, entry);
255 const struct cache_key *key = k, *key2 = &entry->key;
257 if (key->size != key2->size) return key->size < key2->size ? -1 : 1;
258 if (key->glyph != key2->glyph) return (int)key->glyph - (int)key2->glyph;
259 if (key->mode != key2->mode) return (int)key->mode - (int)key2->mode;
260 return 0;
263 static void fontface_cache_init(struct dwrite_fontface *fontface)
265 wine_rb_init(&fontface->cache.tree, fontface_cache_compare);
266 list_init(&fontface->cache.mru);
267 fontface->cache.max_size = 0x8000;
270 static void fontface_cache_clear(struct dwrite_fontface *fontface)
272 struct cache_entry *entry, *entry2;
274 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &fontface->cache.mru, struct cache_entry, mru)
276 list_remove(&entry->mru);
277 fontface_release_cache_entry(entry);
279 memset(&fontface->cache, 0, sizeof(fontface->cache));
282 struct dwrite_font_propvec {
283 FLOAT stretch;
284 FLOAT style;
285 FLOAT weight;
288 struct dwrite_font_data
290 LONG refcount;
292 DWRITE_FONT_STYLE style;
293 DWRITE_FONT_STRETCH stretch;
294 DWRITE_FONT_WEIGHT weight;
295 DWRITE_PANOSE panose;
296 FONTSIGNATURE fontsig;
297 UINT32 flags; /* enum font_flags */
298 struct dwrite_font_propvec propvec;
299 struct dwrite_cmap cmap;
300 /* Static axis for weight/width/italic. */
301 DWRITE_FONT_AXIS_VALUE axis[3];
303 DWRITE_FONT_METRICS1 metrics;
304 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
305 IDWriteLocalizedStrings *family_names;
306 IDWriteLocalizedStrings *names;
308 /* data needed to create fontface instance */
309 DWRITE_FONT_FACE_TYPE face_type;
310 IDWriteFontFile *file;
311 UINT32 face_index;
313 WCHAR *facename;
315 USHORT simulations;
317 LOGFONTW lf;
319 /* used to mark font as tested when scanning for simulation candidate */
320 unsigned int bold_sim_tested : 1;
321 unsigned int oblique_sim_tested : 1;
324 struct dwrite_fontfamily_data
326 LONG refcount;
328 IDWriteLocalizedStrings *familyname;
330 struct dwrite_font_data **fonts;
331 size_t size;
332 size_t count;
334 unsigned int has_normal_face : 1;
335 unsigned int has_oblique_face : 1;
336 unsigned int has_italic_face : 1;
339 struct dwrite_fontcollection
341 IDWriteFontCollection3 IDWriteFontCollection3_iface;
342 LONG refcount;
344 IDWriteFactory7 *factory;
345 DWRITE_FONT_FAMILY_MODEL family_model;
346 struct dwrite_fontfamily_data **family_data;
347 size_t size;
348 size_t count;
351 struct dwrite_fontfamily
353 IDWriteFontFamily2 IDWriteFontFamily2_iface;
354 IDWriteFontList2 IDWriteFontList2_iface;
355 LONG refcount;
357 struct dwrite_fontfamily_data *data;
358 struct dwrite_fontcollection *collection;
361 struct dwrite_fontlist
363 IDWriteFontList2 IDWriteFontList2_iface;
364 LONG refcount;
366 struct dwrite_font_data **fonts;
367 UINT32 font_count;
368 struct dwrite_fontfamily *family;
371 struct dwrite_font
373 IDWriteFont3 IDWriteFont3_iface;
374 LONG refcount;
376 DWRITE_FONT_STYLE style;
377 struct dwrite_font_data *data;
378 struct dwrite_fontfamily *family;
381 enum runanalysis_flags {
382 RUNANALYSIS_BOUNDS_READY = 1 << 0,
383 RUNANALYSIS_BITMAP_READY = 1 << 1,
384 RUNANALYSIS_USE_TRANSFORM = 1 << 2
387 struct dwrite_glyphrunanalysis
389 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
390 LONG refcount;
392 DWRITE_RENDERING_MODE1 rendering_mode;
393 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
394 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
395 DWRITE_MATRIX m;
396 UINT16 *glyphs;
397 D2D_POINT_2F *origins;
399 UINT8 flags;
400 RECT bounds;
401 BYTE *bitmap;
402 UINT32 max_glyph_bitmap_size;
405 struct dwrite_colorglyphenum
407 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
408 LONG refcount;
410 D2D1_POINT_2F origin; /* original run origin */
412 IDWriteFontFace5 *fontface; /* for convenience */
413 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
414 DWRITE_GLYPH_RUN run; /* base run */
415 UINT32 palette; /* palette index to get layer color from */
416 FLOAT *advances; /* original or measured advances for base glyphs */
417 FLOAT *color_advances; /* returned color run points to this */
418 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
419 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
420 UINT16 *glyphindices; /* returned color run points to this */
421 struct dwrite_colorglyph *glyphs; /* current glyph color info */
422 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
423 UINT16 current_layer; /* enumerator position, updated with MoveNext */
424 UINT16 max_layer_num; /* max number of layers for this run */
425 struct dwrite_fonttable colr; /* used to access layers */
428 struct dwrite_fontfile
430 IDWriteFontFile IDWriteFontFile_iface;
431 LONG refcount;
433 IDWriteFontFileLoader *loader;
434 void *reference_key;
435 UINT32 key_size;
436 IDWriteFontFileStream *stream;
439 struct dwrite_fontfacereference
441 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
442 LONG refcount;
444 IDWriteFontFile *file;
445 UINT32 index;
446 USHORT simulations;
447 DWRITE_FONT_AXIS_VALUE *axis_values;
448 UINT32 axis_values_count;
449 IDWriteFactory7 *factory;
452 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
454 struct dwrite_fontresource
456 IDWriteFontResource IDWriteFontResource_iface;
457 LONG refcount;
459 IDWriteFontFile *file;
460 UINT32 face_index;
461 IDWriteFactory7 *factory;
463 struct dwrite_var_axis *axis;
464 unsigned int axis_count;
467 struct dwrite_fontset_entry_desc
469 IDWriteFontFile *file;
470 DWRITE_FONT_FACE_TYPE face_type;
471 unsigned int face_index;
472 unsigned int simulations;
475 struct dwrite_fontset_entry
477 LONG refcount;
478 struct dwrite_fontset_entry_desc desc;
479 IDWriteLocalizedStrings *props[DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME + 1];
482 struct dwrite_fontset
484 IDWriteFontSet3 IDWriteFontSet3_iface;
485 LONG refcount;
486 IDWriteFactory7 *factory;
488 struct dwrite_fontset_entry **entries;
489 unsigned int count;
492 struct dwrite_fontset_builder
494 IDWriteFontSetBuilder2 IDWriteFontSetBuilder2_iface;
495 LONG refcount;
496 IDWriteFactory7 *factory;
498 struct dwrite_fontset_entry **entries;
499 size_t count;
500 size_t capacity;
503 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
504 unsigned int count, IDWriteFontSet1 **ret);
506 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
508 struct dwrite_fontface *fontface = context;
509 BOOL exists = FALSE;
511 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
512 size, data_context, &exists)) || !exists)
514 *data = NULL;
515 *size = 0;
516 *data_context = NULL;
520 static void dwrite_release_font_table(void *context, void *data_context)
522 struct dwrite_fontface *fontface = context;
523 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
526 static UINT16 dwrite_get_font_upem(void *context)
528 struct dwrite_fontface *fontface = context;
529 return fontface->metrics.designUnitsPerEm;
532 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
534 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
535 return opentype_cmap_get_glyph(&fontface->cmap, ch);
538 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
540 struct dwrite_fontface *fontface = context;
541 return !!dwritefontface_get_glyph(fontface, codepoint);
544 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
546 struct dwrite_fontface *fontface = context;
547 return dwritefontface_get_glyph(fontface, codepoint);
550 static const struct shaping_font_ops dwrite_font_ops =
552 dwrite_grab_font_table,
553 dwrite_release_font_table,
554 dwrite_get_font_upem,
555 dwrite_has_glyph,
556 dwrite_get_glyph,
559 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
561 if (fontface->shaping_cache)
562 return fontface->shaping_cache;
564 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
567 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
569 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
572 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
574 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
577 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
579 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
582 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
584 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
586 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
589 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
591 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
594 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
596 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
599 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
601 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
604 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
606 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
609 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
611 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
614 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
616 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
619 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
621 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
624 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
626 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
629 static struct dwrite_fontset_builder *impl_from_IDWriteFontSetBuilder2(IDWriteFontSetBuilder2 *iface)
631 return CONTAINING_RECORD(iface, struct dwrite_fontset_builder, IDWriteFontSetBuilder2_iface);
634 static struct dwrite_fontset *impl_from_IDWriteFontSet3(IDWriteFontSet3 *iface)
636 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
639 static struct dwrite_fontset *unsafe_impl_from_IDWriteFontSet(IDWriteFontSet *iface);
641 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
643 static const DWRITE_GLYPH_METRICS nil;
644 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
646 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
647 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
648 return S_OK;
651 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
653 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
655 if (!*block)
657 /* start new block */
658 if (!(*block = calloc(GLYPH_BLOCK_SIZE, sizeof(*metrics))))
659 return E_OUTOFMEMORY;
662 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
663 return S_OK;
666 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
668 HRESULT hr;
670 if (table->data || !table->exists)
671 return table->data;
673 table->exists = FALSE;
674 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
675 &table->exists);
676 if (FAILED(hr) || !table->exists) {
677 TRACE("Font does not have %s table\n", debugstr_tag(tag));
678 return NULL;
681 return table->data;
684 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
685 struct dwrite_font_propvec *vec)
687 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
688 vec->style = style * 7.0f;
689 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
692 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
694 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
697 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
699 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
702 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
704 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
705 return &fontface->vdmx;
708 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
710 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
711 return &fontface->gasp;
714 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
716 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
717 return &fontface->cpal;
720 static struct dwrite_font_data * addref_font_data(struct dwrite_font_data *data)
722 InterlockedIncrement(&data->refcount);
723 return data;
726 static void release_font_data(struct dwrite_font_data *data)
728 int i;
730 if (InterlockedDecrement(&data->refcount) > 0)
731 return;
733 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
735 if (data->info_strings[i])
736 IDWriteLocalizedStrings_Release(data->info_strings[i]);
738 if (data->names)
739 IDWriteLocalizedStrings_Release(data->names);
741 if (data->family_names)
742 IDWriteLocalizedStrings_Release(data->family_names);
744 dwrite_cmap_release(&data->cmap);
745 IDWriteFontFile_Release(data->file);
746 free(data->facename);
747 free(data);
750 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
752 size_t i;
754 if (InterlockedDecrement(&data->refcount) > 0)
755 return;
757 for (i = 0; i < data->count; ++i)
758 release_font_data(data->fonts[i]);
759 free(data->fonts);
760 IDWriteLocalizedStrings_Release(data->familyname);
761 free(data);
764 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
766 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
767 fontface->cached = NULL;
770 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
772 UINT32 left_key_size, right_key_size;
773 const void *left_key, *right_key;
774 HRESULT hr;
776 if (left == right)
777 return TRUE;
779 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
780 if (FAILED(hr))
781 return FALSE;
783 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
784 if (FAILED(hr))
785 return FALSE;
787 if (left_key_size != right_key_size)
788 return FALSE;
790 return !memcmp(left_key, right_key, left_key_size);
793 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
795 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
797 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
799 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
800 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
801 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
802 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
803 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
804 IsEqualIID(riid, &IID_IDWriteFontFace) ||
805 IsEqualIID(riid, &IID_IUnknown))
807 *obj = iface;
809 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
810 *obj = &fontface->IDWriteFontFaceReference_iface;
811 else
812 *obj = NULL;
814 if (*obj)
816 if (InterlockedIncrement(&fontface->refcount) == 1)
818 InterlockedDecrement(&fontface->refcount);
819 *obj = NULL;
820 return E_FAIL;
822 return S_OK;
825 WARN("%s not implemented.\n", debugstr_guid(riid));
827 return E_NOINTERFACE;
830 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
832 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
833 ULONG refcount = InterlockedIncrement(&fontface->refcount);
835 TRACE("%p, refcount %lu.\n", iface, refcount);
837 return refcount;
840 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
842 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
843 ULONG refcount = InterlockedDecrement(&fontface->refcount);
844 struct release_font_object_params params = { fontface->font_object };
846 TRACE("%p, refcount %lu.\n", iface, refcount);
848 if (!refcount)
850 UINT32 i;
852 if (fontface->cached)
854 factory_lock(fontface->factory);
855 list_remove(&fontface->cached->entry);
856 factory_unlock(fontface->factory);
857 free(fontface->cached);
859 release_scriptshaping_cache(fontface->shaping_cache);
860 if (fontface->vdmx.context)
861 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
862 if (fontface->gasp.context)
863 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
864 if (fontface->cpal.context)
865 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
866 if (fontface->colr.context)
867 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
868 if (fontface->kern.context)
869 IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
870 if (fontface->file)
871 IDWriteFontFile_Release(fontface->file);
872 if (fontface->names)
873 IDWriteLocalizedStrings_Release(fontface->names);
874 if (fontface->family_names)
875 IDWriteLocalizedStrings_Release(fontface->family_names);
876 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
878 if (fontface->info_strings[i])
879 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
882 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
883 free(fontface->glyphs[i]);
885 UNIX_CALL(release_font_object, &params);
886 if (fontface->stream)
888 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, fontface->data_context);
889 IDWriteFontFileStream_Release(fontface->stream);
891 fontface_cache_clear(fontface);
893 dwrite_cmap_release(&fontface->cmap);
894 IDWriteFactory7_Release(fontface->factory);
895 DeleteCriticalSection(&fontface->cs);
896 free(fontface);
899 return refcount;
902 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
904 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
906 TRACE("%p.\n", iface);
908 return fontface->type;
911 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
912 IDWriteFontFile **fontfiles)
914 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
916 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
918 if (!fontfiles)
920 *number_of_files = 1;
921 return S_OK;
924 if (!*number_of_files)
925 return E_INVALIDARG;
927 IDWriteFontFile_AddRef(fontface->file);
928 *fontfiles = fontface->file;
930 return S_OK;
933 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
935 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
937 TRACE("%p.\n", iface);
939 return fontface->index;
942 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
944 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
946 TRACE("%p.\n", iface);
948 return fontface->simulations;
951 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
953 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
955 TRACE("%p.\n", iface);
957 return !!(fontface->flags & FONT_IS_SYMBOL);
960 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
962 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
964 TRACE("%p, %p.\n", iface, metrics);
966 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
969 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
971 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
972 struct get_glyph_count_params params;
973 unsigned int count;
975 TRACE("%p.\n", iface);
977 params.object = fontface->get_font_object(fontface);
978 params.count = &count;
979 UNIX_CALL(get_glyph_count, &params);
981 return count;
984 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
985 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
987 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
988 struct get_design_glyph_metrics_params params;
989 DWRITE_GLYPH_METRICS metrics;
990 HRESULT hr = S_OK;
991 unsigned int i;
993 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
995 if (!glyphs)
996 return E_INVALIDARG;
998 if (is_sideways)
999 FIXME("sideways metrics are not supported.\n");
1001 params.object = fontface->get_font_object(fontface);
1002 params.simulations = fontface->simulations;
1003 params.upem = fontface->metrics.designUnitsPerEm;
1004 params.ascent = fontface->typo_metrics.ascent;
1005 params.metrics = &metrics;
1007 EnterCriticalSection(&fontface->cs);
1008 for (i = 0; i < glyph_count; ++i)
1011 if (get_cached_glyph_metrics(fontface, glyphs[i], &metrics) != S_OK)
1013 params.glyph = glyphs[i];
1014 UNIX_CALL(get_design_glyph_metrics, &params);
1015 if (FAILED(hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics))) break;
1017 ret[i] = metrics;
1019 LeaveCriticalSection(&fontface->cs);
1021 return hr;
1024 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
1025 UINT32 count, UINT16 *glyphs)
1027 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1028 unsigned int i;
1030 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
1032 if (!glyphs)
1033 return E_INVALIDARG;
1035 if (!codepoints)
1037 memset(glyphs, 0, count * sizeof(*glyphs));
1038 return E_INVALIDARG;
1041 for (i = 0; i < count; ++i)
1042 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
1044 return S_OK;
1047 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
1048 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
1050 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1051 struct file_stream_desc stream_desc;
1053 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
1055 stream_desc.stream = fontface->stream;
1056 stream_desc.face_type = fontface->type;
1057 stream_desc.face_index = fontface->index;
1058 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
1061 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
1063 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1065 TRACE("%p, %p.\n", iface, table_context);
1067 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
1070 static void apply_outline_point_offset(const D2D1_POINT_2F *src, const D2D1_POINT_2F *offset,
1071 D2D1_POINT_2F *dst)
1073 dst->x = src->x + offset->x;
1074 dst->y = src->y + offset->y;
1077 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
1078 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
1079 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
1081 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1082 D2D1_POINT_2F *origins, baseline_origin = { 0 };
1083 struct dwrite_outline outline, outline_size;
1084 struct get_glyph_outline_params params;
1085 D2D1_BEZIER_SEGMENT segment;
1086 D2D1_POINT_2F point;
1087 DWRITE_GLYPH_RUN run;
1088 unsigned int i, j, p;
1089 NTSTATUS status;
1090 HRESULT hr;
1092 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
1093 count, is_sideways, is_rtl, sink);
1095 if (!glyphs || !sink)
1096 return E_INVALIDARG;
1098 if (!count)
1099 return S_OK;
1101 run.fontFace = (IDWriteFontFace *)iface;
1102 run.fontEmSize = emSize;
1103 run.glyphCount = count;
1104 run.glyphIndices = glyphs;
1105 run.glyphAdvances = advances;
1106 run.glyphOffsets = offsets;
1107 run.isSideways = is_sideways;
1108 run.bidiLevel = is_rtl ? 1 : 0;
1110 if (!(origins = malloc(sizeof(*origins) * count)))
1111 return E_OUTOFMEMORY;
1113 if (FAILED(hr = compute_glyph_origins(&run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins)))
1115 free(origins);
1116 return hr;
1119 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
1121 memset(&outline_size, 0, sizeof(outline_size));
1122 memset(&outline, 0, sizeof(outline));
1124 params.object = fontface->get_font_object(fontface);
1125 params.simulations = fontface->simulations;
1126 params.emsize = emSize;
1128 for (i = 0; i < count; ++i)
1130 outline.tags.count = outline.points.count = 0;
1132 EnterCriticalSection(&fontface->cs);
1134 params.glyph = glyphs[i];
1135 params.outline = &outline_size;
1137 if (!(status = UNIX_CALL(get_glyph_outline, &params)))
1139 dwrite_array_reserve((void **)&outline.tags.values, &outline.tags.size, outline_size.tags.count,
1140 sizeof(*outline.tags.values));
1141 dwrite_array_reserve((void **)&outline.points.values, &outline.points.size, outline_size.points.count,
1142 sizeof(*outline.points.values));
1144 params.outline = &outline;
1145 if ((status = UNIX_CALL(get_glyph_outline, &params)))
1147 WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
1150 LeaveCriticalSection(&fontface->cs);
1152 if (status)
1153 continue;
1155 for (j = 0, p = 0; j < outline.tags.count; ++j)
1157 switch (outline.tags.values[j])
1159 case OUTLINE_BEGIN_FIGURE:
1160 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1161 ID2D1SimplifiedGeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
1162 break;
1163 case OUTLINE_END_FIGURE:
1164 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
1165 break;
1166 case OUTLINE_LINE:
1167 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1168 ID2D1SimplifiedGeometrySink_AddLines(sink, &point, 1);
1169 break;
1170 case OUTLINE_BEZIER:
1171 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point1);
1172 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point2);
1173 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point3);
1174 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &segment, 1);
1175 break;
1180 free(outline.tags.values);
1181 free(outline.points.values);
1182 free(origins);
1184 return S_OK;
1187 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
1188 float ppem, unsigned int gasp)
1190 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
1192 switch (measuring)
1194 case DWRITE_MEASURING_MODE_NATURAL:
1196 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
1197 mode = DWRITE_RENDERING_MODE_NATURAL;
1198 else
1199 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
1200 break;
1202 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1203 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
1204 break;
1205 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1206 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
1207 break;
1208 default:
1212 return mode;
1215 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1216 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
1218 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1219 unsigned int flags;
1220 FLOAT ppem;
1222 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
1224 if (!params) {
1225 *mode = DWRITE_RENDERING_MODE_DEFAULT;
1226 return E_INVALIDARG;
1229 *mode = IDWriteRenderingParams_GetRenderingMode(params);
1230 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
1231 return S_OK;
1233 ppem = emSize * ppdip;
1235 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
1236 *mode = DWRITE_RENDERING_MODE_OUTLINE;
1237 return S_OK;
1240 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
1241 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
1242 return S_OK;
1245 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
1246 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
1248 DWRITE_FONT_METRICS1 metrics1;
1249 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
1250 memcpy(metrics, &metrics1, sizeof(*metrics));
1251 return hr;
1254 static inline int round_metric(FLOAT metric)
1256 return (int)floorf(metric + 0.5f);
1259 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
1261 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
1262 return 0;
1264 return (fontface->metrics.designUnitsPerEm + 49) / 50;
1267 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
1268 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
1269 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
1271 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1272 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
1273 DWRITE_MEASURING_MODE mode;
1274 FLOAT scale, size;
1275 HRESULT hr = S_OK;
1276 UINT32 i;
1278 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
1279 glyph_count, metrics, is_sideways);
1281 if (m && memcmp(m, &identity, sizeof(*m)))
1282 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
1284 size = emSize * ppdip;
1285 scale = size / fontface->metrics.designUnitsPerEm;
1286 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1288 EnterCriticalSection(&fontface->cs);
1289 for (i = 0; i < glyph_count; ++i)
1291 DWRITE_GLYPH_METRICS *ret = metrics + i;
1292 DWRITE_GLYPH_METRICS design;
1293 BOOL has_contours;
1295 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
1296 if (FAILED(hr))
1297 break;
1299 ret->advanceWidth = fontface_get_glyph_advance(fontface, size, glyphs[i], mode, &has_contours);
1300 if (has_contours)
1301 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
1302 else
1303 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
1305 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
1306 SCALE_METRIC(leftSideBearing);
1307 SCALE_METRIC(rightSideBearing);
1308 SCALE_METRIC(topSideBearing);
1309 SCALE_METRIC(advanceHeight);
1310 SCALE_METRIC(bottomSideBearing);
1311 SCALE_METRIC(verticalOriginY);
1312 #undef SCALE_METRIC
1314 LeaveCriticalSection(&fontface->cs);
1316 return S_OK;
1319 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
1321 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1323 TRACE("%p, %p.\n", iface, metrics);
1325 *metrics = fontface->metrics;
1328 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
1329 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
1331 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1332 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
1333 UINT16 ascent, descent;
1334 FLOAT scale;
1336 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
1338 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
1339 memset(metrics, 0, sizeof(*metrics));
1340 return E_INVALIDARG;
1343 em_size *= pixels_per_dip;
1344 if (m && m->m22 != 0.0f)
1345 em_size *= fabs(m->m22);
1347 scale = em_size / design->designUnitsPerEm;
1348 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
1350 ascent = round_metric(design->ascent * scale);
1351 descent = round_metric(design->descent * scale);
1354 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
1355 metrics->designUnitsPerEm = design->designUnitsPerEm;
1356 metrics->ascent = round_metric(ascent / scale);
1357 metrics->descent = round_metric(descent / scale);
1359 SCALE_METRIC(lineGap);
1360 SCALE_METRIC(capHeight);
1361 SCALE_METRIC(xHeight);
1362 SCALE_METRIC(underlinePosition);
1363 SCALE_METRIC(underlineThickness);
1364 SCALE_METRIC(strikethroughPosition);
1365 SCALE_METRIC(strikethroughThickness);
1366 SCALE_METRIC(glyphBoxLeft);
1367 SCALE_METRIC(glyphBoxTop);
1368 SCALE_METRIC(glyphBoxRight);
1369 SCALE_METRIC(glyphBoxBottom);
1370 SCALE_METRIC(subscriptPositionX);
1371 SCALE_METRIC(subscriptPositionY);
1372 SCALE_METRIC(subscriptSizeX);
1373 SCALE_METRIC(subscriptSizeY);
1374 SCALE_METRIC(superscriptPositionX);
1375 SCALE_METRIC(superscriptPositionY);
1376 SCALE_METRIC(superscriptSizeX);
1377 SCALE_METRIC(superscriptSizeY);
1379 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1380 #undef SCALE_METRIC
1382 return S_OK;
1385 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1387 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1389 TRACE("%p, %p.\n", iface, metrics);
1391 *metrics = fontface->caret;
1394 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1395 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1397 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1399 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1401 *count = 0;
1402 if (max_count && !ranges)
1403 return E_INVALIDARG;
1405 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1406 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1409 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1411 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1413 TRACE("%p.\n", iface);
1415 return !!(fontface->flags & FONT_IS_MONOSPACED);
1418 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1419 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1421 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1422 BOOL has_contours;
1423 int advance;
1425 if (is_sideways)
1426 FIXME("Sideways mode is not supported.\n");
1428 switch (measuring_mode)
1430 case DWRITE_MEASURING_MODE_NATURAL:
1431 advance = fontface_get_glyph_advance(fontface, fontface->metrics.designUnitsPerEm, glyph,
1432 measuring_mode, &has_contours);
1433 if (has_contours)
1434 advance += adjustment;
1436 return advance;
1437 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1438 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1439 emsize *= ppdip;
1440 if (emsize == 0.0f)
1441 return 0.0f;
1443 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1444 FIXME("Transform is not supported.\n");
1446 advance = fontface_get_glyph_advance(fontface, emsize, glyph, measuring_mode, &has_contours);
1447 if (has_contours)
1448 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1449 else
1450 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1452 return advance;
1453 default:
1454 WARN("Unknown measuring mode %u.\n", measuring_mode);
1455 return 0;
1459 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1460 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1462 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1463 unsigned int i;
1465 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1467 if (is_sideways)
1468 FIXME("sideways mode not supported\n");
1470 EnterCriticalSection(&fontface->cs);
1471 for (i = 0; i < glyph_count; ++i)
1473 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1474 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1476 LeaveCriticalSection(&fontface->cs);
1478 return S_OK;
1481 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1482 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1483 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1485 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1486 DWRITE_MEASURING_MODE measuring_mode;
1487 UINT32 i;
1489 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1490 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1492 if (em_size < 0.0f || ppdip <= 0.0f) {
1493 memset(advances, 0, sizeof(*advances) * glyph_count);
1494 return E_INVALIDARG;
1497 if (em_size == 0.0f) {
1498 memset(advances, 0, sizeof(*advances) * glyph_count);
1499 return S_OK;
1502 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1504 EnterCriticalSection(&fontface->cs);
1505 for (i = 0; i < glyph_count; ++i)
1507 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1508 glyphs[i], is_sideways);
1510 LeaveCriticalSection(&fontface->cs);
1512 return S_OK;
1515 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1516 const UINT16 *glyphs, INT32 *values)
1518 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1520 TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
1522 if (!(glyphs || values) || !count)
1523 return E_INVALIDARG;
1525 if (!glyphs || count == 1)
1527 memset(values, 0, count * sizeof(*values));
1528 return E_INVALIDARG;
1531 return opentype_get_kerning_pairs(fontface, count, glyphs, values);
1534 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1536 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1538 TRACE("%p.\n", iface);
1540 return opentype_has_kerning_pairs(fontface);
1543 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1544 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1545 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1547 DWRITE_GRID_FIT_MODE gridfitmode;
1548 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1549 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1552 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1553 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1555 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1557 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1559 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1562 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1564 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1566 TRACE("%p.\n", iface);
1568 return opentype_has_vertical_variants(fontface);
1571 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1573 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1575 TRACE("%p.\n", iface);
1577 return !!(fontface->flags & FONT_IS_COLORED);
1580 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1582 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1584 TRACE("%p.\n", iface);
1586 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1589 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1591 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1593 TRACE("%p.\n", iface);
1595 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1598 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1599 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1601 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1603 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1605 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1608 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1609 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1610 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1611 DWRITE_GRID_FIT_MODE *gridfitmode)
1613 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1614 unsigned int flags;
1615 FLOAT emthreshold;
1617 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1618 measuringmode, params, renderingmode, gridfitmode);
1620 if (m && memcmp(m, &identity, sizeof(*m)))
1621 FIXME("transform not supported %s\n", debugstr_matrix(m));
1623 if (is_sideways)
1624 FIXME("sideways mode not supported\n");
1626 emSize *= max(dpiX, dpiY) / 96.0f;
1628 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1629 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1630 if (params) {
1631 IDWriteRenderingParams2 *params2;
1632 HRESULT hr;
1634 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1635 if (hr == S_OK) {
1636 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1637 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1638 IDWriteRenderingParams2_Release(params2);
1640 else
1641 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1644 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1646 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1648 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1649 if (emSize >= emthreshold)
1650 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1651 else
1652 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1655 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1656 if (emSize >= emthreshold)
1657 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1658 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1659 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1660 else
1661 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1662 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1665 return S_OK;
1668 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1669 IDWriteFontFaceReference **reference)
1671 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1673 TRACE("%p, %p.\n", iface, reference);
1675 *reference = &fontface->IDWriteFontFaceReference_iface;
1676 IDWriteFontFaceReference_AddRef(*reference);
1678 return S_OK;
1681 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1683 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1685 TRACE("%p, %p.\n", iface, panose);
1687 *panose = fontface->panose;
1690 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1692 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1694 TRACE("%p.\n", iface);
1696 return fontface->weight;
1699 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1701 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1703 TRACE("%p.\n", iface);
1705 return fontface->stretch;
1708 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1710 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1712 TRACE("%p.\n", iface);
1714 return fontface->style;
1717 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1719 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1721 TRACE("%p, %p.\n", iface, names);
1723 return clone_localizedstrings(fontface->family_names, names);
1726 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1728 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1730 TRACE("%p, %p.\n", iface, names);
1732 return clone_localizedstrings(fontface->names, names);
1735 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1736 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1737 IDWriteLocalizedStrings **ret, BOOL *exists)
1739 HRESULT hr = S_OK;
1741 *exists = FALSE;
1742 *ret = NULL;
1744 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1745 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1747 return S_OK;
1750 if (!strings_cache[stringid])
1752 struct file_stream_desc desc = *stream_desc;
1754 if (!desc.stream)
1755 hr = get_filestream_from_file(file, &desc.stream);
1756 if (SUCCEEDED(hr))
1757 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1759 if (!stream_desc->stream && desc.stream)
1760 IDWriteFontFileStream_Release(desc.stream);
1763 if (SUCCEEDED(hr) && strings_cache[stringid])
1765 hr = clone_localizedstrings(strings_cache[stringid], ret);
1766 if (SUCCEEDED(hr))
1767 *exists = TRUE;
1770 return hr;
1773 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1774 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1776 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1777 struct file_stream_desc stream_desc;
1779 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1781 stream_desc.stream = fontface->stream;
1782 stream_desc.face_index = fontface->index;
1783 stream_desc.face_type = fontface->type;
1784 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1787 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1789 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1791 TRACE("%p, %#x.\n", iface, ch);
1793 return !!dwritefontface_get_glyph(fontface, ch);
1796 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1797 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1798 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1800 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1801 unsigned int flags;
1802 FLOAT emthreshold;
1804 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1805 measuring_mode, params, rendering_mode, gridfit_mode);
1807 if (m && memcmp(m, &identity, sizeof(*m)))
1808 FIXME("transform not supported %s\n", debugstr_matrix(m));
1810 if (is_sideways)
1811 FIXME("sideways mode not supported\n");
1813 emSize *= max(dpiX, dpiY) / 96.0f;
1815 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1816 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1817 if (params) {
1818 IDWriteRenderingParams3 *params3;
1819 HRESULT hr;
1821 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1822 if (hr == S_OK) {
1823 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1824 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1825 IDWriteRenderingParams3_Release(params3);
1827 else
1828 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1831 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1833 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1835 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1836 if (emSize >= emthreshold)
1837 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1838 else
1839 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1842 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1843 if (emSize >= emthreshold)
1844 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1845 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1846 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1847 else
1848 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1849 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1852 return S_OK;
1855 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1857 FIXME("%p, %#x: stub\n", iface, ch);
1859 return FALSE;
1862 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1864 FIXME("%p, %u: stub\n", iface, glyph);
1866 return FALSE;
1869 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1870 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1872 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1874 return E_NOTIMPL;
1877 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1878 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1880 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1882 return E_NOTIMPL;
1885 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1886 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1888 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1890 return E_NOTIMPL;
1893 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1895 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1897 TRACE("%p.\n", iface);
1899 return fontface->glyph_image_formats;
1902 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1903 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1905 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1907 return E_NOTIMPL;
1910 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1912 FIXME("%p, %p: stub\n", iface, context);
1915 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1917 FIXME("%p: stub\n", iface);
1919 return 0;
1922 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1923 UINT32 value_count)
1925 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1927 return E_NOTIMPL;
1930 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1932 static int once;
1934 if (!once++)
1935 FIXME("%p: stub\n", iface);
1937 return FALSE;
1940 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1942 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1944 TRACE("%p, %p.\n", iface, resource);
1946 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1949 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1951 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1953 TRACE("%p, %p.\n", iface, other);
1955 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1956 return FALSE;
1958 /* TODO: add variations support */
1960 return fontface->index == other_face->index &&
1961 fontface->simulations == other_face->simulations &&
1962 is_same_fontfile(fontface->file, other_face->file);
1965 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1967 dwritefontface_QueryInterface,
1968 dwritefontface_AddRef,
1969 dwritefontface_Release,
1970 dwritefontface_GetType,
1971 dwritefontface_GetFiles,
1972 dwritefontface_GetIndex,
1973 dwritefontface_GetSimulations,
1974 dwritefontface_IsSymbolFont,
1975 dwritefontface_GetMetrics,
1976 dwritefontface_GetGlyphCount,
1977 dwritefontface_GetDesignGlyphMetrics,
1978 dwritefontface_GetGlyphIndices,
1979 dwritefontface_TryGetFontTable,
1980 dwritefontface_ReleaseFontTable,
1981 dwritefontface_GetGlyphRunOutline,
1982 dwritefontface_GetRecommendedRenderingMode,
1983 dwritefontface_GetGdiCompatibleMetrics,
1984 dwritefontface_GetGdiCompatibleGlyphMetrics,
1985 dwritefontface1_GetMetrics,
1986 dwritefontface1_GetGdiCompatibleMetrics,
1987 dwritefontface1_GetCaretMetrics,
1988 dwritefontface1_GetUnicodeRanges,
1989 dwritefontface1_IsMonospacedFont,
1990 dwritefontface1_GetDesignGlyphAdvances,
1991 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1992 dwritefontface1_GetKerningPairAdjustments,
1993 dwritefontface1_HasKerningPairs,
1994 dwritefontface1_GetRecommendedRenderingMode,
1995 dwritefontface1_GetVerticalGlyphVariants,
1996 dwritefontface1_HasVerticalGlyphVariants,
1997 dwritefontface2_IsColorFont,
1998 dwritefontface2_GetColorPaletteCount,
1999 dwritefontface2_GetPaletteEntryCount,
2000 dwritefontface2_GetPaletteEntries,
2001 dwritefontface2_GetRecommendedRenderingMode,
2002 dwritefontface3_GetFontFaceReference,
2003 dwritefontface3_GetPanose,
2004 dwritefontface3_GetWeight,
2005 dwritefontface3_GetStretch,
2006 dwritefontface3_GetStyle,
2007 dwritefontface3_GetFamilyNames,
2008 dwritefontface3_GetFaceNames,
2009 dwritefontface3_GetInformationalStrings,
2010 dwritefontface3_HasCharacter,
2011 dwritefontface3_GetRecommendedRenderingMode,
2012 dwritefontface3_IsCharacterLocal,
2013 dwritefontface3_IsGlyphLocal,
2014 dwritefontface3_AreCharactersLocal,
2015 dwritefontface3_AreGlyphsLocal,
2016 dwritefontface4_GetGlyphImageFormats_,
2017 dwritefontface4_GetGlyphImageFormats,
2018 dwritefontface4_GetGlyphImageData,
2019 dwritefontface4_ReleaseGlyphImageData,
2020 dwritefontface5_GetFontAxisValueCount,
2021 dwritefontface5_GetFontAxisValues,
2022 dwritefontface5_HasVariations,
2023 dwritefontface5_GetFontResource,
2024 dwritefontface5_Equals,
2027 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
2029 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2030 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
2033 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
2035 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2036 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
2039 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
2041 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2042 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
2045 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
2046 IDWriteFontFace3 **ret)
2048 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2050 TRACE("%p, %p.\n", iface, ret);
2052 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
2053 IDWriteFontFace3_AddRef(*ret);
2055 return S_OK;
2058 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
2059 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
2061 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2062 DWRITE_FONT_FILE_TYPE file_type;
2063 DWRITE_FONT_FACE_TYPE face_type;
2064 IDWriteFontFace *face;
2065 BOOL is_supported;
2066 UINT32 face_num;
2067 HRESULT hr;
2069 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
2071 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
2072 if (FAILED(hr))
2073 return hr;
2075 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
2076 simulations, &face);
2077 if (SUCCEEDED(hr))
2079 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
2080 IDWriteFontFace_Release(face);
2083 return hr;
2086 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
2088 FIXME("%p, %p.\n", iface, ref);
2090 return E_NOTIMPL;
2093 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
2095 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2097 TRACE("%p.\n", iface);
2099 return fontface->index;
2102 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
2104 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2106 TRACE("%p.\n", iface);
2108 return fontface->simulations;
2111 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
2113 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2115 TRACE("%p, %p.\n", iface, file);
2117 *file = fontface->file;
2118 IDWriteFontFile_AddRef(*file);
2120 return S_OK;
2123 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
2125 FIXME("%p.\n", iface);
2127 return 0;
2130 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
2132 FIXME("%p.\n", iface);
2134 return 0;
2137 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
2139 FIXME("%p, %p.\n", iface, writetime);
2141 return E_NOTIMPL;
2144 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
2146 FIXME("%p.\n", iface);
2148 return DWRITE_LOCALITY_LOCAL;
2151 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
2153 FIXME("%p.\n", iface);
2155 return E_NOTIMPL;
2158 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
2159 WCHAR const *chars, UINT32 count)
2161 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
2163 return E_NOTIMPL;
2166 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
2167 UINT16 const *glyphs, UINT32 count)
2169 FIXME("%p, %p, %u.\n", iface, glyphs, count);
2171 return E_NOTIMPL;
2174 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
2175 UINT64 offset, UINT64 size)
2177 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
2179 return E_NOTIMPL;
2182 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
2184 dwritefontface_reference_QueryInterface,
2185 dwritefontface_reference_AddRef,
2186 dwritefontface_reference_Release,
2187 dwritefontface_reference_CreateFontFace,
2188 dwritefontface_reference_CreateFontFaceWithSimulations,
2189 dwritefontface_reference_Equals,
2190 dwritefontface_reference_GetFontFaceIndex,
2191 dwritefontface_reference_GetSimulations,
2192 dwritefontface_reference_GetFontFile,
2193 dwritefontface_reference_GetLocalFileSize,
2194 dwritefontface_reference_GetFileSize,
2195 dwritefontface_reference_GetFileTime,
2196 dwritefontface_reference_GetLocality,
2197 dwritefontface_reference_EnqueueFontDownloadRequest,
2198 dwritefontface_reference_EnqueueCharacterDownloadRequest,
2199 dwritefontface_reference_EnqueueGlyphDownloadRequest,
2200 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
2203 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
2205 struct dwrite_font_data *data = font->data;
2206 struct fontface_desc desc;
2207 struct list *cached_list;
2208 HRESULT hr;
2210 *fontface = NULL;
2212 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
2213 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
2214 if (hr == S_OK)
2215 return hr;
2217 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
2218 return hr;
2220 desc.factory = font->family->collection->factory;
2221 desc.face_type = data->face_type;
2222 desc.file = data->file;
2223 desc.index = data->face_index;
2224 desc.simulations = data->simulations;
2225 desc.font_data = data;
2226 hr = create_fontface(&desc, cached_list, fontface);
2228 IDWriteFontFileStream_Release(desc.stream);
2229 return hr;
2232 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
2234 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2236 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
2237 IsEqualIID(riid, &IID_IDWriteFont2) ||
2238 IsEqualIID(riid, &IID_IDWriteFont1) ||
2239 IsEqualIID(riid, &IID_IDWriteFont) ||
2240 IsEqualIID(riid, &IID_IUnknown))
2242 *obj = iface;
2243 IDWriteFont3_AddRef(iface);
2244 return S_OK;
2247 WARN("%s not implemented.\n", debugstr_guid(riid));
2249 *obj = NULL;
2250 return E_NOINTERFACE;
2253 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
2255 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2256 ULONG refcount = InterlockedIncrement(&font->refcount);
2258 TRACE("%p, refcount %ld.\n", iface, refcount);
2260 return refcount;
2263 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
2265 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2266 ULONG refcount = InterlockedDecrement(&font->refcount);
2268 TRACE("%p, refcount %ld.\n", iface, refcount);
2270 if (!refcount)
2272 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
2273 release_font_data(font->data);
2274 free(font);
2277 return refcount;
2280 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
2282 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2284 TRACE("%p, %p.\n", iface, family);
2286 *family = (IDWriteFontFamily *)&font->family->IDWriteFontFamily2_iface;
2287 IDWriteFontFamily_AddRef(*family);
2288 return S_OK;
2291 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
2293 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2295 TRACE("%p.\n", iface);
2297 return font->data->weight;
2300 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
2302 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2304 TRACE("%p.\n", iface);
2306 return font->data->stretch;
2309 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
2311 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2313 TRACE("%p.\n", iface);
2315 return font->style;
2318 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2320 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2322 TRACE("%p.\n", iface);
2324 return !!(font->data->flags & FONT_IS_SYMBOL);
2327 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2329 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2331 TRACE("%p, %p.\n", iface, names);
2333 return clone_localizedstrings(font->data->names, names);
2336 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2337 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2339 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2340 struct dwrite_font_data *data = font->data;
2341 struct file_stream_desc stream_desc;
2343 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2345 /* Stream will be created if necessary. */
2346 stream_desc.stream = NULL;
2347 stream_desc.face_index = data->face_index;
2348 stream_desc.face_type = data->face_type;
2349 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2352 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2354 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2356 TRACE("%p.\n", iface);
2358 return font->data->simulations;
2361 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2363 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2365 TRACE("%p, %p.\n", iface, metrics);
2367 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2370 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2372 UINT16 glyph;
2373 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2374 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2375 return glyph != 0;
2378 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2380 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2382 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2384 *exists = dwritefont_has_character(font, ch);
2386 return S_OK;
2389 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2391 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2393 TRACE("%p, %p.\n", iface, fontface);
2395 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2398 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2400 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2402 TRACE("%p, %p.\n", iface, metrics);
2404 *metrics = font->data->metrics;
2407 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2409 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2411 TRACE("%p, %p.\n", iface, panose);
2413 *panose = font->data->panose;
2416 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2417 UINT32 *count)
2419 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2421 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2423 *count = 0;
2424 if (max_count && !ranges)
2425 return E_INVALIDARG;
2427 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2428 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2431 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2433 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2435 TRACE("%p.\n", iface);
2437 return !!(font->data->flags & FONT_IS_MONOSPACED);
2440 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2442 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2444 TRACE("%p.\n", iface);
2446 return !!(font->data->flags & FONT_IS_COLORED);
2449 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2451 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2453 TRACE("%p, %p.\n", iface, fontface);
2455 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2458 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2460 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2462 TRACE("%p, %p.\n", iface, other);
2464 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2465 return FALSE;
2467 return font->data->face_index == other_font->data->face_index
2468 && font->data->simulations == other_font->data->simulations
2469 && is_same_fontfile(font->data->file, other_font->data->file);
2472 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2474 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2476 TRACE("%p, %p.\n", iface, reference);
2478 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2479 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2480 (IDWriteFontFaceReference1 **)reference);
2483 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2485 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2487 TRACE("%p, %#x.\n", iface, ch);
2489 return dwritefont_has_character(font, ch);
2492 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2494 FIXME("%p: stub.\n", iface);
2496 return DWRITE_LOCALITY_LOCAL;
2499 static const IDWriteFont3Vtbl dwritefontvtbl = {
2500 dwritefont_QueryInterface,
2501 dwritefont_AddRef,
2502 dwritefont_Release,
2503 dwritefont_GetFontFamily,
2504 dwritefont_GetWeight,
2505 dwritefont_GetStretch,
2506 dwritefont_GetStyle,
2507 dwritefont_IsSymbolFont,
2508 dwritefont_GetFaceNames,
2509 dwritefont_GetInformationalStrings,
2510 dwritefont_GetSimulations,
2511 dwritefont_GetMetrics,
2512 dwritefont_HasCharacter,
2513 dwritefont_CreateFontFace,
2514 dwritefont1_GetMetrics,
2515 dwritefont1_GetPanose,
2516 dwritefont1_GetUnicodeRanges,
2517 dwritefont1_IsMonospacedFont,
2518 dwritefont2_IsColorFont,
2519 dwritefont3_CreateFontFace,
2520 dwritefont3_Equals,
2521 dwritefont3_GetFontFaceReference,
2522 dwritefont3_HasCharacter,
2523 dwritefont3_GetLocality
2526 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2528 if (!iface)
2529 return NULL;
2530 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2531 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2534 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2536 if (!iface)
2537 return NULL;
2538 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2539 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2542 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2544 if (!iface)
2545 return NULL;
2546 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2547 return NULL;
2548 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2549 IDWriteFontFaceReference1_iface);
2552 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2554 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2555 *lf = font->data->lf;
2558 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2560 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2561 *lf = fontface->lf;
2564 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2566 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2567 *fontsig = font->data->fontsig;
2568 return S_OK;
2571 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2573 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2574 *fontsig = fontface->fontsig;
2575 return S_OK;
2578 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2580 struct dwrite_font *object;
2582 *font = NULL;
2584 if (!(object = calloc(1, sizeof(*object))))
2585 return E_OUTOFMEMORY;
2587 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2588 object->refcount = 1;
2589 object->family = family;
2590 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2591 object->data = family->data->fonts[index];
2592 object->style = object->data->style;
2593 addref_font_data(object->data);
2595 *font = &object->IDWriteFont3_iface;
2597 return S_OK;
2600 /* IDWriteFontList2 */
2601 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2603 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2605 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2606 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2607 IsEqualIID(riid, &IID_IDWriteFontList) ||
2608 IsEqualIID(riid, &IID_IUnknown))
2610 *obj = iface;
2611 IDWriteFontList2_AddRef(iface);
2612 return S_OK;
2615 WARN("%s not implemented.\n", debugstr_guid(riid));
2617 *obj = NULL;
2618 return E_NOINTERFACE;
2621 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2623 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2624 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2626 TRACE("%p, refcount %lu.\n", iface, refcount);
2628 return refcount;
2631 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2633 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2634 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2636 TRACE("%p, refcount %lu.\n", iface, refcount);
2638 if (!refcount)
2640 unsigned int i;
2642 for (i = 0; i < fontlist->font_count; i++)
2643 release_font_data(fontlist->fonts[i]);
2644 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2645 free(fontlist->fonts);
2646 free(fontlist);
2649 return refcount;
2652 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2654 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2655 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2658 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2660 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2662 TRACE("%p.\n", iface);
2664 return fontlist->font_count;
2667 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2669 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2671 TRACE("%p, %u, %p.\n", iface, index, font);
2673 *font = NULL;
2675 if (fontlist->font_count == 0)
2676 return S_FALSE;
2678 if (index >= fontlist->font_count)
2679 return E_INVALIDARG;
2681 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2684 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2686 FIXME("%p, %u.\n", iface, index);
2688 return DWRITE_LOCALITY_LOCAL;
2691 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2692 IDWriteFont3 **font)
2694 *font = NULL;
2696 if (fontlist->font_count == 0)
2697 return S_FALSE;
2699 if (index >= fontlist->font_count)
2700 return E_FAIL;
2702 return create_font(fontlist->family, index, font);
2705 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2707 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2709 TRACE("%p, %u, %p.\n", iface, index, font);
2711 return fontlist_get_font(fontlist, index, font);
2714 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2715 IDWriteFontFaceReference **reference)
2717 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2718 IDWriteFont3 *font;
2719 HRESULT hr;
2721 TRACE("%p, %u, %p.\n", iface, index, reference);
2723 *reference = NULL;
2725 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2727 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2728 IDWriteFont3_Release(font);
2731 return hr;
2734 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2736 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2738 TRACE("%p, %p.\n", iface, fontset);
2740 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2741 fontlist->font_count, fontset);
2744 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2746 dwritefontlist_QueryInterface,
2747 dwritefontlist_AddRef,
2748 dwritefontlist_Release,
2749 dwritefontlist_GetFontCollection,
2750 dwritefontlist_GetFontCount,
2751 dwritefontlist_GetFont,
2752 dwritefontlist1_GetFontLocality,
2753 dwritefontlist1_GetFont,
2754 dwritefontlist1_GetFontFaceReference,
2755 dwritefontlist2_GetFontSet,
2758 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2760 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2762 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2764 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2765 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2766 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2767 IsEqualIID(riid, &IID_IUnknown))
2769 *obj = iface;
2771 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2772 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2773 IsEqualIID(riid, &IID_IDWriteFontList))
2775 *obj = &family->IDWriteFontList2_iface;
2777 else
2779 WARN("%s not implemented.\n", debugstr_guid(riid));
2780 *obj = NULL;
2781 return E_NOINTERFACE;
2784 IUnknown_AddRef((IUnknown *)*obj);
2785 return S_OK;
2788 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2790 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2791 ULONG refcount = InterlockedIncrement(&family->refcount);
2793 TRACE("%p, %lu.\n", iface, refcount);
2795 return refcount;
2798 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2800 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2801 ULONG refcount = InterlockedDecrement(&family->refcount);
2803 TRACE("%p, %lu.\n", iface, refcount);
2805 if (!refcount)
2807 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2808 release_fontfamily_data(family->data);
2809 free(family);
2812 return refcount;
2815 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2817 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2819 TRACE("%p, %p.\n", iface, collection);
2821 *collection = (IDWriteFontCollection *)&family->collection->IDWriteFontCollection3_iface;
2822 IDWriteFontCollection_AddRef(*collection);
2823 return S_OK;
2826 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2828 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2830 TRACE("%p.\n", iface);
2832 return family->data->count;
2835 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2837 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2839 TRACE("%p, %u, %p.\n", iface, index, font);
2841 *font = NULL;
2843 if (!family->data->count)
2844 return S_FALSE;
2846 if (index >= family->data->count)
2847 return E_INVALIDARG;
2849 return create_font(family, index, (IDWriteFont3 **)font);
2852 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2854 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2856 TRACE("%p, %p.\n", iface, names);
2858 return clone_localizedstrings(family->data->familyname, names);
2861 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2862 const struct dwrite_font_propvec *req)
2864 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2865 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2866 FLOAT cur_req_prod, next_req_prod;
2868 if (next_to_req < cur_to_req)
2869 return TRUE;
2871 if (next_to_req > cur_to_req)
2872 return FALSE;
2874 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2875 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2877 if (next_req_prod > cur_req_prod)
2878 return TRUE;
2880 if (next_req_prod < cur_req_prod)
2881 return FALSE;
2883 if (next->stretch > cur->stretch)
2884 return TRUE;
2885 if (next->stretch < cur->stretch)
2886 return FALSE;
2888 if (next->style > cur->style)
2889 return TRUE;
2890 if (next->style < cur->style)
2891 return FALSE;
2893 if (next->weight > cur->weight)
2894 return TRUE;
2895 if (next->weight < cur->weight)
2896 return FALSE;
2898 /* full match, no reason to prefer new variant */
2899 return FALSE;
2902 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2903 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2905 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2906 struct dwrite_font_propvec req;
2907 size_t i, match;
2909 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2911 if (!family->data->count)
2913 *font = NULL;
2914 return DWRITE_E_NOFONT;
2917 init_font_prop_vec(weight, stretch, style, &req);
2918 match = 0;
2920 for (i = 1; i < family->data->count; ++i)
2922 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2923 match = i;
2926 return create_font(family, match, (IDWriteFont3 **)font);
2929 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2931 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2933 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2936 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2938 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2941 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2943 UINT32 b = fonts->font_count - 1, j, t;
2945 while (1) {
2946 t = b;
2948 for (j = 0; j < b; j++) {
2949 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2950 struct dwrite_font_data *s = fonts->fonts[j];
2951 fonts->fonts[j] = fonts->fonts[j+1];
2952 fonts->fonts[j+1] = s;
2953 t = j;
2957 if (t == b)
2958 break;
2959 b = t;
2963 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2964 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2966 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2967 matching_filter_func func = NULL;
2968 struct dwrite_font_propvec req;
2969 struct dwrite_fontlist *fonts;
2970 size_t i;
2972 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2974 *ret = NULL;
2976 if (!(fonts = malloc(sizeof(*fonts))))
2977 return E_OUTOFMEMORY;
2979 /* Allocate as many as family has, not all of them will be necessary used. */
2980 if (!(fonts->fonts = calloc(family->data->count, sizeof(*fonts->fonts))))
2982 free(fonts);
2983 return E_OUTOFMEMORY;
2986 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2987 fonts->refcount = 1;
2988 fonts->family = family;
2989 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2990 fonts->font_count = 0;
2992 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2993 if (style == DWRITE_FONT_STYLE_NORMAL) {
2994 if (family->data->has_normal_face || family->data->has_italic_face)
2995 func = is_font_acceptable_for_normal;
2997 else /* requested oblique or italic */ {
2998 if (family->data->has_oblique_face || family->data->has_italic_face)
2999 func = is_font_acceptable_for_oblique_italic;
3002 for (i = 0; i < family->data->count; ++i)
3004 if (!func || func(family->data->fonts[i]))
3006 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
3010 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
3011 init_font_prop_vec(weight, stretch, style, &req);
3012 matchingfonts_sort(fonts, &req);
3014 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
3015 return S_OK;
3018 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
3020 FIXME("%p, %u.\n", iface, index);
3022 return DWRITE_LOCALITY_LOCAL;
3025 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
3027 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3029 TRACE("%p, %u, %p.\n", iface, index, font);
3031 *font = NULL;
3033 if (!family->data->count)
3034 return S_FALSE;
3036 if (index >= family->data->count)
3037 return E_FAIL;
3039 return create_font(family, index, font);
3042 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
3043 IDWriteFontFaceReference **reference)
3045 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3046 const struct dwrite_font_data *font;
3048 TRACE("%p, %u, %p.\n", iface, index, reference);
3050 *reference = NULL;
3052 if (index >= family->data->count)
3053 return E_FAIL;
3055 font = family->data->fonts[index];
3056 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
3057 font->file, font->face_index, font->simulations, reference);
3060 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
3061 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
3063 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
3065 return E_NOTIMPL;
3068 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
3070 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3072 TRACE("%p, %p.\n", iface, fontset);
3074 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3075 family->data->count, fontset);
3078 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
3080 dwritefontfamily_QueryInterface,
3081 dwritefontfamily_AddRef,
3082 dwritefontfamily_Release,
3083 dwritefontfamily_GetFontCollection,
3084 dwritefontfamily_GetFontCount,
3085 dwritefontfamily_GetFont,
3086 dwritefontfamily_GetFamilyNames,
3087 dwritefontfamily_GetFirstMatchingFont,
3088 dwritefontfamily_GetMatchingFonts,
3089 dwritefontfamily1_GetFontLocality,
3090 dwritefontfamily1_GetFont,
3091 dwritefontfamily1_GetFontFaceReference,
3092 dwritefontfamily2_GetMatchingFonts,
3093 dwritefontfamily2_GetFontSet,
3096 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
3098 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3099 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
3102 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
3104 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3105 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
3108 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
3110 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3111 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
3114 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
3115 IDWriteFontCollection **collection)
3117 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3118 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
3121 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
3123 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3124 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
3127 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
3129 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3130 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3133 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
3135 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3136 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
3139 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
3141 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3142 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3145 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
3146 IDWriteFontFaceReference **reference)
3148 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3149 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
3152 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
3154 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3156 TRACE("%p, %p.\n", iface, fontset);
3158 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3159 family->data->count, fontset);
3162 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
3164 dwritefontfamilylist_QueryInterface,
3165 dwritefontfamilylist_AddRef,
3166 dwritefontfamilylist_Release,
3167 dwritefontfamilylist_GetFontCollection,
3168 dwritefontfamilylist_GetFontCount,
3169 dwritefontfamilylist_GetFont,
3170 dwritefontfamilylist1_GetFontLocality,
3171 dwritefontfamilylist1_GetFont,
3172 dwritefontfamilylist1_GetFontFaceReference,
3173 dwritefontfamilylist2_GetFontSet,
3176 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
3177 struct dwrite_fontfamily **family)
3179 struct dwrite_fontfamily *object;
3181 *family = NULL;
3183 if (!(object = calloc(1, sizeof(*object))))
3184 return E_OUTOFMEMORY;
3186 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
3187 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
3188 object->refcount = 1;
3189 object->collection = collection;
3190 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
3191 object->data = collection->family_data[index];
3192 InterlockedIncrement(&object->data->refcount);
3194 *family = object;
3196 return S_OK;
3199 BOOL is_system_collection(IDWriteFontCollection *collection)
3201 void *obj;
3202 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
3205 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3207 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3209 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
3211 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3212 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3213 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3214 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3215 IsEqualIID(riid, &IID_IUnknown))
3217 *obj = iface;
3218 IDWriteFontCollection3_AddRef(iface);
3219 return S_OK;
3222 *obj = NULL;
3224 if (IsEqualIID(riid, &IID_issystemcollection))
3225 return S_OK;
3227 WARN("%s not implemented.\n", debugstr_guid(riid));
3229 return E_NOINTERFACE;
3232 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3234 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3236 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3237 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3238 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3239 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3240 IsEqualIID(riid, &IID_IUnknown))
3242 *obj = iface;
3243 IDWriteFontCollection3_AddRef(iface);
3244 return S_OK;
3247 WARN("%s not implemented.\n", debugstr_guid(riid));
3249 *obj = NULL;
3251 return E_NOINTERFACE;
3254 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
3256 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3257 ULONG refcount = InterlockedIncrement(&collection->refcount);
3259 TRACE("%p, refcount %ld.\n", collection, refcount);
3261 return refcount;
3264 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
3266 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3267 ULONG refcount = InterlockedDecrement(&collection->refcount);
3268 size_t i;
3270 TRACE("%p, refcount %ld.\n", iface, refcount);
3272 if (!refcount)
3274 factory_detach_fontcollection(collection->factory, iface);
3275 for (i = 0; i < collection->count; ++i)
3276 release_fontfamily_data(collection->family_data[i]);
3277 free(collection->family_data);
3278 free(collection);
3281 return refcount;
3284 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
3286 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3288 TRACE("%p.\n", iface);
3290 return collection->count;
3293 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3294 IDWriteFontFamily **ret)
3296 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3297 struct dwrite_fontfamily *family;
3298 HRESULT hr;
3300 TRACE("%p, %u, %p.\n", iface, index, ret);
3302 *ret = NULL;
3304 if (index >= collection->count)
3305 return E_FAIL;
3307 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3308 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
3310 return hr;
3313 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
3315 size_t i;
3317 for (i = 0; i < collection->count; ++i)
3319 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3320 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3321 HRESULT hr;
3323 for (j = 0; j < count; j++)
3325 WCHAR buffer[255];
3326 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3327 if (SUCCEEDED(hr) && !wcsicmp(buffer, name))
3328 return i;
3332 return ~0u;
3335 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3336 UINT32 *index, BOOL *exists)
3338 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3340 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3342 *index = collection_find_family(collection, name);
3343 *exists = *index != ~0u;
3344 return S_OK;
3347 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3348 IDWriteFont **font)
3350 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3351 struct dwrite_fontfamily *family;
3352 BOOL found_font = FALSE;
3353 IDWriteFontFile *file;
3354 UINT32 face_index, count;
3355 size_t i, j;
3356 HRESULT hr;
3358 TRACE("%p, %p, %p.\n", iface, face, font);
3360 *font = NULL;
3362 if (!face)
3363 return E_INVALIDARG;
3365 count = 1;
3366 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3367 if (FAILED(hr))
3368 return hr;
3369 face_index = IDWriteFontFace_GetIndex(face);
3371 found_font = FALSE;
3372 for (i = 0; i < collection->count; ++i)
3374 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3376 for (j = 0; j < family_data->count; ++j)
3378 struct dwrite_font_data *font_data = family_data->fonts[j];
3380 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3381 found_font = TRUE;
3382 break;
3386 if (found_font)
3387 break;
3389 IDWriteFontFile_Release(file);
3391 if (!found_font)
3392 return DWRITE_E_NOFONT;
3394 hr = create_fontfamily(collection, i, &family);
3395 if (FAILED(hr))
3396 return hr;
3398 hr = create_font(family, j, (IDWriteFont3 **)font);
3399 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3400 return hr;
3403 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3405 FIXME("%p, %p.\n", iface, fontset);
3407 return E_NOTIMPL;
3410 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3411 IDWriteFontFamily1 **ret)
3413 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3414 struct dwrite_fontfamily *family;
3415 HRESULT hr;
3417 TRACE("%p, %u, %p.\n", iface, index, ret);
3419 *ret = NULL;
3421 if (index >= collection->count)
3422 return E_FAIL;
3424 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3425 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3427 return hr;
3430 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3431 UINT32 index, IDWriteFontFamily2 **ret)
3433 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3434 struct dwrite_fontfamily *family;
3435 HRESULT hr;
3437 TRACE("%p, %u, %p.\n", iface, index, ret);
3439 *ret = NULL;
3441 if (index >= collection->count)
3442 return E_FAIL;
3444 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3445 *ret = &family->IDWriteFontFamily2_iface;
3447 return hr;
3450 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3451 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3452 IDWriteFontList2 **fontlist)
3454 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3456 return E_NOTIMPL;
3459 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3461 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3463 TRACE("%p.\n", iface);
3465 return collection->family_model;
3468 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3470 FIXME("%p, %p.\n", iface, fontset);
3472 return E_NOTIMPL;
3475 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3477 FIXME("%p.\n", iface);
3479 return NULL;
3482 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3484 dwritefontcollection_QueryInterface,
3485 dwritefontcollection_AddRef,
3486 dwritefontcollection_Release,
3487 dwritefontcollection_GetFontFamilyCount,
3488 dwritefontcollection_GetFontFamily,
3489 dwritefontcollection_FindFamilyName,
3490 dwritefontcollection_GetFontFromFontFace,
3491 dwritefontcollection1_GetFontSet,
3492 dwritefontcollection1_GetFontFamily,
3493 dwritefontcollection2_GetFontFamily,
3494 dwritefontcollection2_GetMatchingFonts,
3495 dwritefontcollection2_GetFontFamilyModel,
3496 dwritefontcollection2_GetFontSet,
3497 dwritefontcollection3_GetExpirationEvent,
3500 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3502 dwritesystemfontcollection_QueryInterface,
3503 dwritefontcollection_AddRef,
3504 dwritefontcollection_Release,
3505 dwritefontcollection_GetFontFamilyCount,
3506 dwritefontcollection_GetFontFamily,
3507 dwritefontcollection_FindFamilyName,
3508 dwritefontcollection_GetFontFromFontFace,
3509 dwritefontcollection1_GetFontSet,
3510 dwritefontcollection1_GetFontFamily,
3511 dwritefontcollection2_GetFontFamily,
3512 dwritefontcollection2_GetMatchingFonts,
3513 dwritefontcollection2_GetFontFamilyModel,
3514 dwritefontcollection2_GetFontSet,
3515 dwritefontcollection3_GetExpirationEvent,
3518 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3520 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3521 sizeof(*family_data->fonts)))
3523 return E_OUTOFMEMORY;
3526 family_data->fonts[family_data->count++] = font_data;
3527 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3528 family_data->has_normal_face = 1;
3529 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3530 family_data->has_oblique_face = 1;
3531 else
3532 family_data->has_italic_face = 1;
3533 return S_OK;
3536 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3537 struct dwrite_fontfamily_data *family)
3539 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3540 sizeof(*collection->family_data)))
3542 return E_OUTOFMEMORY;
3545 collection->family_data[collection->count++] = family;
3546 return S_OK;
3549 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, IDWriteFactory7 *factory,
3550 DWRITE_FONT_FAMILY_MODEL family_model, BOOL is_system)
3552 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3553 collection->refcount = 1;
3554 collection->factory = factory;
3555 IDWriteFactory7_AddRef(collection->factory);
3556 collection->family_model = family_model;
3558 return S_OK;
3561 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3563 IDWriteFontFileLoader *loader;
3564 const void *key;
3565 UINT32 key_size;
3566 HRESULT hr;
3568 *stream = NULL;
3570 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3571 if (FAILED(hr))
3572 return hr;
3574 hr = IDWriteFontFile_GetLoader(file, &loader);
3575 if (FAILED(hr))
3576 return hr;
3578 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3579 IDWriteFontFileLoader_Release(loader);
3580 if (FAILED(hr))
3581 return hr;
3583 return hr;
3586 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3588 BOOL exists = FALSE;
3589 UINT32 index;
3590 HRESULT hr;
3592 buffer[0] = 0;
3593 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
3594 if (FAILED(hr) || !exists)
3595 return;
3597 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3600 static int trim_spaces(WCHAR *in, WCHAR *ret)
3602 int len;
3604 while (iswspace(*in))
3605 in++;
3607 ret[0] = 0;
3608 if (!(len = wcslen(in)))
3609 return 0;
3611 while (iswspace(in[len-1]))
3612 len--;
3614 memcpy(ret, in, len*sizeof(WCHAR));
3615 ret[len] = 0;
3617 return len;
3620 struct name_token {
3621 struct list entry;
3622 const WCHAR *ptr;
3623 INT len; /* token length */
3624 INT fulllen; /* full length including following separators */
3627 static inline BOOL is_name_separator_char(WCHAR ch)
3629 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3632 struct name_pattern {
3633 const WCHAR *part1; /* NULL indicates end of list */
3634 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3637 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3639 const struct name_pattern *pattern;
3640 struct name_token *token;
3641 int i = 0;
3643 while ((pattern = &patterns[i++])->part1)
3645 int len_part1 = wcslen(pattern->part1);
3646 int len_part2 = pattern->part2 ? wcslen(pattern->part2) : 0;
3648 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry)
3650 if (!len_part2)
3652 /* simple case with single part pattern */
3653 if (token->len != len_part1)
3654 continue;
3656 if (!wcsnicmp(token->ptr, pattern->part1, len_part1))
3658 if (match) *match = *token;
3659 list_remove(&token->entry);
3660 free(token);
3661 return TRUE;
3664 else
3666 struct name_token *next_token;
3667 struct list *next_entry;
3669 /* pattern parts are stored in reading order, tokens list is reversed */
3670 if (token->len < len_part2)
3671 continue;
3673 /* it's possible to have combined string as a token, like ExtraCondensed */
3674 if (token->len == len_part1 + len_part2)
3676 if (wcsnicmp(token->ptr, pattern->part1, len_part1))
3677 continue;
3679 if (wcsnicmp(&token->ptr[len_part1], pattern->part2, len_part2))
3680 continue;
3682 /* combined string match */
3683 if (match) *match = *token;
3684 list_remove(&token->entry);
3685 free(token);
3686 return TRUE;
3689 /* now it's only possible to have two tokens matched to respective pattern parts */
3690 if (token->len != len_part2)
3691 continue;
3693 next_entry = list_next(tokens, &token->entry);
3694 if (next_entry) {
3695 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3696 if (next_token->len != len_part1)
3697 continue;
3699 if (wcsnicmp(token->ptr, pattern->part2, len_part2))
3700 continue;
3702 if (wcsnicmp(next_token->ptr, pattern->part1, len_part1))
3703 continue;
3705 /* both parts matched, remove tokens */
3706 if (match) {
3707 match->ptr = next_token->ptr;
3708 match->len = (token->ptr - next_token->ptr) + token->len;
3710 list_remove(&token->entry);
3711 list_remove(&next_token->entry);
3712 free(next_token);
3713 free(token);
3714 return TRUE;
3720 if (match) {
3721 match->ptr = NULL;
3722 match->len = 0;
3724 return FALSE;
3727 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3729 static const struct name_pattern italic_patterns[] =
3731 { L"ita" },
3732 { L"ital" },
3733 { L"italic" },
3734 { L"cursive" },
3735 { L"kursiv" },
3736 { NULL }
3739 static const struct name_pattern oblique_patterns[] =
3741 { L"inclined" },
3742 { L"oblique" },
3743 { L"backslanted" },
3744 { L"backslant" },
3745 { L"slanted" },
3746 { NULL }
3749 /* italic patterns first */
3750 if (match_pattern_list(tokens, italic_patterns, match))
3751 return DWRITE_FONT_STYLE_ITALIC;
3753 /* oblique patterns */
3754 if (match_pattern_list(tokens, oblique_patterns, match))
3755 return DWRITE_FONT_STYLE_OBLIQUE;
3757 return style;
3760 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3761 struct name_token *match)
3763 static const struct name_pattern ultracondensed_patterns[] =
3765 { L"extra", L"compressed" },
3766 { L"ext", L"compressed" },
3767 { L"ultra", L"compressed" },
3768 { L"ultra", L"condensed" },
3769 { L"ultra", L"cond" },
3770 { NULL }
3773 static const struct name_pattern extracondensed_patterns[] =
3775 { L"compressed" },
3776 { L"extra", L"condensed" },
3777 { L"ext", L"condensed" },
3778 { L"extra", L"cond" },
3779 { L"ext", L"cond" },
3780 { NULL }
3783 static const struct name_pattern semicondensed_patterns[] =
3785 { L"narrow" },
3786 { L"compact" },
3787 { L"semi", L"condensed" },
3788 { L"semi", L"cond" },
3789 { NULL }
3792 static const struct name_pattern semiexpanded_patterns[] =
3794 { L"wide" },
3795 { L"semi", L"expanded" },
3796 { L"semi", L"extended" },
3797 { NULL }
3800 static const struct name_pattern extraexpanded_patterns[] =
3802 { L"extra", L"expanded" },
3803 { L"ext", L"expanded" },
3804 { L"extra", L"extended" },
3805 { L"ext", L"extended" },
3806 { NULL }
3809 static const struct name_pattern ultraexpanded_patterns[] =
3811 { L"ultra", L"expanded" },
3812 { L"ultra", L"extended" },
3813 { NULL }
3816 static const struct name_pattern condensed_patterns[] =
3818 { L"condensed" },
3819 { L"cond" },
3820 { NULL }
3823 static const struct name_pattern expanded_patterns[] =
3825 { L"expanded" },
3826 { L"extended" },
3827 { NULL }
3830 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3831 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3833 if (match_pattern_list(tokens, extracondensed_patterns, match))
3834 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3836 if (match_pattern_list(tokens, semicondensed_patterns, match))
3837 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3839 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3840 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3842 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3843 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3845 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3846 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3848 if (match_pattern_list(tokens, condensed_patterns, match))
3849 return DWRITE_FONT_STRETCH_CONDENSED;
3851 if (match_pattern_list(tokens, expanded_patterns, match))
3852 return DWRITE_FONT_STRETCH_EXPANDED;
3854 return stretch;
3857 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3858 struct name_token *match)
3860 static const struct name_pattern thin_patterns[] =
3862 { L"extra", L"thin" },
3863 { L"ext", L"thin" },
3864 { L"ultra", L"thin" },
3865 { NULL }
3868 static const struct name_pattern extralight_patterns[] =
3870 { L"extra", L"light" },
3871 { L"ext", L"light" },
3872 { L"ultra", L"light" },
3873 { NULL }
3876 static const struct name_pattern semilight_patterns[] =
3878 { L"semi", L"light" },
3879 { NULL }
3882 static const struct name_pattern demibold_patterns[] =
3884 { L"semi", L"bold" },
3885 { L"demi", L"bold" },
3886 { NULL }
3889 static const struct name_pattern extrabold_patterns[] =
3891 { L"extra", L"bold" },
3892 { L"ext", L"bold" },
3893 { L"ultra", L"bold" },
3894 { NULL }
3897 static const struct name_pattern extrablack_patterns[] =
3899 { L"extra", L"black" },
3900 { L"ext", L"black" },
3901 { L"ultra", L"black" },
3902 { NULL }
3905 static const struct name_pattern bold_patterns[] =
3907 { L"bold" },
3908 { NULL }
3911 static const struct name_pattern thin2_patterns[] =
3913 { L"thin" },
3914 { NULL }
3917 static const struct name_pattern light_patterns[] =
3919 { L"light" },
3920 { NULL }
3923 static const struct name_pattern medium_patterns[] =
3925 { L"medium" },
3926 { NULL }
3929 static const struct name_pattern black_patterns[] =
3931 { L"black" },
3932 { L"heavy" },
3933 { L"nord" },
3934 { NULL }
3937 static const struct name_pattern demibold2_patterns[] =
3939 { L"demi" },
3940 { NULL }
3943 static const struct name_pattern extrabold2_patterns[] =
3945 { L"ultra" },
3946 { NULL }
3949 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3950 matching pattern. */
3952 if (match_pattern_list(tokens, thin_patterns, match))
3953 return DWRITE_FONT_WEIGHT_THIN;
3955 if (match_pattern_list(tokens, extralight_patterns, match))
3956 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3958 if (match_pattern_list(tokens, semilight_patterns, match))
3959 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3961 if (match_pattern_list(tokens, demibold_patterns, match))
3962 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3964 if (match_pattern_list(tokens, extrabold_patterns, match))
3965 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3967 if (match_pattern_list(tokens, extrablack_patterns, match))
3968 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3970 if (match_pattern_list(tokens, bold_patterns, match))
3971 return DWRITE_FONT_WEIGHT_BOLD;
3973 if (match_pattern_list(tokens, thin2_patterns, match))
3974 return DWRITE_FONT_WEIGHT_THIN;
3976 if (match_pattern_list(tokens, light_patterns, match))
3977 return DWRITE_FONT_WEIGHT_LIGHT;
3979 if (match_pattern_list(tokens, medium_patterns, match))
3980 return DWRITE_FONT_WEIGHT_MEDIUM;
3982 if (match_pattern_list(tokens, black_patterns, match))
3983 return DWRITE_FONT_WEIGHT_BLACK;
3985 if (match_pattern_list(tokens, black_patterns, match))
3986 return DWRITE_FONT_WEIGHT_BLACK;
3988 if (match_pattern_list(tokens, demibold2_patterns, match))
3989 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3991 if (match_pattern_list(tokens, extrabold2_patterns, match))
3992 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3994 /* FIXME: use abbreviated names to extract weight */
3996 return weight;
3999 struct knownweight_entry
4001 const WCHAR *nameW;
4002 DWRITE_FONT_WEIGHT weight;
4005 static int __cdecl compare_knownweights(const void *a, const void* b)
4007 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
4008 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
4009 int ret = 0;
4011 if (target > entry->weight)
4012 ret = 1;
4013 else if (target < entry->weight)
4014 ret = -1;
4016 return ret;
4019 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
4021 static const struct knownweight_entry knownweights[] =
4023 { L"Thin", DWRITE_FONT_WEIGHT_THIN },
4024 { L"Extra Light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
4025 { L"Light", DWRITE_FONT_WEIGHT_LIGHT },
4026 { L"Semi Light", DWRITE_FONT_WEIGHT_SEMI_LIGHT },
4027 { L"Medium", DWRITE_FONT_WEIGHT_MEDIUM },
4028 { L"Demi Bold", DWRITE_FONT_WEIGHT_DEMI_BOLD },
4029 { L"Bold", DWRITE_FONT_WEIGHT_BOLD },
4030 { L"Extra Bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD },
4031 { L"Black", DWRITE_FONT_WEIGHT_BLACK },
4032 { L"Extra Black", DWRITE_FONT_WEIGHT_EXTRA_BLACK }
4034 const struct knownweight_entry *ptr;
4036 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(*knownweights),
4037 compare_knownweights);
4038 if (!ptr) {
4039 nameW[0] = 0;
4040 return FALSE;
4043 wcscpy(nameW, ptr->nameW);
4044 return TRUE;
4047 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
4049 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
4050 strW[name->len] = 0;
4053 /* Modifies facenameW string, and returns pointer to regular term that was removed */
4054 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
4056 static const WCHAR *regular_patterns[] =
4058 L"Book",
4059 L"Normal",
4060 L"Regular",
4061 L"Roman",
4062 L"Upright",
4063 NULL
4066 const WCHAR *regular_ptr = NULL, *ptr;
4067 int i = 0;
4069 if (len == -1)
4070 len = wcslen(facenameW);
4072 /* remove rightmost regular variant from face name */
4073 while (!regular_ptr && (ptr = regular_patterns[i++]))
4075 int pattern_len = wcslen(ptr);
4076 WCHAR *src;
4078 if (pattern_len > len)
4079 continue;
4081 src = facenameW + len - pattern_len;
4082 while (src >= facenameW)
4084 if (!wcsnicmp(src, ptr, pattern_len))
4086 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
4087 len = wcslen(facenameW);
4088 regular_ptr = ptr;
4089 break;
4091 else
4092 src--;
4096 return regular_ptr;
4099 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
4101 const WCHAR *ptr;
4103 list_init(tokens);
4104 ptr = nameW;
4106 while (*ptr)
4108 struct name_token *token = malloc(sizeof(*token));
4109 token->ptr = ptr;
4110 token->len = 0;
4111 token->fulllen = 0;
4113 while (*ptr && !is_name_separator_char(*ptr)) {
4114 token->len++;
4115 token->fulllen++;
4116 ptr++;
4119 /* skip separators */
4120 while (is_name_separator_char(*ptr)) {
4121 token->fulllen++;
4122 ptr++;
4125 list_add_head(tokens, &token->entry);
4129 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
4131 struct name_token *token, *token2;
4132 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
4133 int len;
4135 list_remove(&token->entry);
4137 /* don't include last separator */
4138 len = list_empty(tokens) ? token->len : token->fulllen;
4139 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
4140 nameW += len;
4142 free(token);
4144 *nameW = 0;
4147 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
4149 struct name_token stretch_name, weight_name, style_name;
4150 WCHAR familynameW[255], facenameW[255], finalW[255];
4151 WCHAR weightW[32], stretchW[32], styleW[32];
4152 const WCHAR *regular_ptr = NULL;
4153 DWRITE_FONT_STRETCH stretch;
4154 DWRITE_FONT_WEIGHT weight;
4155 struct list tokens;
4156 int len;
4158 /* remove leading and trailing spaces from family and face name */
4159 trim_spaces(familyW, familynameW);
4160 len = trim_spaces(faceW, facenameW);
4162 /* remove rightmost regular variant from face name */
4163 regular_ptr = facename_remove_regular_term(facenameW, len);
4165 /* append face name to family name, FIXME check if face name is a substring of family name */
4166 if (*facenameW)
4168 wcscat(familynameW, L" ");
4169 wcscat(familynameW, facenameW);
4172 /* tokenize with " .-_" */
4173 fontname_tokenize(&tokens, familynameW);
4175 /* extract and resolve style */
4176 font->style = font_extract_style(&tokens, font->style, &style_name);
4178 /* extract stretch */
4179 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
4181 /* extract weight */
4182 weight = font_extract_weight(&tokens, font->weight, &weight_name);
4184 /* resolve weight */
4185 if (weight != font->weight)
4187 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
4188 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
4189 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
4190 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
4191 !(abs((int)weight - (int)font->weight) <= 150 &&
4192 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
4193 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
4194 font->weight != DWRITE_FONT_WEIGHT_BOLD))
4196 font->weight = weight;
4200 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
4201 it's leaning in opposite direction from normal comparing to specified stretch or if specified
4202 stretch itself is normal (extracted stretch is never normal). */
4203 if (stretch != font->stretch) {
4204 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
4205 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
4206 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
4208 font->stretch = stretch;
4212 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
4214 /* get final combined string from what's left in token list, list is released */
4215 fontname_tokens_to_str(&tokens, finalW);
4217 if (!wcscmp(familyW, finalW))
4218 return FALSE;
4220 /* construct face name */
4221 wcscpy(familyW, finalW);
4223 /* resolved weight name */
4224 if (weight_name.ptr)
4225 font_name_token_to_str(&weight_name, weightW);
4226 /* ignore normal weight */
4227 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
4228 weightW[0] = 0;
4229 /* for known weight values use appropriate names */
4230 else if (is_known_weight_value(font->weight, weightW)) {
4232 /* use Wnnn format as a fallback in case weight is not one of known values */
4233 else
4234 swprintf(weightW, ARRAY_SIZE(weightW), L"W%d", font->weight);
4236 /* resolved stretch name */
4237 if (stretch_name.ptr)
4238 font_name_token_to_str(&stretch_name, stretchW);
4239 /* ignore normal stretch */
4240 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
4241 stretchW[0] = 0;
4242 /* use predefined stretch names */
4243 else
4245 static const WCHAR *stretchnamesW[] =
4247 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
4248 L"Ultra Condensed",
4249 L"Extra Condensed",
4250 L"Condensed",
4251 L"Semi Condensed",
4252 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
4253 L"Semi Expanded",
4254 L"Expanded",
4255 L"Extra Expanded",
4256 L"Ultra Expanded"
4258 wcscpy(stretchW, stretchnamesW[font->stretch]);
4261 /* resolved style name */
4262 if (style_name.ptr)
4263 font_name_token_to_str(&style_name, styleW);
4264 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
4265 styleW[0] = 0;
4266 /* use predefined names */
4267 else
4268 wcscpy(styleW, font->style == DWRITE_FONT_STYLE_ITALIC ? L"Italic" : L"Oblique");
4270 /* use Regular match if it was found initially */
4271 if (!*weightW && !*stretchW && !*styleW)
4272 wcscpy(faceW, regular_ptr ? regular_ptr : L"Regular");
4273 else
4275 faceW[0] = 0;
4277 if (*stretchW) wcscpy(faceW, stretchW);
4279 if (*weightW)
4281 if (*faceW) wcscat(faceW, L" ");
4282 wcscat(faceW, weightW);
4285 if (*styleW)
4287 if (*faceW) wcscat(faceW, L" ");
4288 wcscat(faceW, styleW);
4292 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
4293 return TRUE;
4296 static HRESULT init_font_data(const struct fontface_desc *desc, DWRITE_FONT_FAMILY_MODEL family_model,
4297 struct dwrite_font_data **ret)
4299 static const float width_axis_values[] =
4301 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
4302 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
4303 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
4304 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
4305 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
4306 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
4307 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
4308 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
4309 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
4310 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
4313 struct file_stream_desc stream_desc;
4314 struct dwrite_font_props props;
4315 struct dwrite_font_data *data;
4316 WCHAR familyW[255], faceW[255];
4317 HRESULT hr;
4319 *ret = NULL;
4321 if (!(data = calloc(1, sizeof(*data))))
4322 return E_OUTOFMEMORY;
4324 data->refcount = 1;
4325 data->file = desc->file;
4326 data->face_index = desc->index;
4327 data->face_type = desc->face_type;
4328 IDWriteFontFile_AddRef(data->file);
4330 stream_desc.stream = desc->stream;
4331 stream_desc.face_type = desc->face_type;
4332 stream_desc.face_index = desc->index;
4333 opentype_get_font_properties(&stream_desc, &props);
4334 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4335 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4337 if (FAILED(hr = opentype_get_font_familyname(&stream_desc, family_model, &data->family_names)))
4339 WARN("Unable to get family name from the font file, hr %#lx.\n", hr);
4340 release_font_data(data);
4341 return hr;
4344 data->style = props.style;
4345 data->stretch = props.stretch;
4346 data->weight = props.weight;
4347 data->panose = props.panose;
4348 data->fontsig = props.fontsig;
4349 data->lf = props.lf;
4350 data->flags = props.flags;
4352 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4353 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4355 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE
4356 && font_apply_differentiation_rules(data, familyW, faceW))
4358 set_en_localizedstring(data->family_names, familyW);
4359 set_en_localizedstring(data->names, faceW);
4362 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4364 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4365 data->axis[0].value = props.weight;
4366 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4367 data->axis[1].value = width_axis_values[props.stretch];
4368 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4369 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4371 *ret = data;
4372 return S_OK;
4375 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4376 const WCHAR *facenameW, struct dwrite_font_data **ret)
4378 struct dwrite_font_data *data;
4380 *ret = NULL;
4382 if (!(data = calloc(1, sizeof(*data))))
4383 return E_OUTOFMEMORY;
4385 *data = *src;
4386 data->refcount = 1;
4387 data->simulations |= simulations;
4388 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4389 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4390 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4391 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4392 memset(data->info_strings, 0, sizeof(data->info_strings));
4393 data->names = NULL;
4394 IDWriteFontFile_AddRef(data->file);
4395 IDWriteLocalizedStrings_AddRef(data->family_names);
4397 create_localizedstrings(&data->names);
4398 add_localizedstring(data->names, L"en-us", facenameW);
4400 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4402 *ret = data;
4403 return S_OK;
4406 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4408 struct dwrite_fontfamily_data *data;
4410 if (!(data = calloc(1, sizeof(*data))))
4411 return E_OUTOFMEMORY;
4413 data->refcount = 1;
4414 data->familyname = familyname;
4415 IDWriteLocalizedStrings_AddRef(familyname);
4417 *ret = data;
4419 return S_OK;
4422 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4424 size_t i, j, heaviest;
4426 for (i = 0; i < family->count; ++i)
4428 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4429 heaviest = i;
4431 if (family->fonts[i]->bold_sim_tested)
4432 continue;
4434 family->fonts[i]->bold_sim_tested = 1;
4435 for (j = i; j < family->count; ++j)
4437 if (family->fonts[j]->bold_sim_tested)
4438 continue;
4440 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4441 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4442 if (family->fonts[j]->weight > weight) {
4443 weight = family->fonts[j]->weight;
4444 heaviest = j;
4446 family->fonts[j]->bold_sim_tested = 1;
4450 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550)
4452 static const struct name_pattern weightsim_patterns[] =
4454 { L"extra", L"light" },
4455 { L"ext", L"light" },
4456 { L"ultra", L"light" },
4457 { L"semi", L"light" },
4458 { L"semi", L"bold" },
4459 { L"demi", L"bold" },
4460 { L"bold" },
4461 { L"thin" },
4462 { L"light" },
4463 { L"medium" },
4464 { L"demi" },
4465 { NULL }
4468 WCHAR facenameW[255], initialW[255];
4469 struct dwrite_font_data *boldface;
4470 struct list tokens;
4472 /* add Bold simulation based on heaviest face data */
4474 /* Simulated face name should only contain Bold as weight term,
4475 so remove existing regular and weight terms. */
4476 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4477 facename_remove_regular_term(initialW, -1);
4479 /* remove current weight pattern */
4480 fontname_tokenize(&tokens, initialW);
4481 match_pattern_list(&tokens, weightsim_patterns, NULL);
4482 fontname_tokens_to_str(&tokens, facenameW);
4484 /* Bold suffix for new name */
4485 if (*facenameW) wcscat(facenameW, L" ");
4486 wcscat(facenameW, L"Bold");
4488 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4489 boldface->bold_sim_tested = 1;
4490 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4491 fontfamily_add_font(family, boldface);
4497 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4499 size_t i, j;
4501 for (i = 0; i < family->count; ++i)
4503 UINT32 regular = ~0u, oblique = ~0u;
4504 struct dwrite_font_data *obliqueface;
4505 WCHAR facenameW[255];
4507 if (family->fonts[i]->oblique_sim_tested)
4508 continue;
4510 family->fonts[i]->oblique_sim_tested = 1;
4511 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4512 regular = i;
4513 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4514 oblique = i;
4516 /* find regular style with same weight/stretch values */
4517 for (j = i; j < family->count; ++j)
4519 if (family->fonts[j]->oblique_sim_tested)
4520 continue;
4522 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4523 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4525 family->fonts[j]->oblique_sim_tested = 1;
4526 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4527 regular = j;
4529 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4530 oblique = j;
4533 if (regular != ~0u && oblique != ~0u)
4534 break;
4537 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4538 if (regular == ~0u)
4539 continue;
4541 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4542 if (oblique != ~0u)
4543 continue;
4545 /* add oblique simulation based on this regular face */
4547 /* remove regular term if any, append 'Oblique' */
4548 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4549 facename_remove_regular_term(facenameW, -1);
4551 if (*facenameW) wcscat(facenameW, L" ");
4552 wcscat(facenameW, L"Oblique");
4554 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4555 obliqueface->oblique_sim_tested = 1;
4556 obliqueface->lf.lfItalic = 1;
4557 fontfamily_add_font(family, obliqueface);
4562 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4563 const WCHAR *replacement_name)
4565 UINT32 i = collection_find_family(collection, replacement_name);
4566 struct dwrite_fontfamily_data *target;
4567 IDWriteLocalizedStrings *strings;
4568 HRESULT hr;
4570 /* replacement does not exist */
4571 if (i == ~0u)
4572 return FALSE;
4574 hr = create_localizedstrings(&strings);
4575 if (FAILED(hr))
4576 return FALSE;
4578 /* add a new family with target name, reuse font data from replacement */
4579 add_localizedstring(strings, L"en-us", target_name);
4580 hr = init_fontfamily_data(strings, &target);
4581 if (hr == S_OK) {
4582 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4583 WCHAR nameW[255];
4585 for (i = 0; i < replacement->count; ++i)
4587 fontfamily_add_font(target, replacement->fonts[i]);
4588 addref_font_data(replacement->fonts[i]);
4591 fontcollection_add_family(collection, target);
4592 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4593 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4595 IDWriteLocalizedStrings_Release(strings);
4596 return TRUE;
4599 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4600 system font collections. */
4601 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4603 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4604 WCHAR *name;
4605 void *data;
4606 HKEY hkey;
4608 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4609 return;
4611 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4612 RegCloseKey(hkey);
4613 return;
4616 max_namelen++; /* returned value doesn't include room for '\0' */
4617 name = malloc(max_namelen * sizeof(WCHAR));
4618 data = malloc(max_datalen);
4620 datalen = max_datalen;
4621 namelen = max_namelen;
4622 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4623 if (collection_find_family(collection, name) == ~0u) {
4624 if (type == REG_MULTI_SZ) {
4625 WCHAR *replacement = data;
4626 while (*replacement) {
4627 if (fontcollection_add_replacement(collection, name, replacement))
4628 break;
4629 replacement += wcslen(replacement) + 1;
4632 else if (type == REG_SZ)
4633 fontcollection_add_replacement(collection, name, data);
4635 else
4636 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4638 datalen = max_datalen;
4639 namelen = max_namelen;
4642 free(data);
4643 free(name);
4644 RegCloseKey(hkey);
4647 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4648 IDWriteFontCollection3 **ret)
4650 struct fontfile_enum {
4651 struct list entry;
4652 IDWriteFontFile *file;
4654 struct fontfile_enum *fileenum, *fileenum2;
4655 struct dwrite_fontcollection *collection;
4656 struct list scannedfiles;
4657 BOOL current = FALSE;
4658 HRESULT hr = S_OK;
4659 size_t i;
4661 *ret = NULL;
4663 if (!(collection = calloc(1, sizeof(*collection))))
4664 return E_OUTOFMEMORY;
4666 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, is_system);
4667 if (FAILED(hr))
4669 free(collection);
4670 return hr;
4673 *ret = &collection->IDWriteFontCollection3_iface;
4675 TRACE("building font collection:\n");
4677 list_init(&scannedfiles);
4678 while (hr == S_OK) {
4679 DWRITE_FONT_FACE_TYPE face_type;
4680 DWRITE_FONT_FILE_TYPE file_type;
4681 BOOL supported, same = FALSE;
4682 IDWriteFontFileStream *stream;
4683 IDWriteFontFile *file;
4684 UINT32 face_count;
4686 current = FALSE;
4687 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4688 if (FAILED(hr) || !current)
4689 break;
4691 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4692 if (FAILED(hr))
4693 break;
4695 /* check if we've scanned this file already */
4696 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4697 if ((same = is_same_fontfile(fileenum->file, file)))
4698 break;
4701 if (same) {
4702 IDWriteFontFile_Release(file);
4703 continue;
4706 if (FAILED(get_filestream_from_file(file, &stream))) {
4707 IDWriteFontFile_Release(file);
4708 continue;
4711 /* Unsupported formats are skipped. */
4712 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4713 if (FAILED(hr) || !supported || face_count == 0) {
4714 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
4715 IDWriteFontFileStream_Release(stream);
4716 IDWriteFontFile_Release(file);
4717 hr = S_OK;
4718 continue;
4721 /* add to scanned list */
4722 fileenum = malloc(sizeof(*fileenum));
4723 fileenum->file = file;
4724 list_add_tail(&scannedfiles, &fileenum->entry);
4726 for (i = 0; i < face_count; ++i)
4728 struct dwrite_font_data *font_data;
4729 struct fontface_desc desc;
4730 WCHAR familyW[255];
4731 UINT32 index;
4733 desc.factory = factory;
4734 desc.face_type = face_type;
4735 desc.file = file;
4736 desc.stream = stream;
4737 desc.index = i;
4738 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4739 desc.font_data = NULL;
4741 /* Allocate an initialize new font data structure. */
4742 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
4743 if (FAILED(hr))
4745 /* move to next one */
4746 hr = S_OK;
4747 continue;
4750 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4752 /* ignore dot named faces */
4753 if (familyW[0] == '.')
4755 WARN("Ignoring face %s\n", debugstr_w(familyW));
4756 release_font_data(font_data);
4757 continue;
4760 index = collection_find_family(collection, familyW);
4761 if (index != ~0u)
4762 hr = fontfamily_add_font(collection->family_data[index], font_data);
4763 else {
4764 struct dwrite_fontfamily_data *family_data;
4766 /* create and init new family */
4767 hr = init_fontfamily_data(font_data->family_names, &family_data);
4768 if (hr == S_OK) {
4769 /* add font to family, family - to collection */
4770 hr = fontfamily_add_font(family_data, font_data);
4771 if (hr == S_OK)
4772 hr = fontcollection_add_family(collection, family_data);
4774 if (FAILED(hr))
4775 release_fontfamily_data(family_data);
4779 if (FAILED(hr))
4781 release_font_data(font_data);
4782 break;
4786 IDWriteFontFileStream_Release(stream);
4789 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry)
4791 IDWriteFontFile_Release(fileenum->file);
4792 list_remove(&fileenum->entry);
4793 free(fileenum);
4796 for (i = 0; i < collection->count; ++i)
4798 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4799 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4802 if (is_system)
4803 fontcollection_add_replacements(collection);
4805 return hr;
4808 static HRESULT collection_add_font_entry(struct dwrite_fontcollection *collection, const struct fontface_desc *desc)
4810 struct dwrite_font_data *font_data;
4811 WCHAR familyW[255];
4812 UINT32 index;
4813 HRESULT hr;
4815 if (FAILED(hr = init_font_data(desc, collection->family_model, &font_data)))
4816 return hr;
4818 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4820 /* ignore dot named faces */
4821 if (familyW[0] == '.')
4823 WARN("Ignoring face %s\n", debugstr_w(familyW));
4824 release_font_data(font_data);
4825 return S_OK;
4828 index = collection_find_family(collection, familyW);
4829 if (index != ~0u)
4830 hr = fontfamily_add_font(collection->family_data[index], font_data);
4831 else
4833 struct dwrite_fontfamily_data *family_data;
4835 /* Create and initialize new family */
4836 hr = init_fontfamily_data(font_data->family_names, &family_data);
4837 if (hr == S_OK)
4839 /* add font to family, family - to collection */
4840 hr = fontfamily_add_font(family_data, font_data);
4841 if (hr == S_OK)
4842 hr = fontcollection_add_family(collection, family_data);
4844 if (FAILED(hr))
4845 release_fontfamily_data(family_data);
4849 if (FAILED(hr))
4850 release_font_data(font_data);
4852 return hr;
4855 HRESULT create_font_collection_from_set(IDWriteFactory7 *factory, IDWriteFontSet *fontset,
4856 DWRITE_FONT_FAMILY_MODEL family_model, REFGUID riid, void **ret)
4858 struct dwrite_fontset *set = unsafe_impl_from_IDWriteFontSet(fontset);
4859 struct dwrite_fontcollection *collection;
4860 HRESULT hr = S_OK;
4861 size_t i;
4863 *ret = NULL;
4865 if (!(collection = calloc(1, sizeof(*collection))))
4866 return E_OUTOFMEMORY;
4868 if (FAILED(hr = init_font_collection(collection, factory, family_model, FALSE)))
4870 free(collection);
4871 return hr;
4874 for (i = 0; i < set->count; ++i)
4876 const struct dwrite_fontset_entry *entry = set->entries[i];
4877 IDWriteFontFileStream *stream;
4878 struct fontface_desc desc;
4880 if (FAILED(get_filestream_from_file(entry->desc.file, &stream)))
4882 WARN("Failed to get file stream.\n");
4883 continue;
4886 desc.factory = factory;
4887 desc.face_type = entry->desc.face_type;
4888 desc.file = entry->desc.file;
4889 desc.stream = stream;
4890 desc.index = entry->desc.face_index;
4891 desc.simulations = entry->desc.simulations;
4892 desc.font_data = NULL;
4894 if (FAILED(hr = collection_add_font_entry(collection, &desc)))
4895 WARN("Failed to add font collection element, hr %#lx.\n", hr);
4897 IDWriteFontFileStream_Release(stream);
4900 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE)
4902 for (i = 0; i < collection->count; ++i)
4904 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4905 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4909 hr = IDWriteFontCollection3_QueryInterface(&collection->IDWriteFontCollection3_iface, riid, ret);
4910 IDWriteFontCollection3_Release(&collection->IDWriteFontCollection3_iface);
4912 return hr;
4915 struct system_fontfile_enumerator
4917 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4918 LONG refcount;
4920 IDWriteFactory7 *factory;
4921 HKEY hkey;
4922 int index;
4924 WCHAR *filename;
4925 DWORD filename_size;
4928 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4930 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4933 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4935 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4936 IDWriteFontFileEnumerator_AddRef(iface);
4937 *obj = iface;
4938 return S_OK;
4941 WARN("%s not implemented.\n", debugstr_guid(riid));
4943 *obj = NULL;
4945 return E_NOINTERFACE;
4948 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4950 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4951 return InterlockedIncrement(&enumerator->refcount);
4954 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4956 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4957 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4959 if (!refcount)
4961 IDWriteFactory7_Release(enumerator->factory);
4962 RegCloseKey(enumerator->hkey);
4963 free(enumerator->filename);
4964 free(enumerator);
4967 return refcount;
4970 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4972 HRESULT hr;
4974 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4975 if (!wcschr(filename, '\\'))
4977 WCHAR fullpathW[MAX_PATH];
4979 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4980 wcscat(fullpathW, L"\\fonts\\");
4981 wcscat(fullpathW, filename);
4983 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4985 else
4986 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4988 return hr;
4991 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4993 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4995 *file = NULL;
4997 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4998 return E_FAIL;
5000 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
5003 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
5005 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
5006 WCHAR name_buf[256], *name = name_buf;
5007 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
5008 HRESULT hr = S_OK;
5009 LONG r;
5011 *current = FALSE;
5012 enumerator->index++;
5014 /* iterate until we find next string value */
5015 for (;;) {
5016 do {
5017 name_count = max_name_count;
5018 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
5020 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
5021 NULL, &type, (BYTE *)enumerator->filename, &data_size);
5022 if (r == ERROR_MORE_DATA) {
5023 if (name_count >= max_name_count) {
5024 if (name != name_buf) free(name);
5025 max_name_count *= 2;
5026 name = malloc(max_name_count * sizeof(*name));
5027 if (!name) return E_OUTOFMEMORY;
5029 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename))
5031 free(enumerator->filename);
5032 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
5033 if (!(enumerator->filename = malloc(enumerator->filename_size)))
5035 hr = E_OUTOFMEMORY;
5036 goto err;
5040 } while (r == ERROR_MORE_DATA);
5042 if (r != ERROR_SUCCESS) {
5043 enumerator->filename[0] = 0;
5044 break;
5046 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
5047 if (type == REG_SZ && *name != '@') {
5048 *current = TRUE;
5049 break;
5051 enumerator->index++;
5053 TRACE("index = %d, current = %d\n", enumerator->index, *current);
5055 err:
5056 if (name != name_buf) free(name);
5057 return hr;
5060 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
5062 systemfontfileenumerator_QueryInterface,
5063 systemfontfileenumerator_AddRef,
5064 systemfontfileenumerator_Release,
5065 systemfontfileenumerator_MoveNext,
5066 systemfontfileenumerator_GetCurrentFontFile
5069 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
5071 struct system_fontfile_enumerator *enumerator;
5073 *ret = NULL;
5075 if (!(enumerator = calloc(1, sizeof(*enumerator))))
5076 return E_OUTOFMEMORY;
5078 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
5079 enumerator->refcount = 1;
5080 enumerator->factory = factory;
5081 enumerator->index = -1;
5082 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
5083 enumerator->filename = malloc(enumerator->filename_size);
5084 if (!enumerator->filename)
5086 free(enumerator);
5087 return E_OUTOFMEMORY;
5090 IDWriteFactory7_AddRef(factory);
5092 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0,
5093 GENERIC_READ, &enumerator->hkey))
5095 ERR("failed to open fonts list key\n");
5096 IDWriteFactory7_Release(factory);
5097 free(enumerator->filename);
5098 free(enumerator);
5099 return E_FAIL;
5102 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
5104 return S_OK;
5107 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, DWRITE_FONT_FAMILY_MODEL family_model,
5108 IDWriteFontCollection **collection)
5110 IDWriteFontFileEnumerator *enumerator;
5111 IDWriteFontSet *fontset;
5112 HRESULT hr;
5114 *collection = NULL;
5116 if (family_model == DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC)
5118 if (SUCCEEDED(hr = create_system_fontset(factory, &IID_IDWriteFontSet, (void **)&fontset)))
5120 hr = create_font_collection_from_set(factory, fontset, family_model,
5121 &IID_IDWriteFontCollection, (void **)collection);
5122 IDWriteFontSet_Release(fontset);
5125 else
5127 if (SUCCEEDED(hr = create_system_fontfile_enumerator(factory, &enumerator)))
5129 TRACE("Building system font collection for factory %p.\n", factory);
5130 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
5131 IDWriteFontFileEnumerator_Release(enumerator);
5135 return hr;
5138 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
5139 const WCHAR *keynameW, const WCHAR *pathW)
5141 struct dwrite_fontfamily_data *family_data;
5142 IDWriteLocalizedStrings *names;
5143 DWRITE_FONT_FACE_TYPE face_type;
5144 DWRITE_FONT_FILE_TYPE file_type;
5145 IDWriteFontFileStream *stream;
5146 IDWriteFontFile *file;
5147 UINT32 face_count, i;
5148 BOOL supported;
5149 HRESULT hr;
5151 /* create font file from this path */
5152 hr = create_local_file_reference(factory, pathW, &file);
5153 if (FAILED(hr))
5154 return S_FALSE;
5156 if (FAILED(get_filestream_from_file(file, &stream))) {
5157 IDWriteFontFile_Release(file);
5158 return S_FALSE;
5161 /* Unsupported formats are skipped. */
5162 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
5163 if (FAILED(hr) || !supported || face_count == 0) {
5164 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
5165 IDWriteFontFileStream_Release(stream);
5166 IDWriteFontFile_Release(file);
5167 return S_FALSE;
5170 /* create and init new family */
5172 /* Family names are added for non-specific locale, represented with empty string.
5173 Default family appears with empty family name. */
5174 create_localizedstrings(&names);
5175 if (!wcsicmp(keynameW, L"SystemDefaultEUDCFont"))
5176 add_localizedstring(names, L"", L"");
5177 else
5178 add_localizedstring(names, L"", keynameW);
5180 hr = init_fontfamily_data(names, &family_data);
5181 IDWriteLocalizedStrings_Release(names);
5182 if (hr != S_OK) {
5183 IDWriteFontFile_Release(file);
5184 return hr;
5187 /* fill with faces */
5188 for (i = 0; i < face_count; i++) {
5189 struct dwrite_font_data *font_data;
5190 struct fontface_desc desc;
5192 /* Allocate new font data structure. */
5193 desc.factory = factory;
5194 desc.face_type = face_type;
5195 desc.index = i;
5196 desc.file = file;
5197 desc.stream = stream;
5198 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
5199 desc.font_data = NULL;
5201 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5202 if (FAILED(hr))
5203 continue;
5205 /* add font to family */
5206 hr = fontfamily_add_font(family_data, font_data);
5207 if (hr != S_OK)
5208 release_font_data(font_data);
5211 /* add family to collection */
5212 hr = fontcollection_add_family(collection, family_data);
5213 if (FAILED(hr))
5214 release_fontfamily_data(family_data);
5215 IDWriteFontFileStream_Release(stream);
5216 IDWriteFontFile_Release(file);
5218 return hr;
5221 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
5223 struct dwrite_fontcollection *collection;
5224 WCHAR eudckeypathW[16];
5225 HKEY eudckey;
5226 UINT32 index;
5227 BOOL exists;
5228 LONG retval;
5229 HRESULT hr;
5230 size_t i;
5232 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
5234 *ret = NULL;
5236 if (!(collection = calloc(1, sizeof(*collection))))
5237 return E_OUTOFMEMORY;
5239 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, FALSE);
5240 if (FAILED(hr))
5242 free(collection);
5243 return hr;
5246 *ret = &collection->IDWriteFontCollection3_iface;
5248 /* return empty collection if EUDC fonts are not configured */
5249 swprintf(eudckeypathW, ARRAY_SIZE(eudckeypathW), L"EUDC\\%u", GetACP());
5250 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
5251 return S_OK;
5253 retval = ERROR_SUCCESS;
5254 index = 0;
5255 while (retval != ERROR_NO_MORE_ITEMS) {
5256 WCHAR keynameW[64], pathW[MAX_PATH];
5257 DWORD type, path_len, name_len;
5259 path_len = ARRAY_SIZE(pathW);
5260 name_len = ARRAY_SIZE(keynameW);
5261 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
5262 if (retval || type != REG_SZ)
5263 continue;
5265 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
5266 if (hr != S_OK)
5267 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
5269 RegCloseKey(eudckey);
5271 /* try to add global default if not defined for specific codepage */
5272 exists = FALSE;
5273 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, L"",
5274 &index, &exists);
5275 if (FAILED(hr) || !exists)
5277 hr = eudc_collection_add_family(factory, collection, L"", L"EUDC.TTE");
5278 if (hr != S_OK)
5279 WARN("failed to add global default EUDC font, 0x%08lx\n", hr);
5282 /* EUDC collection offers simulated faces too */
5283 for (i = 0; i < collection->count; ++i)
5285 fontfamily_add_bold_simulated_face(collection->family_data[i]);
5286 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
5289 return S_OK;
5292 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
5294 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5296 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
5298 *obj = iface;
5299 IDWriteFontFile_AddRef(iface);
5300 return S_OK;
5303 WARN("%s not implemented.\n", debugstr_guid(riid));
5305 *obj = NULL;
5306 return E_NOINTERFACE;
5309 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
5311 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5312 ULONG refcount = InterlockedIncrement(&file->refcount);
5314 TRACE("%p, refcount %ld.\n", iface, refcount);
5316 return refcount;
5319 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
5321 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5322 ULONG refcount = InterlockedDecrement(&file->refcount);
5324 TRACE("%p, refcount %ld.\n", iface, refcount);
5326 if (!refcount)
5328 IDWriteFontFileLoader_Release(file->loader);
5329 if (file->stream)
5330 IDWriteFontFileStream_Release(file->stream);
5331 free(file->reference_key);
5332 free(file);
5335 return refcount;
5338 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
5340 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5342 TRACE("%p, %p, %p.\n", iface, key, key_size);
5344 *key = file->reference_key;
5345 *key_size = file->key_size;
5347 return S_OK;
5350 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
5352 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5354 TRACE("%p, %p.\n", iface, loader);
5356 *loader = file->loader;
5357 IDWriteFontFileLoader_AddRef(*loader);
5359 return S_OK;
5362 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
5363 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
5365 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5366 IDWriteFontFileStream *stream;
5367 HRESULT hr;
5369 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
5371 *is_supported = FALSE;
5372 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
5373 if (face_type)
5374 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
5375 *face_count = 0;
5377 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
5378 if (FAILED(hr))
5379 return hr;
5381 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
5383 /* TODO: Further Analysis */
5384 IDWriteFontFileStream_Release(stream);
5385 return S_OK;
5388 static const IDWriteFontFileVtbl dwritefontfilevtbl =
5390 dwritefontfile_QueryInterface,
5391 dwritefontfile_AddRef,
5392 dwritefontfile_Release,
5393 dwritefontfile_GetReferenceKey,
5394 dwritefontfile_GetLoader,
5395 dwritefontfile_Analyze,
5398 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
5399 IDWriteFontFile **ret)
5401 struct dwrite_fontfile *file;
5402 void *key;
5404 *ret = NULL;
5406 file = calloc(1, sizeof(*file));
5407 key = malloc(key_size);
5408 if (!file || !key)
5410 free(file);
5411 free(key);
5412 return E_OUTOFMEMORY;
5415 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
5416 file->refcount = 1;
5417 IDWriteFontFileLoader_AddRef(loader);
5418 file->loader = loader;
5419 file->stream = NULL;
5420 file->reference_key = key;
5421 memcpy(file->reference_key, reference_key, key_size);
5422 file->key_size = key_size;
5424 *ret = &file->IDWriteFontFile_iface;
5426 return S_OK;
5429 static UINT64 dwrite_fontface_get_font_object(struct dwrite_fontface *fontface)
5431 struct create_font_object_params create_params;
5432 struct release_font_object_params release_params;
5433 UINT64 font_object, size;
5434 const void *data_ptr;
5435 void *data_context;
5437 if (!fontface->font_object && SUCCEEDED(IDWriteFontFileStream_GetFileSize(fontface->stream, &size)))
5439 if (SUCCEEDED(IDWriteFontFileStream_ReadFileFragment(fontface->stream, &data_ptr, 0, size, &data_context)))
5441 create_params.data = data_ptr;
5442 create_params.size = size;
5443 create_params.index = fontface->index;
5444 create_params.object = &font_object;
5446 UNIX_CALL(create_font_object, &create_params);
5448 if (!font_object)
5450 WARN("Backend failed to create font object.\n");
5451 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5452 return 0;
5455 if (!InterlockedCompareExchange64((LONGLONG *)&fontface->font_object, font_object, 0))
5457 fontface->data_context = data_context;
5459 else
5461 release_params.object = font_object;
5462 UNIX_CALL(release_font_object, &release_params);
5463 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5468 return fontface->font_object;
5471 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5473 struct file_stream_desc stream_desc;
5474 struct dwrite_font_data *font_data;
5475 struct dwrite_fontface *fontface;
5476 HRESULT hr;
5477 int i;
5479 *ret = NULL;
5481 if (!(fontface = calloc(1, sizeof(*fontface))))
5482 return E_OUTOFMEMORY;
5484 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5485 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5486 fontface->refcount = 1;
5487 fontface->type = desc->face_type;
5488 fontface->vdmx.exists = TRUE;
5489 fontface->gasp.exists = TRUE;
5490 fontface->cpal.exists = TRUE;
5491 fontface->colr.exists = TRUE;
5492 fontface->kern.exists = TRUE;
5493 fontface->index = desc->index;
5494 fontface->simulations = desc->simulations;
5495 fontface->factory = desc->factory;
5496 IDWriteFactory7_AddRef(fontface->factory);
5497 fontface->file = desc->file;
5498 IDWriteFontFile_AddRef(fontface->file);
5499 fontface->stream = desc->stream;
5500 IDWriteFontFileStream_AddRef(fontface->stream);
5501 InitializeCriticalSection(&fontface->cs);
5502 fontface_cache_init(fontface);
5504 stream_desc.stream = fontface->stream;
5505 stream_desc.face_type = desc->face_type;
5506 stream_desc.face_index = desc->index;
5507 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5508 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5509 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5510 /* TODO: test what happens if caret is already slanted */
5511 if (fontface->caret.slopeRise == 1) {
5512 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5513 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5516 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5518 /* Font properties are reused from font object when 'normal' face creation path is used:
5519 collection -> family -> matching font -> fontface.
5521 If face is created directly from factory we have to go through properties resolution.
5523 if (desc->font_data)
5525 font_data = addref_font_data(desc->font_data);
5527 else
5529 hr = init_font_data(desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5530 if (FAILED(hr))
5532 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5533 return hr;
5537 fontface->weight = font_data->weight;
5538 fontface->style = font_data->style;
5539 fontface->stretch = font_data->stretch;
5540 fontface->panose = font_data->panose;
5541 fontface->fontsig = font_data->fontsig;
5542 fontface->lf = font_data->lf;
5543 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5544 fontface->names = font_data->names;
5545 if (fontface->names)
5546 IDWriteLocalizedStrings_AddRef(fontface->names);
5547 fontface->family_names = font_data->family_names;
5548 if (fontface->family_names)
5549 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5550 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5551 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5553 if (fontface->info_strings[i])
5554 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5556 fontface->cmap.stream = fontface->stream;
5557 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5558 release_font_data(font_data);
5560 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5561 fontface->get_font_object = dwrite_fontface_get_font_object;
5563 *ret = &fontface->IDWriteFontFace5_iface;
5565 return S_OK;
5568 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5569 struct local_refkey
5571 FILETIME writetime;
5572 WCHAR name[1];
5575 struct local_cached_stream
5577 struct list entry;
5578 IDWriteFontFileStream *stream;
5579 struct local_refkey *key;
5580 UINT32 key_size;
5583 struct dwrite_localfontfilestream
5585 IDWriteFontFileStream IDWriteFontFileStream_iface;
5586 LONG refcount;
5588 struct local_cached_stream *entry;
5589 const void *file_ptr;
5590 UINT64 size;
5593 struct dwrite_localfontfileloader
5595 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5596 LONG refcount;
5598 struct list streams;
5599 CRITICAL_SECTION cs;
5602 static struct dwrite_localfontfileloader local_fontfile_loader;
5604 struct dwrite_inmemory_stream_data
5606 LONG refcount;
5607 IUnknown *owner;
5608 void *data;
5609 UINT32 size;
5612 struct dwrite_inmemory_filestream
5614 IDWriteFontFileStream IDWriteFontFileStream_iface;
5615 LONG refcount;
5617 struct dwrite_inmemory_stream_data *data;
5620 struct dwrite_inmemory_fileloader
5622 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5623 LONG refcount;
5625 struct dwrite_inmemory_stream_data **streams;
5626 size_t size;
5627 size_t count;
5630 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5632 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5635 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5637 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5640 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5642 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5645 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5647 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5650 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5652 if (InterlockedDecrement(&stream->refcount) == 0)
5654 if (stream->owner)
5655 IUnknown_Release(stream->owner);
5656 else
5657 free(stream->data);
5658 free(stream);
5662 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5664 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5666 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5668 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5669 IsEqualIID(riid, &IID_IUnknown))
5671 *obj = iface;
5672 if (InterlockedIncrement(&stream->refcount) == 1)
5674 InterlockedDecrement(&stream->refcount);
5675 *obj = NULL;
5676 return E_FAIL;
5678 return S_OK;
5681 WARN("%s not implemented.\n", debugstr_guid(riid));
5683 *obj = NULL;
5684 return E_NOINTERFACE;
5687 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5689 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5690 ULONG refcount = InterlockedIncrement(&stream->refcount);
5692 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5694 return refcount;
5697 static inline void release_cached_stream(struct local_cached_stream *stream)
5699 list_remove(&stream->entry);
5700 free(stream->key);
5701 free(stream);
5704 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5706 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5707 ULONG refcount = InterlockedDecrement(&stream->refcount);
5709 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5711 if (!refcount)
5713 UnmapViewOfFile(stream->file_ptr);
5715 EnterCriticalSection(&local_fontfile_loader.cs);
5716 release_cached_stream(stream->entry);
5717 LeaveCriticalSection(&local_fontfile_loader.cs);
5719 free(stream);
5722 return refcount;
5725 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5726 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5728 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5730 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5731 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5733 *fragment_context = NULL;
5735 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5737 *fragment_start = NULL;
5738 return E_FAIL;
5741 *fragment_start = (char *)stream->file_ptr + offset;
5742 return S_OK;
5745 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5747 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5750 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5752 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5754 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5756 *size = stream->size;
5757 return S_OK;
5760 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5762 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5763 ULARGE_INTEGER li;
5765 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5767 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5768 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5769 *last_writetime = li.QuadPart;
5771 return S_OK;
5774 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5776 localfontfilestream_QueryInterface,
5777 localfontfilestream_AddRef,
5778 localfontfilestream_Release,
5779 localfontfilestream_ReadFileFragment,
5780 localfontfilestream_ReleaseFileFragment,
5781 localfontfilestream_GetFileSize,
5782 localfontfilestream_GetLastWriteTime
5785 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5786 IDWriteFontFileStream **ret)
5788 struct dwrite_localfontfilestream *object;
5790 *ret = NULL;
5792 if (!(object = calloc(1, sizeof(*object))))
5793 return E_OUTOFMEMORY;
5795 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5796 object->refcount = 1;
5798 object->file_ptr = file_ptr;
5799 object->size = size;
5800 object->entry = entry;
5802 *ret = &object->IDWriteFontFileStream_iface;
5804 return S_OK;
5807 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5809 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5811 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5812 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5813 IsEqualIID(riid, &IID_IUnknown))
5815 *obj = iface;
5816 IDWriteLocalFontFileLoader_AddRef(iface);
5817 return S_OK;
5820 WARN("%s not implemented.\n", debugstr_guid(riid));
5822 *obj = NULL;
5823 return E_NOINTERFACE;
5826 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5828 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5829 ULONG refcount = InterlockedIncrement(&loader->refcount);
5831 TRACE("%p, refcount %ld.\n", iface, refcount);
5833 return refcount;
5836 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5838 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5839 ULONG refcount = InterlockedDecrement(&loader->refcount);
5841 TRACE("%p, refcount %ld.\n", iface, refcount);
5843 return refcount;
5846 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5848 const struct local_refkey *refkey = key;
5849 struct local_cached_stream *stream;
5850 IDWriteFontFileStream *filestream;
5851 HANDLE file, mapping;
5852 LARGE_INTEGER size;
5853 void *file_ptr;
5854 HRESULT hr = S_OK;
5856 *ret = NULL;
5858 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5859 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5860 if (file == INVALID_HANDLE_VALUE) {
5861 WARN_(dwrite_file)("Failed to open the file %s, error %ld.\n", debugstr_w(refkey->name), GetLastError());
5862 return E_FAIL;
5865 GetFileSizeEx(file, &size);
5866 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5867 CloseHandle(file);
5868 if (!mapping)
5869 return E_FAIL;
5871 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5872 CloseHandle(mapping);
5873 if (!file_ptr) {
5874 ERR("mapping failed, file size %s, error %ld\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5875 return E_FAIL;
5878 if (!(stream = malloc(sizeof(*stream))))
5880 UnmapViewOfFile(file_ptr);
5881 return E_OUTOFMEMORY;
5884 if (!(stream->key = malloc(key_size)))
5886 UnmapViewOfFile(file_ptr);
5887 free(stream);
5888 return E_OUTOFMEMORY;
5891 stream->key_size = key_size;
5892 memcpy(stream->key, key, key_size);
5894 if (FAILED(hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream)))
5896 UnmapViewOfFile(file_ptr);
5897 free(stream->key);
5898 free(stream);
5899 return hr;
5902 stream->stream = filestream;
5904 *ret = stream;
5906 return S_OK;
5909 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5910 UINT32 key_size, IDWriteFontFileStream **ret)
5912 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5913 struct local_cached_stream *stream;
5914 HRESULT hr = S_OK;
5916 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5918 EnterCriticalSection(&loader->cs);
5920 *ret = NULL;
5922 /* search cache first */
5923 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5925 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5926 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5927 break;
5931 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5933 list_add_head(&loader->streams, &stream->entry);
5934 *ret = stream->stream;
5937 LeaveCriticalSection(&loader->cs);
5939 return hr;
5942 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5943 UINT32 key_size, UINT32 *length)
5945 const struct local_refkey *refkey = key;
5947 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5949 *length = wcslen(refkey->name);
5950 return S_OK;
5953 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5954 UINT32 key_size, WCHAR *path, UINT32 length)
5956 const struct local_refkey *refkey = key;
5958 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5960 if (length < wcslen(refkey->name))
5961 return E_INVALIDARG;
5963 wcscpy(path, refkey->name);
5964 return S_OK;
5967 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5968 UINT32 key_size, FILETIME *writetime)
5970 const struct local_refkey *refkey = key;
5972 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5974 *writetime = refkey->writetime;
5975 return S_OK;
5978 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5980 localfontfileloader_QueryInterface,
5981 localfontfileloader_AddRef,
5982 localfontfileloader_Release,
5983 localfontfileloader_CreateStreamFromKey,
5984 localfontfileloader_GetFilePathLengthFromKey,
5985 localfontfileloader_GetFilePathFromKey,
5986 localfontfileloader_GetLastWriteTimeFromKey
5989 void init_local_fontfile_loader(void)
5991 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5992 local_fontfile_loader.refcount = 1;
5993 list_init(&local_fontfile_loader.streams);
5994 InitializeCriticalSection(&local_fontfile_loader.cs);
5995 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5998 IDWriteFontFileLoader *get_local_fontfile_loader(void)
6000 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
6003 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
6005 struct local_refkey *refkey;
6007 if (!path)
6008 return E_INVALIDARG;
6010 *size = FIELD_OFFSET(struct local_refkey, name) + (wcslen(path)+1)*sizeof(WCHAR);
6011 *key = NULL;
6013 if (!(refkey = malloc(*size)))
6014 return E_OUTOFMEMORY;
6016 if (writetime)
6017 refkey->writetime = *writetime;
6018 else {
6019 WIN32_FILE_ATTRIBUTE_DATA info;
6021 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
6022 refkey->writetime = info.ftLastWriteTime;
6023 else
6024 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
6026 wcscpy(refkey->name, path);
6028 *key = refkey;
6030 return S_OK;
6033 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
6035 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6037 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
6038 IsEqualIID(riid, &IID_IUnknown))
6040 *ppv = iface;
6041 IDWriteGlyphRunAnalysis_AddRef(iface);
6042 return S_OK;
6045 WARN("%s not implemented.\n", debugstr_guid(riid));
6047 *ppv = NULL;
6048 return E_NOINTERFACE;
6051 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
6053 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6054 ULONG refcount = InterlockedIncrement(&analysis->refcount);
6056 TRACE("%p, refcount %ld.\n", iface, refcount);
6058 return refcount;
6061 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
6063 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6064 ULONG refcount = InterlockedDecrement(&analysis->refcount);
6066 TRACE("%p, refcount %ld.\n", iface, refcount);
6068 if (!refcount)
6070 if (analysis->run.fontFace)
6071 IDWriteFontFace_Release(analysis->run.fontFace);
6072 free(analysis->glyphs);
6073 free(analysis->origins);
6074 free(analysis->bitmap);
6075 free(analysis);
6078 return refcount;
6081 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
6083 struct dwrite_glyphbitmap glyph_bitmap;
6084 UINT32 i;
6086 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
6087 *bounds = analysis->bounds;
6088 return;
6091 if (analysis->run.isSideways)
6092 FIXME("sideways runs are not supported.\n");
6094 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6095 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(analysis->run.fontFace);
6096 glyph_bitmap.emsize = analysis->run.fontEmSize;
6097 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6098 glyph_bitmap.m = &analysis->m;
6100 for (i = 0; i < analysis->run.glyphCount; i++) {
6101 RECT *bbox = &glyph_bitmap.bbox;
6102 UINT32 bitmap_size;
6104 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6105 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6107 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
6108 (bbox->bottom - bbox->top);
6109 if (bitmap_size > analysis->max_glyph_bitmap_size)
6110 analysis->max_glyph_bitmap_size = bitmap_size;
6112 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6113 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
6116 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
6117 *bounds = analysis->bounds;
6120 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
6121 DWRITE_TEXTURE_TYPE type, RECT *bounds)
6123 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6125 TRACE("%p, %d, %p.\n", iface, type, bounds);
6127 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
6128 SetRectEmpty(bounds);
6129 return E_INVALIDARG;
6132 if (type != analysis->texture_type)
6134 SetRectEmpty(bounds);
6135 return S_OK;
6138 glyphrunanalysis_get_texturebounds(analysis, bounds);
6139 return S_OK;
6142 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
6144 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6145 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
6146 (runbounds->left - bounds->left) * 3;
6147 else
6148 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
6149 runbounds->left - bounds->left;
6152 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
6154 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6155 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(analysis->run.fontFace);
6156 struct dwrite_glyphbitmap glyph_bitmap;
6157 D2D_POINT_2F origin;
6158 UINT32 i, size;
6159 RECT *bbox;
6161 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
6162 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6163 size *= 3;
6164 if (!(analysis->bitmap = calloc(1, size)))
6166 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
6167 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
6168 return E_OUTOFMEMORY;
6171 origin.x = origin.y = 0.0f;
6173 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6174 glyph_bitmap.simulations = fontface->simulations;
6175 glyph_bitmap.emsize = analysis->run.fontEmSize;
6176 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6177 glyph_bitmap.m = &analysis->m;
6178 if (!(glyph_bitmap.buf = malloc(analysis->max_glyph_bitmap_size)))
6179 return E_OUTOFMEMORY;
6181 bbox = &glyph_bitmap.bbox;
6183 for (i = 0; i < analysis->run.glyphCount; ++i)
6185 BYTE *src = glyph_bitmap.buf, *dst;
6186 int x, y, width, height;
6187 unsigned int is_1bpp;
6189 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6190 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6192 if (IsRectEmpty(bbox))
6193 continue;
6195 width = bbox->right - bbox->left;
6196 height = bbox->bottom - bbox->top;
6198 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
6199 memset(src, 0, height * glyph_bitmap.pitch);
6201 if (FAILED(dwrite_fontface_get_glyph_bitmap(fontface, analysis->rendering_mode, &is_1bpp, &glyph_bitmap)))
6203 WARN("Failed to render glyph[%u] = %#x.\n", i, glyph_bitmap.glyph);
6204 continue;
6207 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6209 /* blit to analysis bitmap */
6210 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
6212 if (is_1bpp) {
6213 /* convert 1bpp to 8bpp/24bpp */
6214 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6215 for (y = 0; y < height; y++) {
6216 for (x = 0; x < width; x++)
6217 if (src[x / 8] & masks[x % 8])
6218 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
6219 src += glyph_bitmap.pitch;
6220 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6223 else {
6224 for (y = 0; y < height; y++) {
6225 for (x = 0; x < width; x++)
6226 if (src[x / 8] & masks[x % 8])
6227 dst[x] = DWRITE_ALPHA_MAX;
6228 src += glyph_bitmap.pitch;
6229 dst += analysis->bounds.right - analysis->bounds.left;
6233 else {
6234 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6235 for (y = 0; y < height; y++) {
6236 for (x = 0; x < width; x++)
6237 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
6238 src += glyph_bitmap.pitch;
6239 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6242 else {
6243 for (y = 0; y < height; y++) {
6244 for (x = 0; x < width; x++)
6245 dst[x] |= src[x];
6246 src += glyph_bitmap.pitch;
6247 dst += analysis->bounds.right - analysis->bounds.left;
6252 free(glyph_bitmap.buf);
6254 analysis->flags |= RUNANALYSIS_BITMAP_READY;
6256 /* we don't need this anymore */
6257 free(analysis->glyphs);
6258 free(analysis->origins);
6259 IDWriteFontFace_Release(analysis->run.fontFace);
6261 analysis->glyphs = NULL;
6262 analysis->origins = NULL;
6263 analysis->run.glyphIndices = NULL;
6264 analysis->run.fontFace = NULL;
6266 return S_OK;
6269 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
6270 RECT const *bounds, BYTE *bitmap, UINT32 size)
6272 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6273 UINT32 required;
6274 RECT runbounds;
6276 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
6278 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
6279 return E_INVALIDARG;
6281 /* make sure buffer is large enough for requested texture type */
6282 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
6283 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6284 required *= 3;
6286 if (size < required)
6287 return E_NOT_SUFFICIENT_BUFFER;
6289 /* validate requested texture type */
6290 if (analysis->texture_type != type)
6291 return DWRITE_E_UNSUPPORTEDOPERATION;
6293 memset(bitmap, 0, size);
6294 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
6295 if (IntersectRect(&runbounds, &runbounds, bounds))
6297 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
6298 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
6299 int dst_width = (bounds->right - bounds->left) * pixel_size;
6300 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
6301 BYTE *src, *dst;
6302 int y;
6304 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
6306 HRESULT hr;
6308 if (FAILED(hr = glyphrunanalysis_render(analysis)))
6309 return hr;
6312 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
6313 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
6315 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
6316 memcpy(dst, src, draw_width);
6317 src += src_width;
6318 dst += dst_width;
6322 return S_OK;
6325 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
6326 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
6328 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6330 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
6332 if (!params)
6333 return E_INVALIDARG;
6335 switch (analysis->rendering_mode)
6337 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
6338 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
6340 UINT value = 0;
6341 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6342 *gamma = (FLOAT)value / 1000.0f;
6343 *contrast = 0.0f;
6344 *cleartypelevel = 1.0f;
6345 break;
6347 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
6348 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
6349 /* fallthrough */
6350 case DWRITE_RENDERING_MODE1_ALIASED:
6351 case DWRITE_RENDERING_MODE1_NATURAL:
6352 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
6353 *gamma = IDWriteRenderingParams_GetGamma(params);
6354 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
6355 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
6356 break;
6357 default:
6361 return S_OK;
6364 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
6366 glyphrunanalysis_QueryInterface,
6367 glyphrunanalysis_AddRef,
6368 glyphrunanalysis_Release,
6369 glyphrunanalysis_GetAlphaTextureBounds,
6370 glyphrunanalysis_CreateAlphaTexture,
6371 glyphrunanalysis_GetAlphaBlendParams
6374 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
6376 D2D_POINT_2F ret;
6377 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
6378 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
6379 *point = ret;
6382 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
6383 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
6385 unsigned int upem = fontface->metrics.designUnitsPerEm;
6386 int advance;
6388 if (is_sideways)
6389 FIXME("Sideways mode is not supported.\n");
6391 EnterCriticalSection(&fontface->cs);
6392 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
6393 LeaveCriticalSection(&fontface->cs);
6395 switch (measuring_mode)
6397 case DWRITE_MEASURING_MODE_NATURAL:
6398 return (float)advance * emsize / (float)upem;
6399 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6400 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6401 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
6402 default:
6403 WARN("Unknown measuring mode %u.\n", measuring_mode);
6404 return 0.0f;
6408 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
6410 struct dwrite_glyphrunanalysis *analysis;
6411 unsigned int i;
6413 *ret = NULL;
6415 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
6416 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
6417 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
6418 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
6419 return E_INVALIDARG;
6421 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6422 return E_INVALIDARG;
6424 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
6425 return E_INVALIDARG;
6427 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
6428 return E_INVALIDARG;
6430 if (!(analysis = calloc(1, sizeof(*analysis))))
6431 return E_OUTOFMEMORY;
6433 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
6434 analysis->refcount = 1;
6435 analysis->rendering_mode = desc->rendering_mode;
6437 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
6438 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6439 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6440 else
6441 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6443 analysis->run = *desc->run;
6444 IDWriteFontFace_AddRef(analysis->run.fontFace);
6445 analysis->glyphs = calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6446 analysis->origins = calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6448 if (!analysis->glyphs || !analysis->origins)
6450 free(analysis->glyphs);
6451 free(analysis->origins);
6453 analysis->glyphs = NULL;
6454 analysis->origins = NULL;
6456 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6457 return E_OUTOFMEMORY;
6460 /* check if transform is usable */
6461 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6462 analysis->m = *desc->transform;
6463 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6466 analysis->run.glyphIndices = analysis->glyphs;
6467 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6469 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6470 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6472 for (i = 0; i < desc->run->glyphCount; ++i)
6473 transform_point(&analysis->origins[i], &analysis->m);
6476 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6477 return S_OK;
6480 /* IDWriteColorGlyphRunEnumerator1 */
6481 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6483 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6485 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6486 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6487 IsEqualIID(riid, &IID_IUnknown))
6489 *ppv = iface;
6490 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6491 return S_OK;
6494 WARN("%s not implemented.\n", debugstr_guid(riid));
6496 *ppv = NULL;
6497 return E_NOINTERFACE;
6500 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6502 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6503 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6505 TRACE("%p, refcount %lu.\n", iface, refcount);
6507 return refcount;
6510 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6512 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6513 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6515 TRACE("%p, refcount %lu.\n", iface, refcount);
6517 if (!refcount)
6519 free(glyphenum->advances);
6520 free(glyphenum->color_advances);
6521 free(glyphenum->offsets);
6522 free(glyphenum->color_offsets);
6523 free(glyphenum->glyphindices);
6524 free(glyphenum->glyphs);
6525 if (glyphenum->colr.context)
6526 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6527 IDWriteFontFace5_Release(glyphenum->fontface);
6528 free(glyphenum);
6531 return refcount;
6534 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6536 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6537 FLOAT origin = 0.0f;
6539 if (g == 0)
6540 return 0.0f;
6542 while (g--)
6543 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6544 return origin;
6547 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6549 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6550 FLOAT advance_adj = 0.0f;
6551 BOOL got_palette_index;
6552 UINT32 g;
6554 /* start with regular glyphs */
6555 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6556 UINT32 first_glyph = 0;
6558 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6559 if (glyphenum->glyphs[g].num_layers == 0) {
6560 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6561 first_glyph = min(first_glyph, g);
6563 else
6564 glyphenum->glyphindices[g] = 1;
6565 glyphenum->color_advances[g] = glyphenum->advances[g];
6566 if (glyphenum->color_offsets)
6567 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6570 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, first_glyph);
6571 colorrun->baselineOriginY = glyphenum->origin.y;
6572 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6573 colorrun->paletteIndex = 0xffff;
6574 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6575 glyphenum->has_regular_glyphs = FALSE;
6576 return TRUE;
6578 else {
6579 colorrun->glyphRun.glyphCount = 0;
6580 got_palette_index = FALSE;
6583 advance_adj = 0.0f;
6584 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6586 glyphenum->glyphindices[g] = 1;
6588 /* all glyph layers were returned */
6589 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6590 advance_adj += glyphenum->advances[g];
6591 continue;
6594 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6595 UINT32 index = colorrun->glyphRun.glyphCount;
6596 if (!got_palette_index) {
6597 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6598 /* use foreground color or request one from the font */
6599 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6600 if (colorrun->paletteIndex != 0xffff)
6602 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6603 colorrun->paletteIndex, 1, &colorrun->runColor);
6604 if (FAILED(hr))
6605 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08lx\n", glyphenum->fontface,
6606 glyphenum->palette, colorrun->paletteIndex, hr);
6608 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6609 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, g);
6610 colorrun->baselineOriginY = glyphenum->origin.y;
6611 glyphenum->color_advances[index] = glyphenum->advances[g];
6612 got_palette_index = TRUE;
6615 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6616 /* offsets are relative to glyph origin, nothing to fix up */
6617 if (glyphenum->color_offsets)
6618 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6619 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6620 if (index)
6621 glyphenum->color_advances[index-1] += advance_adj;
6622 colorrun->glyphRun.glyphCount++;
6623 advance_adj = 0.0f;
6625 else
6626 advance_adj += glyphenum->advances[g];
6629 /* reset last advance */
6630 if (colorrun->glyphRun.glyphCount)
6631 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6633 return colorrun->glyphRun.glyphCount > 0;
6636 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6638 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6640 TRACE("%p, %p.\n", iface, has_run);
6642 *has_run = FALSE;
6644 glyphenum->colorrun.glyphRun.glyphCount = 0;
6645 while (glyphenum->current_layer < glyphenum->max_layer_num)
6647 if (colorglyphenum_build_color_run(glyphenum))
6648 break;
6649 else
6650 glyphenum->current_layer++;
6653 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6655 return S_OK;
6658 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6659 DWRITE_COLOR_GLYPH_RUN1 const **run)
6661 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6663 *run = NULL;
6664 return E_NOT_VALID_STATE;
6667 *run = &glyphenum->colorrun;
6668 return S_OK;
6671 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6672 DWRITE_COLOR_GLYPH_RUN const **run)
6674 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6676 TRACE("%p, %p.\n", iface, run);
6678 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6681 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6682 DWRITE_COLOR_GLYPH_RUN1 const **run)
6684 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6686 TRACE("%p, %p.\n", iface, run);
6688 return colorglyphenum_get_current_run(glyphenum, run);
6691 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6693 colorglyphenum_QueryInterface,
6694 colorglyphenum_AddRef,
6695 colorglyphenum_Release,
6696 colorglyphenum_MoveNext,
6697 colorglyphenum_GetCurrentRun,
6698 colorglyphenum1_GetCurrentRun,
6701 HRESULT create_colorglyphenum(D2D1_POINT_2F origin, const DWRITE_GLYPH_RUN *run,
6702 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_GLYPH_IMAGE_FORMATS formats, DWRITE_MEASURING_MODE measuring_mode,
6703 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator1 **ret)
6705 struct dwrite_colorglyphenum *colorglyphenum;
6706 BOOL colorfont, has_colored_glyph;
6707 struct dwrite_fontface *fontface;
6708 unsigned int i;
6710 *ret = NULL;
6712 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6714 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6715 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6716 if (!colorfont)
6717 return DWRITE_E_NOCOLOR;
6719 if (!(formats & (DWRITE_GLYPH_IMAGE_FORMATS_COLR |
6720 DWRITE_GLYPH_IMAGE_FORMATS_SVG |
6721 DWRITE_GLYPH_IMAGE_FORMATS_PNG |
6722 DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
6723 DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
6724 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8)))
6726 return DWRITE_E_NOCOLOR;
6729 if (formats & ~(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_CFF | DWRITE_GLYPH_IMAGE_FORMATS_COLR))
6731 FIXME("Unimplemented formats requested %#x.\n", formats);
6732 return E_NOTIMPL;
6735 if (!(colorglyphenum = calloc(1, sizeof(*colorglyphenum))))
6736 return E_OUTOFMEMORY;
6738 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6739 colorglyphenum->refcount = 1;
6740 colorglyphenum->origin = origin;
6741 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6742 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6743 colorglyphenum->glyphs = NULL;
6744 colorglyphenum->run = *run;
6745 colorglyphenum->run.glyphIndices = NULL;
6746 colorglyphenum->run.glyphAdvances = NULL;
6747 colorglyphenum->run.glyphOffsets = NULL;
6748 colorglyphenum->palette = palette;
6749 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6750 colorglyphenum->colr.exists = TRUE;
6751 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6752 colorglyphenum->current_layer = 0;
6753 colorglyphenum->max_layer_num = 0;
6755 colorglyphenum->glyphs = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphs));
6757 has_colored_glyph = FALSE;
6758 colorglyphenum->has_regular_glyphs = FALSE;
6759 for (i = 0; i < run->glyphCount; i++) {
6760 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6761 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6762 has_colored_glyph = TRUE;
6764 if (colorglyphenum->glyphs[i].num_layers == 0)
6765 colorglyphenum->has_regular_glyphs = TRUE;
6768 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6769 is supposed to proceed normally, like if font had no color info at all. */
6770 if (!has_colored_glyph) {
6771 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6772 return DWRITE_E_NOCOLOR;
6775 colorglyphenum->advances = calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6776 colorglyphenum->color_advances = calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6777 colorglyphenum->glyphindices = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6778 if (run->glyphOffsets) {
6779 colorglyphenum->offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6780 colorglyphenum->color_offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6781 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6784 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6785 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6786 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6787 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6788 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6789 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6790 colorglyphenum->colorrun.measuringMode = measuring_mode;
6791 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6793 if (run->glyphAdvances)
6794 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6795 else
6797 for (i = 0; i < run->glyphCount; ++i)
6798 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6799 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6802 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6804 return S_OK;
6807 /* IDWriteFontFaceReference */
6808 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6810 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6812 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6813 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6814 IsEqualIID(riid, &IID_IUnknown))
6816 *obj = iface;
6817 IDWriteFontFaceReference1_AddRef(iface);
6818 return S_OK;
6821 WARN("%s not implemented.\n", debugstr_guid(riid));
6823 *obj = NULL;
6825 return E_NOINTERFACE;
6828 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6830 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6831 ULONG refcount = InterlockedIncrement(&reference->refcount);
6833 TRACE("%p, refcount %lu.\n", iface, refcount);
6835 return refcount;
6838 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6840 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6841 ULONG refcount = InterlockedDecrement(&reference->refcount);
6843 TRACE("%p, refcount %lu.\n", iface, refcount);
6845 if (!refcount)
6847 IDWriteFontFile_Release(reference->file);
6848 IDWriteFactory7_Release(reference->factory);
6849 free(reference->axis_values);
6850 free(reference);
6853 return refcount;
6856 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6858 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6860 TRACE("%p, %p.\n", iface, fontface);
6862 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6865 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6866 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6868 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6869 DWRITE_FONT_FILE_TYPE file_type;
6870 DWRITE_FONT_FACE_TYPE face_type;
6871 IDWriteFontFace *fontface;
6872 BOOL is_supported;
6873 UINT32 face_num;
6874 HRESULT hr;
6876 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6878 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6879 if (FAILED(hr))
6880 return hr;
6882 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6883 simulations, &fontface);
6884 if (SUCCEEDED(hr))
6886 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6887 IDWriteFontFace_Release(fontface);
6890 return hr;
6893 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6895 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6896 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6897 BOOL ret;
6899 TRACE("%p, %p.\n", iface, ref);
6901 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6902 reference->simulations == other->simulations;
6903 if (reference->axis_values_count)
6905 ret &= reference->axis_values_count == other->axis_values_count &&
6906 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6909 return ret;
6912 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6914 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6916 TRACE("%p.\n", iface);
6918 return reference->index;
6921 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6923 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6925 TRACE("%p.\n", iface);
6927 return reference->simulations;
6930 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6932 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6933 IDWriteFontFileLoader *loader;
6934 const void *key;
6935 UINT32 key_size;
6936 HRESULT hr;
6938 TRACE("%p, %p.\n", iface, file);
6940 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6941 if (FAILED(hr))
6942 return hr;
6944 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6945 if (FAILED(hr))
6946 return hr;
6948 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6949 IDWriteFontFileLoader_Release(loader);
6951 return hr;
6954 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6956 FIXME("%p.\n", iface);
6958 return 0;
6961 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6963 FIXME("%p.\n", iface);
6965 return 0;
6968 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6970 FIXME("%p, %p.\n", iface, writetime);
6972 return E_NOTIMPL;
6975 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6977 FIXME("%p.\n", iface);
6979 return DWRITE_LOCALITY_LOCAL;
6982 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6984 FIXME("%p.\n", iface);
6986 return E_NOTIMPL;
6989 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6990 WCHAR const *chars, UINT32 count)
6992 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6994 return E_NOTIMPL;
6997 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6998 UINT16 const *glyphs, UINT32 count)
7000 FIXME("%p, %p, %u.\n", iface, glyphs, count);
7002 return E_NOTIMPL;
7005 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
7006 UINT64 offset, UINT64 size)
7008 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
7010 return E_NOTIMPL;
7013 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
7015 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7016 IDWriteFontFace3 *fontface3;
7017 HRESULT hr;
7019 TRACE("%p, %p.\n", iface, fontface);
7021 /* FIXME: created instance should likely respect given axis. */
7022 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
7023 &fontface3)))
7025 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
7026 IDWriteFontFace3_Release(fontface3);
7029 return hr;
7032 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
7034 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7036 TRACE("%p.\n", iface);
7038 return reference->axis_values_count;
7041 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
7042 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
7044 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7046 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
7048 if (value_count < reference->axis_values_count)
7049 return E_NOT_SUFFICIENT_BUFFER;
7051 memcpy(axis_values, reference->axis_values, reference->axis_values_count * sizeof(*axis_values));
7053 return S_OK;
7056 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
7058 fontfacereference_QueryInterface,
7059 fontfacereference_AddRef,
7060 fontfacereference_Release,
7061 fontfacereference_CreateFontFace,
7062 fontfacereference_CreateFontFaceWithSimulations,
7063 fontfacereference_Equals,
7064 fontfacereference_GetFontFaceIndex,
7065 fontfacereference_GetSimulations,
7066 fontfacereference_GetFontFile,
7067 fontfacereference_GetLocalFileSize,
7068 fontfacereference_GetFileSize,
7069 fontfacereference_GetFileTime,
7070 fontfacereference_GetLocality,
7071 fontfacereference_EnqueueFontDownloadRequest,
7072 fontfacereference_EnqueueCharacterDownloadRequest,
7073 fontfacereference_EnqueueGlyphDownloadRequest,
7074 fontfacereference_EnqueueFileFragmentDownloadRequest,
7075 fontfacereference1_CreateFontFace,
7076 fontfacereference1_GetFontAxisValueCount,
7077 fontfacereference1_GetFontAxisValues,
7080 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
7081 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
7082 IDWriteFontFaceReference1 **ret)
7084 struct dwrite_fontfacereference *object;
7086 *ret = NULL;
7088 if (!is_simulation_valid(simulations))
7089 return E_INVALIDARG;
7091 if (!(object = calloc(1, sizeof(*object))))
7092 return E_OUTOFMEMORY;
7094 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
7095 object->refcount = 1;
7097 object->factory = factory;
7098 IDWriteFactory7_AddRef(object->factory);
7099 object->file = file;
7100 IDWriteFontFile_AddRef(object->file);
7101 object->index = index;
7102 object->simulations = simulations;
7103 if (axis_values_count)
7105 if (!(object->axis_values = malloc(axis_values_count * sizeof(*axis_values))))
7107 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
7108 return E_OUTOFMEMORY;
7110 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
7111 object->axis_values_count = axis_values_count;
7114 *ret = &object->IDWriteFontFaceReference1_iface;
7116 return S_OK;
7119 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
7121 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7123 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
7124 *obj = iface;
7125 IDWriteFontFileStream_AddRef(iface);
7126 return S_OK;
7129 *obj = NULL;
7131 WARN("%s not implemented.\n", debugstr_guid(riid));
7132 return E_NOINTERFACE;
7135 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
7137 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7138 ULONG refcount = InterlockedIncrement(&stream->refcount);
7140 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7142 return refcount;
7145 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
7147 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7148 ULONG refcount = InterlockedDecrement(&stream->refcount);
7150 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7152 if (!refcount)
7154 release_inmemory_stream(stream->data);
7155 free(stream);
7158 return refcount;
7161 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
7162 UINT64 offset, UINT64 fragment_size, void **fragment_context)
7164 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7166 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
7167 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
7169 *fragment_context = NULL;
7171 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
7172 *fragment_start = NULL;
7173 return E_FAIL;
7176 *fragment_start = (char *)stream->data->data + offset;
7177 return S_OK;
7180 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
7182 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
7185 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
7187 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7189 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
7191 *size = stream->data->size;
7193 return S_OK;
7196 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
7198 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
7200 *last_writetime = 0;
7202 return E_NOTIMPL;
7205 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
7206 inmemoryfilestream_QueryInterface,
7207 inmemoryfilestream_AddRef,
7208 inmemoryfilestream_Release,
7209 inmemoryfilestream_ReadFileFragment,
7210 inmemoryfilestream_ReleaseFileFragment,
7211 inmemoryfilestream_GetFileSize,
7212 inmemoryfilestream_GetLastWriteTime,
7215 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
7216 REFIID riid, void **obj)
7218 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7220 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
7221 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
7222 IsEqualIID(riid, &IID_IUnknown))
7224 *obj = iface;
7225 IDWriteInMemoryFontFileLoader_AddRef(iface);
7226 return S_OK;
7229 WARN("%s not implemented.\n", debugstr_guid(riid));
7231 *obj = NULL;
7233 return E_NOINTERFACE;
7236 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
7238 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7239 ULONG refcount = InterlockedIncrement(&loader->refcount);
7241 TRACE("%p, refcount %lu.\n", iface, refcount);
7243 return refcount;
7246 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
7248 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7249 ULONG refcount = InterlockedDecrement(&loader->refcount);
7250 size_t i;
7252 TRACE("%p, refcount %lu.\n", iface, refcount);
7254 if (!refcount)
7256 for (i = 0; i < loader->count; ++i)
7257 release_inmemory_stream(loader->streams[i]);
7258 free(loader->streams);
7259 free(loader);
7262 return refcount;
7265 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
7266 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
7268 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7269 struct dwrite_inmemory_filestream *stream;
7270 DWORD index;
7272 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
7274 *ret = NULL;
7276 if (key_size != sizeof(DWORD))
7277 return E_INVALIDARG;
7279 index = *(DWORD *)key;
7281 if (index >= loader->count)
7282 return E_INVALIDARG;
7284 if (!(stream = malloc(sizeof(*stream))))
7285 return E_OUTOFMEMORY;
7287 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
7288 stream->refcount = 1;
7289 stream->data = loader->streams[index];
7290 InterlockedIncrement(&stream->data->refcount);
7292 *ret = &stream->IDWriteFontFileStream_iface;
7294 return S_OK;
7297 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
7298 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
7300 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7301 struct dwrite_inmemory_stream_data *stream;
7302 DWORD key;
7304 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
7306 *fontfile = NULL;
7308 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
7309 return E_OUTOFMEMORY;
7311 if (!(stream = malloc(sizeof(*stream))))
7312 return E_OUTOFMEMORY;
7314 stream->refcount = 1;
7315 stream->size = data_size;
7316 stream->owner = owner;
7317 if (stream->owner) {
7318 IUnknown_AddRef(stream->owner);
7319 stream->data = (void *)data;
7321 else {
7322 if (!(stream->data = malloc(data_size)))
7324 free(stream);
7325 return E_OUTOFMEMORY;
7327 memcpy(stream->data, data, data_size);
7330 key = loader->count;
7331 loader->streams[loader->count++] = stream;
7333 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
7334 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
7337 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
7339 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7341 TRACE("%p.\n", iface);
7343 return loader->count;
7346 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
7348 inmemoryfontfileloader_QueryInterface,
7349 inmemoryfontfileloader_AddRef,
7350 inmemoryfontfileloader_Release,
7351 inmemoryfontfileloader_CreateStreamFromKey,
7352 inmemoryfontfileloader_CreateInMemoryFontFileReference,
7353 inmemoryfontfileloader_GetFileCount,
7356 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
7358 struct dwrite_inmemory_fileloader *loader;
7360 *ret = NULL;
7362 if (!(loader = calloc(1, sizeof(*loader))))
7363 return E_OUTOFMEMORY;
7365 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
7366 loader->refcount = 1;
7368 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
7370 return S_OK;
7373 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
7375 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7377 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
7378 IsEqualIID(riid, &IID_IUnknown))
7380 *obj = iface;
7381 IDWriteFontResource_AddRef(iface);
7382 return S_OK;
7385 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7387 return E_NOINTERFACE;
7390 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
7392 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7393 ULONG refcount = InterlockedIncrement(&resource->refcount);
7395 TRACE("%p, refcount %lu.\n", iface, refcount);
7397 return refcount;
7400 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
7402 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7403 ULONG refcount = InterlockedDecrement(&resource->refcount);
7405 TRACE("%p, refcount %lu.\n", iface, refcount);
7407 if (!refcount)
7409 IDWriteFactory7_Release(resource->factory);
7410 IDWriteFontFile_Release(resource->file);
7411 free(resource->axis);
7412 free(resource);
7415 return refcount;
7418 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
7420 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7422 TRACE("%p, %p.\n", iface, fontfile);
7424 *fontfile = resource->file;
7425 IDWriteFontFile_AddRef(*fontfile);
7427 return S_OK;
7430 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
7432 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7434 TRACE("%p.\n", iface);
7436 return resource->face_index;
7439 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
7441 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7443 TRACE("%p.\n", iface);
7445 return resource->axis_count;
7448 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
7449 DWRITE_FONT_AXIS_VALUE *values, UINT32 count)
7451 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7452 unsigned int i;
7454 TRACE("%p, %p, %u.\n", iface, values, count);
7456 if (count < resource->axis_count)
7457 return E_NOT_SUFFICIENT_BUFFER;
7459 for (i = 0; i < resource->axis_count; ++i)
7461 values[i].axisTag = resource->axis[i].tag;
7462 values[i].value = resource->axis[i].default_value;
7465 return S_OK;
7468 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7469 DWRITE_FONT_AXIS_RANGE *ranges, UINT32 count)
7471 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7472 unsigned int i;
7474 TRACE("%p, %p, %u.\n", iface, ranges, count);
7476 if (count < resource->axis_count)
7477 return E_NOT_SUFFICIENT_BUFFER;
7479 for (i = 0; i < resource->axis_count; ++i)
7481 ranges[i].axisTag = resource->axis[i].tag;
7482 ranges[i].minValue = resource->axis[i].min_value;
7483 ranges[i].maxValue = resource->axis[i].max_value;
7486 return S_OK;
7489 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7490 UINT32 axis)
7492 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7494 TRACE("%p, %u.\n", iface, axis);
7496 return axis < resource->axis_count ? resource->axis[axis].attributes : 0;
7499 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7500 IDWriteLocalizedStrings **names)
7502 FIXME("%p, %u, %p.\n", iface, axis, names);
7504 return E_NOTIMPL;
7507 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7509 FIXME("%p, %u.\n", iface, axis);
7511 return 0;
7514 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7515 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7517 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7519 return E_NOTIMPL;
7522 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7524 FIXME("%p.\n", iface);
7526 return FALSE;
7529 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7530 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7531 IDWriteFontFace5 **fontface)
7533 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7534 IDWriteFontFaceReference1 *reference;
7535 HRESULT hr;
7537 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7539 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7540 simulations, axis_values, num_values, &reference);
7541 if (SUCCEEDED(hr))
7543 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7544 IDWriteFontFaceReference1_Release(reference);
7547 return hr;
7550 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7551 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7552 IDWriteFontFaceReference1 **reference)
7554 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7556 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7558 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7559 simulations, axis_values, num_values, reference);
7562 static const IDWriteFontResourceVtbl fontresourcevtbl =
7564 dwritefontresource_QueryInterface,
7565 dwritefontresource_AddRef,
7566 dwritefontresource_Release,
7567 dwritefontresource_GetFontFile,
7568 dwritefontresource_GetFontFaceIndex,
7569 dwritefontresource_GetFontAxisCount,
7570 dwritefontresource_GetDefaultFontAxisValues,
7571 dwritefontresource_GetFontAxisRanges,
7572 dwritefontresource_GetFontAxisAttributes,
7573 dwritefontresource_GetAxisNames,
7574 dwritefontresource_GetAxisValueNameCount,
7575 dwritefontresource_GetAxisValueNames,
7576 dwritefontresource_HasVariations,
7577 dwritefontresource_CreateFontFace,
7578 dwritefontresource_CreateFontFaceReference,
7581 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7582 IDWriteFontResource **ret)
7584 struct dwrite_fontresource *resource;
7585 struct file_stream_desc stream_desc;
7586 DWRITE_FONT_FILE_TYPE file_type;
7587 DWRITE_FONT_FACE_TYPE face_type;
7588 unsigned int face_count;
7589 BOOL supported = FALSE;
7590 HRESULT hr;
7592 *ret = NULL;
7594 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
7595 return hr;
7597 if (!supported)
7598 return DWRITE_E_FILEFORMAT;
7600 if (!(resource = calloc(1, sizeof(*resource))))
7601 return E_OUTOFMEMORY;
7603 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7604 resource->refcount = 1;
7605 resource->face_index = face_index;
7606 resource->file = file;
7607 IDWriteFontFile_AddRef(resource->file);
7608 resource->factory = factory;
7609 IDWriteFactory7_AddRef(resource->factory);
7611 get_filestream_from_file(file, &stream_desc.stream);
7612 stream_desc.face_type = face_type;
7613 stream_desc.face_index = face_index;
7615 opentype_get_font_var_axis(&stream_desc, &resource->axis, &resource->axis_count);
7617 if (stream_desc.stream)
7618 IDWriteFontFileStream_Release(stream_desc.stream);
7620 *ret = &resource->IDWriteFontResource_iface;
7622 return S_OK;
7625 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7627 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7629 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7630 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7631 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7632 IsEqualIID(riid, &IID_IDWriteFontSet))
7634 *obj = iface;
7635 IDWriteFontSet3_AddRef(iface);
7636 return S_OK;
7639 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7640 *obj = NULL;
7641 return E_NOINTERFACE;
7644 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7646 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7647 ULONG refcount = InterlockedIncrement(&set->refcount);
7649 TRACE("%p, refcount %lu.\n", iface, refcount);
7651 return refcount;
7654 #define MISSING_SET_PROP ((void *)0x1)
7656 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7658 unsigned int i;
7660 if (InterlockedDecrement(&entry->refcount) > 0)
7661 return;
7662 IDWriteFontFile_Release(entry->desc.file);
7663 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7665 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7666 IDWriteLocalizedStrings_Release(entry->props[i]);
7668 free(entry);
7671 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7673 InterlockedIncrement(&entry->refcount);
7674 return entry;
7677 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7678 DWRITE_FONT_PROPERTY_ID property)
7680 struct file_stream_desc stream_desc = { 0 };
7681 IDWriteLocalizedStrings *value;
7683 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7685 if (entry->props[property] == MISSING_SET_PROP)
7686 return NULL;
7688 if ((value = entry->props[property]))
7690 IDWriteLocalizedStrings_AddRef(value);
7691 return value;
7694 get_filestream_from_file(entry->desc.file, &stream_desc.stream);
7695 stream_desc.face_type = entry->desc.face_type;
7696 stream_desc.face_index = entry->desc.face_index;
7698 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7699 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7700 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7701 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7702 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7703 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7704 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7705 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7706 else if (property == DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME)
7707 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &value);
7708 else
7709 WARN("Unsupported property %u.\n", property);
7711 if (stream_desc.stream)
7712 IDWriteFontFileStream_Release(stream_desc.stream);
7714 if (value)
7716 entry->props[property] = value;
7717 IDWriteLocalizedStrings_AddRef(value);
7719 else
7720 entry->props[property] = MISSING_SET_PROP;
7722 return value;
7725 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7726 struct dwrite_fontset_entry **entries, unsigned int count);
7728 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7730 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7731 ULONG refcount = InterlockedDecrement(&set->refcount);
7732 unsigned int i;
7734 TRACE("%p, refcount %lu.\n", iface, refcount);
7736 if (!refcount)
7738 IDWriteFactory7_Release(set->factory);
7739 for (i = 0; i < set->count; ++i)
7740 release_fontset_entry(set->entries[i]);
7741 free(set->entries);
7742 free(set);
7745 return refcount;
7748 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7750 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7752 TRACE("%p.\n", iface);
7754 return set->count;
7757 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7758 IDWriteFontFaceReference **reference)
7760 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7762 TRACE("%p, %u, %p.\n", iface, index, reference);
7764 *reference = NULL;
7766 if (index >= set->count)
7767 return E_INVALIDARG;
7769 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->desc.file,
7770 set->entries[index]->desc.face_index, set->entries[index]->desc.simulations, reference);
7773 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7774 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7776 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7778 return E_NOTIMPL;
7781 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7782 UINT32 *index, BOOL *exists)
7784 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7786 return E_NOTIMPL;
7789 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7790 IDWriteStringList **values)
7792 FIXME("%p, %d, %p.\n", iface, id, values);
7794 return E_NOTIMPL;
7797 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7798 WCHAR const *preferred_locales, IDWriteStringList **values)
7800 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7802 return E_NOTIMPL;
7805 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7806 BOOL *exists, IDWriteLocalizedStrings **values)
7808 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7810 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7812 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7813 index >= set->count)
7815 *values = NULL;
7816 *exists = FALSE;
7817 return E_INVALIDARG;
7820 *values = fontset_entry_get_property(set->entries[index], id);
7821 *exists = !!*values;
7823 return S_OK;
7826 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7827 UINT32 *count)
7829 FIXME("%p, %p, %p.\n", iface, property, count);
7831 return E_NOTIMPL;
7834 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7835 unsigned int count)
7837 IDWriteLocalizedStrings *value;
7838 unsigned int i;
7839 BOOL ret;
7841 for (i = 0; i < count; ++i)
7843 switch (props[i].propertyId)
7845 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7846 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7847 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7848 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7849 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7850 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7851 return FALSE;
7853 ret = localizedstrings_contains(value, props[i].propertyValue);
7854 IDWriteLocalizedStrings_Release(value);
7855 if (!ret) return FALSE;
7856 break;
7857 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7858 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7859 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7860 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7861 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7862 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7863 case DWRITE_FONT_PROPERTY_ID_STYLE:
7864 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7865 FIXME("Unsupported property %d.\n", props[i].propertyId);
7866 /* fallthrough */
7867 default:
7868 return FALSE;
7872 return TRUE;
7875 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7876 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7878 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7880 return E_NOTIMPL;
7883 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7884 IDWriteFontSet **filtered_set)
7886 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7887 struct dwrite_fontset_entry **entries;
7888 unsigned int i, matched_count = 0;
7889 struct dwrite_fontset *object;
7891 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7893 if (!props && count)
7894 return E_INVALIDARG;
7896 if (!(object = calloc(1, sizeof(*object))))
7897 return E_OUTOFMEMORY;
7899 if (!(entries = calloc(set->count, sizeof(*entries))))
7901 free(object);
7902 return E_OUTOFMEMORY;
7905 for (i = 0; i < set->count; ++i)
7907 if (fontset_entry_is_matching(set->entries[i], props, count))
7909 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7913 if (!matched_count)
7915 free(entries);
7916 entries = NULL;
7919 init_fontset(object, set->factory, entries, matched_count);
7921 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7923 return S_OK;
7926 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7927 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7929 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7931 return E_NOTIMPL;
7934 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7936 FIXME("%p, %p.\n", iface, fontset);
7938 return E_NOTIMPL;
7941 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7942 UINT32 num_indices, IDWriteFontSet1 **fontset)
7944 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7946 return E_NOTIMPL;
7949 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7950 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7952 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7954 return E_NOTIMPL;
7957 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7958 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7960 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7962 return E_NOTIMPL;
7965 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7966 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7968 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7970 return E_NOTIMPL;
7973 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7974 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7976 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7977 num_indices, actual_num_indices);
7979 return E_NOTIMPL;
7982 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7983 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7985 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7987 return E_NOTIMPL;
7990 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7991 UINT32 num_ranges, UINT32 *actual_num_ranges)
7993 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7995 return E_NOTIMPL;
7998 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7999 IDWriteFontFaceReference1 **reference)
8001 FIXME("%p, %u, %p.\n", iface, index, reference);
8003 return E_NOTIMPL;
8006 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
8008 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
8010 TRACE("%p, %u, %p.\n", iface, index, resource);
8012 *resource = NULL;
8014 if (index >= set->count)
8015 return E_INVALIDARG;
8017 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->desc.file,
8018 set->entries[index]->desc.face_index, resource);
8021 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
8023 FIXME("%p, %u, %p.\n", iface, index, fontface);
8025 return E_NOTIMPL;
8028 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
8030 FIXME("%p, %u.\n", iface, index);
8032 return DWRITE_LOCALITY_LOCAL;
8035 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
8037 FIXME("%p.\n", iface);
8039 return NULL;
8042 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
8044 FIXME("%p, %u.\n", iface, index);
8046 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
8049 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
8051 FIXME("%p, %u.\n", iface, index);
8053 return 0;
8056 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
8058 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
8060 return E_NOTIMPL;
8063 static const IDWriteFontSet3Vtbl fontsetvtbl =
8065 dwritefontset_QueryInterface,
8066 dwritefontset_AddRef,
8067 dwritefontset_Release,
8068 dwritefontset_GetFontCount,
8069 dwritefontset_GetFontFaceReference,
8070 dwritefontset_FindFontFaceReference,
8071 dwritefontset_FindFontFace,
8072 dwritefontset_GetPropertyValues__,
8073 dwritefontset_GetPropertyValues_,
8074 dwritefontset_GetPropertyValues,
8075 dwritefontset_GetPropertyOccurrenceCount,
8076 dwritefontset_GetMatchingFonts_,
8077 dwritefontset_GetMatchingFonts,
8078 dwritefontset1_GetMatchingFonts,
8079 dwritefontset1_GetFirstFontResources,
8080 dwritefontset1_GetFilteredFonts__,
8081 dwritefontset1_GetFilteredFonts_,
8082 dwritefontset1_GetFilteredFonts,
8083 dwritefontset1_GetFilteredFontIndices_,
8084 dwritefontset1_GetFilteredFontIndices,
8085 dwritefontset1_GetFontAxisRanges_,
8086 dwritefontset1_GetFontAxisRanges,
8087 dwritefontset1_GetFontFaceReference,
8088 dwritefontset1_CreateFontResource,
8089 dwritefontset1_CreateFontFace,
8090 dwritefontset1_GetFontLocality,
8091 dwritefontset2_GetExpirationEvent,
8092 dwritefontset3_GetFontSourceType,
8093 dwritefontset3_GetFontSourceNameLength,
8094 dwritefontset3_GetFontSourceName,
8097 static struct dwrite_fontset *unsafe_impl_from_IDWriteFontSet(IDWriteFontSet *iface)
8099 if (!iface)
8100 return NULL;
8101 assert(iface->lpVtbl == (IDWriteFontSetVtbl *)&fontsetvtbl);
8102 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
8105 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
8106 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
8108 struct dwrite_fontset_entry *entry;
8110 if (!(entry = calloc(1, sizeof(*entry))))
8111 return E_OUTOFMEMORY;
8113 entry->refcount = 1;
8114 entry->desc.file = file;
8115 IDWriteFontFile_AddRef(entry->desc.file);
8116 entry->desc.face_type = face_type;
8117 entry->desc.face_index = face_index;
8118 entry->desc.simulations = simulations;
8120 *ret = entry;
8122 return S_OK;
8125 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
8126 struct dwrite_fontset_entry **entries, unsigned int count)
8128 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
8129 object->refcount = 1;
8130 object->factory = factory;
8131 IDWriteFactory7_AddRef(object->factory);
8132 object->entries = entries;
8133 object->count = count;
8136 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
8137 unsigned int count, IDWriteFontSet1 **ret)
8139 struct dwrite_fontset_entry **entries = NULL;
8140 struct dwrite_fontset *object;
8141 unsigned int i;
8143 if (!(object = calloc(1, sizeof(*object))))
8144 return E_OUTOFMEMORY;
8146 if (count)
8148 entries = calloc(count, sizeof(*entries));
8150 /* FIXME: set available properties too */
8152 for (i = 0; i < count; ++i)
8154 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
8155 fonts[i]->simulations, &entries[i]);
8158 init_fontset(object, factory, entries, count);
8160 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
8162 return S_OK;
8165 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
8166 unsigned int count, IDWriteFontSet **ret)
8168 struct dwrite_fontset_entry **entries = NULL;
8169 struct dwrite_fontset *object;
8170 unsigned int i;
8172 if (!(object = calloc(1, sizeof(*object))))
8173 return E_OUTOFMEMORY;
8175 if (count)
8177 entries = calloc(count, sizeof(*entries));
8179 for (i = 0; i < count; ++i)
8180 entries[i] = addref_fontset_entry(src_entries[i]);
8182 init_fontset(object, factory, entries, count);
8184 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
8186 return S_OK;
8189 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
8190 REFIID riid, void **obj)
8192 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
8194 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
8195 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
8196 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
8197 IsEqualIID(riid, &IID_IUnknown))
8199 *obj = iface;
8200 IDWriteFontSetBuilder2_AddRef(iface);
8201 return S_OK;
8204 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
8205 *obj = NULL;
8206 return E_NOINTERFACE;
8209 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
8211 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8212 ULONG refcount = InterlockedIncrement(&builder->refcount);
8214 TRACE("%p, refcount %lu.\n", iface, refcount);
8216 return refcount;
8219 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
8221 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8222 ULONG refcount = InterlockedDecrement(&builder->refcount);
8223 unsigned int i;
8225 TRACE("%p, refcount %lu.\n", iface, refcount);
8227 if (!refcount)
8229 IDWriteFactory7_Release(builder->factory);
8230 for (i = 0; i < builder->count; ++i)
8231 release_fontset_entry(builder->entries[i]);
8232 free(builder->entries);
8233 free(builder);
8236 return refcount;
8239 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, const struct dwrite_fontset_entry_desc *desc)
8241 struct dwrite_fontset_entry *entry;
8242 HRESULT hr;
8244 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
8245 sizeof(*builder->entries)))
8247 return E_OUTOFMEMORY;
8250 if (FAILED(hr = fontset_create_entry(desc->file, desc->face_type, desc->face_index, desc->simulations, &entry)))
8251 return hr;
8253 builder->entries[builder->count++] = entry;
8255 return S_OK;
8258 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
8260 struct dwrite_fontset_entry_desc desc = { 0 };
8261 DWRITE_FONT_FILE_TYPE filetype;
8262 unsigned int i, face_count;
8263 BOOL supported = FALSE;
8264 HRESULT hr;
8266 desc.file = file;
8267 if (FAILED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &filetype, &desc.face_type, &face_count)))
8268 return hr;
8270 if (!supported)
8271 return DWRITE_E_FILEFORMAT;
8273 for (i = 0; i < face_count; ++i)
8275 desc.face_index = i;
8276 if (FAILED(hr = fontset_builder_add_entry(builder, &desc)))
8277 break;
8280 return hr;
8283 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
8284 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
8286 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
8288 return E_NOTIMPL;
8291 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
8292 IDWriteFontFaceReference *reference)
8294 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8295 struct dwrite_fontset_entry_desc desc = { 0 };
8296 DWRITE_FONT_FILE_TYPE file_type;
8297 unsigned int face_count;
8298 BOOL supported;
8299 HRESULT hr;
8301 TRACE("%p, %p.\n", iface, reference);
8303 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(reference, &desc.file))) return hr;
8305 if (SUCCEEDED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &file_type, &desc.face_type, &face_count)))
8307 if (!supported)
8308 hr = DWRITE_E_FILEFORMAT;
8310 if (SUCCEEDED(hr))
8312 desc.face_index = IDWriteFontFaceReference_GetFontFaceIndex(reference);
8313 desc.simulations = IDWriteFontFaceReference_GetSimulations(reference);
8314 hr = fontset_builder_add_entry(builder, &desc);
8318 IDWriteFontFile_Release(desc.file);
8320 return hr;
8323 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
8325 FIXME("%p, %p.\n", iface, fontset);
8327 return E_NOTIMPL;
8330 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
8332 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8334 TRACE("%p, %p.\n", iface, fontset);
8336 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
8339 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
8341 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8343 TRACE("%p, %p.\n", iface, file);
8345 return fontset_builder_add_file(builder, file);
8348 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
8349 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
8350 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
8351 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
8353 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
8354 axis_ranges, num_ranges, props, num_properties);
8356 return E_NOTIMPL;
8359 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
8361 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8362 IDWriteFontFile *file;
8363 HRESULT hr;
8365 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
8367 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
8368 return hr;
8370 hr = fontset_builder_add_file(builder, file);
8371 IDWriteFontFile_Release(file);
8372 return hr;
8375 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
8377 dwritefontsetbuilder_QueryInterface,
8378 dwritefontsetbuilder_AddRef,
8379 dwritefontsetbuilder_Release,
8380 dwritefontsetbuilder_AddFontFaceReference_,
8381 dwritefontsetbuilder_AddFontFaceReference,
8382 dwritefontsetbuilder_AddFontSet,
8383 dwritefontsetbuilder_CreateFontSet,
8384 dwritefontsetbuilder1_AddFontFile,
8385 dwritefontsetbuilder2_AddFont,
8386 dwritefontsetbuilder2_AddFontFile,
8389 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
8391 struct dwrite_fontset_builder *builder;
8393 *ret = NULL;
8395 if (!(builder = calloc(1, sizeof(*builder))))
8396 return E_OUTOFMEMORY;
8398 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
8399 builder->refcount = 1;
8400 builder->factory = factory;
8401 IDWriteFactory7_AddRef(builder->factory);
8403 *ret = &builder->IDWriteFontSetBuilder2_iface;
8405 return S_OK;