cmd: Use CRT's popen instead of rewriting it.
[wine.git] / dlls / dwrite / font.c
blob83a293e57fea40ad360b53dafbce3c4275125e2a
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_MODE1 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_fourcc(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 = (float)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_fourcc(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, mode;
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 mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1825 IDWriteRenderingParams3_Release(params3);
1827 else
1828 mode = IDWriteRenderingParams_GetRenderingMode(params);
1829 *rendering_mode = mode;
1832 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1834 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1836 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1837 if (emSize >= emthreshold)
1838 mode = DWRITE_RENDERING_MODE1_OUTLINE;
1839 else
1840 mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1841 *rendering_mode = mode;
1844 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1845 if (emSize >= emthreshold)
1846 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1847 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1848 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1849 else
1850 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1851 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1854 return S_OK;
1857 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1859 FIXME("%p, %#x: stub\n", iface, ch);
1861 return FALSE;
1864 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1866 FIXME("%p, %u: stub\n", iface, glyph);
1868 return FALSE;
1871 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1872 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1874 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1876 return E_NOTIMPL;
1879 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1880 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1882 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1884 return E_NOTIMPL;
1887 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1888 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1890 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1892 return E_NOTIMPL;
1895 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1897 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1899 TRACE("%p.\n", iface);
1901 return fontface->glyph_image_formats;
1904 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1905 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1907 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1909 return E_NOTIMPL;
1912 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1914 FIXME("%p, %p: stub\n", iface, context);
1917 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1919 FIXME("%p: stub\n", iface);
1921 return 0;
1924 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1925 UINT32 value_count)
1927 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1929 return E_NOTIMPL;
1932 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1934 static int once;
1936 if (!once++)
1937 FIXME("%p: stub\n", iface);
1939 return FALSE;
1942 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1944 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1946 TRACE("%p, %p.\n", iface, resource);
1948 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1951 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1953 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1955 TRACE("%p, %p.\n", iface, other);
1957 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1958 return FALSE;
1960 /* TODO: add variations support */
1962 return fontface->index == other_face->index &&
1963 fontface->simulations == other_face->simulations &&
1964 is_same_fontfile(fontface->file, other_face->file);
1967 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1969 dwritefontface_QueryInterface,
1970 dwritefontface_AddRef,
1971 dwritefontface_Release,
1972 dwritefontface_GetType,
1973 dwritefontface_GetFiles,
1974 dwritefontface_GetIndex,
1975 dwritefontface_GetSimulations,
1976 dwritefontface_IsSymbolFont,
1977 dwritefontface_GetMetrics,
1978 dwritefontface_GetGlyphCount,
1979 dwritefontface_GetDesignGlyphMetrics,
1980 dwritefontface_GetGlyphIndices,
1981 dwritefontface_TryGetFontTable,
1982 dwritefontface_ReleaseFontTable,
1983 dwritefontface_GetGlyphRunOutline,
1984 dwritefontface_GetRecommendedRenderingMode,
1985 dwritefontface_GetGdiCompatibleMetrics,
1986 dwritefontface_GetGdiCompatibleGlyphMetrics,
1987 dwritefontface1_GetMetrics,
1988 dwritefontface1_GetGdiCompatibleMetrics,
1989 dwritefontface1_GetCaretMetrics,
1990 dwritefontface1_GetUnicodeRanges,
1991 dwritefontface1_IsMonospacedFont,
1992 dwritefontface1_GetDesignGlyphAdvances,
1993 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1994 dwritefontface1_GetKerningPairAdjustments,
1995 dwritefontface1_HasKerningPairs,
1996 dwritefontface1_GetRecommendedRenderingMode,
1997 dwritefontface1_GetVerticalGlyphVariants,
1998 dwritefontface1_HasVerticalGlyphVariants,
1999 dwritefontface2_IsColorFont,
2000 dwritefontface2_GetColorPaletteCount,
2001 dwritefontface2_GetPaletteEntryCount,
2002 dwritefontface2_GetPaletteEntries,
2003 dwritefontface2_GetRecommendedRenderingMode,
2004 dwritefontface3_GetFontFaceReference,
2005 dwritefontface3_GetPanose,
2006 dwritefontface3_GetWeight,
2007 dwritefontface3_GetStretch,
2008 dwritefontface3_GetStyle,
2009 dwritefontface3_GetFamilyNames,
2010 dwritefontface3_GetFaceNames,
2011 dwritefontface3_GetInformationalStrings,
2012 dwritefontface3_HasCharacter,
2013 dwritefontface3_GetRecommendedRenderingMode,
2014 dwritefontface3_IsCharacterLocal,
2015 dwritefontface3_IsGlyphLocal,
2016 dwritefontface3_AreCharactersLocal,
2017 dwritefontface3_AreGlyphsLocal,
2018 dwritefontface4_GetGlyphImageFormats_,
2019 dwritefontface4_GetGlyphImageFormats,
2020 dwritefontface4_GetGlyphImageData,
2021 dwritefontface4_ReleaseGlyphImageData,
2022 dwritefontface5_GetFontAxisValueCount,
2023 dwritefontface5_GetFontAxisValues,
2024 dwritefontface5_HasVariations,
2025 dwritefontface5_GetFontResource,
2026 dwritefontface5_Equals,
2029 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
2031 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2032 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
2035 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
2037 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2038 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
2041 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
2043 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2044 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
2047 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
2048 IDWriteFontFace3 **ret)
2050 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2052 TRACE("%p, %p.\n", iface, ret);
2054 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
2055 IDWriteFontFace3_AddRef(*ret);
2057 return S_OK;
2060 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
2061 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
2063 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2064 DWRITE_FONT_FILE_TYPE file_type;
2065 DWRITE_FONT_FACE_TYPE face_type;
2066 IDWriteFontFace *face;
2067 BOOL is_supported;
2068 UINT32 face_num;
2069 HRESULT hr;
2071 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
2073 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
2074 if (FAILED(hr))
2075 return hr;
2077 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
2078 simulations, &face);
2079 if (SUCCEEDED(hr))
2081 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
2082 IDWriteFontFace_Release(face);
2085 return hr;
2088 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
2090 FIXME("%p, %p.\n", iface, ref);
2092 return E_NOTIMPL;
2095 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
2097 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2099 TRACE("%p.\n", iface);
2101 return fontface->index;
2104 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
2106 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2108 TRACE("%p.\n", iface);
2110 return fontface->simulations;
2113 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
2115 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2117 TRACE("%p, %p.\n", iface, file);
2119 *file = fontface->file;
2120 IDWriteFontFile_AddRef(*file);
2122 return S_OK;
2125 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
2127 FIXME("%p.\n", iface);
2129 return 0;
2132 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
2134 FIXME("%p.\n", iface);
2136 return 0;
2139 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
2141 FIXME("%p, %p.\n", iface, writetime);
2143 return E_NOTIMPL;
2146 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
2148 FIXME("%p.\n", iface);
2150 return DWRITE_LOCALITY_LOCAL;
2153 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
2155 FIXME("%p.\n", iface);
2157 return E_NOTIMPL;
2160 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
2161 WCHAR const *chars, UINT32 count)
2163 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
2165 return E_NOTIMPL;
2168 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
2169 UINT16 const *glyphs, UINT32 count)
2171 FIXME("%p, %p, %u.\n", iface, glyphs, count);
2173 return E_NOTIMPL;
2176 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
2177 UINT64 offset, UINT64 size)
2179 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
2181 return E_NOTIMPL;
2184 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
2186 dwritefontface_reference_QueryInterface,
2187 dwritefontface_reference_AddRef,
2188 dwritefontface_reference_Release,
2189 dwritefontface_reference_CreateFontFace,
2190 dwritefontface_reference_CreateFontFaceWithSimulations,
2191 dwritefontface_reference_Equals,
2192 dwritefontface_reference_GetFontFaceIndex,
2193 dwritefontface_reference_GetSimulations,
2194 dwritefontface_reference_GetFontFile,
2195 dwritefontface_reference_GetLocalFileSize,
2196 dwritefontface_reference_GetFileSize,
2197 dwritefontface_reference_GetFileTime,
2198 dwritefontface_reference_GetLocality,
2199 dwritefontface_reference_EnqueueFontDownloadRequest,
2200 dwritefontface_reference_EnqueueCharacterDownloadRequest,
2201 dwritefontface_reference_EnqueueGlyphDownloadRequest,
2202 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
2205 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
2207 struct dwrite_font_data *data = font->data;
2208 struct fontface_desc desc;
2209 struct list *cached_list;
2210 HRESULT hr;
2212 *fontface = NULL;
2214 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
2215 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
2216 if (hr == S_OK)
2217 return hr;
2219 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
2220 return hr;
2222 desc.factory = font->family->collection->factory;
2223 desc.face_type = data->face_type;
2224 desc.file = data->file;
2225 desc.index = data->face_index;
2226 desc.simulations = data->simulations;
2227 desc.font_data = data;
2228 hr = create_fontface(&desc, cached_list, fontface);
2230 IDWriteFontFileStream_Release(desc.stream);
2231 return hr;
2234 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
2236 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2238 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
2239 IsEqualIID(riid, &IID_IDWriteFont2) ||
2240 IsEqualIID(riid, &IID_IDWriteFont1) ||
2241 IsEqualIID(riid, &IID_IDWriteFont) ||
2242 IsEqualIID(riid, &IID_IUnknown))
2244 *obj = iface;
2245 IDWriteFont3_AddRef(iface);
2246 return S_OK;
2249 WARN("%s not implemented.\n", debugstr_guid(riid));
2251 *obj = NULL;
2252 return E_NOINTERFACE;
2255 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
2257 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2258 ULONG refcount = InterlockedIncrement(&font->refcount);
2260 TRACE("%p, refcount %ld.\n", iface, refcount);
2262 return refcount;
2265 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
2267 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2268 ULONG refcount = InterlockedDecrement(&font->refcount);
2270 TRACE("%p, refcount %ld.\n", iface, refcount);
2272 if (!refcount)
2274 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
2275 release_font_data(font->data);
2276 free(font);
2279 return refcount;
2282 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
2284 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2286 TRACE("%p, %p.\n", iface, family);
2288 *family = (IDWriteFontFamily *)&font->family->IDWriteFontFamily2_iface;
2289 IDWriteFontFamily_AddRef(*family);
2290 return S_OK;
2293 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
2295 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2297 TRACE("%p.\n", iface);
2299 return font->data->weight;
2302 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
2304 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2306 TRACE("%p.\n", iface);
2308 return font->data->stretch;
2311 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
2313 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2315 TRACE("%p.\n", iface);
2317 return font->style;
2320 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2322 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2324 TRACE("%p.\n", iface);
2326 return !!(font->data->flags & FONT_IS_SYMBOL);
2329 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2331 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2333 TRACE("%p, %p.\n", iface, names);
2335 return clone_localizedstrings(font->data->names, names);
2338 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2339 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2341 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2342 struct dwrite_font_data *data = font->data;
2343 struct file_stream_desc stream_desc;
2345 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2347 /* Stream will be created if necessary. */
2348 stream_desc.stream = NULL;
2349 stream_desc.face_index = data->face_index;
2350 stream_desc.face_type = data->face_type;
2351 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2354 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2356 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2358 TRACE("%p.\n", iface);
2360 return font->data->simulations;
2363 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2365 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2367 TRACE("%p, %p.\n", iface, metrics);
2369 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2372 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2374 UINT16 glyph;
2375 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2376 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2377 return glyph != 0;
2380 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2382 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2384 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2386 *exists = dwritefont_has_character(font, ch);
2388 return S_OK;
2391 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2393 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2395 TRACE("%p, %p.\n", iface, fontface);
2397 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2400 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2402 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2404 TRACE("%p, %p.\n", iface, metrics);
2406 *metrics = font->data->metrics;
2409 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2411 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2413 TRACE("%p, %p.\n", iface, panose);
2415 *panose = font->data->panose;
2418 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2419 UINT32 *count)
2421 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2423 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2425 *count = 0;
2426 if (max_count && !ranges)
2427 return E_INVALIDARG;
2429 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2430 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2433 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2435 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2437 TRACE("%p.\n", iface);
2439 return !!(font->data->flags & FONT_IS_MONOSPACED);
2442 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2444 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2446 TRACE("%p.\n", iface);
2448 return !!(font->data->flags & FONT_IS_COLORED);
2451 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2453 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2455 TRACE("%p, %p.\n", iface, fontface);
2457 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2460 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2462 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2464 TRACE("%p, %p.\n", iface, other);
2466 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2467 return FALSE;
2469 return font->data->face_index == other_font->data->face_index
2470 && font->data->simulations == other_font->data->simulations
2471 && is_same_fontfile(font->data->file, other_font->data->file);
2474 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2476 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2478 TRACE("%p, %p.\n", iface, reference);
2480 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2481 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2482 (IDWriteFontFaceReference1 **)reference);
2485 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2487 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2489 TRACE("%p, %#x.\n", iface, ch);
2491 return dwritefont_has_character(font, ch);
2494 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2496 FIXME("%p: stub.\n", iface);
2498 return DWRITE_LOCALITY_LOCAL;
2501 static const IDWriteFont3Vtbl dwritefontvtbl = {
2502 dwritefont_QueryInterface,
2503 dwritefont_AddRef,
2504 dwritefont_Release,
2505 dwritefont_GetFontFamily,
2506 dwritefont_GetWeight,
2507 dwritefont_GetStretch,
2508 dwritefont_GetStyle,
2509 dwritefont_IsSymbolFont,
2510 dwritefont_GetFaceNames,
2511 dwritefont_GetInformationalStrings,
2512 dwritefont_GetSimulations,
2513 dwritefont_GetMetrics,
2514 dwritefont_HasCharacter,
2515 dwritefont_CreateFontFace,
2516 dwritefont1_GetMetrics,
2517 dwritefont1_GetPanose,
2518 dwritefont1_GetUnicodeRanges,
2519 dwritefont1_IsMonospacedFont,
2520 dwritefont2_IsColorFont,
2521 dwritefont3_CreateFontFace,
2522 dwritefont3_Equals,
2523 dwritefont3_GetFontFaceReference,
2524 dwritefont3_HasCharacter,
2525 dwritefont3_GetLocality
2528 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2530 if (!iface)
2531 return NULL;
2532 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2533 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2536 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2538 if (!iface)
2539 return NULL;
2540 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2541 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2544 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2546 if (!iface)
2547 return NULL;
2548 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2549 return NULL;
2550 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2551 IDWriteFontFaceReference1_iface);
2554 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2556 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2557 *lf = font->data->lf;
2560 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2562 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2563 *lf = fontface->lf;
2566 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2568 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2569 *fontsig = font->data->fontsig;
2570 return S_OK;
2573 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2575 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2576 *fontsig = fontface->fontsig;
2577 return S_OK;
2580 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2582 struct dwrite_font *object;
2584 *font = NULL;
2586 if (!(object = calloc(1, sizeof(*object))))
2587 return E_OUTOFMEMORY;
2589 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2590 object->refcount = 1;
2591 object->family = family;
2592 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2593 object->data = family->data->fonts[index];
2594 object->style = object->data->style;
2595 addref_font_data(object->data);
2597 *font = &object->IDWriteFont3_iface;
2599 return S_OK;
2602 /* IDWriteFontList2 */
2603 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2605 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2607 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2608 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2609 IsEqualIID(riid, &IID_IDWriteFontList) ||
2610 IsEqualIID(riid, &IID_IUnknown))
2612 *obj = iface;
2613 IDWriteFontList2_AddRef(iface);
2614 return S_OK;
2617 WARN("%s not implemented.\n", debugstr_guid(riid));
2619 *obj = NULL;
2620 return E_NOINTERFACE;
2623 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2625 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2626 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2628 TRACE("%p, refcount %lu.\n", iface, refcount);
2630 return refcount;
2633 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2635 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2636 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2638 TRACE("%p, refcount %lu.\n", iface, refcount);
2640 if (!refcount)
2642 unsigned int i;
2644 for (i = 0; i < fontlist->font_count; i++)
2645 release_font_data(fontlist->fonts[i]);
2646 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2647 free(fontlist->fonts);
2648 free(fontlist);
2651 return refcount;
2654 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2656 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2657 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2660 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2662 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2664 TRACE("%p.\n", iface);
2666 return fontlist->font_count;
2669 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2671 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2673 TRACE("%p, %u, %p.\n", iface, index, font);
2675 *font = NULL;
2677 if (fontlist->font_count == 0)
2678 return S_FALSE;
2680 if (index >= fontlist->font_count)
2681 return E_INVALIDARG;
2683 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2686 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2688 FIXME("%p, %u.\n", iface, index);
2690 return DWRITE_LOCALITY_LOCAL;
2693 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2694 IDWriteFont3 **font)
2696 *font = NULL;
2698 if (fontlist->font_count == 0)
2699 return S_FALSE;
2701 if (index >= fontlist->font_count)
2702 return E_FAIL;
2704 return create_font(fontlist->family, index, font);
2707 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2709 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2711 TRACE("%p, %u, %p.\n", iface, index, font);
2713 return fontlist_get_font(fontlist, index, font);
2716 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2717 IDWriteFontFaceReference **reference)
2719 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2720 IDWriteFont3 *font;
2721 HRESULT hr;
2723 TRACE("%p, %u, %p.\n", iface, index, reference);
2725 *reference = NULL;
2727 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2729 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2730 IDWriteFont3_Release(font);
2733 return hr;
2736 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2738 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2740 TRACE("%p, %p.\n", iface, fontset);
2742 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2743 fontlist->font_count, fontset);
2746 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2748 dwritefontlist_QueryInterface,
2749 dwritefontlist_AddRef,
2750 dwritefontlist_Release,
2751 dwritefontlist_GetFontCollection,
2752 dwritefontlist_GetFontCount,
2753 dwritefontlist_GetFont,
2754 dwritefontlist1_GetFontLocality,
2755 dwritefontlist1_GetFont,
2756 dwritefontlist1_GetFontFaceReference,
2757 dwritefontlist2_GetFontSet,
2760 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2762 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2764 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2766 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2767 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2768 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2769 IsEqualIID(riid, &IID_IUnknown))
2771 *obj = iface;
2773 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2774 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2775 IsEqualIID(riid, &IID_IDWriteFontList))
2777 *obj = &family->IDWriteFontList2_iface;
2779 else
2781 WARN("%s not implemented.\n", debugstr_guid(riid));
2782 *obj = NULL;
2783 return E_NOINTERFACE;
2786 IUnknown_AddRef((IUnknown *)*obj);
2787 return S_OK;
2790 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2792 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2793 ULONG refcount = InterlockedIncrement(&family->refcount);
2795 TRACE("%p, %lu.\n", iface, refcount);
2797 return refcount;
2800 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2802 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2803 ULONG refcount = InterlockedDecrement(&family->refcount);
2805 TRACE("%p, %lu.\n", iface, refcount);
2807 if (!refcount)
2809 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2810 release_fontfamily_data(family->data);
2811 free(family);
2814 return refcount;
2817 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2819 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2821 TRACE("%p, %p.\n", iface, collection);
2823 *collection = (IDWriteFontCollection *)&family->collection->IDWriteFontCollection3_iface;
2824 IDWriteFontCollection_AddRef(*collection);
2825 return S_OK;
2828 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2830 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2832 TRACE("%p.\n", iface);
2834 return family->data->count;
2837 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2839 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2841 TRACE("%p, %u, %p.\n", iface, index, font);
2843 *font = NULL;
2845 if (!family->data->count)
2846 return S_FALSE;
2848 if (index >= family->data->count)
2849 return E_INVALIDARG;
2851 return create_font(family, index, (IDWriteFont3 **)font);
2854 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2856 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2858 TRACE("%p, %p.\n", iface, names);
2860 return clone_localizedstrings(family->data->familyname, names);
2863 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2864 const struct dwrite_font_propvec *req)
2866 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2867 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2868 FLOAT cur_req_prod, next_req_prod;
2870 if (next_to_req < cur_to_req)
2871 return TRUE;
2873 if (next_to_req > cur_to_req)
2874 return FALSE;
2876 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2877 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2879 if (next_req_prod > cur_req_prod)
2880 return TRUE;
2882 if (next_req_prod < cur_req_prod)
2883 return FALSE;
2885 if (next->stretch > cur->stretch)
2886 return TRUE;
2887 if (next->stretch < cur->stretch)
2888 return FALSE;
2890 if (next->style > cur->style)
2891 return TRUE;
2892 if (next->style < cur->style)
2893 return FALSE;
2895 if (next->weight > cur->weight)
2896 return TRUE;
2897 if (next->weight < cur->weight)
2898 return FALSE;
2900 /* full match, no reason to prefer new variant */
2901 return FALSE;
2904 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2905 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2907 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2908 struct dwrite_font_propvec req;
2909 size_t i, match;
2911 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2913 if (!family->data->count)
2915 *font = NULL;
2916 return DWRITE_E_NOFONT;
2919 init_font_prop_vec(weight, stretch, style, &req);
2920 match = 0;
2922 for (i = 1; i < family->data->count; ++i)
2924 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2925 match = i;
2928 return create_font(family, match, (IDWriteFont3 **)font);
2931 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2933 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2935 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2938 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2940 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2943 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2945 UINT32 b = fonts->font_count - 1, j, t;
2947 while (1) {
2948 t = b;
2950 for (j = 0; j < b; j++) {
2951 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2952 struct dwrite_font_data *s = fonts->fonts[j];
2953 fonts->fonts[j] = fonts->fonts[j+1];
2954 fonts->fonts[j+1] = s;
2955 t = j;
2959 if (t == b)
2960 break;
2961 b = t;
2965 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2966 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2968 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2969 matching_filter_func func = NULL;
2970 struct dwrite_font_propvec req;
2971 struct dwrite_fontlist *fonts;
2972 size_t i;
2974 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2976 *ret = NULL;
2978 if (!(fonts = malloc(sizeof(*fonts))))
2979 return E_OUTOFMEMORY;
2981 /* Allocate as many as family has, not all of them will be necessary used. */
2982 if (!(fonts->fonts = calloc(family->data->count, sizeof(*fonts->fonts))))
2984 free(fonts);
2985 return E_OUTOFMEMORY;
2988 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2989 fonts->refcount = 1;
2990 fonts->family = family;
2991 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2992 fonts->font_count = 0;
2994 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2995 if (style == DWRITE_FONT_STYLE_NORMAL) {
2996 if (family->data->has_normal_face || family->data->has_italic_face)
2997 func = is_font_acceptable_for_normal;
2999 else /* requested oblique or italic */ {
3000 if (family->data->has_oblique_face || family->data->has_italic_face)
3001 func = is_font_acceptable_for_oblique_italic;
3004 for (i = 0; i < family->data->count; ++i)
3006 if (!func || func(family->data->fonts[i]))
3008 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
3012 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
3013 init_font_prop_vec(weight, stretch, style, &req);
3014 matchingfonts_sort(fonts, &req);
3016 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
3017 return S_OK;
3020 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
3022 FIXME("%p, %u.\n", iface, index);
3024 return DWRITE_LOCALITY_LOCAL;
3027 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
3029 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3031 TRACE("%p, %u, %p.\n", iface, index, font);
3033 *font = NULL;
3035 if (!family->data->count)
3036 return S_FALSE;
3038 if (index >= family->data->count)
3039 return E_FAIL;
3041 return create_font(family, index, font);
3044 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
3045 IDWriteFontFaceReference **reference)
3047 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3048 const struct dwrite_font_data *font;
3050 TRACE("%p, %u, %p.\n", iface, index, reference);
3052 *reference = NULL;
3054 if (index >= family->data->count)
3055 return E_FAIL;
3057 font = family->data->fonts[index];
3058 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
3059 font->file, font->face_index, font->simulations, reference);
3062 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
3063 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
3065 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
3067 return E_NOTIMPL;
3070 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
3072 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3074 TRACE("%p, %p.\n", iface, fontset);
3076 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3077 family->data->count, fontset);
3080 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
3082 dwritefontfamily_QueryInterface,
3083 dwritefontfamily_AddRef,
3084 dwritefontfamily_Release,
3085 dwritefontfamily_GetFontCollection,
3086 dwritefontfamily_GetFontCount,
3087 dwritefontfamily_GetFont,
3088 dwritefontfamily_GetFamilyNames,
3089 dwritefontfamily_GetFirstMatchingFont,
3090 dwritefontfamily_GetMatchingFonts,
3091 dwritefontfamily1_GetFontLocality,
3092 dwritefontfamily1_GetFont,
3093 dwritefontfamily1_GetFontFaceReference,
3094 dwritefontfamily2_GetMatchingFonts,
3095 dwritefontfamily2_GetFontSet,
3098 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
3100 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3101 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
3104 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
3106 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3107 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
3110 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
3112 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3113 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
3116 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
3117 IDWriteFontCollection **collection)
3119 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3120 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
3123 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
3125 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3126 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
3129 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
3131 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3132 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3135 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
3137 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3138 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
3141 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
3143 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3144 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3147 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
3148 IDWriteFontFaceReference **reference)
3150 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3151 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
3154 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
3156 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3158 TRACE("%p, %p.\n", iface, fontset);
3160 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3161 family->data->count, fontset);
3164 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
3166 dwritefontfamilylist_QueryInterface,
3167 dwritefontfamilylist_AddRef,
3168 dwritefontfamilylist_Release,
3169 dwritefontfamilylist_GetFontCollection,
3170 dwritefontfamilylist_GetFontCount,
3171 dwritefontfamilylist_GetFont,
3172 dwritefontfamilylist1_GetFontLocality,
3173 dwritefontfamilylist1_GetFont,
3174 dwritefontfamilylist1_GetFontFaceReference,
3175 dwritefontfamilylist2_GetFontSet,
3178 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
3179 struct dwrite_fontfamily **family)
3181 struct dwrite_fontfamily *object;
3183 *family = NULL;
3185 if (!(object = calloc(1, sizeof(*object))))
3186 return E_OUTOFMEMORY;
3188 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
3189 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
3190 object->refcount = 1;
3191 object->collection = collection;
3192 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
3193 object->data = collection->family_data[index];
3194 InterlockedIncrement(&object->data->refcount);
3196 *family = object;
3198 return S_OK;
3201 BOOL is_system_collection(IDWriteFontCollection *collection)
3203 void *obj;
3204 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
3207 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3209 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3211 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
3213 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3214 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3215 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3216 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3217 IsEqualIID(riid, &IID_IUnknown))
3219 *obj = iface;
3220 IDWriteFontCollection3_AddRef(iface);
3221 return S_OK;
3224 *obj = NULL;
3226 if (IsEqualIID(riid, &IID_issystemcollection))
3227 return S_OK;
3229 WARN("%s not implemented.\n", debugstr_guid(riid));
3231 return E_NOINTERFACE;
3234 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3236 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3238 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3239 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3240 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3241 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3242 IsEqualIID(riid, &IID_IUnknown))
3244 *obj = iface;
3245 IDWriteFontCollection3_AddRef(iface);
3246 return S_OK;
3249 WARN("%s not implemented.\n", debugstr_guid(riid));
3251 *obj = NULL;
3253 return E_NOINTERFACE;
3256 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
3258 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3259 ULONG refcount = InterlockedIncrement(&collection->refcount);
3261 TRACE("%p, refcount %ld.\n", collection, refcount);
3263 return refcount;
3266 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
3268 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3269 ULONG refcount = InterlockedDecrement(&collection->refcount);
3270 size_t i;
3272 TRACE("%p, refcount %ld.\n", iface, refcount);
3274 if (!refcount)
3276 factory_detach_fontcollection(collection->factory, iface);
3277 for (i = 0; i < collection->count; ++i)
3278 release_fontfamily_data(collection->family_data[i]);
3279 free(collection->family_data);
3280 free(collection);
3283 return refcount;
3286 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
3288 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3290 TRACE("%p.\n", iface);
3292 return collection->count;
3295 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3296 IDWriteFontFamily **ret)
3298 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3299 struct dwrite_fontfamily *family;
3300 HRESULT hr;
3302 TRACE("%p, %u, %p.\n", iface, index, ret);
3304 *ret = NULL;
3306 if (index >= collection->count)
3307 return E_FAIL;
3309 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3310 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
3312 return hr;
3315 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
3317 size_t i;
3319 for (i = 0; i < collection->count; ++i)
3321 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3322 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3323 HRESULT hr;
3325 for (j = 0; j < count; j++)
3327 WCHAR buffer[255];
3328 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3329 if (SUCCEEDED(hr) && !wcsicmp(buffer, name))
3330 return i;
3334 return ~0u;
3337 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3338 UINT32 *index, BOOL *exists)
3340 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3342 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3344 *index = collection_find_family(collection, name);
3345 *exists = *index != ~0u;
3346 return S_OK;
3349 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3350 IDWriteFont **font)
3352 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3353 struct dwrite_fontfamily *family;
3354 BOOL found_font = FALSE;
3355 IDWriteFontFile *file;
3356 UINT32 face_index, count;
3357 size_t i, j;
3358 HRESULT hr;
3360 TRACE("%p, %p, %p.\n", iface, face, font);
3362 *font = NULL;
3364 if (!face)
3365 return E_INVALIDARG;
3367 count = 1;
3368 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3369 if (FAILED(hr))
3370 return hr;
3371 face_index = IDWriteFontFace_GetIndex(face);
3373 found_font = FALSE;
3374 for (i = 0; i < collection->count; ++i)
3376 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3378 for (j = 0; j < family_data->count; ++j)
3380 struct dwrite_font_data *font_data = family_data->fonts[j];
3382 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3383 found_font = TRUE;
3384 break;
3388 if (found_font)
3389 break;
3391 IDWriteFontFile_Release(file);
3393 if (!found_font)
3394 return DWRITE_E_NOFONT;
3396 hr = create_fontfamily(collection, i, &family);
3397 if (FAILED(hr))
3398 return hr;
3400 hr = create_font(family, j, (IDWriteFont3 **)font);
3401 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3402 return hr;
3405 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3407 FIXME("%p, %p.\n", iface, fontset);
3409 return E_NOTIMPL;
3412 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3413 IDWriteFontFamily1 **ret)
3415 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3416 struct dwrite_fontfamily *family;
3417 HRESULT hr;
3419 TRACE("%p, %u, %p.\n", iface, index, ret);
3421 *ret = NULL;
3423 if (index >= collection->count)
3424 return E_FAIL;
3426 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3427 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3429 return hr;
3432 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3433 UINT32 index, IDWriteFontFamily2 **ret)
3435 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3436 struct dwrite_fontfamily *family;
3437 HRESULT hr;
3439 TRACE("%p, %u, %p.\n", iface, index, ret);
3441 *ret = NULL;
3443 if (index >= collection->count)
3444 return E_FAIL;
3446 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3447 *ret = &family->IDWriteFontFamily2_iface;
3449 return hr;
3452 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3453 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3454 IDWriteFontList2 **fontlist)
3456 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3458 return E_NOTIMPL;
3461 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3463 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3465 TRACE("%p.\n", iface);
3467 return collection->family_model;
3470 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3472 FIXME("%p, %p.\n", iface, fontset);
3474 return E_NOTIMPL;
3477 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3479 FIXME("%p.\n", iface);
3481 return NULL;
3484 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3486 dwritefontcollection_QueryInterface,
3487 dwritefontcollection_AddRef,
3488 dwritefontcollection_Release,
3489 dwritefontcollection_GetFontFamilyCount,
3490 dwritefontcollection_GetFontFamily,
3491 dwritefontcollection_FindFamilyName,
3492 dwritefontcollection_GetFontFromFontFace,
3493 dwritefontcollection1_GetFontSet,
3494 dwritefontcollection1_GetFontFamily,
3495 dwritefontcollection2_GetFontFamily,
3496 dwritefontcollection2_GetMatchingFonts,
3497 dwritefontcollection2_GetFontFamilyModel,
3498 dwritefontcollection2_GetFontSet,
3499 dwritefontcollection3_GetExpirationEvent,
3502 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3504 dwritesystemfontcollection_QueryInterface,
3505 dwritefontcollection_AddRef,
3506 dwritefontcollection_Release,
3507 dwritefontcollection_GetFontFamilyCount,
3508 dwritefontcollection_GetFontFamily,
3509 dwritefontcollection_FindFamilyName,
3510 dwritefontcollection_GetFontFromFontFace,
3511 dwritefontcollection1_GetFontSet,
3512 dwritefontcollection1_GetFontFamily,
3513 dwritefontcollection2_GetFontFamily,
3514 dwritefontcollection2_GetMatchingFonts,
3515 dwritefontcollection2_GetFontFamilyModel,
3516 dwritefontcollection2_GetFontSet,
3517 dwritefontcollection3_GetExpirationEvent,
3520 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3522 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3523 sizeof(*family_data->fonts)))
3525 return E_OUTOFMEMORY;
3528 family_data->fonts[family_data->count++] = font_data;
3529 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3530 family_data->has_normal_face = 1;
3531 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3532 family_data->has_oblique_face = 1;
3533 else
3534 family_data->has_italic_face = 1;
3535 return S_OK;
3538 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3539 struct dwrite_fontfamily_data *family)
3541 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3542 sizeof(*collection->family_data)))
3544 return E_OUTOFMEMORY;
3547 collection->family_data[collection->count++] = family;
3548 return S_OK;
3551 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, IDWriteFactory7 *factory,
3552 DWRITE_FONT_FAMILY_MODEL family_model, BOOL is_system)
3554 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3555 collection->refcount = 1;
3556 collection->factory = factory;
3557 IDWriteFactory7_AddRef(collection->factory);
3558 collection->family_model = family_model;
3560 return S_OK;
3563 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3565 IDWriteFontFileLoader *loader;
3566 const void *key;
3567 UINT32 key_size;
3568 HRESULT hr;
3570 *stream = NULL;
3572 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3573 if (FAILED(hr))
3574 return hr;
3576 hr = IDWriteFontFile_GetLoader(file, &loader);
3577 if (FAILED(hr))
3578 return hr;
3580 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3581 IDWriteFontFileLoader_Release(loader);
3582 if (FAILED(hr))
3583 return hr;
3585 return hr;
3588 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3590 BOOL exists = FALSE;
3591 UINT32 index;
3592 HRESULT hr;
3594 buffer[0] = 0;
3595 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
3596 if (FAILED(hr) || !exists)
3597 return;
3599 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3602 static int trim_spaces(WCHAR *in, WCHAR *ret)
3604 int len;
3606 while (iswspace(*in))
3607 in++;
3609 ret[0] = 0;
3610 if (!(len = wcslen(in)))
3611 return 0;
3613 while (iswspace(in[len-1]))
3614 len--;
3616 memcpy(ret, in, len*sizeof(WCHAR));
3617 ret[len] = 0;
3619 return len;
3622 struct name_token {
3623 struct list entry;
3624 const WCHAR *ptr;
3625 INT len; /* token length */
3626 INT fulllen; /* full length including following separators */
3629 static inline BOOL is_name_separator_char(WCHAR ch)
3631 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3634 struct name_pattern {
3635 const WCHAR *part1; /* NULL indicates end of list */
3636 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3639 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3641 const struct name_pattern *pattern;
3642 struct name_token *token;
3643 int i = 0;
3645 while ((pattern = &patterns[i++])->part1)
3647 int len_part1 = wcslen(pattern->part1);
3648 int len_part2 = pattern->part2 ? wcslen(pattern->part2) : 0;
3650 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry)
3652 if (!len_part2)
3654 /* simple case with single part pattern */
3655 if (token->len != len_part1)
3656 continue;
3658 if (!wcsnicmp(token->ptr, pattern->part1, len_part1))
3660 if (match) *match = *token;
3661 list_remove(&token->entry);
3662 free(token);
3663 return TRUE;
3666 else
3668 struct name_token *next_token;
3669 struct list *next_entry;
3671 /* pattern parts are stored in reading order, tokens list is reversed */
3672 if (token->len < len_part2)
3673 continue;
3675 /* it's possible to have combined string as a token, like ExtraCondensed */
3676 if (token->len == len_part1 + len_part2)
3678 if (wcsnicmp(token->ptr, pattern->part1, len_part1))
3679 continue;
3681 if (wcsnicmp(&token->ptr[len_part1], pattern->part2, len_part2))
3682 continue;
3684 /* combined string match */
3685 if (match) *match = *token;
3686 list_remove(&token->entry);
3687 free(token);
3688 return TRUE;
3691 /* now it's only possible to have two tokens matched to respective pattern parts */
3692 if (token->len != len_part2)
3693 continue;
3695 next_entry = list_next(tokens, &token->entry);
3696 if (next_entry) {
3697 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3698 if (next_token->len != len_part1)
3699 continue;
3701 if (wcsnicmp(token->ptr, pattern->part2, len_part2))
3702 continue;
3704 if (wcsnicmp(next_token->ptr, pattern->part1, len_part1))
3705 continue;
3707 /* both parts matched, remove tokens */
3708 if (match) {
3709 match->ptr = next_token->ptr;
3710 match->len = (token->ptr - next_token->ptr) + token->len;
3712 list_remove(&token->entry);
3713 list_remove(&next_token->entry);
3714 free(next_token);
3715 free(token);
3716 return TRUE;
3722 if (match) {
3723 match->ptr = NULL;
3724 match->len = 0;
3726 return FALSE;
3729 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3731 static const struct name_pattern italic_patterns[] =
3733 { L"ita" },
3734 { L"ital" },
3735 { L"italic" },
3736 { L"cursive" },
3737 { L"kursiv" },
3738 { NULL }
3741 static const struct name_pattern oblique_patterns[] =
3743 { L"inclined" },
3744 { L"oblique" },
3745 { L"backslanted" },
3746 { L"backslant" },
3747 { L"slanted" },
3748 { NULL }
3751 /* italic patterns first */
3752 if (match_pattern_list(tokens, italic_patterns, match))
3753 return DWRITE_FONT_STYLE_ITALIC;
3755 /* oblique patterns */
3756 if (match_pattern_list(tokens, oblique_patterns, match))
3757 return DWRITE_FONT_STYLE_OBLIQUE;
3759 return style;
3762 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3763 struct name_token *match)
3765 static const struct name_pattern ultracondensed_patterns[] =
3767 { L"extra", L"compressed" },
3768 { L"ext", L"compressed" },
3769 { L"ultra", L"compressed" },
3770 { L"ultra", L"condensed" },
3771 { L"ultra", L"cond" },
3772 { NULL }
3775 static const struct name_pattern extracondensed_patterns[] =
3777 { L"compressed" },
3778 { L"extra", L"condensed" },
3779 { L"ext", L"condensed" },
3780 { L"extra", L"cond" },
3781 { L"ext", L"cond" },
3782 { NULL }
3785 static const struct name_pattern semicondensed_patterns[] =
3787 { L"narrow" },
3788 { L"compact" },
3789 { L"semi", L"condensed" },
3790 { L"semi", L"cond" },
3791 { NULL }
3794 static const struct name_pattern semiexpanded_patterns[] =
3796 { L"wide" },
3797 { L"semi", L"expanded" },
3798 { L"semi", L"extended" },
3799 { NULL }
3802 static const struct name_pattern extraexpanded_patterns[] =
3804 { L"extra", L"expanded" },
3805 { L"ext", L"expanded" },
3806 { L"extra", L"extended" },
3807 { L"ext", L"extended" },
3808 { NULL }
3811 static const struct name_pattern ultraexpanded_patterns[] =
3813 { L"ultra", L"expanded" },
3814 { L"ultra", L"extended" },
3815 { NULL }
3818 static const struct name_pattern condensed_patterns[] =
3820 { L"condensed" },
3821 { L"cond" },
3822 { NULL }
3825 static const struct name_pattern expanded_patterns[] =
3827 { L"expanded" },
3828 { L"extended" },
3829 { NULL }
3832 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3833 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3835 if (match_pattern_list(tokens, extracondensed_patterns, match))
3836 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3838 if (match_pattern_list(tokens, semicondensed_patterns, match))
3839 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3841 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3842 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3844 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3845 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3847 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3848 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3850 if (match_pattern_list(tokens, condensed_patterns, match))
3851 return DWRITE_FONT_STRETCH_CONDENSED;
3853 if (match_pattern_list(tokens, expanded_patterns, match))
3854 return DWRITE_FONT_STRETCH_EXPANDED;
3856 return stretch;
3859 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3860 struct name_token *match)
3862 static const struct name_pattern thin_patterns[] =
3864 { L"extra", L"thin" },
3865 { L"ext", L"thin" },
3866 { L"ultra", L"thin" },
3867 { NULL }
3870 static const struct name_pattern extralight_patterns[] =
3872 { L"extra", L"light" },
3873 { L"ext", L"light" },
3874 { L"ultra", L"light" },
3875 { NULL }
3878 static const struct name_pattern semilight_patterns[] =
3880 { L"semi", L"light" },
3881 { NULL }
3884 static const struct name_pattern demibold_patterns[] =
3886 { L"semi", L"bold" },
3887 { L"demi", L"bold" },
3888 { NULL }
3891 static const struct name_pattern extrabold_patterns[] =
3893 { L"extra", L"bold" },
3894 { L"ext", L"bold" },
3895 { L"ultra", L"bold" },
3896 { NULL }
3899 static const struct name_pattern extrablack_patterns[] =
3901 { L"extra", L"black" },
3902 { L"ext", L"black" },
3903 { L"ultra", L"black" },
3904 { NULL }
3907 static const struct name_pattern bold_patterns[] =
3909 { L"bold" },
3910 { NULL }
3913 static const struct name_pattern thin2_patterns[] =
3915 { L"thin" },
3916 { NULL }
3919 static const struct name_pattern light_patterns[] =
3921 { L"light" },
3922 { NULL }
3925 static const struct name_pattern medium_patterns[] =
3927 { L"medium" },
3928 { NULL }
3931 static const struct name_pattern black_patterns[] =
3933 { L"black" },
3934 { L"heavy" },
3935 { L"nord" },
3936 { NULL }
3939 static const struct name_pattern demibold2_patterns[] =
3941 { L"demi" },
3942 { NULL }
3945 static const struct name_pattern extrabold2_patterns[] =
3947 { L"ultra" },
3948 { NULL }
3951 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3952 matching pattern. */
3954 if (match_pattern_list(tokens, thin_patterns, match))
3955 return DWRITE_FONT_WEIGHT_THIN;
3957 if (match_pattern_list(tokens, extralight_patterns, match))
3958 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3960 if (match_pattern_list(tokens, semilight_patterns, match))
3961 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3963 if (match_pattern_list(tokens, demibold_patterns, match))
3964 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3966 if (match_pattern_list(tokens, extrabold_patterns, match))
3967 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3969 if (match_pattern_list(tokens, extrablack_patterns, match))
3970 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3972 if (match_pattern_list(tokens, bold_patterns, match))
3973 return DWRITE_FONT_WEIGHT_BOLD;
3975 if (match_pattern_list(tokens, thin2_patterns, match))
3976 return DWRITE_FONT_WEIGHT_THIN;
3978 if (match_pattern_list(tokens, light_patterns, match))
3979 return DWRITE_FONT_WEIGHT_LIGHT;
3981 if (match_pattern_list(tokens, medium_patterns, match))
3982 return DWRITE_FONT_WEIGHT_MEDIUM;
3984 if (match_pattern_list(tokens, black_patterns, match))
3985 return DWRITE_FONT_WEIGHT_BLACK;
3987 if (match_pattern_list(tokens, black_patterns, match))
3988 return DWRITE_FONT_WEIGHT_BLACK;
3990 if (match_pattern_list(tokens, demibold2_patterns, match))
3991 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3993 if (match_pattern_list(tokens, extrabold2_patterns, match))
3994 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3996 /* FIXME: use abbreviated names to extract weight */
3998 return weight;
4001 struct knownweight_entry
4003 const WCHAR *nameW;
4004 DWRITE_FONT_WEIGHT weight;
4007 static int __cdecl compare_knownweights(const void *a, const void* b)
4009 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
4010 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
4011 int ret = 0;
4013 if (target > entry->weight)
4014 ret = 1;
4015 else if (target < entry->weight)
4016 ret = -1;
4018 return ret;
4021 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
4023 static const struct knownweight_entry knownweights[] =
4025 { L"Thin", DWRITE_FONT_WEIGHT_THIN },
4026 { L"Extra Light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
4027 { L"Light", DWRITE_FONT_WEIGHT_LIGHT },
4028 { L"Semi Light", DWRITE_FONT_WEIGHT_SEMI_LIGHT },
4029 { L"Medium", DWRITE_FONT_WEIGHT_MEDIUM },
4030 { L"Demi Bold", DWRITE_FONT_WEIGHT_DEMI_BOLD },
4031 { L"Bold", DWRITE_FONT_WEIGHT_BOLD },
4032 { L"Extra Bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD },
4033 { L"Black", DWRITE_FONT_WEIGHT_BLACK },
4034 { L"Extra Black", DWRITE_FONT_WEIGHT_EXTRA_BLACK }
4036 const struct knownweight_entry *ptr;
4038 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(*knownweights),
4039 compare_knownweights);
4040 if (!ptr) {
4041 nameW[0] = 0;
4042 return FALSE;
4045 wcscpy(nameW, ptr->nameW);
4046 return TRUE;
4049 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
4051 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
4052 strW[name->len] = 0;
4055 /* Modifies facenameW string, and returns pointer to regular term that was removed */
4056 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
4058 static const WCHAR *regular_patterns[] =
4060 L"Book",
4061 L"Normal",
4062 L"Regular",
4063 L"Roman",
4064 L"Upright",
4065 NULL
4068 const WCHAR *regular_ptr = NULL, *ptr;
4069 int i = 0;
4071 if (len == -1)
4072 len = wcslen(facenameW);
4074 /* remove rightmost regular variant from face name */
4075 while (!regular_ptr && (ptr = regular_patterns[i++]))
4077 int pattern_len = wcslen(ptr);
4078 WCHAR *src;
4080 if (pattern_len > len)
4081 continue;
4083 src = facenameW + len - pattern_len;
4084 while (src >= facenameW)
4086 if (!wcsnicmp(src, ptr, pattern_len))
4088 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
4089 len = wcslen(facenameW);
4090 regular_ptr = ptr;
4091 break;
4093 else
4094 src--;
4098 return regular_ptr;
4101 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
4103 const WCHAR *ptr;
4105 list_init(tokens);
4106 ptr = nameW;
4108 while (*ptr)
4110 struct name_token *token = malloc(sizeof(*token));
4111 token->ptr = ptr;
4112 token->len = 0;
4113 token->fulllen = 0;
4115 while (*ptr && !is_name_separator_char(*ptr)) {
4116 token->len++;
4117 token->fulllen++;
4118 ptr++;
4121 /* skip separators */
4122 while (is_name_separator_char(*ptr)) {
4123 token->fulllen++;
4124 ptr++;
4127 list_add_head(tokens, &token->entry);
4131 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
4133 struct name_token *token, *token2;
4134 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
4135 int len;
4137 list_remove(&token->entry);
4139 /* don't include last separator */
4140 len = list_empty(tokens) ? token->len : token->fulllen;
4141 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
4142 nameW += len;
4144 free(token);
4146 *nameW = 0;
4149 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
4151 struct name_token stretch_name, weight_name, style_name;
4152 WCHAR familynameW[255], facenameW[255], finalW[255];
4153 WCHAR weightW[32], stretchW[32], styleW[32];
4154 const WCHAR *regular_ptr = NULL;
4155 DWRITE_FONT_STRETCH stretch;
4156 DWRITE_FONT_WEIGHT weight;
4157 struct list tokens;
4158 int len;
4160 /* remove leading and trailing spaces from family and face name */
4161 trim_spaces(familyW, familynameW);
4162 len = trim_spaces(faceW, facenameW);
4164 /* remove rightmost regular variant from face name */
4165 regular_ptr = facename_remove_regular_term(facenameW, len);
4167 /* append face name to family name, FIXME check if face name is a substring of family name */
4168 if (*facenameW)
4170 wcscat(familynameW, L" ");
4171 wcscat(familynameW, facenameW);
4174 /* tokenize with " .-_" */
4175 fontname_tokenize(&tokens, familynameW);
4177 /* extract and resolve style */
4178 font->style = font_extract_style(&tokens, font->style, &style_name);
4180 /* extract stretch */
4181 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
4183 /* extract weight */
4184 weight = font_extract_weight(&tokens, font->weight, &weight_name);
4186 /* resolve weight */
4187 if (weight != font->weight)
4189 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
4190 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
4191 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
4192 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
4193 !(abs((int)weight - (int)font->weight) <= 150 &&
4194 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
4195 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
4196 font->weight != DWRITE_FONT_WEIGHT_BOLD))
4198 font->weight = weight;
4202 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
4203 it's leaning in opposite direction from normal comparing to specified stretch or if specified
4204 stretch itself is normal (extracted stretch is never normal). */
4205 if (stretch != font->stretch) {
4206 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
4207 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
4208 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
4210 font->stretch = stretch;
4214 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
4216 /* get final combined string from what's left in token list, list is released */
4217 fontname_tokens_to_str(&tokens, finalW);
4219 if (!wcscmp(familyW, finalW))
4220 return FALSE;
4222 /* construct face name */
4223 wcscpy(familyW, finalW);
4225 /* resolved weight name */
4226 if (weight_name.ptr)
4227 font_name_token_to_str(&weight_name, weightW);
4228 /* ignore normal weight */
4229 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
4230 weightW[0] = 0;
4231 /* for known weight values use appropriate names */
4232 else if (is_known_weight_value(font->weight, weightW)) {
4234 /* use Wnnn format as a fallback in case weight is not one of known values */
4235 else
4236 swprintf(weightW, ARRAY_SIZE(weightW), L"W%d", font->weight);
4238 /* resolved stretch name */
4239 if (stretch_name.ptr)
4240 font_name_token_to_str(&stretch_name, stretchW);
4241 /* ignore normal stretch */
4242 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
4243 stretchW[0] = 0;
4244 /* use predefined stretch names */
4245 else
4247 static const WCHAR *stretchnamesW[] =
4249 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
4250 L"Ultra Condensed",
4251 L"Extra Condensed",
4252 L"Condensed",
4253 L"Semi Condensed",
4254 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
4255 L"Semi Expanded",
4256 L"Expanded",
4257 L"Extra Expanded",
4258 L"Ultra Expanded"
4260 wcscpy(stretchW, stretchnamesW[font->stretch]);
4263 /* resolved style name */
4264 if (style_name.ptr)
4265 font_name_token_to_str(&style_name, styleW);
4266 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
4267 styleW[0] = 0;
4268 /* use predefined names */
4269 else
4270 wcscpy(styleW, font->style == DWRITE_FONT_STYLE_ITALIC ? L"Italic" : L"Oblique");
4272 /* use Regular match if it was found initially */
4273 if (!*weightW && !*stretchW && !*styleW)
4274 wcscpy(faceW, regular_ptr ? regular_ptr : L"Regular");
4275 else
4277 faceW[0] = 0;
4279 if (*stretchW) wcscpy(faceW, stretchW);
4281 if (*weightW)
4283 if (*faceW) wcscat(faceW, L" ");
4284 wcscat(faceW, weightW);
4287 if (*styleW)
4289 if (*faceW) wcscat(faceW, L" ");
4290 wcscat(faceW, styleW);
4294 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
4295 return TRUE;
4298 static HRESULT init_font_data(const struct fontface_desc *desc, DWRITE_FONT_FAMILY_MODEL family_model,
4299 struct dwrite_font_data **ret)
4301 static const float width_axis_values[] =
4303 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
4304 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
4305 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
4306 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
4307 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
4308 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
4309 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
4310 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
4311 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
4312 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
4315 struct file_stream_desc stream_desc;
4316 struct dwrite_font_props props;
4317 struct dwrite_font_data *data;
4318 WCHAR familyW[255], faceW[255];
4319 HRESULT hr;
4321 *ret = NULL;
4323 if (!(data = calloc(1, sizeof(*data))))
4324 return E_OUTOFMEMORY;
4326 data->refcount = 1;
4327 data->file = desc->file;
4328 data->face_index = desc->index;
4329 data->face_type = desc->face_type;
4330 IDWriteFontFile_AddRef(data->file);
4332 stream_desc.stream = desc->stream;
4333 stream_desc.face_type = desc->face_type;
4334 stream_desc.face_index = desc->index;
4335 opentype_get_font_properties(&stream_desc, &props);
4336 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4337 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4339 if (FAILED(hr = opentype_get_font_familyname(&stream_desc, family_model, &data->family_names)))
4341 WARN("Unable to get family name from the font file, hr %#lx.\n", hr);
4342 release_font_data(data);
4343 return hr;
4346 data->style = props.style;
4347 data->stretch = props.stretch;
4348 data->weight = props.weight;
4349 data->panose = props.panose;
4350 data->fontsig = props.fontsig;
4351 data->lf = props.lf;
4352 data->flags = props.flags;
4354 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4355 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4357 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE
4358 && font_apply_differentiation_rules(data, familyW, faceW))
4360 set_en_localizedstring(data->family_names, familyW);
4361 set_en_localizedstring(data->names, faceW);
4364 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4366 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4367 data->axis[0].value = props.weight;
4368 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4369 data->axis[1].value = width_axis_values[props.stretch];
4370 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4371 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4373 *ret = data;
4374 return S_OK;
4377 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4378 const WCHAR *facenameW, struct dwrite_font_data **ret)
4380 struct dwrite_font_data *data;
4382 *ret = NULL;
4384 if (!(data = calloc(1, sizeof(*data))))
4385 return E_OUTOFMEMORY;
4387 *data = *src;
4388 data->refcount = 1;
4389 data->simulations |= simulations;
4390 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4391 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4392 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4393 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4394 memset(data->info_strings, 0, sizeof(data->info_strings));
4395 data->names = NULL;
4396 IDWriteFontFile_AddRef(data->file);
4397 IDWriteLocalizedStrings_AddRef(data->family_names);
4399 create_localizedstrings(&data->names);
4400 add_localizedstring(data->names, L"en-us", facenameW);
4402 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4404 *ret = data;
4405 return S_OK;
4408 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4410 struct dwrite_fontfamily_data *data;
4412 if (!(data = calloc(1, sizeof(*data))))
4413 return E_OUTOFMEMORY;
4415 data->refcount = 1;
4416 data->familyname = familyname;
4417 IDWriteLocalizedStrings_AddRef(familyname);
4419 *ret = data;
4421 return S_OK;
4424 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4426 size_t i, j, heaviest;
4428 for (i = 0; i < family->count; ++i)
4430 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4431 heaviest = i;
4433 if (family->fonts[i]->bold_sim_tested)
4434 continue;
4436 family->fonts[i]->bold_sim_tested = 1;
4437 for (j = i; j < family->count; ++j)
4439 if (family->fonts[j]->bold_sim_tested)
4440 continue;
4442 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4443 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4444 if (family->fonts[j]->weight > weight) {
4445 weight = family->fonts[j]->weight;
4446 heaviest = j;
4448 family->fonts[j]->bold_sim_tested = 1;
4452 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550)
4454 static const struct name_pattern weightsim_patterns[] =
4456 { L"extra", L"light" },
4457 { L"ext", L"light" },
4458 { L"ultra", L"light" },
4459 { L"semi", L"light" },
4460 { L"semi", L"bold" },
4461 { L"demi", L"bold" },
4462 { L"bold" },
4463 { L"thin" },
4464 { L"light" },
4465 { L"medium" },
4466 { L"demi" },
4467 { NULL }
4470 WCHAR facenameW[255], initialW[255];
4471 struct dwrite_font_data *boldface;
4472 struct list tokens;
4474 /* add Bold simulation based on heaviest face data */
4476 /* Simulated face name should only contain Bold as weight term,
4477 so remove existing regular and weight terms. */
4478 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4479 facename_remove_regular_term(initialW, -1);
4481 /* remove current weight pattern */
4482 fontname_tokenize(&tokens, initialW);
4483 match_pattern_list(&tokens, weightsim_patterns, NULL);
4484 fontname_tokens_to_str(&tokens, facenameW);
4486 /* Bold suffix for new name */
4487 if (*facenameW) wcscat(facenameW, L" ");
4488 wcscat(facenameW, L"Bold");
4490 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4491 boldface->bold_sim_tested = 1;
4492 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4493 fontfamily_add_font(family, boldface);
4499 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4501 size_t i, j;
4503 for (i = 0; i < family->count; ++i)
4505 UINT32 regular = ~0u, oblique = ~0u;
4506 struct dwrite_font_data *obliqueface;
4507 WCHAR facenameW[255];
4509 if (family->fonts[i]->oblique_sim_tested)
4510 continue;
4512 family->fonts[i]->oblique_sim_tested = 1;
4513 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4514 regular = i;
4515 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4516 oblique = i;
4518 /* find regular style with same weight/stretch values */
4519 for (j = i; j < family->count; ++j)
4521 if (family->fonts[j]->oblique_sim_tested)
4522 continue;
4524 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4525 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4527 family->fonts[j]->oblique_sim_tested = 1;
4528 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4529 regular = j;
4531 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4532 oblique = j;
4535 if (regular != ~0u && oblique != ~0u)
4536 break;
4539 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4540 if (regular == ~0u)
4541 continue;
4543 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4544 if (oblique != ~0u)
4545 continue;
4547 /* add oblique simulation based on this regular face */
4549 /* remove regular term if any, append 'Oblique' */
4550 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4551 facename_remove_regular_term(facenameW, -1);
4553 if (*facenameW) wcscat(facenameW, L" ");
4554 wcscat(facenameW, L"Oblique");
4556 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4557 obliqueface->oblique_sim_tested = 1;
4558 obliqueface->lf.lfItalic = 1;
4559 fontfamily_add_font(family, obliqueface);
4564 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4565 const WCHAR *replacement_name)
4567 UINT32 i = collection_find_family(collection, replacement_name);
4568 struct dwrite_fontfamily_data *target;
4569 IDWriteLocalizedStrings *strings;
4570 HRESULT hr;
4572 /* replacement does not exist */
4573 if (i == ~0u)
4574 return FALSE;
4576 hr = create_localizedstrings(&strings);
4577 if (FAILED(hr))
4578 return FALSE;
4580 /* add a new family with target name, reuse font data from replacement */
4581 add_localizedstring(strings, L"en-us", target_name);
4582 hr = init_fontfamily_data(strings, &target);
4583 if (hr == S_OK) {
4584 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4585 WCHAR nameW[255];
4587 for (i = 0; i < replacement->count; ++i)
4589 fontfamily_add_font(target, replacement->fonts[i]);
4590 addref_font_data(replacement->fonts[i]);
4593 fontcollection_add_family(collection, target);
4594 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4595 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4597 IDWriteLocalizedStrings_Release(strings);
4598 return TRUE;
4601 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4602 system font collections. */
4603 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4605 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4606 WCHAR *name;
4607 void *data;
4608 HKEY hkey;
4610 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4611 return;
4613 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4614 RegCloseKey(hkey);
4615 return;
4618 max_namelen++; /* returned value doesn't include room for '\0' */
4619 name = malloc(max_namelen * sizeof(WCHAR));
4620 data = malloc(max_datalen);
4622 datalen = max_datalen;
4623 namelen = max_namelen;
4624 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4625 if (collection_find_family(collection, name) == ~0u) {
4626 if (type == REG_MULTI_SZ) {
4627 WCHAR *replacement = data;
4628 while (*replacement) {
4629 if (fontcollection_add_replacement(collection, name, replacement))
4630 break;
4631 replacement += wcslen(replacement) + 1;
4634 else if (type == REG_SZ)
4635 fontcollection_add_replacement(collection, name, data);
4637 else
4638 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4640 datalen = max_datalen;
4641 namelen = max_namelen;
4644 free(data);
4645 free(name);
4646 RegCloseKey(hkey);
4649 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4650 IDWriteFontCollection3 **ret)
4652 struct fontfile_enum {
4653 struct list entry;
4654 IDWriteFontFile *file;
4656 struct fontfile_enum *fileenum, *fileenum2;
4657 struct dwrite_fontcollection *collection;
4658 struct list scannedfiles;
4659 BOOL current = FALSE;
4660 HRESULT hr = S_OK;
4661 size_t i;
4663 *ret = NULL;
4665 if (!(collection = calloc(1, sizeof(*collection))))
4666 return E_OUTOFMEMORY;
4668 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, is_system);
4669 if (FAILED(hr))
4671 free(collection);
4672 return hr;
4675 *ret = &collection->IDWriteFontCollection3_iface;
4677 TRACE("building font collection:\n");
4679 list_init(&scannedfiles);
4680 while (hr == S_OK) {
4681 DWRITE_FONT_FACE_TYPE face_type;
4682 DWRITE_FONT_FILE_TYPE file_type;
4683 BOOL supported, same = FALSE;
4684 IDWriteFontFileStream *stream;
4685 IDWriteFontFile *file;
4686 UINT32 face_count;
4688 current = FALSE;
4689 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4690 if (FAILED(hr) || !current)
4691 break;
4693 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4694 if (FAILED(hr))
4695 break;
4697 /* check if we've scanned this file already */
4698 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4699 if ((same = is_same_fontfile(fileenum->file, file)))
4700 break;
4703 if (same) {
4704 IDWriteFontFile_Release(file);
4705 continue;
4708 if (FAILED(get_filestream_from_file(file, &stream))) {
4709 IDWriteFontFile_Release(file);
4710 continue;
4713 /* Unsupported formats are skipped. */
4714 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4715 if (FAILED(hr) || !supported || face_count == 0) {
4716 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
4717 IDWriteFontFileStream_Release(stream);
4718 IDWriteFontFile_Release(file);
4719 hr = S_OK;
4720 continue;
4723 /* add to scanned list */
4724 fileenum = malloc(sizeof(*fileenum));
4725 fileenum->file = file;
4726 list_add_tail(&scannedfiles, &fileenum->entry);
4728 for (i = 0; i < face_count; ++i)
4730 struct dwrite_font_data *font_data;
4731 struct fontface_desc desc;
4732 WCHAR familyW[255];
4733 UINT32 index;
4735 desc.factory = factory;
4736 desc.face_type = face_type;
4737 desc.file = file;
4738 desc.stream = stream;
4739 desc.index = i;
4740 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4741 desc.font_data = NULL;
4743 /* Allocate an initialize new font data structure. */
4744 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
4745 if (FAILED(hr))
4747 /* move to next one */
4748 hr = S_OK;
4749 continue;
4752 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4754 /* ignore dot named faces */
4755 if (familyW[0] == '.')
4757 WARN("Ignoring face %s\n", debugstr_w(familyW));
4758 release_font_data(font_data);
4759 continue;
4762 index = collection_find_family(collection, familyW);
4763 if (index != ~0u)
4764 hr = fontfamily_add_font(collection->family_data[index], font_data);
4765 else {
4766 struct dwrite_fontfamily_data *family_data;
4768 /* create and init new family */
4769 hr = init_fontfamily_data(font_data->family_names, &family_data);
4770 if (hr == S_OK) {
4771 /* add font to family, family - to collection */
4772 hr = fontfamily_add_font(family_data, font_data);
4773 if (hr == S_OK)
4774 hr = fontcollection_add_family(collection, family_data);
4776 if (FAILED(hr))
4777 release_fontfamily_data(family_data);
4781 if (FAILED(hr))
4783 release_font_data(font_data);
4784 break;
4788 IDWriteFontFileStream_Release(stream);
4791 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry)
4793 IDWriteFontFile_Release(fileenum->file);
4794 list_remove(&fileenum->entry);
4795 free(fileenum);
4798 for (i = 0; i < collection->count; ++i)
4800 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4801 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4804 if (is_system)
4805 fontcollection_add_replacements(collection);
4807 return hr;
4810 static HRESULT collection_add_font_entry(struct dwrite_fontcollection *collection, const struct fontface_desc *desc)
4812 struct dwrite_font_data *font_data;
4813 WCHAR familyW[255];
4814 UINT32 index;
4815 HRESULT hr;
4817 if (FAILED(hr = init_font_data(desc, collection->family_model, &font_data)))
4818 return hr;
4820 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4822 /* ignore dot named faces */
4823 if (familyW[0] == '.')
4825 WARN("Ignoring face %s\n", debugstr_w(familyW));
4826 release_font_data(font_data);
4827 return S_OK;
4830 index = collection_find_family(collection, familyW);
4831 if (index != ~0u)
4832 hr = fontfamily_add_font(collection->family_data[index], font_data);
4833 else
4835 struct dwrite_fontfamily_data *family_data;
4837 /* Create and initialize new family */
4838 hr = init_fontfamily_data(font_data->family_names, &family_data);
4839 if (hr == S_OK)
4841 /* add font to family, family - to collection */
4842 hr = fontfamily_add_font(family_data, font_data);
4843 if (hr == S_OK)
4844 hr = fontcollection_add_family(collection, family_data);
4846 if (FAILED(hr))
4847 release_fontfamily_data(family_data);
4851 if (FAILED(hr))
4852 release_font_data(font_data);
4854 return hr;
4857 HRESULT create_font_collection_from_set(IDWriteFactory7 *factory, IDWriteFontSet *fontset,
4858 DWRITE_FONT_FAMILY_MODEL family_model, REFGUID riid, void **ret)
4860 struct dwrite_fontset *set = unsafe_impl_from_IDWriteFontSet(fontset);
4861 struct dwrite_fontcollection *collection;
4862 HRESULT hr = S_OK;
4863 size_t i;
4865 *ret = NULL;
4867 if (!(collection = calloc(1, sizeof(*collection))))
4868 return E_OUTOFMEMORY;
4870 if (FAILED(hr = init_font_collection(collection, factory, family_model, FALSE)))
4872 free(collection);
4873 return hr;
4876 for (i = 0; i < set->count; ++i)
4878 const struct dwrite_fontset_entry *entry = set->entries[i];
4879 IDWriteFontFileStream *stream;
4880 struct fontface_desc desc;
4882 if (FAILED(get_filestream_from_file(entry->desc.file, &stream)))
4884 WARN("Failed to get file stream.\n");
4885 continue;
4888 desc.factory = factory;
4889 desc.face_type = entry->desc.face_type;
4890 desc.file = entry->desc.file;
4891 desc.stream = stream;
4892 desc.index = entry->desc.face_index;
4893 desc.simulations = entry->desc.simulations;
4894 desc.font_data = NULL;
4896 if (FAILED(hr = collection_add_font_entry(collection, &desc)))
4897 WARN("Failed to add font collection element, hr %#lx.\n", hr);
4899 IDWriteFontFileStream_Release(stream);
4902 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE)
4904 for (i = 0; i < collection->count; ++i)
4906 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4907 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4911 hr = IDWriteFontCollection3_QueryInterface(&collection->IDWriteFontCollection3_iface, riid, ret);
4912 IDWriteFontCollection3_Release(&collection->IDWriteFontCollection3_iface);
4914 return hr;
4917 struct system_fontfile_enumerator
4919 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4920 LONG refcount;
4922 IDWriteFactory7 *factory;
4923 HKEY hkey;
4924 int index;
4926 WCHAR *filename;
4927 DWORD filename_size;
4930 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4932 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4935 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4937 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4938 IDWriteFontFileEnumerator_AddRef(iface);
4939 *obj = iface;
4940 return S_OK;
4943 WARN("%s not implemented.\n", debugstr_guid(riid));
4945 *obj = NULL;
4947 return E_NOINTERFACE;
4950 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4952 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4953 return InterlockedIncrement(&enumerator->refcount);
4956 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4958 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4959 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4961 if (!refcount)
4963 IDWriteFactory7_Release(enumerator->factory);
4964 RegCloseKey(enumerator->hkey);
4965 free(enumerator->filename);
4966 free(enumerator);
4969 return refcount;
4972 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4974 HRESULT hr;
4976 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4977 if (!wcschr(filename, '\\'))
4979 WCHAR fullpathW[MAX_PATH];
4981 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4982 wcscat(fullpathW, L"\\fonts\\");
4983 wcscat(fullpathW, filename);
4985 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4987 else
4988 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4990 return hr;
4993 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4995 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4997 *file = NULL;
4999 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
5000 return E_FAIL;
5002 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
5005 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
5007 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
5008 WCHAR name_buf[256], *name = name_buf;
5009 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
5010 HRESULT hr = S_OK;
5011 LONG r;
5013 *current = FALSE;
5014 enumerator->index++;
5016 /* iterate until we find next string value */
5017 for (;;) {
5018 do {
5019 name_count = max_name_count;
5020 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
5022 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
5023 NULL, &type, (BYTE *)enumerator->filename, &data_size);
5024 if (r == ERROR_MORE_DATA) {
5025 if (name_count >= max_name_count) {
5026 if (name != name_buf) free(name);
5027 max_name_count *= 2;
5028 name = malloc(max_name_count * sizeof(*name));
5029 if (!name) return E_OUTOFMEMORY;
5031 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename))
5033 free(enumerator->filename);
5034 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
5035 if (!(enumerator->filename = malloc(enumerator->filename_size)))
5037 hr = E_OUTOFMEMORY;
5038 goto err;
5042 } while (r == ERROR_MORE_DATA);
5044 if (r != ERROR_SUCCESS) {
5045 enumerator->filename[0] = 0;
5046 break;
5048 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
5049 if (type == REG_SZ && *name != '@') {
5050 *current = TRUE;
5051 break;
5053 enumerator->index++;
5055 TRACE("index = %d, current = %d\n", enumerator->index, *current);
5057 err:
5058 if (name != name_buf) free(name);
5059 return hr;
5062 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
5064 systemfontfileenumerator_QueryInterface,
5065 systemfontfileenumerator_AddRef,
5066 systemfontfileenumerator_Release,
5067 systemfontfileenumerator_MoveNext,
5068 systemfontfileenumerator_GetCurrentFontFile
5071 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
5073 struct system_fontfile_enumerator *enumerator;
5075 *ret = NULL;
5077 if (!(enumerator = calloc(1, sizeof(*enumerator))))
5078 return E_OUTOFMEMORY;
5080 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
5081 enumerator->refcount = 1;
5082 enumerator->factory = factory;
5083 enumerator->index = -1;
5084 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
5085 enumerator->filename = malloc(enumerator->filename_size);
5086 if (!enumerator->filename)
5088 free(enumerator);
5089 return E_OUTOFMEMORY;
5092 IDWriteFactory7_AddRef(factory);
5094 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0,
5095 GENERIC_READ, &enumerator->hkey))
5097 ERR("failed to open fonts list key\n");
5098 IDWriteFactory7_Release(factory);
5099 free(enumerator->filename);
5100 free(enumerator);
5101 return E_FAIL;
5104 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
5106 return S_OK;
5109 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, DWRITE_FONT_FAMILY_MODEL family_model,
5110 IDWriteFontCollection **collection)
5112 IDWriteFontFileEnumerator *enumerator;
5113 IDWriteFontSet *fontset;
5114 HRESULT hr;
5116 *collection = NULL;
5118 if (family_model == DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC)
5120 if (SUCCEEDED(hr = create_system_fontset(factory, &IID_IDWriteFontSet, (void **)&fontset)))
5122 hr = create_font_collection_from_set(factory, fontset, family_model,
5123 &IID_IDWriteFontCollection, (void **)collection);
5124 IDWriteFontSet_Release(fontset);
5127 else
5129 if (SUCCEEDED(hr = create_system_fontfile_enumerator(factory, &enumerator)))
5131 TRACE("Building system font collection for factory %p.\n", factory);
5132 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
5133 IDWriteFontFileEnumerator_Release(enumerator);
5137 return hr;
5140 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
5141 const WCHAR *keynameW, const WCHAR *pathW)
5143 struct dwrite_fontfamily_data *family_data;
5144 IDWriteLocalizedStrings *names;
5145 DWRITE_FONT_FACE_TYPE face_type;
5146 DWRITE_FONT_FILE_TYPE file_type;
5147 IDWriteFontFileStream *stream;
5148 IDWriteFontFile *file;
5149 UINT32 face_count, i;
5150 BOOL supported;
5151 HRESULT hr;
5153 /* create font file from this path */
5154 hr = create_local_file_reference(factory, pathW, &file);
5155 if (FAILED(hr))
5156 return S_FALSE;
5158 if (FAILED(get_filestream_from_file(file, &stream))) {
5159 IDWriteFontFile_Release(file);
5160 return S_FALSE;
5163 /* Unsupported formats are skipped. */
5164 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
5165 if (FAILED(hr) || !supported || face_count == 0) {
5166 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
5167 IDWriteFontFileStream_Release(stream);
5168 IDWriteFontFile_Release(file);
5169 return S_FALSE;
5172 /* create and init new family */
5174 /* Family names are added for non-specific locale, represented with empty string.
5175 Default family appears with empty family name. */
5176 create_localizedstrings(&names);
5177 if (!wcsicmp(keynameW, L"SystemDefaultEUDCFont"))
5178 add_localizedstring(names, L"", L"");
5179 else
5180 add_localizedstring(names, L"", keynameW);
5182 hr = init_fontfamily_data(names, &family_data);
5183 IDWriteLocalizedStrings_Release(names);
5184 if (hr != S_OK) {
5185 IDWriteFontFile_Release(file);
5186 return hr;
5189 /* fill with faces */
5190 for (i = 0; i < face_count; i++) {
5191 struct dwrite_font_data *font_data;
5192 struct fontface_desc desc;
5194 /* Allocate new font data structure. */
5195 desc.factory = factory;
5196 desc.face_type = face_type;
5197 desc.index = i;
5198 desc.file = file;
5199 desc.stream = stream;
5200 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
5201 desc.font_data = NULL;
5203 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5204 if (FAILED(hr))
5205 continue;
5207 /* add font to family */
5208 hr = fontfamily_add_font(family_data, font_data);
5209 if (hr != S_OK)
5210 release_font_data(font_data);
5213 /* add family to collection */
5214 hr = fontcollection_add_family(collection, family_data);
5215 if (FAILED(hr))
5216 release_fontfamily_data(family_data);
5217 IDWriteFontFileStream_Release(stream);
5218 IDWriteFontFile_Release(file);
5220 return hr;
5223 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
5225 struct dwrite_fontcollection *collection;
5226 WCHAR eudckeypathW[16];
5227 HKEY eudckey;
5228 UINT32 index;
5229 BOOL exists;
5230 LONG retval;
5231 HRESULT hr;
5232 size_t i;
5234 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
5236 *ret = NULL;
5238 if (!(collection = calloc(1, sizeof(*collection))))
5239 return E_OUTOFMEMORY;
5241 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, FALSE);
5242 if (FAILED(hr))
5244 free(collection);
5245 return hr;
5248 *ret = &collection->IDWriteFontCollection3_iface;
5250 /* return empty collection if EUDC fonts are not configured */
5251 swprintf(eudckeypathW, ARRAY_SIZE(eudckeypathW), L"EUDC\\%u", GetACP());
5252 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
5253 return S_OK;
5255 retval = ERROR_SUCCESS;
5256 index = 0;
5257 while (retval != ERROR_NO_MORE_ITEMS) {
5258 WCHAR keynameW[64], pathW[MAX_PATH];
5259 DWORD type, path_len, name_len;
5261 path_len = ARRAY_SIZE(pathW);
5262 name_len = ARRAY_SIZE(keynameW);
5263 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
5264 if (retval || type != REG_SZ)
5265 continue;
5267 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
5268 if (hr != S_OK)
5269 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
5271 RegCloseKey(eudckey);
5273 /* try to add global default if not defined for specific codepage */
5274 exists = FALSE;
5275 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, L"",
5276 &index, &exists);
5277 if (FAILED(hr) || !exists)
5279 hr = eudc_collection_add_family(factory, collection, L"", L"EUDC.TTE");
5280 if (hr != S_OK)
5281 WARN("failed to add global default EUDC font, 0x%08lx\n", hr);
5284 /* EUDC collection offers simulated faces too */
5285 for (i = 0; i < collection->count; ++i)
5287 fontfamily_add_bold_simulated_face(collection->family_data[i]);
5288 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
5291 return S_OK;
5294 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
5296 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5298 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
5300 *obj = iface;
5301 IDWriteFontFile_AddRef(iface);
5302 return S_OK;
5305 WARN("%s not implemented.\n", debugstr_guid(riid));
5307 *obj = NULL;
5308 return E_NOINTERFACE;
5311 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
5313 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5314 ULONG refcount = InterlockedIncrement(&file->refcount);
5316 TRACE("%p, refcount %ld.\n", iface, refcount);
5318 return refcount;
5321 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
5323 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5324 ULONG refcount = InterlockedDecrement(&file->refcount);
5326 TRACE("%p, refcount %ld.\n", iface, refcount);
5328 if (!refcount)
5330 IDWriteFontFileLoader_Release(file->loader);
5331 if (file->stream)
5332 IDWriteFontFileStream_Release(file->stream);
5333 free(file->reference_key);
5334 free(file);
5337 return refcount;
5340 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
5342 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5344 TRACE("%p, %p, %p.\n", iface, key, key_size);
5346 *key = file->reference_key;
5347 *key_size = file->key_size;
5349 return S_OK;
5352 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
5354 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5356 TRACE("%p, %p.\n", iface, loader);
5358 *loader = file->loader;
5359 IDWriteFontFileLoader_AddRef(*loader);
5361 return S_OK;
5364 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
5365 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
5367 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5368 IDWriteFontFileStream *stream;
5369 HRESULT hr;
5371 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
5373 *is_supported = FALSE;
5374 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
5375 if (face_type)
5376 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
5377 *face_count = 0;
5379 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
5380 if (FAILED(hr))
5381 return hr;
5383 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
5385 /* TODO: Further Analysis */
5386 IDWriteFontFileStream_Release(stream);
5387 return S_OK;
5390 static const IDWriteFontFileVtbl dwritefontfilevtbl =
5392 dwritefontfile_QueryInterface,
5393 dwritefontfile_AddRef,
5394 dwritefontfile_Release,
5395 dwritefontfile_GetReferenceKey,
5396 dwritefontfile_GetLoader,
5397 dwritefontfile_Analyze,
5400 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
5401 IDWriteFontFile **ret)
5403 struct dwrite_fontfile *file;
5404 void *key;
5406 *ret = NULL;
5408 file = calloc(1, sizeof(*file));
5409 key = malloc(key_size);
5410 if (!file || !key)
5412 free(file);
5413 free(key);
5414 return E_OUTOFMEMORY;
5417 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
5418 file->refcount = 1;
5419 IDWriteFontFileLoader_AddRef(loader);
5420 file->loader = loader;
5421 file->stream = NULL;
5422 file->reference_key = key;
5423 memcpy(file->reference_key, reference_key, key_size);
5424 file->key_size = key_size;
5426 *ret = &file->IDWriteFontFile_iface;
5428 return S_OK;
5431 static UINT64 dwrite_fontface_get_font_object(struct dwrite_fontface *fontface)
5433 struct create_font_object_params create_params;
5434 struct release_font_object_params release_params;
5435 UINT64 font_object, size;
5436 const void *data_ptr;
5437 void *data_context;
5439 if (!fontface->font_object && SUCCEEDED(IDWriteFontFileStream_GetFileSize(fontface->stream, &size)))
5441 if (SUCCEEDED(IDWriteFontFileStream_ReadFileFragment(fontface->stream, &data_ptr, 0, size, &data_context)))
5443 create_params.data = data_ptr;
5444 create_params.size = size;
5445 create_params.index = fontface->index;
5446 create_params.object = &font_object;
5448 UNIX_CALL(create_font_object, &create_params);
5450 if (!font_object)
5452 WARN("Backend failed to create font object.\n");
5453 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5454 return 0;
5457 if (!InterlockedCompareExchange64((LONGLONG *)&fontface->font_object, font_object, 0))
5459 fontface->data_context = data_context;
5461 else
5463 release_params.object = font_object;
5464 UNIX_CALL(release_font_object, &release_params);
5465 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5470 return fontface->font_object;
5473 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5475 struct file_stream_desc stream_desc;
5476 struct dwrite_font_data *font_data;
5477 struct dwrite_fontface *fontface;
5478 HRESULT hr;
5479 int i;
5481 *ret = NULL;
5483 if (!(fontface = calloc(1, sizeof(*fontface))))
5484 return E_OUTOFMEMORY;
5486 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5487 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5488 fontface->refcount = 1;
5489 fontface->type = desc->face_type;
5490 fontface->vdmx.exists = TRUE;
5491 fontface->gasp.exists = TRUE;
5492 fontface->cpal.exists = TRUE;
5493 fontface->colr.exists = TRUE;
5494 fontface->kern.exists = TRUE;
5495 fontface->index = desc->index;
5496 fontface->simulations = desc->simulations;
5497 fontface->factory = desc->factory;
5498 IDWriteFactory7_AddRef(fontface->factory);
5499 fontface->file = desc->file;
5500 IDWriteFontFile_AddRef(fontface->file);
5501 fontface->stream = desc->stream;
5502 IDWriteFontFileStream_AddRef(fontface->stream);
5503 InitializeCriticalSection(&fontface->cs);
5504 fontface_cache_init(fontface);
5506 stream_desc.stream = fontface->stream;
5507 stream_desc.face_type = desc->face_type;
5508 stream_desc.face_index = desc->index;
5509 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5510 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5511 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5512 /* TODO: test what happens if caret is already slanted */
5513 if (fontface->caret.slopeRise == 1) {
5514 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5515 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5518 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5520 /* Font properties are reused from font object when 'normal' face creation path is used:
5521 collection -> family -> matching font -> fontface.
5523 If face is created directly from factory we have to go through properties resolution.
5525 if (desc->font_data)
5527 font_data = addref_font_data(desc->font_data);
5529 else
5531 hr = init_font_data(desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5532 if (FAILED(hr))
5534 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5535 return hr;
5539 fontface->weight = font_data->weight;
5540 fontface->style = font_data->style;
5541 fontface->stretch = font_data->stretch;
5542 fontface->panose = font_data->panose;
5543 fontface->fontsig = font_data->fontsig;
5544 fontface->lf = font_data->lf;
5545 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5546 fontface->names = font_data->names;
5547 if (fontface->names)
5548 IDWriteLocalizedStrings_AddRef(fontface->names);
5549 fontface->family_names = font_data->family_names;
5550 if (fontface->family_names)
5551 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5552 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5553 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5555 if (fontface->info_strings[i])
5556 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5558 fontface->cmap.stream = fontface->stream;
5559 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5560 release_font_data(font_data);
5562 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5563 fontface->get_font_object = dwrite_fontface_get_font_object;
5565 *ret = &fontface->IDWriteFontFace5_iface;
5567 return S_OK;
5570 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5571 struct local_refkey
5573 FILETIME writetime;
5574 WCHAR name[1];
5577 struct local_cached_stream
5579 struct list entry;
5580 IDWriteFontFileStream *stream;
5581 struct local_refkey *key;
5582 UINT32 key_size;
5585 struct dwrite_localfontfilestream
5587 IDWriteFontFileStream IDWriteFontFileStream_iface;
5588 LONG refcount;
5590 struct local_cached_stream *entry;
5591 const void *file_ptr;
5592 UINT64 size;
5595 struct dwrite_localfontfileloader
5597 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5598 LONG refcount;
5600 struct list streams;
5601 CRITICAL_SECTION cs;
5604 static struct dwrite_localfontfileloader local_fontfile_loader;
5606 struct dwrite_inmemory_stream_data
5608 LONG refcount;
5609 IUnknown *owner;
5610 void *data;
5611 UINT32 size;
5614 struct dwrite_inmemory_filestream
5616 IDWriteFontFileStream IDWriteFontFileStream_iface;
5617 LONG refcount;
5619 struct dwrite_inmemory_stream_data *data;
5622 struct dwrite_inmemory_fileloader
5624 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5625 LONG refcount;
5627 struct dwrite_inmemory_stream_data **streams;
5628 size_t size;
5629 size_t count;
5632 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5634 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5637 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5639 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5642 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5644 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5647 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5649 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5652 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5654 if (InterlockedDecrement(&stream->refcount) == 0)
5656 if (stream->owner)
5657 IUnknown_Release(stream->owner);
5658 else
5659 free(stream->data);
5660 free(stream);
5664 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5666 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5668 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5670 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5671 IsEqualIID(riid, &IID_IUnknown))
5673 *obj = iface;
5674 if (InterlockedIncrement(&stream->refcount) == 1)
5676 InterlockedDecrement(&stream->refcount);
5677 *obj = NULL;
5678 return E_FAIL;
5680 return S_OK;
5683 WARN("%s not implemented.\n", debugstr_guid(riid));
5685 *obj = NULL;
5686 return E_NOINTERFACE;
5689 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5691 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5692 ULONG refcount = InterlockedIncrement(&stream->refcount);
5694 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5696 return refcount;
5699 static inline void release_cached_stream(struct local_cached_stream *stream)
5701 list_remove(&stream->entry);
5702 free(stream->key);
5703 free(stream);
5706 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5708 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5709 ULONG refcount = InterlockedDecrement(&stream->refcount);
5711 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5713 if (!refcount)
5715 UnmapViewOfFile(stream->file_ptr);
5717 EnterCriticalSection(&local_fontfile_loader.cs);
5718 release_cached_stream(stream->entry);
5719 LeaveCriticalSection(&local_fontfile_loader.cs);
5721 free(stream);
5724 return refcount;
5727 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5728 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5730 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5732 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5733 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5735 *fragment_context = NULL;
5737 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5739 *fragment_start = NULL;
5740 return E_FAIL;
5743 *fragment_start = (char *)stream->file_ptr + offset;
5744 return S_OK;
5747 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5749 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5752 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5754 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5756 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5758 *size = stream->size;
5759 return S_OK;
5762 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5764 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5765 ULARGE_INTEGER li;
5767 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5769 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5770 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5771 *last_writetime = li.QuadPart;
5773 return S_OK;
5776 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5778 localfontfilestream_QueryInterface,
5779 localfontfilestream_AddRef,
5780 localfontfilestream_Release,
5781 localfontfilestream_ReadFileFragment,
5782 localfontfilestream_ReleaseFileFragment,
5783 localfontfilestream_GetFileSize,
5784 localfontfilestream_GetLastWriteTime
5787 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5788 IDWriteFontFileStream **ret)
5790 struct dwrite_localfontfilestream *object;
5792 *ret = NULL;
5794 if (!(object = calloc(1, sizeof(*object))))
5795 return E_OUTOFMEMORY;
5797 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5798 object->refcount = 1;
5800 object->file_ptr = file_ptr;
5801 object->size = size;
5802 object->entry = entry;
5804 *ret = &object->IDWriteFontFileStream_iface;
5806 return S_OK;
5809 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5811 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5813 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5814 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5815 IsEqualIID(riid, &IID_IUnknown))
5817 *obj = iface;
5818 IDWriteLocalFontFileLoader_AddRef(iface);
5819 return S_OK;
5822 WARN("%s not implemented.\n", debugstr_guid(riid));
5824 *obj = NULL;
5825 return E_NOINTERFACE;
5828 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5830 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5831 ULONG refcount = InterlockedIncrement(&loader->refcount);
5833 TRACE("%p, refcount %ld.\n", iface, refcount);
5835 return refcount;
5838 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5840 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5841 ULONG refcount = InterlockedDecrement(&loader->refcount);
5843 TRACE("%p, refcount %ld.\n", iface, refcount);
5845 return refcount;
5848 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5850 const struct local_refkey *refkey = key;
5851 struct local_cached_stream *stream;
5852 IDWriteFontFileStream *filestream;
5853 HANDLE file, mapping;
5854 LARGE_INTEGER size;
5855 void *file_ptr;
5856 HRESULT hr = S_OK;
5858 *ret = NULL;
5860 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5861 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5862 if (file == INVALID_HANDLE_VALUE) {
5863 WARN_(dwrite_file)("Failed to open the file %s, error %ld.\n", debugstr_w(refkey->name), GetLastError());
5864 return E_FAIL;
5867 GetFileSizeEx(file, &size);
5868 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5869 CloseHandle(file);
5870 if (!mapping)
5871 return E_FAIL;
5873 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5874 CloseHandle(mapping);
5875 if (!file_ptr) {
5876 ERR("mapping failed, file size %s, error %ld\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5877 return E_FAIL;
5880 if (!(stream = malloc(sizeof(*stream))))
5882 UnmapViewOfFile(file_ptr);
5883 return E_OUTOFMEMORY;
5886 if (!(stream->key = malloc(key_size)))
5888 UnmapViewOfFile(file_ptr);
5889 free(stream);
5890 return E_OUTOFMEMORY;
5893 stream->key_size = key_size;
5894 memcpy(stream->key, key, key_size);
5896 if (FAILED(hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream)))
5898 UnmapViewOfFile(file_ptr);
5899 free(stream->key);
5900 free(stream);
5901 return hr;
5904 stream->stream = filestream;
5906 *ret = stream;
5908 return S_OK;
5911 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5912 UINT32 key_size, IDWriteFontFileStream **ret)
5914 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5915 struct local_cached_stream *stream;
5916 HRESULT hr = S_OK;
5918 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5920 EnterCriticalSection(&loader->cs);
5922 *ret = NULL;
5924 /* search cache first */
5925 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5927 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5928 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5929 break;
5933 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5935 list_add_head(&loader->streams, &stream->entry);
5936 *ret = stream->stream;
5939 LeaveCriticalSection(&loader->cs);
5941 return hr;
5944 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5945 UINT32 key_size, UINT32 *length)
5947 const struct local_refkey *refkey = key;
5949 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5951 *length = wcslen(refkey->name);
5952 return S_OK;
5955 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5956 UINT32 key_size, WCHAR *path, UINT32 length)
5958 const struct local_refkey *refkey = key;
5960 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5962 if (length < wcslen(refkey->name))
5963 return E_INVALIDARG;
5965 wcscpy(path, refkey->name);
5966 return S_OK;
5969 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5970 UINT32 key_size, FILETIME *writetime)
5972 const struct local_refkey *refkey = key;
5974 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5976 *writetime = refkey->writetime;
5977 return S_OK;
5980 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5982 localfontfileloader_QueryInterface,
5983 localfontfileloader_AddRef,
5984 localfontfileloader_Release,
5985 localfontfileloader_CreateStreamFromKey,
5986 localfontfileloader_GetFilePathLengthFromKey,
5987 localfontfileloader_GetFilePathFromKey,
5988 localfontfileloader_GetLastWriteTimeFromKey
5991 void init_local_fontfile_loader(void)
5993 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5994 local_fontfile_loader.refcount = 1;
5995 list_init(&local_fontfile_loader.streams);
5996 InitializeCriticalSectionEx(&local_fontfile_loader.cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
5997 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
6000 IDWriteFontFileLoader *get_local_fontfile_loader(void)
6002 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
6005 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
6007 struct local_refkey *refkey;
6009 if (!path)
6010 return E_INVALIDARG;
6012 *size = FIELD_OFFSET(struct local_refkey, name) + (wcslen(path)+1)*sizeof(WCHAR);
6013 *key = NULL;
6015 if (!(refkey = malloc(*size)))
6016 return E_OUTOFMEMORY;
6018 if (writetime)
6019 refkey->writetime = *writetime;
6020 else {
6021 WIN32_FILE_ATTRIBUTE_DATA info;
6023 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
6024 refkey->writetime = info.ftLastWriteTime;
6025 else
6026 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
6028 wcscpy(refkey->name, path);
6030 *key = refkey;
6032 return S_OK;
6035 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
6037 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6039 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
6040 IsEqualIID(riid, &IID_IUnknown))
6042 *ppv = iface;
6043 IDWriteGlyphRunAnalysis_AddRef(iface);
6044 return S_OK;
6047 WARN("%s not implemented.\n", debugstr_guid(riid));
6049 *ppv = NULL;
6050 return E_NOINTERFACE;
6053 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
6055 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6056 ULONG refcount = InterlockedIncrement(&analysis->refcount);
6058 TRACE("%p, refcount %ld.\n", iface, refcount);
6060 return refcount;
6063 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
6065 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6066 ULONG refcount = InterlockedDecrement(&analysis->refcount);
6068 TRACE("%p, refcount %ld.\n", iface, refcount);
6070 if (!refcount)
6072 if (analysis->run.fontFace)
6073 IDWriteFontFace_Release(analysis->run.fontFace);
6074 free(analysis->glyphs);
6075 free(analysis->origins);
6076 free(analysis->bitmap);
6077 free(analysis);
6080 return refcount;
6083 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
6085 struct dwrite_glyphbitmap glyph_bitmap;
6086 UINT32 i;
6088 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
6089 *bounds = analysis->bounds;
6090 return;
6093 if (analysis->run.isSideways)
6094 FIXME("sideways runs are not supported.\n");
6096 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6097 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(analysis->run.fontFace);
6098 glyph_bitmap.emsize = analysis->run.fontEmSize;
6099 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6100 glyph_bitmap.m = &analysis->m;
6102 for (i = 0; i < analysis->run.glyphCount; i++) {
6103 RECT *bbox = &glyph_bitmap.bbox;
6104 UINT32 bitmap_size;
6106 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6107 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6109 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
6110 (bbox->bottom - bbox->top);
6111 if (bitmap_size > analysis->max_glyph_bitmap_size)
6112 analysis->max_glyph_bitmap_size = bitmap_size;
6114 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6115 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
6118 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
6119 *bounds = analysis->bounds;
6122 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
6123 DWRITE_TEXTURE_TYPE type, RECT *bounds)
6125 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6127 TRACE("%p, %d, %p.\n", iface, type, bounds);
6129 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
6130 SetRectEmpty(bounds);
6131 return E_INVALIDARG;
6134 if (type != analysis->texture_type)
6136 SetRectEmpty(bounds);
6137 return S_OK;
6140 glyphrunanalysis_get_texturebounds(analysis, bounds);
6141 return S_OK;
6144 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
6146 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6147 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
6148 (runbounds->left - bounds->left) * 3;
6149 else
6150 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
6151 runbounds->left - bounds->left;
6154 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
6156 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6157 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(analysis->run.fontFace);
6158 struct dwrite_glyphbitmap glyph_bitmap;
6159 D2D_POINT_2F origin;
6160 UINT32 i, size;
6161 RECT *bbox;
6163 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
6164 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6165 size *= 3;
6166 if (!(analysis->bitmap = calloc(1, size)))
6168 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
6169 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
6170 return E_OUTOFMEMORY;
6173 origin.x = origin.y = 0.0f;
6175 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6176 glyph_bitmap.simulations = fontface->simulations;
6177 glyph_bitmap.emsize = analysis->run.fontEmSize;
6178 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6179 glyph_bitmap.m = &analysis->m;
6180 if (!(glyph_bitmap.buf = malloc(analysis->max_glyph_bitmap_size)))
6181 return E_OUTOFMEMORY;
6183 bbox = &glyph_bitmap.bbox;
6185 for (i = 0; i < analysis->run.glyphCount; ++i)
6187 BYTE *src = glyph_bitmap.buf, *dst;
6188 int x, y, width, height;
6189 unsigned int is_1bpp;
6191 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6192 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6194 if (IsRectEmpty(bbox))
6195 continue;
6197 width = bbox->right - bbox->left;
6198 height = bbox->bottom - bbox->top;
6200 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
6201 memset(src, 0, height * glyph_bitmap.pitch);
6203 if (FAILED(dwrite_fontface_get_glyph_bitmap(fontface, analysis->rendering_mode, &is_1bpp, &glyph_bitmap)))
6205 WARN("Failed to render glyph[%u] = %#x.\n", i, glyph_bitmap.glyph);
6206 continue;
6209 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6211 /* blit to analysis bitmap */
6212 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
6214 if (is_1bpp) {
6215 /* convert 1bpp to 8bpp/24bpp */
6216 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6217 for (y = 0; y < height; y++) {
6218 for (x = 0; x < width; x++)
6219 if (src[x / 8] & masks[x % 8])
6220 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
6221 src += glyph_bitmap.pitch;
6222 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6225 else {
6226 for (y = 0; y < height; y++) {
6227 for (x = 0; x < width; x++)
6228 if (src[x / 8] & masks[x % 8])
6229 dst[x] = DWRITE_ALPHA_MAX;
6230 src += glyph_bitmap.pitch;
6231 dst += analysis->bounds.right - analysis->bounds.left;
6235 else {
6236 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6237 for (y = 0; y < height; y++) {
6238 for (x = 0; x < width; x++)
6239 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
6240 src += glyph_bitmap.pitch;
6241 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6244 else {
6245 for (y = 0; y < height; y++) {
6246 for (x = 0; x < width; x++)
6247 dst[x] |= src[x];
6248 src += glyph_bitmap.pitch;
6249 dst += analysis->bounds.right - analysis->bounds.left;
6254 free(glyph_bitmap.buf);
6256 analysis->flags |= RUNANALYSIS_BITMAP_READY;
6258 /* we don't need this anymore */
6259 free(analysis->glyphs);
6260 free(analysis->origins);
6261 IDWriteFontFace_Release(analysis->run.fontFace);
6263 analysis->glyphs = NULL;
6264 analysis->origins = NULL;
6265 analysis->run.glyphIndices = NULL;
6266 analysis->run.fontFace = NULL;
6268 return S_OK;
6271 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
6272 RECT const *bounds, BYTE *bitmap, UINT32 size)
6274 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6275 UINT32 required;
6276 RECT runbounds;
6278 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
6280 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
6281 return E_INVALIDARG;
6283 /* make sure buffer is large enough for requested texture type */
6284 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
6285 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6286 required *= 3;
6288 if (size < required)
6289 return E_NOT_SUFFICIENT_BUFFER;
6291 /* validate requested texture type */
6292 if (analysis->texture_type != type)
6293 return DWRITE_E_UNSUPPORTEDOPERATION;
6295 memset(bitmap, 0, size);
6296 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
6297 if (IntersectRect(&runbounds, &runbounds, bounds))
6299 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
6300 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
6301 int dst_width = (bounds->right - bounds->left) * pixel_size;
6302 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
6303 BYTE *src, *dst;
6304 int y;
6306 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
6308 HRESULT hr;
6310 if (FAILED(hr = glyphrunanalysis_render(analysis)))
6311 return hr;
6314 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
6315 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
6317 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
6318 memcpy(dst, src, draw_width);
6319 src += src_width;
6320 dst += dst_width;
6324 return S_OK;
6327 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
6328 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
6330 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6332 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
6334 if (!params)
6335 return E_INVALIDARG;
6337 switch (analysis->rendering_mode)
6339 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
6340 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
6342 UINT value = 0;
6343 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6344 *gamma = (FLOAT)value / 1000.0f;
6345 *contrast = 0.0f;
6346 *cleartypelevel = 1.0f;
6347 break;
6349 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
6350 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
6351 /* fallthrough */
6352 case DWRITE_RENDERING_MODE1_ALIASED:
6353 case DWRITE_RENDERING_MODE1_NATURAL:
6354 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
6355 *gamma = IDWriteRenderingParams_GetGamma(params);
6356 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
6357 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
6358 break;
6359 default:
6363 return S_OK;
6366 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
6368 glyphrunanalysis_QueryInterface,
6369 glyphrunanalysis_AddRef,
6370 glyphrunanalysis_Release,
6371 glyphrunanalysis_GetAlphaTextureBounds,
6372 glyphrunanalysis_CreateAlphaTexture,
6373 glyphrunanalysis_GetAlphaBlendParams
6376 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
6378 D2D_POINT_2F ret;
6379 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
6380 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
6381 *point = ret;
6384 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
6385 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
6387 unsigned int upem = fontface->metrics.designUnitsPerEm;
6388 int advance;
6390 if (is_sideways)
6391 FIXME("Sideways mode is not supported.\n");
6393 EnterCriticalSection(&fontface->cs);
6394 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
6395 LeaveCriticalSection(&fontface->cs);
6397 switch (measuring_mode)
6399 case DWRITE_MEASURING_MODE_NATURAL:
6400 return (float)advance * emsize / (float)upem;
6401 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6402 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6403 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
6404 default:
6405 WARN("Unknown measuring mode %u.\n", measuring_mode);
6406 return 0.0f;
6410 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
6412 struct dwrite_glyphrunanalysis *analysis;
6413 unsigned int i;
6415 *ret = NULL;
6417 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
6418 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
6419 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
6420 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
6421 return E_INVALIDARG;
6423 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6424 return E_INVALIDARG;
6426 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
6427 return E_INVALIDARG;
6429 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
6430 return E_INVALIDARG;
6432 if (!(analysis = calloc(1, sizeof(*analysis))))
6433 return E_OUTOFMEMORY;
6435 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
6436 analysis->refcount = 1;
6437 analysis->rendering_mode = desc->rendering_mode;
6439 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
6440 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6441 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6442 else
6443 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6445 analysis->run = *desc->run;
6446 IDWriteFontFace_AddRef(analysis->run.fontFace);
6447 analysis->glyphs = calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6448 analysis->origins = calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6450 if (!analysis->glyphs || !analysis->origins)
6452 free(analysis->glyphs);
6453 free(analysis->origins);
6455 analysis->glyphs = NULL;
6456 analysis->origins = NULL;
6458 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6459 return E_OUTOFMEMORY;
6462 /* check if transform is usable */
6463 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6464 analysis->m = *desc->transform;
6465 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6468 analysis->run.glyphIndices = analysis->glyphs;
6469 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6471 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6472 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6474 for (i = 0; i < desc->run->glyphCount; ++i)
6475 transform_point(&analysis->origins[i], &analysis->m);
6478 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6479 return S_OK;
6482 /* IDWriteColorGlyphRunEnumerator1 */
6483 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6485 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6487 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6488 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6489 IsEqualIID(riid, &IID_IUnknown))
6491 *ppv = iface;
6492 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6493 return S_OK;
6496 WARN("%s not implemented.\n", debugstr_guid(riid));
6498 *ppv = NULL;
6499 return E_NOINTERFACE;
6502 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6504 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6505 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6507 TRACE("%p, refcount %lu.\n", iface, refcount);
6509 return refcount;
6512 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6514 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6515 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6517 TRACE("%p, refcount %lu.\n", iface, refcount);
6519 if (!refcount)
6521 free(glyphenum->advances);
6522 free(glyphenum->color_advances);
6523 free(glyphenum->offsets);
6524 free(glyphenum->color_offsets);
6525 free(glyphenum->glyphindices);
6526 free(glyphenum->glyphs);
6527 if (glyphenum->colr.context)
6528 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6529 IDWriteFontFace5_Release(glyphenum->fontface);
6530 free(glyphenum);
6533 return refcount;
6536 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6538 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6539 FLOAT origin = 0.0f;
6541 if (g == 0)
6542 return 0.0f;
6544 while (g--)
6545 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6546 return origin;
6549 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6551 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6552 FLOAT advance_adj = 0.0f;
6553 BOOL got_palette_index;
6554 UINT32 g;
6556 /* start with regular glyphs */
6557 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6558 UINT32 first_glyph = 0;
6560 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6561 if (glyphenum->glyphs[g].num_layers == 0) {
6562 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6563 first_glyph = min(first_glyph, g);
6565 else
6566 glyphenum->glyphindices[g] = 1;
6567 glyphenum->color_advances[g] = glyphenum->advances[g];
6568 if (glyphenum->color_offsets)
6569 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6572 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, first_glyph);
6573 colorrun->baselineOriginY = glyphenum->origin.y;
6574 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6575 colorrun->paletteIndex = 0xffff;
6576 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6577 glyphenum->has_regular_glyphs = FALSE;
6578 return TRUE;
6580 else {
6581 colorrun->glyphRun.glyphCount = 0;
6582 got_palette_index = FALSE;
6585 advance_adj = 0.0f;
6586 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6588 glyphenum->glyphindices[g] = 1;
6590 /* all glyph layers were returned */
6591 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6592 advance_adj += glyphenum->advances[g];
6593 continue;
6596 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6597 UINT32 index = colorrun->glyphRun.glyphCount;
6598 if (!got_palette_index) {
6599 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6600 /* use foreground color or request one from the font */
6601 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6602 if (colorrun->paletteIndex != 0xffff)
6604 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6605 colorrun->paletteIndex, 1, &colorrun->runColor);
6606 if (FAILED(hr))
6607 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08lx\n", glyphenum->fontface,
6608 glyphenum->palette, colorrun->paletteIndex, hr);
6610 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6611 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, g);
6612 colorrun->baselineOriginY = glyphenum->origin.y;
6613 glyphenum->color_advances[index] = glyphenum->advances[g];
6614 got_palette_index = TRUE;
6617 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6618 /* offsets are relative to glyph origin, nothing to fix up */
6619 if (glyphenum->color_offsets)
6620 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6621 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6622 if (index)
6623 glyphenum->color_advances[index-1] += advance_adj;
6624 colorrun->glyphRun.glyphCount++;
6625 advance_adj = 0.0f;
6627 else
6628 advance_adj += glyphenum->advances[g];
6631 /* reset last advance */
6632 if (colorrun->glyphRun.glyphCount)
6633 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6635 return colorrun->glyphRun.glyphCount > 0;
6638 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6640 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6642 TRACE("%p, %p.\n", iface, has_run);
6644 *has_run = FALSE;
6646 glyphenum->colorrun.glyphRun.glyphCount = 0;
6647 while (glyphenum->current_layer < glyphenum->max_layer_num)
6649 if (colorglyphenum_build_color_run(glyphenum))
6650 break;
6651 else
6652 glyphenum->current_layer++;
6655 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6657 return S_OK;
6660 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6661 DWRITE_COLOR_GLYPH_RUN1 const **run)
6663 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6665 *run = NULL;
6666 return E_NOT_VALID_STATE;
6669 *run = &glyphenum->colorrun;
6670 return S_OK;
6673 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6674 DWRITE_COLOR_GLYPH_RUN const **run)
6676 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6678 TRACE("%p, %p.\n", iface, run);
6680 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6683 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6684 DWRITE_COLOR_GLYPH_RUN1 const **run)
6686 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6688 TRACE("%p, %p.\n", iface, run);
6690 return colorglyphenum_get_current_run(glyphenum, run);
6693 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6695 colorglyphenum_QueryInterface,
6696 colorglyphenum_AddRef,
6697 colorglyphenum_Release,
6698 colorglyphenum_MoveNext,
6699 colorglyphenum_GetCurrentRun,
6700 colorglyphenum1_GetCurrentRun,
6703 HRESULT create_colorglyphenum(D2D1_POINT_2F origin, const DWRITE_GLYPH_RUN *run,
6704 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_GLYPH_IMAGE_FORMATS formats, DWRITE_MEASURING_MODE measuring_mode,
6705 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator1 **ret)
6707 struct dwrite_colorglyphenum *colorglyphenum;
6708 BOOL colorfont, has_colored_glyph;
6709 struct dwrite_fontface *fontface;
6710 unsigned int i;
6712 *ret = NULL;
6714 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6716 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6717 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6718 if (!colorfont)
6719 return DWRITE_E_NOCOLOR;
6721 if (!(formats & (DWRITE_GLYPH_IMAGE_FORMATS_COLR |
6722 DWRITE_GLYPH_IMAGE_FORMATS_SVG |
6723 DWRITE_GLYPH_IMAGE_FORMATS_PNG |
6724 DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
6725 DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
6726 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8)))
6728 return DWRITE_E_NOCOLOR;
6731 if (formats & ~(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_CFF | DWRITE_GLYPH_IMAGE_FORMATS_COLR))
6733 FIXME("Unimplemented formats requested %#x.\n", formats);
6734 return E_NOTIMPL;
6737 if (!(colorglyphenum = calloc(1, sizeof(*colorglyphenum))))
6738 return E_OUTOFMEMORY;
6740 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6741 colorglyphenum->refcount = 1;
6742 colorglyphenum->origin = origin;
6743 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6744 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6745 colorglyphenum->glyphs = NULL;
6746 colorglyphenum->run = *run;
6747 colorglyphenum->run.glyphIndices = NULL;
6748 colorglyphenum->run.glyphAdvances = NULL;
6749 colorglyphenum->run.glyphOffsets = NULL;
6750 colorglyphenum->palette = palette;
6751 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6752 colorglyphenum->colr.exists = TRUE;
6753 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6754 colorglyphenum->current_layer = 0;
6755 colorglyphenum->max_layer_num = 0;
6757 colorglyphenum->glyphs = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphs));
6759 has_colored_glyph = FALSE;
6760 colorglyphenum->has_regular_glyphs = FALSE;
6761 for (i = 0; i < run->glyphCount; i++) {
6762 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6763 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6764 has_colored_glyph = TRUE;
6766 if (colorglyphenum->glyphs[i].num_layers == 0)
6767 colorglyphenum->has_regular_glyphs = TRUE;
6770 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6771 is supposed to proceed normally, like if font had no color info at all. */
6772 if (!has_colored_glyph) {
6773 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6774 return DWRITE_E_NOCOLOR;
6777 colorglyphenum->advances = calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6778 colorglyphenum->color_advances = calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6779 colorglyphenum->glyphindices = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6780 if (run->glyphOffsets) {
6781 colorglyphenum->offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6782 colorglyphenum->color_offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6783 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6786 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6787 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6788 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6789 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6790 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6791 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6792 colorglyphenum->colorrun.measuringMode = measuring_mode;
6793 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6795 if (run->glyphAdvances)
6796 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6797 else
6799 for (i = 0; i < run->glyphCount; ++i)
6800 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6801 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6804 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6806 return S_OK;
6809 /* IDWriteFontFaceReference */
6810 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6812 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6814 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6815 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6816 IsEqualIID(riid, &IID_IUnknown))
6818 *obj = iface;
6819 IDWriteFontFaceReference1_AddRef(iface);
6820 return S_OK;
6823 WARN("%s not implemented.\n", debugstr_guid(riid));
6825 *obj = NULL;
6827 return E_NOINTERFACE;
6830 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6832 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6833 ULONG refcount = InterlockedIncrement(&reference->refcount);
6835 TRACE("%p, refcount %lu.\n", iface, refcount);
6837 return refcount;
6840 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6842 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6843 ULONG refcount = InterlockedDecrement(&reference->refcount);
6845 TRACE("%p, refcount %lu.\n", iface, refcount);
6847 if (!refcount)
6849 IDWriteFontFile_Release(reference->file);
6850 IDWriteFactory7_Release(reference->factory);
6851 free(reference->axis_values);
6852 free(reference);
6855 return refcount;
6858 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6860 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6862 TRACE("%p, %p.\n", iface, fontface);
6864 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6867 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6868 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6870 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6871 DWRITE_FONT_FILE_TYPE file_type;
6872 DWRITE_FONT_FACE_TYPE face_type;
6873 IDWriteFontFace *fontface;
6874 BOOL is_supported;
6875 UINT32 face_num;
6876 HRESULT hr;
6878 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6880 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6881 if (FAILED(hr))
6882 return hr;
6884 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6885 simulations, &fontface);
6886 if (SUCCEEDED(hr))
6888 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6889 IDWriteFontFace_Release(fontface);
6892 return hr;
6895 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6897 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6898 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6899 BOOL ret;
6901 TRACE("%p, %p.\n", iface, ref);
6903 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6904 reference->simulations == other->simulations;
6905 if (reference->axis_values_count)
6907 ret &= reference->axis_values_count == other->axis_values_count &&
6908 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6911 return ret;
6914 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6916 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6918 TRACE("%p.\n", iface);
6920 return reference->index;
6923 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6925 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6927 TRACE("%p.\n", iface);
6929 return reference->simulations;
6932 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6934 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6935 IDWriteFontFileLoader *loader;
6936 const void *key;
6937 UINT32 key_size;
6938 HRESULT hr;
6940 TRACE("%p, %p.\n", iface, file);
6942 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6943 if (FAILED(hr))
6944 return hr;
6946 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6947 if (FAILED(hr))
6948 return hr;
6950 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6951 IDWriteFontFileLoader_Release(loader);
6953 return hr;
6956 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6958 FIXME("%p.\n", iface);
6960 return 0;
6963 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6965 FIXME("%p.\n", iface);
6967 return 0;
6970 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6972 FIXME("%p, %p.\n", iface, writetime);
6974 return E_NOTIMPL;
6977 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6979 FIXME("%p.\n", iface);
6981 return DWRITE_LOCALITY_LOCAL;
6984 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6986 FIXME("%p.\n", iface);
6988 return E_NOTIMPL;
6991 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6992 WCHAR const *chars, UINT32 count)
6994 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6996 return E_NOTIMPL;
6999 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
7000 UINT16 const *glyphs, UINT32 count)
7002 FIXME("%p, %p, %u.\n", iface, glyphs, count);
7004 return E_NOTIMPL;
7007 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
7008 UINT64 offset, UINT64 size)
7010 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
7012 return E_NOTIMPL;
7015 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
7017 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7018 IDWriteFontFace3 *fontface3;
7019 HRESULT hr;
7021 TRACE("%p, %p.\n", iface, fontface);
7023 /* FIXME: created instance should likely respect given axis. */
7024 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
7025 &fontface3)))
7027 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
7028 IDWriteFontFace3_Release(fontface3);
7031 return hr;
7034 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
7036 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7038 TRACE("%p.\n", iface);
7040 return reference->axis_values_count;
7043 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
7044 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
7046 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7048 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
7050 if (value_count < reference->axis_values_count)
7051 return E_NOT_SUFFICIENT_BUFFER;
7053 memcpy(axis_values, reference->axis_values, reference->axis_values_count * sizeof(*axis_values));
7055 return S_OK;
7058 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
7060 fontfacereference_QueryInterface,
7061 fontfacereference_AddRef,
7062 fontfacereference_Release,
7063 fontfacereference_CreateFontFace,
7064 fontfacereference_CreateFontFaceWithSimulations,
7065 fontfacereference_Equals,
7066 fontfacereference_GetFontFaceIndex,
7067 fontfacereference_GetSimulations,
7068 fontfacereference_GetFontFile,
7069 fontfacereference_GetLocalFileSize,
7070 fontfacereference_GetFileSize,
7071 fontfacereference_GetFileTime,
7072 fontfacereference_GetLocality,
7073 fontfacereference_EnqueueFontDownloadRequest,
7074 fontfacereference_EnqueueCharacterDownloadRequest,
7075 fontfacereference_EnqueueGlyphDownloadRequest,
7076 fontfacereference_EnqueueFileFragmentDownloadRequest,
7077 fontfacereference1_CreateFontFace,
7078 fontfacereference1_GetFontAxisValueCount,
7079 fontfacereference1_GetFontAxisValues,
7082 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
7083 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
7084 IDWriteFontFaceReference1 **ret)
7086 struct dwrite_fontfacereference *object;
7088 *ret = NULL;
7090 if (!is_simulation_valid(simulations))
7091 return E_INVALIDARG;
7093 if (!(object = calloc(1, sizeof(*object))))
7094 return E_OUTOFMEMORY;
7096 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
7097 object->refcount = 1;
7099 object->factory = factory;
7100 IDWriteFactory7_AddRef(object->factory);
7101 object->file = file;
7102 IDWriteFontFile_AddRef(object->file);
7103 object->index = index;
7104 object->simulations = simulations;
7105 if (axis_values_count)
7107 if (!(object->axis_values = malloc(axis_values_count * sizeof(*axis_values))))
7109 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
7110 return E_OUTOFMEMORY;
7112 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
7113 object->axis_values_count = axis_values_count;
7116 *ret = &object->IDWriteFontFaceReference1_iface;
7118 return S_OK;
7121 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
7123 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7125 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
7126 *obj = iface;
7127 IDWriteFontFileStream_AddRef(iface);
7128 return S_OK;
7131 *obj = NULL;
7133 WARN("%s not implemented.\n", debugstr_guid(riid));
7134 return E_NOINTERFACE;
7137 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
7139 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7140 ULONG refcount = InterlockedIncrement(&stream->refcount);
7142 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7144 return refcount;
7147 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
7149 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7150 ULONG refcount = InterlockedDecrement(&stream->refcount);
7152 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7154 if (!refcount)
7156 release_inmemory_stream(stream->data);
7157 free(stream);
7160 return refcount;
7163 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
7164 UINT64 offset, UINT64 fragment_size, void **fragment_context)
7166 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7168 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
7169 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
7171 *fragment_context = NULL;
7173 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
7174 *fragment_start = NULL;
7175 return E_FAIL;
7178 *fragment_start = (char *)stream->data->data + offset;
7179 return S_OK;
7182 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
7184 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
7187 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
7189 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7191 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
7193 *size = stream->data->size;
7195 return S_OK;
7198 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
7200 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
7202 *last_writetime = 0;
7204 return E_NOTIMPL;
7207 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
7208 inmemoryfilestream_QueryInterface,
7209 inmemoryfilestream_AddRef,
7210 inmemoryfilestream_Release,
7211 inmemoryfilestream_ReadFileFragment,
7212 inmemoryfilestream_ReleaseFileFragment,
7213 inmemoryfilestream_GetFileSize,
7214 inmemoryfilestream_GetLastWriteTime,
7217 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
7218 REFIID riid, void **obj)
7220 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7222 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
7223 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
7224 IsEqualIID(riid, &IID_IUnknown))
7226 *obj = iface;
7227 IDWriteInMemoryFontFileLoader_AddRef(iface);
7228 return S_OK;
7231 WARN("%s not implemented.\n", debugstr_guid(riid));
7233 *obj = NULL;
7235 return E_NOINTERFACE;
7238 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
7240 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7241 ULONG refcount = InterlockedIncrement(&loader->refcount);
7243 TRACE("%p, refcount %lu.\n", iface, refcount);
7245 return refcount;
7248 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
7250 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7251 ULONG refcount = InterlockedDecrement(&loader->refcount);
7252 size_t i;
7254 TRACE("%p, refcount %lu.\n", iface, refcount);
7256 if (!refcount)
7258 for (i = 0; i < loader->count; ++i)
7259 release_inmemory_stream(loader->streams[i]);
7260 free(loader->streams);
7261 free(loader);
7264 return refcount;
7267 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
7268 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
7270 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7271 struct dwrite_inmemory_filestream *stream;
7272 DWORD index;
7274 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
7276 *ret = NULL;
7278 if (key_size != sizeof(DWORD))
7279 return E_INVALIDARG;
7281 index = *(DWORD *)key;
7283 if (index >= loader->count)
7284 return E_INVALIDARG;
7286 if (!(stream = malloc(sizeof(*stream))))
7287 return E_OUTOFMEMORY;
7289 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
7290 stream->refcount = 1;
7291 stream->data = loader->streams[index];
7292 InterlockedIncrement(&stream->data->refcount);
7294 *ret = &stream->IDWriteFontFileStream_iface;
7296 return S_OK;
7299 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
7300 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
7302 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7303 struct dwrite_inmemory_stream_data *stream;
7304 DWORD key;
7306 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
7308 *fontfile = NULL;
7310 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
7311 return E_OUTOFMEMORY;
7313 if (!(stream = malloc(sizeof(*stream))))
7314 return E_OUTOFMEMORY;
7316 stream->refcount = 1;
7317 stream->size = data_size;
7318 stream->owner = owner;
7319 if (stream->owner) {
7320 IUnknown_AddRef(stream->owner);
7321 stream->data = (void *)data;
7323 else {
7324 if (!(stream->data = malloc(data_size)))
7326 free(stream);
7327 return E_OUTOFMEMORY;
7329 memcpy(stream->data, data, data_size);
7332 key = loader->count;
7333 loader->streams[loader->count++] = stream;
7335 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
7336 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
7339 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
7341 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7343 TRACE("%p.\n", iface);
7345 return loader->count;
7348 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
7350 inmemoryfontfileloader_QueryInterface,
7351 inmemoryfontfileloader_AddRef,
7352 inmemoryfontfileloader_Release,
7353 inmemoryfontfileloader_CreateStreamFromKey,
7354 inmemoryfontfileloader_CreateInMemoryFontFileReference,
7355 inmemoryfontfileloader_GetFileCount,
7358 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
7360 struct dwrite_inmemory_fileloader *loader;
7362 *ret = NULL;
7364 if (!(loader = calloc(1, sizeof(*loader))))
7365 return E_OUTOFMEMORY;
7367 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
7368 loader->refcount = 1;
7370 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
7372 return S_OK;
7375 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
7377 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7379 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
7380 IsEqualIID(riid, &IID_IUnknown))
7382 *obj = iface;
7383 IDWriteFontResource_AddRef(iface);
7384 return S_OK;
7387 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7389 return E_NOINTERFACE;
7392 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
7394 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7395 ULONG refcount = InterlockedIncrement(&resource->refcount);
7397 TRACE("%p, refcount %lu.\n", iface, refcount);
7399 return refcount;
7402 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
7404 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7405 ULONG refcount = InterlockedDecrement(&resource->refcount);
7407 TRACE("%p, refcount %lu.\n", iface, refcount);
7409 if (!refcount)
7411 IDWriteFactory7_Release(resource->factory);
7412 IDWriteFontFile_Release(resource->file);
7413 free(resource->axis);
7414 free(resource);
7417 return refcount;
7420 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
7422 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7424 TRACE("%p, %p.\n", iface, fontfile);
7426 *fontfile = resource->file;
7427 IDWriteFontFile_AddRef(*fontfile);
7429 return S_OK;
7432 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
7434 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7436 TRACE("%p.\n", iface);
7438 return resource->face_index;
7441 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
7443 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7445 TRACE("%p.\n", iface);
7447 return resource->axis_count;
7450 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
7451 DWRITE_FONT_AXIS_VALUE *values, UINT32 count)
7453 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7454 unsigned int i;
7456 TRACE("%p, %p, %u.\n", iface, values, count);
7458 if (count < resource->axis_count)
7459 return E_NOT_SUFFICIENT_BUFFER;
7461 for (i = 0; i < resource->axis_count; ++i)
7463 values[i].axisTag = resource->axis[i].tag;
7464 values[i].value = resource->axis[i].default_value;
7467 return S_OK;
7470 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7471 DWRITE_FONT_AXIS_RANGE *ranges, UINT32 count)
7473 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7474 unsigned int i;
7476 TRACE("%p, %p, %u.\n", iface, ranges, count);
7478 if (count < resource->axis_count)
7479 return E_NOT_SUFFICIENT_BUFFER;
7481 for (i = 0; i < resource->axis_count; ++i)
7483 ranges[i].axisTag = resource->axis[i].tag;
7484 ranges[i].minValue = resource->axis[i].min_value;
7485 ranges[i].maxValue = resource->axis[i].max_value;
7488 return S_OK;
7491 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7492 UINT32 axis)
7494 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7496 TRACE("%p, %u.\n", iface, axis);
7498 return axis < resource->axis_count ? resource->axis[axis].attributes : 0;
7501 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7502 IDWriteLocalizedStrings **names)
7504 FIXME("%p, %u, %p.\n", iface, axis, names);
7506 return E_NOTIMPL;
7509 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7511 FIXME("%p, %u.\n", iface, axis);
7513 return 0;
7516 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7517 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7519 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7521 return E_NOTIMPL;
7524 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7526 FIXME("%p.\n", iface);
7528 return FALSE;
7531 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7532 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7533 IDWriteFontFace5 **fontface)
7535 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7536 IDWriteFontFaceReference1 *reference;
7537 HRESULT hr;
7539 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7541 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7542 simulations, axis_values, num_values, &reference);
7543 if (SUCCEEDED(hr))
7545 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7546 IDWriteFontFaceReference1_Release(reference);
7549 return hr;
7552 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7553 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7554 IDWriteFontFaceReference1 **reference)
7556 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7558 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7560 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7561 simulations, axis_values, num_values, reference);
7564 static const IDWriteFontResourceVtbl fontresourcevtbl =
7566 dwritefontresource_QueryInterface,
7567 dwritefontresource_AddRef,
7568 dwritefontresource_Release,
7569 dwritefontresource_GetFontFile,
7570 dwritefontresource_GetFontFaceIndex,
7571 dwritefontresource_GetFontAxisCount,
7572 dwritefontresource_GetDefaultFontAxisValues,
7573 dwritefontresource_GetFontAxisRanges,
7574 dwritefontresource_GetFontAxisAttributes,
7575 dwritefontresource_GetAxisNames,
7576 dwritefontresource_GetAxisValueNameCount,
7577 dwritefontresource_GetAxisValueNames,
7578 dwritefontresource_HasVariations,
7579 dwritefontresource_CreateFontFace,
7580 dwritefontresource_CreateFontFaceReference,
7583 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7584 IDWriteFontResource **ret)
7586 struct dwrite_fontresource *resource;
7587 struct file_stream_desc stream_desc;
7588 DWRITE_FONT_FILE_TYPE file_type;
7589 DWRITE_FONT_FACE_TYPE face_type;
7590 unsigned int face_count;
7591 BOOL supported = FALSE;
7592 HRESULT hr;
7594 *ret = NULL;
7596 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
7597 return hr;
7599 if (!supported)
7600 return DWRITE_E_FILEFORMAT;
7602 if (!(resource = calloc(1, sizeof(*resource))))
7603 return E_OUTOFMEMORY;
7605 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7606 resource->refcount = 1;
7607 resource->face_index = face_index;
7608 resource->file = file;
7609 IDWriteFontFile_AddRef(resource->file);
7610 resource->factory = factory;
7611 IDWriteFactory7_AddRef(resource->factory);
7613 get_filestream_from_file(file, &stream_desc.stream);
7614 stream_desc.face_type = face_type;
7615 stream_desc.face_index = face_index;
7617 opentype_get_font_var_axis(&stream_desc, &resource->axis, &resource->axis_count);
7619 if (stream_desc.stream)
7620 IDWriteFontFileStream_Release(stream_desc.stream);
7622 *ret = &resource->IDWriteFontResource_iface;
7624 return S_OK;
7627 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7629 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7631 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7632 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7633 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7634 IsEqualIID(riid, &IID_IDWriteFontSet))
7636 *obj = iface;
7637 IDWriteFontSet3_AddRef(iface);
7638 return S_OK;
7641 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7642 *obj = NULL;
7643 return E_NOINTERFACE;
7646 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7648 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7649 ULONG refcount = InterlockedIncrement(&set->refcount);
7651 TRACE("%p, refcount %lu.\n", iface, refcount);
7653 return refcount;
7656 #define MISSING_SET_PROP ((void *)0x1)
7658 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7660 unsigned int i;
7662 if (InterlockedDecrement(&entry->refcount) > 0)
7663 return;
7664 IDWriteFontFile_Release(entry->desc.file);
7665 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7667 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7668 IDWriteLocalizedStrings_Release(entry->props[i]);
7670 free(entry);
7673 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7675 InterlockedIncrement(&entry->refcount);
7676 return entry;
7679 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7680 DWRITE_FONT_PROPERTY_ID property)
7682 struct file_stream_desc stream_desc = { 0 };
7683 IDWriteLocalizedStrings *value;
7685 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7687 if (entry->props[property] == MISSING_SET_PROP)
7688 return NULL;
7690 if ((value = entry->props[property]))
7692 IDWriteLocalizedStrings_AddRef(value);
7693 return value;
7696 get_filestream_from_file(entry->desc.file, &stream_desc.stream);
7697 stream_desc.face_type = entry->desc.face_type;
7698 stream_desc.face_index = entry->desc.face_index;
7700 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7701 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7702 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7703 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7704 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7705 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7706 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7707 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7708 else if (property == DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME)
7709 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &value);
7710 else
7711 WARN("Unsupported property %u.\n", property);
7713 if (stream_desc.stream)
7714 IDWriteFontFileStream_Release(stream_desc.stream);
7716 if (value)
7718 entry->props[property] = value;
7719 IDWriteLocalizedStrings_AddRef(value);
7721 else
7722 entry->props[property] = MISSING_SET_PROP;
7724 return value;
7727 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7728 struct dwrite_fontset_entry **entries, unsigned int count);
7730 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7732 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7733 ULONG refcount = InterlockedDecrement(&set->refcount);
7734 unsigned int i;
7736 TRACE("%p, refcount %lu.\n", iface, refcount);
7738 if (!refcount)
7740 IDWriteFactory7_Release(set->factory);
7741 for (i = 0; i < set->count; ++i)
7742 release_fontset_entry(set->entries[i]);
7743 free(set->entries);
7744 free(set);
7747 return refcount;
7750 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7752 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7754 TRACE("%p.\n", iface);
7756 return set->count;
7759 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7760 IDWriteFontFaceReference **reference)
7762 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7764 TRACE("%p, %u, %p.\n", iface, index, reference);
7766 *reference = NULL;
7768 if (index >= set->count)
7769 return E_INVALIDARG;
7771 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->desc.file,
7772 set->entries[index]->desc.face_index, set->entries[index]->desc.simulations, reference);
7775 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7776 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7778 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7780 return E_NOTIMPL;
7783 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7784 UINT32 *index, BOOL *exists)
7786 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7788 return E_NOTIMPL;
7791 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7792 IDWriteStringList **values)
7794 FIXME("%p, %d, %p.\n", iface, id, values);
7796 return E_NOTIMPL;
7799 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7800 WCHAR const *preferred_locales, IDWriteStringList **values)
7802 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7804 return E_NOTIMPL;
7807 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7808 BOOL *exists, IDWriteLocalizedStrings **values)
7810 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7812 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7814 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7815 index >= set->count)
7817 *values = NULL;
7818 *exists = FALSE;
7819 return E_INVALIDARG;
7822 *values = fontset_entry_get_property(set->entries[index], id);
7823 *exists = !!*values;
7825 return S_OK;
7828 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7829 UINT32 *count)
7831 FIXME("%p, %p, %p.\n", iface, property, count);
7833 return E_NOTIMPL;
7836 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7837 unsigned int count)
7839 IDWriteLocalizedStrings *value;
7840 unsigned int i;
7841 BOOL ret;
7843 for (i = 0; i < count; ++i)
7845 switch (props[i].propertyId)
7847 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7848 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7849 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7850 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7851 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7852 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7853 return FALSE;
7855 ret = localizedstrings_contains(value, props[i].propertyValue);
7856 IDWriteLocalizedStrings_Release(value);
7857 if (!ret) return FALSE;
7858 break;
7859 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7860 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7861 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7862 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7863 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7864 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7865 case DWRITE_FONT_PROPERTY_ID_STYLE:
7866 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7867 FIXME("Unsupported property %d.\n", props[i].propertyId);
7868 /* fallthrough */
7869 default:
7870 return FALSE;
7874 return TRUE;
7877 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7878 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7880 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7882 return E_NOTIMPL;
7885 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7886 IDWriteFontSet **filtered_set)
7888 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7889 struct dwrite_fontset_entry **entries;
7890 unsigned int i, matched_count = 0;
7891 struct dwrite_fontset *object;
7893 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7895 if (!props && count)
7896 return E_INVALIDARG;
7898 if (!(object = calloc(1, sizeof(*object))))
7899 return E_OUTOFMEMORY;
7901 if (!(entries = calloc(set->count, sizeof(*entries))))
7903 free(object);
7904 return E_OUTOFMEMORY;
7907 for (i = 0; i < set->count; ++i)
7909 if (fontset_entry_is_matching(set->entries[i], props, count))
7911 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7915 if (!matched_count)
7917 free(entries);
7918 entries = NULL;
7921 init_fontset(object, set->factory, entries, matched_count);
7923 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7925 return S_OK;
7928 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7929 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7931 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7933 return E_NOTIMPL;
7936 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7938 FIXME("%p, %p.\n", iface, fontset);
7940 return E_NOTIMPL;
7943 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7944 UINT32 num_indices, IDWriteFontSet1 **fontset)
7946 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7948 return E_NOTIMPL;
7951 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7952 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7954 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7956 return E_NOTIMPL;
7959 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7960 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7962 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7964 return E_NOTIMPL;
7967 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7968 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7970 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7972 return E_NOTIMPL;
7975 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7976 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7978 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7979 num_indices, actual_num_indices);
7981 return E_NOTIMPL;
7984 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7985 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7987 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7989 return E_NOTIMPL;
7992 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7993 UINT32 num_ranges, UINT32 *actual_num_ranges)
7995 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7997 return E_NOTIMPL;
8000 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
8001 IDWriteFontFaceReference1 **reference)
8003 FIXME("%p, %u, %p.\n", iface, index, reference);
8005 return E_NOTIMPL;
8008 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
8010 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
8012 TRACE("%p, %u, %p.\n", iface, index, resource);
8014 *resource = NULL;
8016 if (index >= set->count)
8017 return E_INVALIDARG;
8019 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->desc.file,
8020 set->entries[index]->desc.face_index, resource);
8023 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
8025 FIXME("%p, %u, %p.\n", iface, index, fontface);
8027 return E_NOTIMPL;
8030 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
8032 FIXME("%p, %u.\n", iface, index);
8034 return DWRITE_LOCALITY_LOCAL;
8037 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
8039 FIXME("%p.\n", iface);
8041 return NULL;
8044 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
8046 FIXME("%p, %u.\n", iface, index);
8048 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
8051 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
8053 FIXME("%p, %u.\n", iface, index);
8055 return 0;
8058 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
8060 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
8062 return E_NOTIMPL;
8065 static const IDWriteFontSet3Vtbl fontsetvtbl =
8067 dwritefontset_QueryInterface,
8068 dwritefontset_AddRef,
8069 dwritefontset_Release,
8070 dwritefontset_GetFontCount,
8071 dwritefontset_GetFontFaceReference,
8072 dwritefontset_FindFontFaceReference,
8073 dwritefontset_FindFontFace,
8074 dwritefontset_GetPropertyValues__,
8075 dwritefontset_GetPropertyValues_,
8076 dwritefontset_GetPropertyValues,
8077 dwritefontset_GetPropertyOccurrenceCount,
8078 dwritefontset_GetMatchingFonts_,
8079 dwritefontset_GetMatchingFonts,
8080 dwritefontset1_GetMatchingFonts,
8081 dwritefontset1_GetFirstFontResources,
8082 dwritefontset1_GetFilteredFonts__,
8083 dwritefontset1_GetFilteredFonts_,
8084 dwritefontset1_GetFilteredFonts,
8085 dwritefontset1_GetFilteredFontIndices_,
8086 dwritefontset1_GetFilteredFontIndices,
8087 dwritefontset1_GetFontAxisRanges_,
8088 dwritefontset1_GetFontAxisRanges,
8089 dwritefontset1_GetFontFaceReference,
8090 dwritefontset1_CreateFontResource,
8091 dwritefontset1_CreateFontFace,
8092 dwritefontset1_GetFontLocality,
8093 dwritefontset2_GetExpirationEvent,
8094 dwritefontset3_GetFontSourceType,
8095 dwritefontset3_GetFontSourceNameLength,
8096 dwritefontset3_GetFontSourceName,
8099 static struct dwrite_fontset *unsafe_impl_from_IDWriteFontSet(IDWriteFontSet *iface)
8101 if (!iface)
8102 return NULL;
8103 assert(iface->lpVtbl == (IDWriteFontSetVtbl *)&fontsetvtbl);
8104 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
8107 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
8108 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
8110 struct dwrite_fontset_entry *entry;
8112 if (!(entry = calloc(1, sizeof(*entry))))
8113 return E_OUTOFMEMORY;
8115 entry->refcount = 1;
8116 entry->desc.file = file;
8117 IDWriteFontFile_AddRef(entry->desc.file);
8118 entry->desc.face_type = face_type;
8119 entry->desc.face_index = face_index;
8120 entry->desc.simulations = simulations;
8122 *ret = entry;
8124 return S_OK;
8127 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
8128 struct dwrite_fontset_entry **entries, unsigned int count)
8130 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
8131 object->refcount = 1;
8132 object->factory = factory;
8133 IDWriteFactory7_AddRef(object->factory);
8134 object->entries = entries;
8135 object->count = count;
8138 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
8139 unsigned int count, IDWriteFontSet1 **ret)
8141 struct dwrite_fontset_entry **entries = NULL;
8142 struct dwrite_fontset *object;
8143 unsigned int i;
8145 if (!(object = calloc(1, sizeof(*object))))
8146 return E_OUTOFMEMORY;
8148 if (count)
8150 entries = calloc(count, sizeof(*entries));
8152 /* FIXME: set available properties too */
8154 for (i = 0; i < count; ++i)
8156 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
8157 fonts[i]->simulations, &entries[i]);
8160 init_fontset(object, factory, entries, count);
8162 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
8164 return S_OK;
8167 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
8168 unsigned int count, IDWriteFontSet **ret)
8170 struct dwrite_fontset_entry **entries = NULL;
8171 struct dwrite_fontset *object;
8172 unsigned int i;
8174 if (!(object = calloc(1, sizeof(*object))))
8175 return E_OUTOFMEMORY;
8177 if (count)
8179 entries = calloc(count, sizeof(*entries));
8181 for (i = 0; i < count; ++i)
8182 entries[i] = addref_fontset_entry(src_entries[i]);
8184 init_fontset(object, factory, entries, count);
8186 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
8188 return S_OK;
8191 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
8192 REFIID riid, void **obj)
8194 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
8196 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
8197 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
8198 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
8199 IsEqualIID(riid, &IID_IUnknown))
8201 *obj = iface;
8202 IDWriteFontSetBuilder2_AddRef(iface);
8203 return S_OK;
8206 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
8207 *obj = NULL;
8208 return E_NOINTERFACE;
8211 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
8213 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8214 ULONG refcount = InterlockedIncrement(&builder->refcount);
8216 TRACE("%p, refcount %lu.\n", iface, refcount);
8218 return refcount;
8221 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
8223 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8224 ULONG refcount = InterlockedDecrement(&builder->refcount);
8225 unsigned int i;
8227 TRACE("%p, refcount %lu.\n", iface, refcount);
8229 if (!refcount)
8231 IDWriteFactory7_Release(builder->factory);
8232 for (i = 0; i < builder->count; ++i)
8233 release_fontset_entry(builder->entries[i]);
8234 free(builder->entries);
8235 free(builder);
8238 return refcount;
8241 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, const struct dwrite_fontset_entry_desc *desc)
8243 struct dwrite_fontset_entry *entry;
8244 HRESULT hr;
8246 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
8247 sizeof(*builder->entries)))
8249 return E_OUTOFMEMORY;
8252 if (FAILED(hr = fontset_create_entry(desc->file, desc->face_type, desc->face_index, desc->simulations, &entry)))
8253 return hr;
8255 builder->entries[builder->count++] = entry;
8257 return S_OK;
8260 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
8262 struct dwrite_fontset_entry_desc desc = { 0 };
8263 DWRITE_FONT_FILE_TYPE filetype;
8264 unsigned int i, face_count;
8265 BOOL supported = FALSE;
8266 HRESULT hr;
8268 desc.file = file;
8269 if (FAILED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &filetype, &desc.face_type, &face_count)))
8270 return hr;
8272 if (!supported)
8273 return DWRITE_E_FILEFORMAT;
8275 for (i = 0; i < face_count; ++i)
8277 desc.face_index = i;
8278 if (FAILED(hr = fontset_builder_add_entry(builder, &desc)))
8279 break;
8282 return hr;
8285 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
8286 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
8288 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
8290 return E_NOTIMPL;
8293 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
8294 IDWriteFontFaceReference *reference)
8296 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8297 struct dwrite_fontset_entry_desc desc = { 0 };
8298 DWRITE_FONT_FILE_TYPE file_type;
8299 unsigned int face_count;
8300 BOOL supported;
8301 HRESULT hr;
8303 TRACE("%p, %p.\n", iface, reference);
8305 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(reference, &desc.file))) return hr;
8307 if (SUCCEEDED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &file_type, &desc.face_type, &face_count)))
8309 if (!supported)
8310 hr = DWRITE_E_FILEFORMAT;
8312 if (SUCCEEDED(hr))
8314 desc.face_index = IDWriteFontFaceReference_GetFontFaceIndex(reference);
8315 desc.simulations = IDWriteFontFaceReference_GetSimulations(reference);
8316 hr = fontset_builder_add_entry(builder, &desc);
8320 IDWriteFontFile_Release(desc.file);
8322 return hr;
8325 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
8327 FIXME("%p, %p.\n", iface, fontset);
8329 return E_NOTIMPL;
8332 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
8334 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8336 TRACE("%p, %p.\n", iface, fontset);
8338 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
8341 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
8343 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8345 TRACE("%p, %p.\n", iface, file);
8347 return fontset_builder_add_file(builder, file);
8350 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
8351 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
8352 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
8353 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
8355 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
8356 axis_ranges, num_ranges, props, num_properties);
8358 return E_NOTIMPL;
8361 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
8363 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8364 IDWriteFontFile *file;
8365 HRESULT hr;
8367 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
8369 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
8370 return hr;
8372 hr = fontset_builder_add_file(builder, file);
8373 IDWriteFontFile_Release(file);
8374 return hr;
8377 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
8379 dwritefontsetbuilder_QueryInterface,
8380 dwritefontsetbuilder_AddRef,
8381 dwritefontsetbuilder_Release,
8382 dwritefontsetbuilder_AddFontFaceReference_,
8383 dwritefontsetbuilder_AddFontFaceReference,
8384 dwritefontsetbuilder_AddFontSet,
8385 dwritefontsetbuilder_CreateFontSet,
8386 dwritefontsetbuilder1_AddFontFile,
8387 dwritefontsetbuilder2_AddFont,
8388 dwritefontsetbuilder2_AddFontFile,
8391 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
8393 struct dwrite_fontset_builder *builder;
8395 *ret = NULL;
8397 if (!(builder = calloc(1, sizeof(*builder))))
8398 return E_OUTOFMEMORY;
8400 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
8401 builder->refcount = 1;
8402 builder->factory = factory;
8403 IDWriteFactory7_AddRef(builder->factory);
8405 *ret = &builder->IDWriteFontSetBuilder2_iface;
8407 return S_OK;