ntdll: Validate blocks in the heap pending free request list.
[wine.git] / dlls / dwrite / font.c
blob5e1fb1c8cbffab3ec0e5c1b292bee477fc5f802b
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 static void fontface_release_cache_entry(struct cache_entry *entry)
74 free(entry->bitmap);
75 free(entry);
78 static struct cache_entry * fontface_get_cache_entry(struct dwrite_fontface *fontface, size_t size,
79 const struct cache_key *key)
81 struct cache_entry *entry, *old_entry;
82 struct wine_rb_entry *e;
84 if (!(e = wine_rb_get(&fontface->cache.tree, key)))
86 if (!(entry = calloc(1, sizeof(*entry)))) return NULL;
87 entry->key = *key;
88 list_init(&entry->mru);
90 size += sizeof(*entry);
92 if ((fontface->cache.size + size > fontface->cache.max_size) && !list_empty(&fontface->cache.mru))
94 old_entry = LIST_ENTRY(list_tail(&fontface->cache.mru), struct cache_entry, mru);
95 fontface->cache.size -= (old_entry->bitmap_size + sizeof(*old_entry));
96 wine_rb_remove(&fontface->cache.tree, &old_entry->entry);
97 list_remove(&old_entry->mru);
98 fontface_release_cache_entry(old_entry);
101 if (wine_rb_put(&fontface->cache.tree, &key, &entry->entry) == -1)
103 WARN("Failed to add cache entry.\n");
104 free(entry);
105 return NULL;
108 fontface->cache.size += size;
110 else
111 entry = WINE_RB_ENTRY_VALUE(e, struct cache_entry, entry);
113 list_remove(&entry->mru);
114 list_add_head(&fontface->cache.mru, &entry->mru);
116 return entry;
119 static int fontface_get_glyph_advance(struct dwrite_fontface *fontface, float fontsize, unsigned short glyph,
120 unsigned short mode, BOOL *has_contours)
122 struct cache_key key = { .size = fontsize, .glyph = glyph, .mode = mode };
123 struct get_glyph_advance_params params;
124 struct cache_entry *entry;
125 unsigned int value;
127 if (!(entry = fontface_get_cache_entry(fontface, 0, &key)))
128 return 0;
130 if (!entry->has_advance)
132 params.object = fontface->get_font_object(fontface);
133 params.glyph = glyph;
134 params.mode = mode;
135 params.emsize = fontsize;
136 params.advance = &entry->advance;
137 params.has_contours = &value;
139 UNIX_CALL(get_glyph_advance, &params);
141 entry->has_contours = !!value;
142 entry->has_advance = 1;
145 *has_contours = entry->has_contours;
146 return entry->advance;
149 void dwrite_fontface_get_glyph_bbox(IDWriteFontFace *iface, struct dwrite_glyphbitmap *bitmap)
151 struct cache_key key = { .size = bitmap->emsize, .glyph = bitmap->glyph, .mode = DWRITE_MEASURING_MODE_NATURAL };
152 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
153 struct get_glyph_bbox_params params;
154 struct cache_entry *entry;
156 params.object = fontface->get_font_object(fontface);
157 params.simulations = bitmap->simulations;
158 params.glyph = bitmap->glyph;
159 params.emsize = bitmap->emsize;
160 params.m = bitmap->m ? *bitmap->m : identity;
162 EnterCriticalSection(&fontface->cs);
163 /* For now bypass cache for transformed cases. */
164 if (bitmap->m && memcmp(bitmap->m, &identity, sizeof(*bitmap->m)))
166 params.bbox = &bitmap->bbox;
167 UNIX_CALL(get_glyph_bbox, &params);
169 else if ((entry = fontface_get_cache_entry(fontface, 0, &key)))
171 if (!entry->has_bbox)
173 params.bbox = &entry->bbox;
174 UNIX_CALL(get_glyph_bbox, &params);
175 entry->has_bbox = 1;
177 bitmap->bbox = entry->bbox;
179 LeaveCriticalSection(&fontface->cs);
182 static unsigned int get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
184 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
187 static HRESULT dwrite_fontface_get_glyph_bitmap(struct dwrite_fontface *fontface, DWRITE_RENDERING_MODE rendering_mode,
188 unsigned int *is_1bpp, struct dwrite_glyphbitmap *bitmap)
190 struct cache_key key = { .size = bitmap->emsize, .glyph = bitmap->glyph, .mode = DWRITE_MEASURING_MODE_NATURAL };
191 struct get_glyph_bitmap_params params;
192 const RECT *bbox = &bitmap->bbox;
193 unsigned int bitmap_size, _1bpp;
194 struct cache_entry *entry;
195 HRESULT hr = S_OK;
197 bitmap_size = get_glyph_bitmap_pitch(rendering_mode, bbox->right - bbox->left) *
198 (bbox->bottom - bbox->top);
200 params.object = fontface->get_font_object(fontface);
201 params.simulations = fontface->simulations;
202 params.glyph = bitmap->glyph;
203 params.mode = rendering_mode;
204 params.emsize = bitmap->emsize;
205 params.m = bitmap->m ? *bitmap->m : identity;
206 params.bbox = bitmap->bbox;
207 params.pitch = bitmap->pitch;
208 params.bitmap = bitmap->buf;
209 params.is_1bpp = is_1bpp;
211 EnterCriticalSection(&fontface->cs);
212 /* For now bypass cache for transformed cases. */
213 if (memcmp(&params.m, &identity, sizeof(params.m)))
215 UNIX_CALL(get_glyph_bitmap, &params);
217 else if ((entry = fontface_get_cache_entry(fontface, bitmap_size, &key)))
219 if (entry->has_bitmap)
221 memcpy(bitmap->buf, entry->bitmap, entry->bitmap_size);
223 else
225 params.is_1bpp = &_1bpp;
226 UNIX_CALL(get_glyph_bitmap, &params);
228 entry->bitmap_size = bitmap_size;
229 if ((entry->bitmap = malloc(entry->bitmap_size)))
230 memcpy(entry->bitmap, bitmap->buf, entry->bitmap_size);
231 entry->is_1bpp = !!_1bpp;
232 entry->has_bitmap = 1;
234 *is_1bpp = entry->is_1bpp;
236 else
237 hr = E_FAIL;
238 LeaveCriticalSection(&fontface->cs);
240 return hr;
243 static int fontface_cache_compare(const void *k, const struct wine_rb_entry *e)
245 const struct cache_entry *entry = WINE_RB_ENTRY_VALUE(e, const struct cache_entry, entry);
246 const struct cache_key *key = k, *key2 = &entry->key;
248 if (key->size != key2->size) return key->size < key2->size ? -1 : 1;
249 if (key->glyph != key2->glyph) return (int)key->glyph - (int)key2->glyph;
250 if (key->mode != key2->mode) return (int)key->mode - (int)key2->mode;
251 return 0;
254 static void fontface_cache_init(struct dwrite_fontface *fontface)
256 wine_rb_init(&fontface->cache.tree, fontface_cache_compare);
257 list_init(&fontface->cache.mru);
258 fontface->cache.max_size = 0x8000;
261 static void fontface_cache_clear(struct dwrite_fontface *fontface)
263 struct cache_entry *entry, *entry2;
265 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &fontface->cache.mru, struct cache_entry, mru)
267 list_remove(&entry->mru);
268 fontface_release_cache_entry(entry);
270 memset(&fontface->cache, 0, sizeof(fontface->cache));
273 struct dwrite_font_propvec {
274 FLOAT stretch;
275 FLOAT style;
276 FLOAT weight;
279 struct dwrite_font_data
281 LONG refcount;
283 DWRITE_FONT_STYLE style;
284 DWRITE_FONT_STRETCH stretch;
285 DWRITE_FONT_WEIGHT weight;
286 DWRITE_PANOSE panose;
287 FONTSIGNATURE fontsig;
288 UINT32 flags; /* enum font_flags */
289 struct dwrite_font_propvec propvec;
290 struct dwrite_cmap cmap;
291 /* Static axis for weight/width/italic. */
292 DWRITE_FONT_AXIS_VALUE axis[3];
294 DWRITE_FONT_METRICS1 metrics;
295 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
296 IDWriteLocalizedStrings *family_names;
297 IDWriteLocalizedStrings *names;
299 /* data needed to create fontface instance */
300 DWRITE_FONT_FACE_TYPE face_type;
301 IDWriteFontFile *file;
302 UINT32 face_index;
304 WCHAR *facename;
306 USHORT simulations;
308 LOGFONTW lf;
310 /* used to mark font as tested when scanning for simulation candidate */
311 unsigned int bold_sim_tested : 1;
312 unsigned int oblique_sim_tested : 1;
315 struct dwrite_fontfamily_data
317 LONG refcount;
319 IDWriteLocalizedStrings *familyname;
321 struct dwrite_font_data **fonts;
322 size_t size;
323 size_t count;
325 unsigned int has_normal_face : 1;
326 unsigned int has_oblique_face : 1;
327 unsigned int has_italic_face : 1;
330 struct dwrite_fontcollection
332 IDWriteFontCollection3 IDWriteFontCollection3_iface;
333 LONG refcount;
335 IDWriteFactory7 *factory;
336 DWRITE_FONT_FAMILY_MODEL family_model;
337 struct dwrite_fontfamily_data **family_data;
338 size_t size;
339 size_t count;
342 struct dwrite_fontfamily
344 IDWriteFontFamily2 IDWriteFontFamily2_iface;
345 IDWriteFontList2 IDWriteFontList2_iface;
346 LONG refcount;
348 struct dwrite_fontfamily_data *data;
349 struct dwrite_fontcollection *collection;
352 struct dwrite_fontlist
354 IDWriteFontList2 IDWriteFontList2_iface;
355 LONG refcount;
357 struct dwrite_font_data **fonts;
358 UINT32 font_count;
359 struct dwrite_fontfamily *family;
362 struct dwrite_font
364 IDWriteFont3 IDWriteFont3_iface;
365 LONG refcount;
367 DWRITE_FONT_STYLE style;
368 struct dwrite_font_data *data;
369 struct dwrite_fontfamily *family;
372 enum runanalysis_flags {
373 RUNANALYSIS_BOUNDS_READY = 1 << 0,
374 RUNANALYSIS_BITMAP_READY = 1 << 1,
375 RUNANALYSIS_USE_TRANSFORM = 1 << 2
378 struct dwrite_glyphrunanalysis
380 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
381 LONG refcount;
383 DWRITE_RENDERING_MODE1 rendering_mode;
384 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
385 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
386 DWRITE_MATRIX m;
387 UINT16 *glyphs;
388 D2D_POINT_2F *origins;
390 UINT8 flags;
391 RECT bounds;
392 BYTE *bitmap;
393 UINT32 max_glyph_bitmap_size;
396 struct dwrite_colorglyphenum
398 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
399 LONG refcount;
401 D2D1_POINT_2F origin; /* original run origin */
403 IDWriteFontFace5 *fontface; /* for convenience */
404 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
405 DWRITE_GLYPH_RUN run; /* base run */
406 UINT32 palette; /* palette index to get layer color from */
407 FLOAT *advances; /* original or measured advances for base glyphs */
408 FLOAT *color_advances; /* returned color run points to this */
409 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
410 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
411 UINT16 *glyphindices; /* returned color run points to this */
412 struct dwrite_colorglyph *glyphs; /* current glyph color info */
413 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
414 UINT16 current_layer; /* enumerator position, updated with MoveNext */
415 UINT16 max_layer_num; /* max number of layers for this run */
416 struct dwrite_fonttable colr; /* used to access layers */
419 struct dwrite_fontfile
421 IDWriteFontFile IDWriteFontFile_iface;
422 LONG refcount;
424 IDWriteFontFileLoader *loader;
425 void *reference_key;
426 UINT32 key_size;
427 IDWriteFontFileStream *stream;
430 struct dwrite_fontfacereference
432 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
433 LONG refcount;
435 IDWriteFontFile *file;
436 UINT32 index;
437 USHORT simulations;
438 DWRITE_FONT_AXIS_VALUE *axis_values;
439 UINT32 axis_values_count;
440 IDWriteFactory7 *factory;
443 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
445 struct dwrite_fontresource
447 IDWriteFontResource IDWriteFontResource_iface;
448 LONG refcount;
450 IDWriteFontFile *file;
451 UINT32 face_index;
452 IDWriteFactory7 *factory;
454 struct dwrite_var_axis *axis;
455 unsigned int axis_count;
458 struct dwrite_fontset_entry_desc
460 IDWriteFontFile *file;
461 DWRITE_FONT_FACE_TYPE face_type;
462 unsigned int face_index;
463 unsigned int simulations;
466 struct dwrite_fontset_entry
468 LONG refcount;
469 struct dwrite_fontset_entry_desc desc;
470 IDWriteLocalizedStrings *props[DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME + 1];
473 struct dwrite_fontset
475 IDWriteFontSet3 IDWriteFontSet3_iface;
476 LONG refcount;
477 IDWriteFactory7 *factory;
479 struct dwrite_fontset_entry **entries;
480 unsigned int count;
483 struct dwrite_fontset_builder
485 IDWriteFontSetBuilder2 IDWriteFontSetBuilder2_iface;
486 LONG refcount;
487 IDWriteFactory7 *factory;
489 struct dwrite_fontset_entry **entries;
490 size_t count;
491 size_t capacity;
494 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
495 unsigned int count, IDWriteFontSet1 **ret);
497 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
499 struct dwrite_fontface *fontface = context;
500 BOOL exists = FALSE;
502 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
503 size, data_context, &exists)) || !exists)
505 *data = NULL;
506 *size = 0;
507 *data_context = NULL;
511 static void dwrite_release_font_table(void *context, void *data_context)
513 struct dwrite_fontface *fontface = context;
514 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
517 static UINT16 dwrite_get_font_upem(void *context)
519 struct dwrite_fontface *fontface = context;
520 return fontface->metrics.designUnitsPerEm;
523 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
525 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
526 return opentype_cmap_get_glyph(&fontface->cmap, ch);
529 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
531 struct dwrite_fontface *fontface = context;
532 return !!dwritefontface_get_glyph(fontface, codepoint);
535 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
537 struct dwrite_fontface *fontface = context;
538 return dwritefontface_get_glyph(fontface, codepoint);
541 static const struct shaping_font_ops dwrite_font_ops =
543 dwrite_grab_font_table,
544 dwrite_release_font_table,
545 dwrite_get_font_upem,
546 dwrite_has_glyph,
547 dwrite_get_glyph,
550 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
552 if (fontface->shaping_cache)
553 return fontface->shaping_cache;
555 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
558 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
560 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
563 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
565 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
568 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
570 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
573 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
575 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
577 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
580 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
582 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
585 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
587 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
590 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
592 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
595 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
597 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
600 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
602 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
605 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
607 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
610 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
612 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
615 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
617 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
620 static struct dwrite_fontset_builder *impl_from_IDWriteFontSetBuilder2(IDWriteFontSetBuilder2 *iface)
622 return CONTAINING_RECORD(iface, struct dwrite_fontset_builder, IDWriteFontSetBuilder2_iface);
625 static struct dwrite_fontset *impl_from_IDWriteFontSet3(IDWriteFontSet3 *iface)
627 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
630 static struct dwrite_fontset *unsafe_impl_from_IDWriteFontSet(IDWriteFontSet *iface);
632 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
634 static const DWRITE_GLYPH_METRICS nil;
635 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
637 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
638 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
639 return S_OK;
642 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
644 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
646 if (!*block)
648 /* start new block */
649 if (!(*block = calloc(GLYPH_BLOCK_SIZE, sizeof(*metrics))))
650 return E_OUTOFMEMORY;
653 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
654 return S_OK;
657 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
659 HRESULT hr;
661 if (table->data || !table->exists)
662 return table->data;
664 table->exists = FALSE;
665 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
666 &table->exists);
667 if (FAILED(hr) || !table->exists) {
668 TRACE("Font does not have %s table\n", debugstr_tag(tag));
669 return NULL;
672 return table->data;
675 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
676 struct dwrite_font_propvec *vec)
678 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
679 vec->style = style * 7.0f;
680 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
683 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
685 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
688 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
690 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
693 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
695 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
696 return &fontface->vdmx;
699 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
701 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
702 return &fontface->gasp;
705 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
707 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
708 return &fontface->cpal;
711 static struct dwrite_font_data * addref_font_data(struct dwrite_font_data *data)
713 InterlockedIncrement(&data->refcount);
714 return data;
717 static void release_font_data(struct dwrite_font_data *data)
719 int i;
721 if (InterlockedDecrement(&data->refcount) > 0)
722 return;
724 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
726 if (data->info_strings[i])
727 IDWriteLocalizedStrings_Release(data->info_strings[i]);
729 if (data->names)
730 IDWriteLocalizedStrings_Release(data->names);
732 if (data->family_names)
733 IDWriteLocalizedStrings_Release(data->family_names);
735 dwrite_cmap_release(&data->cmap);
736 IDWriteFontFile_Release(data->file);
737 free(data->facename);
738 free(data);
741 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
743 size_t i;
745 if (InterlockedDecrement(&data->refcount) > 0)
746 return;
748 for (i = 0; i < data->count; ++i)
749 release_font_data(data->fonts[i]);
750 free(data->fonts);
751 IDWriteLocalizedStrings_Release(data->familyname);
752 free(data);
755 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
757 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
758 fontface->cached = NULL;
761 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
763 UINT32 left_key_size, right_key_size;
764 const void *left_key, *right_key;
765 HRESULT hr;
767 if (left == right)
768 return TRUE;
770 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
771 if (FAILED(hr))
772 return FALSE;
774 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
775 if (FAILED(hr))
776 return FALSE;
778 if (left_key_size != right_key_size)
779 return FALSE;
781 return !memcmp(left_key, right_key, left_key_size);
784 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
786 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
788 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
790 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
791 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
792 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
793 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
794 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
795 IsEqualIID(riid, &IID_IDWriteFontFace) ||
796 IsEqualIID(riid, &IID_IUnknown))
798 *obj = iface;
800 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
801 *obj = &fontface->IDWriteFontFaceReference_iface;
802 else
803 *obj = NULL;
805 if (*obj)
807 if (InterlockedIncrement(&fontface->refcount) == 1)
809 InterlockedDecrement(&fontface->refcount);
810 *obj = NULL;
811 return E_FAIL;
813 return S_OK;
816 WARN("%s not implemented.\n", debugstr_guid(riid));
818 return E_NOINTERFACE;
821 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
823 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
824 ULONG refcount = InterlockedIncrement(&fontface->refcount);
826 TRACE("%p, refcount %lu.\n", iface, refcount);
828 return refcount;
831 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
833 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
834 ULONG refcount = InterlockedDecrement(&fontface->refcount);
835 struct release_font_object_params params = { fontface->font_object };
837 TRACE("%p, refcount %lu.\n", iface, refcount);
839 if (!refcount)
841 UINT32 i;
843 if (fontface->cached)
845 factory_lock(fontface->factory);
846 list_remove(&fontface->cached->entry);
847 factory_unlock(fontface->factory);
848 free(fontface->cached);
850 release_scriptshaping_cache(fontface->shaping_cache);
851 if (fontface->vdmx.context)
852 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
853 if (fontface->gasp.context)
854 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
855 if (fontface->cpal.context)
856 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
857 if (fontface->colr.context)
858 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
859 if (fontface->kern.context)
860 IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
861 if (fontface->file)
862 IDWriteFontFile_Release(fontface->file);
863 if (fontface->names)
864 IDWriteLocalizedStrings_Release(fontface->names);
865 if (fontface->family_names)
866 IDWriteLocalizedStrings_Release(fontface->family_names);
867 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
869 if (fontface->info_strings[i])
870 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
873 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
874 free(fontface->glyphs[i]);
876 UNIX_CALL(release_font_object, &params);
877 if (fontface->stream)
879 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, fontface->data_context);
880 IDWriteFontFileStream_Release(fontface->stream);
882 fontface_cache_clear(fontface);
884 dwrite_cmap_release(&fontface->cmap);
885 IDWriteFactory7_Release(fontface->factory);
886 DeleteCriticalSection(&fontface->cs);
887 free(fontface);
890 return refcount;
893 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
895 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
897 TRACE("%p.\n", iface);
899 return fontface->type;
902 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
903 IDWriteFontFile **fontfiles)
905 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
907 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
909 if (!fontfiles)
911 *number_of_files = 1;
912 return S_OK;
915 if (!*number_of_files)
916 return E_INVALIDARG;
918 IDWriteFontFile_AddRef(fontface->file);
919 *fontfiles = fontface->file;
921 return S_OK;
924 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
926 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
928 TRACE("%p.\n", iface);
930 return fontface->index;
933 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
935 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
937 TRACE("%p.\n", iface);
939 return fontface->simulations;
942 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
944 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
946 TRACE("%p.\n", iface);
948 return !!(fontface->flags & FONT_IS_SYMBOL);
951 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
953 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
955 TRACE("%p, %p.\n", iface, metrics);
957 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
960 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
962 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
963 struct get_glyph_count_params params;
964 unsigned int count;
966 TRACE("%p.\n", iface);
968 params.object = fontface->get_font_object(fontface);
969 params.count = &count;
970 UNIX_CALL(get_glyph_count, &params);
972 return count;
975 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
976 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
978 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
979 struct get_design_glyph_metrics_params params;
980 DWRITE_GLYPH_METRICS metrics;
981 HRESULT hr = S_OK;
982 unsigned int i;
984 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
986 if (!glyphs)
987 return E_INVALIDARG;
989 if (is_sideways)
990 FIXME("sideways metrics are not supported.\n");
992 params.object = fontface->get_font_object(fontface);
993 params.simulations = fontface->simulations;
994 params.upem = fontface->metrics.designUnitsPerEm;
995 params.ascent = fontface->typo_metrics.ascent;
996 params.metrics = &metrics;
998 EnterCriticalSection(&fontface->cs);
999 for (i = 0; i < glyph_count; ++i)
1002 if (get_cached_glyph_metrics(fontface, glyphs[i], &metrics) != S_OK)
1004 params.glyph = glyphs[i];
1005 UNIX_CALL(get_design_glyph_metrics, &params);
1006 if (FAILED(hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics))) break;
1008 ret[i] = metrics;
1010 LeaveCriticalSection(&fontface->cs);
1012 return hr;
1015 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
1016 UINT32 count, UINT16 *glyphs)
1018 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1019 unsigned int i;
1021 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
1023 if (!glyphs)
1024 return E_INVALIDARG;
1026 if (!codepoints)
1028 memset(glyphs, 0, count * sizeof(*glyphs));
1029 return E_INVALIDARG;
1032 for (i = 0; i < count; ++i)
1033 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
1035 return S_OK;
1038 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
1039 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
1041 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1042 struct file_stream_desc stream_desc;
1044 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
1046 stream_desc.stream = fontface->stream;
1047 stream_desc.face_type = fontface->type;
1048 stream_desc.face_index = fontface->index;
1049 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
1052 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
1054 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1056 TRACE("%p, %p.\n", iface, table_context);
1058 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
1061 static void apply_outline_point_offset(const D2D1_POINT_2F *src, const D2D1_POINT_2F *offset,
1062 D2D1_POINT_2F *dst)
1064 dst->x = src->x + offset->x;
1065 dst->y = src->y + offset->y;
1068 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
1069 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
1070 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
1072 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1073 D2D1_POINT_2F *origins, baseline_origin = { 0 };
1074 struct dwrite_outline outline, outline_size;
1075 struct get_glyph_outline_params params;
1076 D2D1_BEZIER_SEGMENT segment;
1077 D2D1_POINT_2F point;
1078 DWRITE_GLYPH_RUN run;
1079 unsigned int i, j, p;
1080 NTSTATUS status;
1081 HRESULT hr;
1083 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
1084 count, is_sideways, is_rtl, sink);
1086 if (!glyphs || !sink)
1087 return E_INVALIDARG;
1089 if (!count)
1090 return S_OK;
1092 run.fontFace = (IDWriteFontFace *)iface;
1093 run.fontEmSize = emSize;
1094 run.glyphCount = count;
1095 run.glyphIndices = glyphs;
1096 run.glyphAdvances = advances;
1097 run.glyphOffsets = offsets;
1098 run.isSideways = is_sideways;
1099 run.bidiLevel = is_rtl ? 1 : 0;
1101 if (!(origins = malloc(sizeof(*origins) * count)))
1102 return E_OUTOFMEMORY;
1104 if (FAILED(hr = compute_glyph_origins(&run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins)))
1106 free(origins);
1107 return hr;
1110 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
1112 memset(&outline_size, 0, sizeof(outline_size));
1113 memset(&outline, 0, sizeof(outline));
1115 params.object = fontface->get_font_object(fontface);
1116 params.simulations = fontface->simulations;
1117 params.emsize = emSize;
1119 for (i = 0; i < count; ++i)
1121 outline.tags.count = outline.points.count = 0;
1123 EnterCriticalSection(&fontface->cs);
1125 params.glyph = glyphs[i];
1126 params.outline = &outline_size;
1128 if (!(status = UNIX_CALL(get_glyph_outline, &params)))
1130 dwrite_array_reserve((void **)&outline.tags.values, &outline.tags.size, outline_size.tags.count,
1131 sizeof(*outline.tags.values));
1132 dwrite_array_reserve((void **)&outline.points.values, &outline.points.size, outline_size.points.count,
1133 sizeof(*outline.points.values));
1135 params.outline = &outline;
1136 if ((status = UNIX_CALL(get_glyph_outline, &params)))
1138 WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
1141 LeaveCriticalSection(&fontface->cs);
1143 if (status)
1144 continue;
1146 for (j = 0, p = 0; j < outline.tags.count; ++j)
1148 switch (outline.tags.values[j])
1150 case OUTLINE_BEGIN_FIGURE:
1151 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1152 ID2D1SimplifiedGeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
1153 break;
1154 case OUTLINE_END_FIGURE:
1155 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
1156 break;
1157 case OUTLINE_LINE:
1158 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1159 ID2D1SimplifiedGeometrySink_AddLines(sink, &point, 1);
1160 break;
1161 case OUTLINE_BEZIER:
1162 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point1);
1163 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point2);
1164 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point3);
1165 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &segment, 1);
1166 break;
1171 free(outline.tags.values);
1172 free(outline.points.values);
1173 free(origins);
1175 return S_OK;
1178 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
1179 float ppem, unsigned int gasp)
1181 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
1183 switch (measuring)
1185 case DWRITE_MEASURING_MODE_NATURAL:
1187 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
1188 mode = DWRITE_RENDERING_MODE_NATURAL;
1189 else
1190 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
1191 break;
1193 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1194 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
1195 break;
1196 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1197 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
1198 break;
1199 default:
1203 return mode;
1206 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1207 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
1209 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1210 unsigned int flags;
1211 FLOAT ppem;
1213 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
1215 if (!params) {
1216 *mode = DWRITE_RENDERING_MODE_DEFAULT;
1217 return E_INVALIDARG;
1220 *mode = IDWriteRenderingParams_GetRenderingMode(params);
1221 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
1222 return S_OK;
1224 ppem = emSize * ppdip;
1226 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
1227 *mode = DWRITE_RENDERING_MODE_OUTLINE;
1228 return S_OK;
1231 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
1232 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
1233 return S_OK;
1236 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
1237 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
1239 DWRITE_FONT_METRICS1 metrics1;
1240 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
1241 memcpy(metrics, &metrics1, sizeof(*metrics));
1242 return hr;
1245 static inline int round_metric(FLOAT metric)
1247 return (int)floorf(metric + 0.5f);
1250 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
1252 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
1253 return 0;
1255 return (fontface->metrics.designUnitsPerEm + 49) / 50;
1258 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
1259 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
1260 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
1262 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1263 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
1264 DWRITE_MEASURING_MODE mode;
1265 FLOAT scale, size;
1266 HRESULT hr = S_OK;
1267 UINT32 i;
1269 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
1270 glyph_count, metrics, is_sideways);
1272 if (m && memcmp(m, &identity, sizeof(*m)))
1273 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
1275 size = emSize * ppdip;
1276 scale = size / fontface->metrics.designUnitsPerEm;
1277 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1279 EnterCriticalSection(&fontface->cs);
1280 for (i = 0; i < glyph_count; ++i)
1282 DWRITE_GLYPH_METRICS *ret = metrics + i;
1283 DWRITE_GLYPH_METRICS design;
1284 BOOL has_contours;
1286 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
1287 if (FAILED(hr))
1288 break;
1290 ret->advanceWidth = fontface_get_glyph_advance(fontface, size, glyphs[i], mode, &has_contours);
1291 if (has_contours)
1292 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
1293 else
1294 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
1296 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
1297 SCALE_METRIC(leftSideBearing);
1298 SCALE_METRIC(rightSideBearing);
1299 SCALE_METRIC(topSideBearing);
1300 SCALE_METRIC(advanceHeight);
1301 SCALE_METRIC(bottomSideBearing);
1302 SCALE_METRIC(verticalOriginY);
1303 #undef SCALE_METRIC
1305 LeaveCriticalSection(&fontface->cs);
1307 return S_OK;
1310 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
1312 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1314 TRACE("%p, %p.\n", iface, metrics);
1316 *metrics = fontface->metrics;
1319 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
1320 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
1322 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1323 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
1324 UINT16 ascent, descent;
1325 FLOAT scale;
1327 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
1329 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
1330 memset(metrics, 0, sizeof(*metrics));
1331 return E_INVALIDARG;
1334 em_size *= pixels_per_dip;
1335 if (m && m->m22 != 0.0f)
1336 em_size *= fabs(m->m22);
1338 scale = em_size / design->designUnitsPerEm;
1339 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
1341 ascent = round_metric(design->ascent * scale);
1342 descent = round_metric(design->descent * scale);
1345 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
1346 metrics->designUnitsPerEm = design->designUnitsPerEm;
1347 metrics->ascent = round_metric(ascent / scale);
1348 metrics->descent = round_metric(descent / scale);
1350 SCALE_METRIC(lineGap);
1351 SCALE_METRIC(capHeight);
1352 SCALE_METRIC(xHeight);
1353 SCALE_METRIC(underlinePosition);
1354 SCALE_METRIC(underlineThickness);
1355 SCALE_METRIC(strikethroughPosition);
1356 SCALE_METRIC(strikethroughThickness);
1357 SCALE_METRIC(glyphBoxLeft);
1358 SCALE_METRIC(glyphBoxTop);
1359 SCALE_METRIC(glyphBoxRight);
1360 SCALE_METRIC(glyphBoxBottom);
1361 SCALE_METRIC(subscriptPositionX);
1362 SCALE_METRIC(subscriptPositionY);
1363 SCALE_METRIC(subscriptSizeX);
1364 SCALE_METRIC(subscriptSizeY);
1365 SCALE_METRIC(superscriptPositionX);
1366 SCALE_METRIC(superscriptPositionY);
1367 SCALE_METRIC(superscriptSizeX);
1368 SCALE_METRIC(superscriptSizeY);
1370 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1371 #undef SCALE_METRIC
1373 return S_OK;
1376 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1378 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1380 TRACE("%p, %p.\n", iface, metrics);
1382 *metrics = fontface->caret;
1385 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1386 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1388 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1390 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1392 *count = 0;
1393 if (max_count && !ranges)
1394 return E_INVALIDARG;
1396 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1397 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1400 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1402 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1404 TRACE("%p.\n", iface);
1406 return !!(fontface->flags & FONT_IS_MONOSPACED);
1409 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1410 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1412 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1413 BOOL has_contours;
1414 int advance;
1416 if (is_sideways)
1417 FIXME("Sideways mode is not supported.\n");
1419 switch (measuring_mode)
1421 case DWRITE_MEASURING_MODE_NATURAL:
1422 advance = fontface_get_glyph_advance(fontface, fontface->metrics.designUnitsPerEm, glyph,
1423 measuring_mode, &has_contours);
1424 if (has_contours)
1425 advance += adjustment;
1427 return advance;
1428 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1429 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1430 emsize *= ppdip;
1431 if (emsize == 0.0f)
1432 return 0.0f;
1434 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1435 FIXME("Transform is not supported.\n");
1437 advance = fontface_get_glyph_advance(fontface, emsize, glyph, measuring_mode, &has_contours);
1438 if (has_contours)
1439 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1440 else
1441 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1443 return advance;
1444 default:
1445 WARN("Unknown measuring mode %u.\n", measuring_mode);
1446 return 0;
1450 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1451 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1453 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1454 unsigned int i;
1456 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1458 if (is_sideways)
1459 FIXME("sideways mode not supported\n");
1461 EnterCriticalSection(&fontface->cs);
1462 for (i = 0; i < glyph_count; ++i)
1464 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1465 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1467 LeaveCriticalSection(&fontface->cs);
1469 return S_OK;
1472 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1473 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1474 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1476 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1477 DWRITE_MEASURING_MODE measuring_mode;
1478 UINT32 i;
1480 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1481 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1483 if (em_size < 0.0f || ppdip <= 0.0f) {
1484 memset(advances, 0, sizeof(*advances) * glyph_count);
1485 return E_INVALIDARG;
1488 if (em_size == 0.0f) {
1489 memset(advances, 0, sizeof(*advances) * glyph_count);
1490 return S_OK;
1493 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1495 EnterCriticalSection(&fontface->cs);
1496 for (i = 0; i < glyph_count; ++i)
1498 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1499 glyphs[i], is_sideways);
1501 LeaveCriticalSection(&fontface->cs);
1503 return S_OK;
1506 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1507 const UINT16 *glyphs, INT32 *values)
1509 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1511 TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
1513 if (!(glyphs || values) || !count)
1514 return E_INVALIDARG;
1516 if (!glyphs || count == 1)
1518 memset(values, 0, count * sizeof(*values));
1519 return E_INVALIDARG;
1522 return opentype_get_kerning_pairs(fontface, count, glyphs, values);
1525 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1527 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1529 TRACE("%p.\n", iface);
1531 return opentype_has_kerning_pairs(fontface);
1534 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1535 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1536 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1538 DWRITE_GRID_FIT_MODE gridfitmode;
1539 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1540 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1543 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1544 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1546 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1548 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1550 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1553 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1555 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1557 TRACE("%p.\n", iface);
1559 return opentype_has_vertical_variants(fontface);
1562 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1564 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1566 TRACE("%p.\n", iface);
1568 return !!(fontface->flags & FONT_IS_COLORED);
1571 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1573 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1575 TRACE("%p.\n", iface);
1577 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1580 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1582 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1584 TRACE("%p.\n", iface);
1586 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1589 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1590 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1592 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1594 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1596 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1599 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1600 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1601 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1602 DWRITE_GRID_FIT_MODE *gridfitmode)
1604 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1605 unsigned int flags;
1606 FLOAT emthreshold;
1608 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1609 measuringmode, params, renderingmode, gridfitmode);
1611 if (m && memcmp(m, &identity, sizeof(*m)))
1612 FIXME("transform not supported %s\n", debugstr_matrix(m));
1614 if (is_sideways)
1615 FIXME("sideways mode not supported\n");
1617 emSize *= max(dpiX, dpiY) / 96.0f;
1619 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1620 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1621 if (params) {
1622 IDWriteRenderingParams2 *params2;
1623 HRESULT hr;
1625 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1626 if (hr == S_OK) {
1627 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1628 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1629 IDWriteRenderingParams2_Release(params2);
1631 else
1632 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1635 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1637 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1639 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1640 if (emSize >= emthreshold)
1641 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1642 else
1643 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1646 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1647 if (emSize >= emthreshold)
1648 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1649 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1650 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1651 else
1652 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1653 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1656 return S_OK;
1659 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1660 IDWriteFontFaceReference **reference)
1662 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1664 TRACE("%p, %p.\n", iface, reference);
1666 *reference = &fontface->IDWriteFontFaceReference_iface;
1667 IDWriteFontFaceReference_AddRef(*reference);
1669 return S_OK;
1672 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1674 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1676 TRACE("%p, %p.\n", iface, panose);
1678 *panose = fontface->panose;
1681 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1683 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1685 TRACE("%p.\n", iface);
1687 return fontface->weight;
1690 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1692 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1694 TRACE("%p.\n", iface);
1696 return fontface->stretch;
1699 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1701 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1703 TRACE("%p.\n", iface);
1705 return fontface->style;
1708 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1710 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1712 TRACE("%p, %p.\n", iface, names);
1714 return clone_localizedstrings(fontface->family_names, names);
1717 static HRESULT WINAPI dwritefontface3_GetFaceNames(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->names, names);
1726 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1727 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1728 IDWriteLocalizedStrings **ret, BOOL *exists)
1730 HRESULT hr = S_OK;
1732 *exists = FALSE;
1733 *ret = NULL;
1735 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1736 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1738 return S_OK;
1741 if (!strings_cache[stringid])
1743 struct file_stream_desc desc = *stream_desc;
1745 if (!desc.stream)
1746 hr = get_filestream_from_file(file, &desc.stream);
1747 if (SUCCEEDED(hr))
1748 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1750 if (!stream_desc->stream && desc.stream)
1751 IDWriteFontFileStream_Release(desc.stream);
1754 if (SUCCEEDED(hr) && strings_cache[stringid])
1756 hr = clone_localizedstrings(strings_cache[stringid], ret);
1757 if (SUCCEEDED(hr))
1758 *exists = TRUE;
1761 return hr;
1764 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1765 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1767 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1768 struct file_stream_desc stream_desc;
1770 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1772 stream_desc.stream = fontface->stream;
1773 stream_desc.face_index = fontface->index;
1774 stream_desc.face_type = fontface->type;
1775 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1778 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1780 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1782 TRACE("%p, %#x.\n", iface, ch);
1784 return !!dwritefontface_get_glyph(fontface, ch);
1787 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1788 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1789 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1791 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1792 unsigned int flags;
1793 FLOAT emthreshold;
1795 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1796 measuring_mode, params, rendering_mode, gridfit_mode);
1798 if (m && memcmp(m, &identity, sizeof(*m)))
1799 FIXME("transform not supported %s\n", debugstr_matrix(m));
1801 if (is_sideways)
1802 FIXME("sideways mode not supported\n");
1804 emSize *= max(dpiX, dpiY) / 96.0f;
1806 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1807 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1808 if (params) {
1809 IDWriteRenderingParams3 *params3;
1810 HRESULT hr;
1812 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1813 if (hr == S_OK) {
1814 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1815 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1816 IDWriteRenderingParams3_Release(params3);
1818 else
1819 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1822 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1824 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1826 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1827 if (emSize >= emthreshold)
1828 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1829 else
1830 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1833 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1834 if (emSize >= emthreshold)
1835 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1836 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1837 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1838 else
1839 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1840 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1843 return S_OK;
1846 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1848 FIXME("%p, %#x: stub\n", iface, ch);
1850 return FALSE;
1853 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1855 FIXME("%p, %u: stub\n", iface, glyph);
1857 return FALSE;
1860 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1861 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1863 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1865 return E_NOTIMPL;
1868 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1869 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1871 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1873 return E_NOTIMPL;
1876 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1877 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1879 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1881 return E_NOTIMPL;
1884 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1886 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1888 TRACE("%p.\n", iface);
1890 return fontface->glyph_image_formats;
1893 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1894 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1896 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1898 return E_NOTIMPL;
1901 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1903 FIXME("%p, %p: stub\n", iface, context);
1906 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1908 FIXME("%p: stub\n", iface);
1910 return 0;
1913 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1914 UINT32 value_count)
1916 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1918 return E_NOTIMPL;
1921 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1923 static int once;
1925 if (!once++)
1926 FIXME("%p: stub\n", iface);
1928 return FALSE;
1931 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1933 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1935 TRACE("%p, %p.\n", iface, resource);
1937 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1940 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1942 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1944 TRACE("%p, %p.\n", iface, other);
1946 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1947 return FALSE;
1949 /* TODO: add variations support */
1951 return fontface->index == other_face->index &&
1952 fontface->simulations == other_face->simulations &&
1953 is_same_fontfile(fontface->file, other_face->file);
1956 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1958 dwritefontface_QueryInterface,
1959 dwritefontface_AddRef,
1960 dwritefontface_Release,
1961 dwritefontface_GetType,
1962 dwritefontface_GetFiles,
1963 dwritefontface_GetIndex,
1964 dwritefontface_GetSimulations,
1965 dwritefontface_IsSymbolFont,
1966 dwritefontface_GetMetrics,
1967 dwritefontface_GetGlyphCount,
1968 dwritefontface_GetDesignGlyphMetrics,
1969 dwritefontface_GetGlyphIndices,
1970 dwritefontface_TryGetFontTable,
1971 dwritefontface_ReleaseFontTable,
1972 dwritefontface_GetGlyphRunOutline,
1973 dwritefontface_GetRecommendedRenderingMode,
1974 dwritefontface_GetGdiCompatibleMetrics,
1975 dwritefontface_GetGdiCompatibleGlyphMetrics,
1976 dwritefontface1_GetMetrics,
1977 dwritefontface1_GetGdiCompatibleMetrics,
1978 dwritefontface1_GetCaretMetrics,
1979 dwritefontface1_GetUnicodeRanges,
1980 dwritefontface1_IsMonospacedFont,
1981 dwritefontface1_GetDesignGlyphAdvances,
1982 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1983 dwritefontface1_GetKerningPairAdjustments,
1984 dwritefontface1_HasKerningPairs,
1985 dwritefontface1_GetRecommendedRenderingMode,
1986 dwritefontface1_GetVerticalGlyphVariants,
1987 dwritefontface1_HasVerticalGlyphVariants,
1988 dwritefontface2_IsColorFont,
1989 dwritefontface2_GetColorPaletteCount,
1990 dwritefontface2_GetPaletteEntryCount,
1991 dwritefontface2_GetPaletteEntries,
1992 dwritefontface2_GetRecommendedRenderingMode,
1993 dwritefontface3_GetFontFaceReference,
1994 dwritefontface3_GetPanose,
1995 dwritefontface3_GetWeight,
1996 dwritefontface3_GetStretch,
1997 dwritefontface3_GetStyle,
1998 dwritefontface3_GetFamilyNames,
1999 dwritefontface3_GetFaceNames,
2000 dwritefontface3_GetInformationalStrings,
2001 dwritefontface3_HasCharacter,
2002 dwritefontface3_GetRecommendedRenderingMode,
2003 dwritefontface3_IsCharacterLocal,
2004 dwritefontface3_IsGlyphLocal,
2005 dwritefontface3_AreCharactersLocal,
2006 dwritefontface3_AreGlyphsLocal,
2007 dwritefontface4_GetGlyphImageFormats_,
2008 dwritefontface4_GetGlyphImageFormats,
2009 dwritefontface4_GetGlyphImageData,
2010 dwritefontface4_ReleaseGlyphImageData,
2011 dwritefontface5_GetFontAxisValueCount,
2012 dwritefontface5_GetFontAxisValues,
2013 dwritefontface5_HasVariations,
2014 dwritefontface5_GetFontResource,
2015 dwritefontface5_Equals,
2018 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
2020 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2021 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
2024 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
2026 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2027 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
2030 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
2032 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2033 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
2036 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
2037 IDWriteFontFace3 **ret)
2039 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2041 TRACE("%p, %p.\n", iface, ret);
2043 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
2044 IDWriteFontFace3_AddRef(*ret);
2046 return S_OK;
2049 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
2050 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
2052 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2053 DWRITE_FONT_FILE_TYPE file_type;
2054 DWRITE_FONT_FACE_TYPE face_type;
2055 IDWriteFontFace *face;
2056 BOOL is_supported;
2057 UINT32 face_num;
2058 HRESULT hr;
2060 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
2062 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
2063 if (FAILED(hr))
2064 return hr;
2066 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
2067 simulations, &face);
2068 if (SUCCEEDED(hr))
2070 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
2071 IDWriteFontFace_Release(face);
2074 return hr;
2077 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
2079 FIXME("%p, %p.\n", iface, ref);
2081 return E_NOTIMPL;
2084 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
2086 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2088 TRACE("%p.\n", iface);
2090 return fontface->index;
2093 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
2095 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2097 TRACE("%p.\n", iface);
2099 return fontface->simulations;
2102 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
2104 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2106 TRACE("%p, %p.\n", iface, file);
2108 *file = fontface->file;
2109 IDWriteFontFile_AddRef(*file);
2111 return S_OK;
2114 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
2116 FIXME("%p.\n", iface);
2118 return 0;
2121 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
2123 FIXME("%p.\n", iface);
2125 return 0;
2128 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
2130 FIXME("%p, %p.\n", iface, writetime);
2132 return E_NOTIMPL;
2135 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
2137 FIXME("%p.\n", iface);
2139 return DWRITE_LOCALITY_LOCAL;
2142 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
2144 FIXME("%p.\n", iface);
2146 return E_NOTIMPL;
2149 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
2150 WCHAR const *chars, UINT32 count)
2152 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
2154 return E_NOTIMPL;
2157 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
2158 UINT16 const *glyphs, UINT32 count)
2160 FIXME("%p, %p, %u.\n", iface, glyphs, count);
2162 return E_NOTIMPL;
2165 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
2166 UINT64 offset, UINT64 size)
2168 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
2170 return E_NOTIMPL;
2173 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
2175 dwritefontface_reference_QueryInterface,
2176 dwritefontface_reference_AddRef,
2177 dwritefontface_reference_Release,
2178 dwritefontface_reference_CreateFontFace,
2179 dwritefontface_reference_CreateFontFaceWithSimulations,
2180 dwritefontface_reference_Equals,
2181 dwritefontface_reference_GetFontFaceIndex,
2182 dwritefontface_reference_GetSimulations,
2183 dwritefontface_reference_GetFontFile,
2184 dwritefontface_reference_GetLocalFileSize,
2185 dwritefontface_reference_GetFileSize,
2186 dwritefontface_reference_GetFileTime,
2187 dwritefontface_reference_GetLocality,
2188 dwritefontface_reference_EnqueueFontDownloadRequest,
2189 dwritefontface_reference_EnqueueCharacterDownloadRequest,
2190 dwritefontface_reference_EnqueueGlyphDownloadRequest,
2191 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
2194 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
2196 struct dwrite_font_data *data = font->data;
2197 struct fontface_desc desc;
2198 struct list *cached_list;
2199 HRESULT hr;
2201 *fontface = NULL;
2203 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
2204 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
2205 if (hr == S_OK)
2206 return hr;
2208 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
2209 return hr;
2211 desc.factory = font->family->collection->factory;
2212 desc.face_type = data->face_type;
2213 desc.file = data->file;
2214 desc.index = data->face_index;
2215 desc.simulations = data->simulations;
2216 desc.font_data = data;
2217 hr = create_fontface(&desc, cached_list, fontface);
2219 IDWriteFontFileStream_Release(desc.stream);
2220 return hr;
2223 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
2225 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2227 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
2228 IsEqualIID(riid, &IID_IDWriteFont2) ||
2229 IsEqualIID(riid, &IID_IDWriteFont1) ||
2230 IsEqualIID(riid, &IID_IDWriteFont) ||
2231 IsEqualIID(riid, &IID_IUnknown))
2233 *obj = iface;
2234 IDWriteFont3_AddRef(iface);
2235 return S_OK;
2238 WARN("%s not implemented.\n", debugstr_guid(riid));
2240 *obj = NULL;
2241 return E_NOINTERFACE;
2244 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
2246 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2247 ULONG refcount = InterlockedIncrement(&font->refcount);
2249 TRACE("%p, refcount %ld.\n", iface, refcount);
2251 return refcount;
2254 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
2256 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2257 ULONG refcount = InterlockedDecrement(&font->refcount);
2259 TRACE("%p, refcount %ld.\n", iface, refcount);
2261 if (!refcount)
2263 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
2264 release_font_data(font->data);
2265 free(font);
2268 return refcount;
2271 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
2273 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2275 TRACE("%p, %p.\n", iface, family);
2277 *family = (IDWriteFontFamily *)&font->family->IDWriteFontFamily2_iface;
2278 IDWriteFontFamily_AddRef(*family);
2279 return S_OK;
2282 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
2284 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2286 TRACE("%p.\n", iface);
2288 return font->data->weight;
2291 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
2293 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2295 TRACE("%p.\n", iface);
2297 return font->data->stretch;
2300 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
2302 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2304 TRACE("%p.\n", iface);
2306 return font->style;
2309 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2311 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2313 TRACE("%p.\n", iface);
2315 return !!(font->data->flags & FONT_IS_SYMBOL);
2318 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2320 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2322 TRACE("%p, %p.\n", iface, names);
2324 return clone_localizedstrings(font->data->names, names);
2327 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2328 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2330 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2331 struct dwrite_font_data *data = font->data;
2332 struct file_stream_desc stream_desc;
2334 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2336 /* Stream will be created if necessary. */
2337 stream_desc.stream = NULL;
2338 stream_desc.face_index = data->face_index;
2339 stream_desc.face_type = data->face_type;
2340 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2343 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2345 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2347 TRACE("%p.\n", iface);
2349 return font->data->simulations;
2352 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2354 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2356 TRACE("%p, %p.\n", iface, metrics);
2358 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2361 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2363 UINT16 glyph;
2364 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2365 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2366 return glyph != 0;
2369 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2371 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2373 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2375 *exists = dwritefont_has_character(font, ch);
2377 return S_OK;
2380 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2382 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2384 TRACE("%p, %p.\n", iface, fontface);
2386 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2389 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2391 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2393 TRACE("%p, %p.\n", iface, metrics);
2395 *metrics = font->data->metrics;
2398 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2400 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2402 TRACE("%p, %p.\n", iface, panose);
2404 *panose = font->data->panose;
2407 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2408 UINT32 *count)
2410 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2412 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2414 *count = 0;
2415 if (max_count && !ranges)
2416 return E_INVALIDARG;
2418 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2419 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2422 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2424 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2426 TRACE("%p.\n", iface);
2428 return !!(font->data->flags & FONT_IS_MONOSPACED);
2431 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2433 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2435 TRACE("%p.\n", iface);
2437 return !!(font->data->flags & FONT_IS_COLORED);
2440 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2442 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2444 TRACE("%p, %p.\n", iface, fontface);
2446 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2449 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2451 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2453 TRACE("%p, %p.\n", iface, other);
2455 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2456 return FALSE;
2458 return font->data->face_index == other_font->data->face_index
2459 && font->data->simulations == other_font->data->simulations
2460 && is_same_fontfile(font->data->file, other_font->data->file);
2463 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2465 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2467 TRACE("%p, %p.\n", iface, reference);
2469 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2470 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2471 (IDWriteFontFaceReference1 **)reference);
2474 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2476 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2478 TRACE("%p, %#x.\n", iface, ch);
2480 return dwritefont_has_character(font, ch);
2483 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2485 FIXME("%p: stub.\n", iface);
2487 return DWRITE_LOCALITY_LOCAL;
2490 static const IDWriteFont3Vtbl dwritefontvtbl = {
2491 dwritefont_QueryInterface,
2492 dwritefont_AddRef,
2493 dwritefont_Release,
2494 dwritefont_GetFontFamily,
2495 dwritefont_GetWeight,
2496 dwritefont_GetStretch,
2497 dwritefont_GetStyle,
2498 dwritefont_IsSymbolFont,
2499 dwritefont_GetFaceNames,
2500 dwritefont_GetInformationalStrings,
2501 dwritefont_GetSimulations,
2502 dwritefont_GetMetrics,
2503 dwritefont_HasCharacter,
2504 dwritefont_CreateFontFace,
2505 dwritefont1_GetMetrics,
2506 dwritefont1_GetPanose,
2507 dwritefont1_GetUnicodeRanges,
2508 dwritefont1_IsMonospacedFont,
2509 dwritefont2_IsColorFont,
2510 dwritefont3_CreateFontFace,
2511 dwritefont3_Equals,
2512 dwritefont3_GetFontFaceReference,
2513 dwritefont3_HasCharacter,
2514 dwritefont3_GetLocality
2517 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2519 if (!iface)
2520 return NULL;
2521 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2522 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2525 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2527 if (!iface)
2528 return NULL;
2529 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2530 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2533 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2535 if (!iface)
2536 return NULL;
2537 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2538 return NULL;
2539 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2540 IDWriteFontFaceReference1_iface);
2543 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2545 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2546 *lf = font->data->lf;
2549 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2551 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2552 *lf = fontface->lf;
2555 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2557 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2558 *fontsig = font->data->fontsig;
2559 return S_OK;
2562 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2564 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2565 *fontsig = fontface->fontsig;
2566 return S_OK;
2569 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2571 struct dwrite_font *object;
2573 *font = NULL;
2575 if (!(object = calloc(1, sizeof(*object))))
2576 return E_OUTOFMEMORY;
2578 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2579 object->refcount = 1;
2580 object->family = family;
2581 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2582 object->data = family->data->fonts[index];
2583 object->style = object->data->style;
2584 addref_font_data(object->data);
2586 *font = &object->IDWriteFont3_iface;
2588 return S_OK;
2591 /* IDWriteFontList2 */
2592 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2594 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2596 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2597 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2598 IsEqualIID(riid, &IID_IDWriteFontList) ||
2599 IsEqualIID(riid, &IID_IUnknown))
2601 *obj = iface;
2602 IDWriteFontList2_AddRef(iface);
2603 return S_OK;
2606 WARN("%s not implemented.\n", debugstr_guid(riid));
2608 *obj = NULL;
2609 return E_NOINTERFACE;
2612 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2614 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2615 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2617 TRACE("%p, refcount %lu.\n", iface, refcount);
2619 return refcount;
2622 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2624 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2625 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2627 TRACE("%p, refcount %lu.\n", iface, refcount);
2629 if (!refcount)
2631 unsigned int i;
2633 for (i = 0; i < fontlist->font_count; i++)
2634 release_font_data(fontlist->fonts[i]);
2635 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2636 free(fontlist->fonts);
2637 free(fontlist);
2640 return refcount;
2643 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2645 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2646 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2649 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2651 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2653 TRACE("%p.\n", iface);
2655 return fontlist->font_count;
2658 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2660 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2662 TRACE("%p, %u, %p.\n", iface, index, font);
2664 *font = NULL;
2666 if (fontlist->font_count == 0)
2667 return S_FALSE;
2669 if (index >= fontlist->font_count)
2670 return E_INVALIDARG;
2672 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2675 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2677 FIXME("%p, %u.\n", iface, index);
2679 return DWRITE_LOCALITY_LOCAL;
2682 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2683 IDWriteFont3 **font)
2685 *font = NULL;
2687 if (fontlist->font_count == 0)
2688 return S_FALSE;
2690 if (index >= fontlist->font_count)
2691 return E_FAIL;
2693 return create_font(fontlist->family, index, font);
2696 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2698 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2700 TRACE("%p, %u, %p.\n", iface, index, font);
2702 return fontlist_get_font(fontlist, index, font);
2705 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2706 IDWriteFontFaceReference **reference)
2708 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2709 IDWriteFont3 *font;
2710 HRESULT hr;
2712 TRACE("%p, %u, %p.\n", iface, index, reference);
2714 *reference = NULL;
2716 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2718 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2719 IDWriteFont3_Release(font);
2722 return hr;
2725 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2727 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2729 TRACE("%p, %p.\n", iface, fontset);
2731 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2732 fontlist->font_count, fontset);
2735 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2737 dwritefontlist_QueryInterface,
2738 dwritefontlist_AddRef,
2739 dwritefontlist_Release,
2740 dwritefontlist_GetFontCollection,
2741 dwritefontlist_GetFontCount,
2742 dwritefontlist_GetFont,
2743 dwritefontlist1_GetFontLocality,
2744 dwritefontlist1_GetFont,
2745 dwritefontlist1_GetFontFaceReference,
2746 dwritefontlist2_GetFontSet,
2749 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2751 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2753 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2755 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2756 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2757 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2758 IsEqualIID(riid, &IID_IUnknown))
2760 *obj = iface;
2762 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2763 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2764 IsEqualIID(riid, &IID_IDWriteFontList))
2766 *obj = &family->IDWriteFontList2_iface;
2768 else
2770 WARN("%s not implemented.\n", debugstr_guid(riid));
2771 *obj = NULL;
2772 return E_NOINTERFACE;
2775 IUnknown_AddRef((IUnknown *)*obj);
2776 return S_OK;
2779 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2781 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2782 ULONG refcount = InterlockedIncrement(&family->refcount);
2784 TRACE("%p, %lu.\n", iface, refcount);
2786 return refcount;
2789 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2791 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2792 ULONG refcount = InterlockedDecrement(&family->refcount);
2794 TRACE("%p, %lu.\n", iface, refcount);
2796 if (!refcount)
2798 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2799 release_fontfamily_data(family->data);
2800 free(family);
2803 return refcount;
2806 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2808 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2810 TRACE("%p, %p.\n", iface, collection);
2812 *collection = (IDWriteFontCollection *)&family->collection->IDWriteFontCollection3_iface;
2813 IDWriteFontCollection_AddRef(*collection);
2814 return S_OK;
2817 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2819 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2821 TRACE("%p.\n", iface);
2823 return family->data->count;
2826 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2828 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2830 TRACE("%p, %u, %p.\n", iface, index, font);
2832 *font = NULL;
2834 if (!family->data->count)
2835 return S_FALSE;
2837 if (index >= family->data->count)
2838 return E_INVALIDARG;
2840 return create_font(family, index, (IDWriteFont3 **)font);
2843 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2845 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2847 TRACE("%p, %p.\n", iface, names);
2849 return clone_localizedstrings(family->data->familyname, names);
2852 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2853 const struct dwrite_font_propvec *req)
2855 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2856 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2857 FLOAT cur_req_prod, next_req_prod;
2859 if (next_to_req < cur_to_req)
2860 return TRUE;
2862 if (next_to_req > cur_to_req)
2863 return FALSE;
2865 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2866 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2868 if (next_req_prod > cur_req_prod)
2869 return TRUE;
2871 if (next_req_prod < cur_req_prod)
2872 return FALSE;
2874 if (next->stretch > cur->stretch)
2875 return TRUE;
2876 if (next->stretch < cur->stretch)
2877 return FALSE;
2879 if (next->style > cur->style)
2880 return TRUE;
2881 if (next->style < cur->style)
2882 return FALSE;
2884 if (next->weight > cur->weight)
2885 return TRUE;
2886 if (next->weight < cur->weight)
2887 return FALSE;
2889 /* full match, no reason to prefer new variant */
2890 return FALSE;
2893 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2894 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2896 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2897 struct dwrite_font_propvec req;
2898 size_t i, match;
2900 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2902 if (!family->data->count)
2904 *font = NULL;
2905 return DWRITE_E_NOFONT;
2908 init_font_prop_vec(weight, stretch, style, &req);
2909 match = 0;
2911 for (i = 1; i < family->data->count; ++i)
2913 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2914 match = i;
2917 return create_font(family, match, (IDWriteFont3 **)font);
2920 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2922 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2924 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2927 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2929 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2932 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2934 UINT32 b = fonts->font_count - 1, j, t;
2936 while (1) {
2937 t = b;
2939 for (j = 0; j < b; j++) {
2940 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2941 struct dwrite_font_data *s = fonts->fonts[j];
2942 fonts->fonts[j] = fonts->fonts[j+1];
2943 fonts->fonts[j+1] = s;
2944 t = j;
2948 if (t == b)
2949 break;
2950 b = t;
2954 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2955 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2957 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2958 matching_filter_func func = NULL;
2959 struct dwrite_font_propvec req;
2960 struct dwrite_fontlist *fonts;
2961 size_t i;
2963 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2965 *ret = NULL;
2967 if (!(fonts = malloc(sizeof(*fonts))))
2968 return E_OUTOFMEMORY;
2970 /* Allocate as many as family has, not all of them will be necessary used. */
2971 if (!(fonts->fonts = calloc(family->data->count, sizeof(*fonts->fonts))))
2973 free(fonts);
2974 return E_OUTOFMEMORY;
2977 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2978 fonts->refcount = 1;
2979 fonts->family = family;
2980 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2981 fonts->font_count = 0;
2983 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2984 if (style == DWRITE_FONT_STYLE_NORMAL) {
2985 if (family->data->has_normal_face || family->data->has_italic_face)
2986 func = is_font_acceptable_for_normal;
2988 else /* requested oblique or italic */ {
2989 if (family->data->has_oblique_face || family->data->has_italic_face)
2990 func = is_font_acceptable_for_oblique_italic;
2993 for (i = 0; i < family->data->count; ++i)
2995 if (!func || func(family->data->fonts[i]))
2997 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
3001 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
3002 init_font_prop_vec(weight, stretch, style, &req);
3003 matchingfonts_sort(fonts, &req);
3005 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
3006 return S_OK;
3009 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
3011 FIXME("%p, %u.\n", iface, index);
3013 return DWRITE_LOCALITY_LOCAL;
3016 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
3018 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3020 TRACE("%p, %u, %p.\n", iface, index, font);
3022 *font = NULL;
3024 if (!family->data->count)
3025 return S_FALSE;
3027 if (index >= family->data->count)
3028 return E_FAIL;
3030 return create_font(family, index, font);
3033 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
3034 IDWriteFontFaceReference **reference)
3036 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3037 const struct dwrite_font_data *font;
3039 TRACE("%p, %u, %p.\n", iface, index, reference);
3041 *reference = NULL;
3043 if (index >= family->data->count)
3044 return E_FAIL;
3046 font = family->data->fonts[index];
3047 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
3048 font->file, font->face_index, font->simulations, reference);
3051 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
3052 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
3054 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
3056 return E_NOTIMPL;
3059 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
3061 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3063 TRACE("%p, %p.\n", iface, fontset);
3065 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3066 family->data->count, fontset);
3069 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
3071 dwritefontfamily_QueryInterface,
3072 dwritefontfamily_AddRef,
3073 dwritefontfamily_Release,
3074 dwritefontfamily_GetFontCollection,
3075 dwritefontfamily_GetFontCount,
3076 dwritefontfamily_GetFont,
3077 dwritefontfamily_GetFamilyNames,
3078 dwritefontfamily_GetFirstMatchingFont,
3079 dwritefontfamily_GetMatchingFonts,
3080 dwritefontfamily1_GetFontLocality,
3081 dwritefontfamily1_GetFont,
3082 dwritefontfamily1_GetFontFaceReference,
3083 dwritefontfamily2_GetMatchingFonts,
3084 dwritefontfamily2_GetFontSet,
3087 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
3089 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3090 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
3093 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
3095 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3096 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
3099 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
3101 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3102 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
3105 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
3106 IDWriteFontCollection **collection)
3108 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3109 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
3112 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
3114 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3115 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
3118 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
3120 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3121 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3124 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
3126 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3127 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
3130 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
3132 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3133 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3136 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
3137 IDWriteFontFaceReference **reference)
3139 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3140 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
3143 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
3145 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3147 TRACE("%p, %p.\n", iface, fontset);
3149 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3150 family->data->count, fontset);
3153 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
3155 dwritefontfamilylist_QueryInterface,
3156 dwritefontfamilylist_AddRef,
3157 dwritefontfamilylist_Release,
3158 dwritefontfamilylist_GetFontCollection,
3159 dwritefontfamilylist_GetFontCount,
3160 dwritefontfamilylist_GetFont,
3161 dwritefontfamilylist1_GetFontLocality,
3162 dwritefontfamilylist1_GetFont,
3163 dwritefontfamilylist1_GetFontFaceReference,
3164 dwritefontfamilylist2_GetFontSet,
3167 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
3168 struct dwrite_fontfamily **family)
3170 struct dwrite_fontfamily *object;
3172 *family = NULL;
3174 if (!(object = calloc(1, sizeof(*object))))
3175 return E_OUTOFMEMORY;
3177 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
3178 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
3179 object->refcount = 1;
3180 object->collection = collection;
3181 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
3182 object->data = collection->family_data[index];
3183 InterlockedIncrement(&object->data->refcount);
3185 *family = object;
3187 return S_OK;
3190 BOOL is_system_collection(IDWriteFontCollection *collection)
3192 void *obj;
3193 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
3196 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3198 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3200 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
3202 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3203 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3204 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3205 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3206 IsEqualIID(riid, &IID_IUnknown))
3208 *obj = iface;
3209 IDWriteFontCollection3_AddRef(iface);
3210 return S_OK;
3213 *obj = NULL;
3215 if (IsEqualIID(riid, &IID_issystemcollection))
3216 return S_OK;
3218 WARN("%s not implemented.\n", debugstr_guid(riid));
3220 return E_NOINTERFACE;
3223 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3225 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3227 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3228 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3229 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3230 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3231 IsEqualIID(riid, &IID_IUnknown))
3233 *obj = iface;
3234 IDWriteFontCollection3_AddRef(iface);
3235 return S_OK;
3238 WARN("%s not implemented.\n", debugstr_guid(riid));
3240 *obj = NULL;
3242 return E_NOINTERFACE;
3245 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
3247 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3248 ULONG refcount = InterlockedIncrement(&collection->refcount);
3250 TRACE("%p, refcount %ld.\n", collection, refcount);
3252 return refcount;
3255 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
3257 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3258 ULONG refcount = InterlockedDecrement(&collection->refcount);
3259 size_t i;
3261 TRACE("%p, refcount %ld.\n", iface, refcount);
3263 if (!refcount)
3265 factory_detach_fontcollection(collection->factory, iface);
3266 for (i = 0; i < collection->count; ++i)
3267 release_fontfamily_data(collection->family_data[i]);
3268 free(collection->family_data);
3269 free(collection);
3272 return refcount;
3275 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
3277 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3279 TRACE("%p.\n", iface);
3281 return collection->count;
3284 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3285 IDWriteFontFamily **ret)
3287 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3288 struct dwrite_fontfamily *family;
3289 HRESULT hr;
3291 TRACE("%p, %u, %p.\n", iface, index, ret);
3293 *ret = NULL;
3295 if (index >= collection->count)
3296 return E_FAIL;
3298 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3299 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
3301 return hr;
3304 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
3306 size_t i;
3308 for (i = 0; i < collection->count; ++i)
3310 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3311 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3312 HRESULT hr;
3314 for (j = 0; j < count; j++)
3316 WCHAR buffer[255];
3317 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3318 if (SUCCEEDED(hr) && !wcsicmp(buffer, name))
3319 return i;
3323 return ~0u;
3326 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3327 UINT32 *index, BOOL *exists)
3329 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3331 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3333 *index = collection_find_family(collection, name);
3334 *exists = *index != ~0u;
3335 return S_OK;
3338 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3339 IDWriteFont **font)
3341 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3342 struct dwrite_fontfamily *family;
3343 BOOL found_font = FALSE;
3344 IDWriteFontFile *file;
3345 UINT32 face_index, count;
3346 size_t i, j;
3347 HRESULT hr;
3349 TRACE("%p, %p, %p.\n", iface, face, font);
3351 *font = NULL;
3353 if (!face)
3354 return E_INVALIDARG;
3356 count = 1;
3357 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3358 if (FAILED(hr))
3359 return hr;
3360 face_index = IDWriteFontFace_GetIndex(face);
3362 found_font = FALSE;
3363 for (i = 0; i < collection->count; ++i)
3365 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3367 for (j = 0; j < family_data->count; ++j)
3369 struct dwrite_font_data *font_data = family_data->fonts[j];
3371 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3372 found_font = TRUE;
3373 break;
3377 if (found_font)
3378 break;
3380 IDWriteFontFile_Release(file);
3382 if (!found_font)
3383 return DWRITE_E_NOFONT;
3385 hr = create_fontfamily(collection, i, &family);
3386 if (FAILED(hr))
3387 return hr;
3389 hr = create_font(family, j, (IDWriteFont3 **)font);
3390 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3391 return hr;
3394 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3396 FIXME("%p, %p.\n", iface, fontset);
3398 return E_NOTIMPL;
3401 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3402 IDWriteFontFamily1 **ret)
3404 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3405 struct dwrite_fontfamily *family;
3406 HRESULT hr;
3408 TRACE("%p, %u, %p.\n", iface, index, ret);
3410 *ret = NULL;
3412 if (index >= collection->count)
3413 return E_FAIL;
3415 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3416 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3418 return hr;
3421 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3422 UINT32 index, IDWriteFontFamily2 **ret)
3424 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3425 struct dwrite_fontfamily *family;
3426 HRESULT hr;
3428 TRACE("%p, %u, %p.\n", iface, index, ret);
3430 *ret = NULL;
3432 if (index >= collection->count)
3433 return E_FAIL;
3435 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3436 *ret = &family->IDWriteFontFamily2_iface;
3438 return hr;
3441 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3442 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3443 IDWriteFontList2 **fontlist)
3445 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3447 return E_NOTIMPL;
3450 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3452 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3454 TRACE("%p.\n", iface);
3456 return collection->family_model;
3459 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3461 FIXME("%p, %p.\n", iface, fontset);
3463 return E_NOTIMPL;
3466 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3468 FIXME("%p.\n", iface);
3470 return NULL;
3473 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3475 dwritefontcollection_QueryInterface,
3476 dwritefontcollection_AddRef,
3477 dwritefontcollection_Release,
3478 dwritefontcollection_GetFontFamilyCount,
3479 dwritefontcollection_GetFontFamily,
3480 dwritefontcollection_FindFamilyName,
3481 dwritefontcollection_GetFontFromFontFace,
3482 dwritefontcollection1_GetFontSet,
3483 dwritefontcollection1_GetFontFamily,
3484 dwritefontcollection2_GetFontFamily,
3485 dwritefontcollection2_GetMatchingFonts,
3486 dwritefontcollection2_GetFontFamilyModel,
3487 dwritefontcollection2_GetFontSet,
3488 dwritefontcollection3_GetExpirationEvent,
3491 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3493 dwritesystemfontcollection_QueryInterface,
3494 dwritefontcollection_AddRef,
3495 dwritefontcollection_Release,
3496 dwritefontcollection_GetFontFamilyCount,
3497 dwritefontcollection_GetFontFamily,
3498 dwritefontcollection_FindFamilyName,
3499 dwritefontcollection_GetFontFromFontFace,
3500 dwritefontcollection1_GetFontSet,
3501 dwritefontcollection1_GetFontFamily,
3502 dwritefontcollection2_GetFontFamily,
3503 dwritefontcollection2_GetMatchingFonts,
3504 dwritefontcollection2_GetFontFamilyModel,
3505 dwritefontcollection2_GetFontSet,
3506 dwritefontcollection3_GetExpirationEvent,
3509 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3511 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3512 sizeof(*family_data->fonts)))
3514 return E_OUTOFMEMORY;
3517 family_data->fonts[family_data->count++] = font_data;
3518 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3519 family_data->has_normal_face = 1;
3520 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3521 family_data->has_oblique_face = 1;
3522 else
3523 family_data->has_italic_face = 1;
3524 return S_OK;
3527 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3528 struct dwrite_fontfamily_data *family)
3530 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3531 sizeof(*collection->family_data)))
3533 return E_OUTOFMEMORY;
3536 collection->family_data[collection->count++] = family;
3537 return S_OK;
3540 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, IDWriteFactory7 *factory,
3541 DWRITE_FONT_FAMILY_MODEL family_model, BOOL is_system)
3543 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3544 collection->refcount = 1;
3545 collection->factory = factory;
3546 IDWriteFactory7_AddRef(collection->factory);
3547 collection->family_model = family_model;
3549 return S_OK;
3552 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3554 IDWriteFontFileLoader *loader;
3555 const void *key;
3556 UINT32 key_size;
3557 HRESULT hr;
3559 *stream = NULL;
3561 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3562 if (FAILED(hr))
3563 return hr;
3565 hr = IDWriteFontFile_GetLoader(file, &loader);
3566 if (FAILED(hr))
3567 return hr;
3569 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3570 IDWriteFontFileLoader_Release(loader);
3571 if (FAILED(hr))
3572 return hr;
3574 return hr;
3577 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3579 BOOL exists = FALSE;
3580 UINT32 index;
3581 HRESULT hr;
3583 buffer[0] = 0;
3584 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
3585 if (FAILED(hr) || !exists)
3586 return;
3588 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3591 static int trim_spaces(WCHAR *in, WCHAR *ret)
3593 int len;
3595 while (iswspace(*in))
3596 in++;
3598 ret[0] = 0;
3599 if (!(len = wcslen(in)))
3600 return 0;
3602 while (iswspace(in[len-1]))
3603 len--;
3605 memcpy(ret, in, len*sizeof(WCHAR));
3606 ret[len] = 0;
3608 return len;
3611 struct name_token {
3612 struct list entry;
3613 const WCHAR *ptr;
3614 INT len; /* token length */
3615 INT fulllen; /* full length including following separators */
3618 static inline BOOL is_name_separator_char(WCHAR ch)
3620 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3623 struct name_pattern {
3624 const WCHAR *part1; /* NULL indicates end of list */
3625 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3628 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3630 const struct name_pattern *pattern;
3631 struct name_token *token;
3632 int i = 0;
3634 while ((pattern = &patterns[i++])->part1)
3636 int len_part1 = wcslen(pattern->part1);
3637 int len_part2 = pattern->part2 ? wcslen(pattern->part2) : 0;
3639 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry)
3641 if (!len_part2)
3643 /* simple case with single part pattern */
3644 if (token->len != len_part1)
3645 continue;
3647 if (!wcsnicmp(token->ptr, pattern->part1, len_part1))
3649 if (match) *match = *token;
3650 list_remove(&token->entry);
3651 free(token);
3652 return TRUE;
3655 else
3657 struct name_token *next_token;
3658 struct list *next_entry;
3660 /* pattern parts are stored in reading order, tokens list is reversed */
3661 if (token->len < len_part2)
3662 continue;
3664 /* it's possible to have combined string as a token, like ExtraCondensed */
3665 if (token->len == len_part1 + len_part2)
3667 if (wcsnicmp(token->ptr, pattern->part1, len_part1))
3668 continue;
3670 if (wcsnicmp(&token->ptr[len_part1], pattern->part2, len_part2))
3671 continue;
3673 /* combined string match */
3674 if (match) *match = *token;
3675 list_remove(&token->entry);
3676 free(token);
3677 return TRUE;
3680 /* now it's only possible to have two tokens matched to respective pattern parts */
3681 if (token->len != len_part2)
3682 continue;
3684 next_entry = list_next(tokens, &token->entry);
3685 if (next_entry) {
3686 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3687 if (next_token->len != len_part1)
3688 continue;
3690 if (wcsnicmp(token->ptr, pattern->part2, len_part2))
3691 continue;
3693 if (wcsnicmp(next_token->ptr, pattern->part1, len_part1))
3694 continue;
3696 /* both parts matched, remove tokens */
3697 if (match) {
3698 match->ptr = next_token->ptr;
3699 match->len = (token->ptr - next_token->ptr) + token->len;
3701 list_remove(&token->entry);
3702 list_remove(&next_token->entry);
3703 free(next_token);
3704 free(token);
3705 return TRUE;
3711 if (match) {
3712 match->ptr = NULL;
3713 match->len = 0;
3715 return FALSE;
3718 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3720 static const struct name_pattern italic_patterns[] =
3722 { L"ita" },
3723 { L"ital" },
3724 { L"italic" },
3725 { L"cursive" },
3726 { L"kursiv" },
3727 { NULL }
3730 static const struct name_pattern oblique_patterns[] =
3732 { L"inclined" },
3733 { L"oblique" },
3734 { L"backslanted" },
3735 { L"backslant" },
3736 { L"slanted" },
3737 { NULL }
3740 /* italic patterns first */
3741 if (match_pattern_list(tokens, italic_patterns, match))
3742 return DWRITE_FONT_STYLE_ITALIC;
3744 /* oblique patterns */
3745 if (match_pattern_list(tokens, oblique_patterns, match))
3746 return DWRITE_FONT_STYLE_OBLIQUE;
3748 return style;
3751 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3752 struct name_token *match)
3754 static const struct name_pattern ultracondensed_patterns[] =
3756 { L"extra", L"compressed" },
3757 { L"ext", L"compressed" },
3758 { L"ultra", L"compressed" },
3759 { L"ultra", L"condensed" },
3760 { L"ultra", L"cond" },
3761 { NULL }
3764 static const struct name_pattern extracondensed_patterns[] =
3766 { L"compressed" },
3767 { L"extra", L"condensed" },
3768 { L"ext", L"condensed" },
3769 { L"extra", L"cond" },
3770 { L"ext", L"cond" },
3771 { NULL }
3774 static const struct name_pattern semicondensed_patterns[] =
3776 { L"narrow" },
3777 { L"compact" },
3778 { L"semi", L"condensed" },
3779 { L"semi", L"cond" },
3780 { NULL }
3783 static const struct name_pattern semiexpanded_patterns[] =
3785 { L"wide" },
3786 { L"semi", L"expanded" },
3787 { L"semi", L"extended" },
3788 { NULL }
3791 static const struct name_pattern extraexpanded_patterns[] =
3793 { L"extra", L"expanded" },
3794 { L"ext", L"expanded" },
3795 { L"extra", L"extended" },
3796 { L"ext", L"extended" },
3797 { NULL }
3800 static const struct name_pattern ultraexpanded_patterns[] =
3802 { L"ultra", L"expanded" },
3803 { L"ultra", L"extended" },
3804 { NULL }
3807 static const struct name_pattern condensed_patterns[] =
3809 { L"condensed" },
3810 { L"cond" },
3811 { NULL }
3814 static const struct name_pattern expanded_patterns[] =
3816 { L"expanded" },
3817 { L"extended" },
3818 { NULL }
3821 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3822 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3824 if (match_pattern_list(tokens, extracondensed_patterns, match))
3825 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3827 if (match_pattern_list(tokens, semicondensed_patterns, match))
3828 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3830 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3831 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3833 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3834 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3836 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3837 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3839 if (match_pattern_list(tokens, condensed_patterns, match))
3840 return DWRITE_FONT_STRETCH_CONDENSED;
3842 if (match_pattern_list(tokens, expanded_patterns, match))
3843 return DWRITE_FONT_STRETCH_EXPANDED;
3845 return stretch;
3848 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3849 struct name_token *match)
3851 static const struct name_pattern thin_patterns[] =
3853 { L"extra", L"thin" },
3854 { L"ext", L"thin" },
3855 { L"ultra", L"thin" },
3856 { NULL }
3859 static const struct name_pattern extralight_patterns[] =
3861 { L"extra", L"light" },
3862 { L"ext", L"light" },
3863 { L"ultra", L"light" },
3864 { NULL }
3867 static const struct name_pattern semilight_patterns[] =
3869 { L"semi", L"light" },
3870 { NULL }
3873 static const struct name_pattern demibold_patterns[] =
3875 { L"semi", L"bold" },
3876 { L"demi", L"bold" },
3877 { NULL }
3880 static const struct name_pattern extrabold_patterns[] =
3882 { L"extra", L"bold" },
3883 { L"ext", L"bold" },
3884 { L"ultra", L"bold" },
3885 { NULL }
3888 static const struct name_pattern extrablack_patterns[] =
3890 { L"extra", L"black" },
3891 { L"ext", L"black" },
3892 { L"ultra", L"black" },
3893 { NULL }
3896 static const struct name_pattern bold_patterns[] =
3898 { L"bold" },
3899 { NULL }
3902 static const struct name_pattern thin2_patterns[] =
3904 { L"thin" },
3905 { NULL }
3908 static const struct name_pattern light_patterns[] =
3910 { L"light" },
3911 { NULL }
3914 static const struct name_pattern medium_patterns[] =
3916 { L"medium" },
3917 { NULL }
3920 static const struct name_pattern black_patterns[] =
3922 { L"black" },
3923 { L"heavy" },
3924 { L"nord" },
3925 { NULL }
3928 static const struct name_pattern demibold2_patterns[] =
3930 { L"demi" },
3931 { NULL }
3934 static const struct name_pattern extrabold2_patterns[] =
3936 { L"ultra" },
3937 { NULL }
3940 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3941 matching pattern. */
3943 if (match_pattern_list(tokens, thin_patterns, match))
3944 return DWRITE_FONT_WEIGHT_THIN;
3946 if (match_pattern_list(tokens, extralight_patterns, match))
3947 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3949 if (match_pattern_list(tokens, semilight_patterns, match))
3950 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3952 if (match_pattern_list(tokens, demibold_patterns, match))
3953 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3955 if (match_pattern_list(tokens, extrabold_patterns, match))
3956 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3958 if (match_pattern_list(tokens, extrablack_patterns, match))
3959 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3961 if (match_pattern_list(tokens, bold_patterns, match))
3962 return DWRITE_FONT_WEIGHT_BOLD;
3964 if (match_pattern_list(tokens, thin2_patterns, match))
3965 return DWRITE_FONT_WEIGHT_THIN;
3967 if (match_pattern_list(tokens, light_patterns, match))
3968 return DWRITE_FONT_WEIGHT_LIGHT;
3970 if (match_pattern_list(tokens, medium_patterns, match))
3971 return DWRITE_FONT_WEIGHT_MEDIUM;
3973 if (match_pattern_list(tokens, black_patterns, match))
3974 return DWRITE_FONT_WEIGHT_BLACK;
3976 if (match_pattern_list(tokens, black_patterns, match))
3977 return DWRITE_FONT_WEIGHT_BLACK;
3979 if (match_pattern_list(tokens, demibold2_patterns, match))
3980 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3982 if (match_pattern_list(tokens, extrabold2_patterns, match))
3983 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3985 /* FIXME: use abbreviated names to extract weight */
3987 return weight;
3990 struct knownweight_entry
3992 const WCHAR *nameW;
3993 DWRITE_FONT_WEIGHT weight;
3996 static int __cdecl compare_knownweights(const void *a, const void* b)
3998 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3999 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
4000 int ret = 0;
4002 if (target > entry->weight)
4003 ret = 1;
4004 else if (target < entry->weight)
4005 ret = -1;
4007 return ret;
4010 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
4012 static const struct knownweight_entry knownweights[] =
4014 { L"Thin", DWRITE_FONT_WEIGHT_THIN },
4015 { L"Extra Light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
4016 { L"Light", DWRITE_FONT_WEIGHT_LIGHT },
4017 { L"Semi Light", DWRITE_FONT_WEIGHT_SEMI_LIGHT },
4018 { L"Medium", DWRITE_FONT_WEIGHT_MEDIUM },
4019 { L"Demi Bold", DWRITE_FONT_WEIGHT_DEMI_BOLD },
4020 { L"Bold", DWRITE_FONT_WEIGHT_BOLD },
4021 { L"Extra Bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD },
4022 { L"Black", DWRITE_FONT_WEIGHT_BLACK },
4023 { L"Extra Black", DWRITE_FONT_WEIGHT_EXTRA_BLACK }
4025 const struct knownweight_entry *ptr;
4027 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(*knownweights),
4028 compare_knownweights);
4029 if (!ptr) {
4030 nameW[0] = 0;
4031 return FALSE;
4034 wcscpy(nameW, ptr->nameW);
4035 return TRUE;
4038 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
4040 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
4041 strW[name->len] = 0;
4044 /* Modifies facenameW string, and returns pointer to regular term that was removed */
4045 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
4047 static const WCHAR *regular_patterns[] =
4049 L"Book",
4050 L"Normal",
4051 L"Regular",
4052 L"Roman",
4053 L"Upright",
4054 NULL
4057 const WCHAR *regular_ptr = NULL, *ptr;
4058 int i = 0;
4060 if (len == -1)
4061 len = wcslen(facenameW);
4063 /* remove rightmost regular variant from face name */
4064 while (!regular_ptr && (ptr = regular_patterns[i++]))
4066 int pattern_len = wcslen(ptr);
4067 WCHAR *src;
4069 if (pattern_len > len)
4070 continue;
4072 src = facenameW + len - pattern_len;
4073 while (src >= facenameW)
4075 if (!wcsnicmp(src, ptr, pattern_len))
4077 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
4078 len = wcslen(facenameW);
4079 regular_ptr = ptr;
4080 break;
4082 else
4083 src--;
4087 return regular_ptr;
4090 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
4092 const WCHAR *ptr;
4094 list_init(tokens);
4095 ptr = nameW;
4097 while (*ptr)
4099 struct name_token *token = malloc(sizeof(*token));
4100 token->ptr = ptr;
4101 token->len = 0;
4102 token->fulllen = 0;
4104 while (*ptr && !is_name_separator_char(*ptr)) {
4105 token->len++;
4106 token->fulllen++;
4107 ptr++;
4110 /* skip separators */
4111 while (is_name_separator_char(*ptr)) {
4112 token->fulllen++;
4113 ptr++;
4116 list_add_head(tokens, &token->entry);
4120 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
4122 struct name_token *token, *token2;
4123 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
4124 int len;
4126 list_remove(&token->entry);
4128 /* don't include last separator */
4129 len = list_empty(tokens) ? token->len : token->fulllen;
4130 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
4131 nameW += len;
4133 free(token);
4135 *nameW = 0;
4138 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
4140 struct name_token stretch_name, weight_name, style_name;
4141 WCHAR familynameW[255], facenameW[255], finalW[255];
4142 WCHAR weightW[32], stretchW[32], styleW[32];
4143 const WCHAR *regular_ptr = NULL;
4144 DWRITE_FONT_STRETCH stretch;
4145 DWRITE_FONT_WEIGHT weight;
4146 struct list tokens;
4147 int len;
4149 /* remove leading and trailing spaces from family and face name */
4150 trim_spaces(familyW, familynameW);
4151 len = trim_spaces(faceW, facenameW);
4153 /* remove rightmost regular variant from face name */
4154 regular_ptr = facename_remove_regular_term(facenameW, len);
4156 /* append face name to family name, FIXME check if face name is a substring of family name */
4157 if (*facenameW)
4159 wcscat(familynameW, L" ");
4160 wcscat(familynameW, facenameW);
4163 /* tokenize with " .-_" */
4164 fontname_tokenize(&tokens, familynameW);
4166 /* extract and resolve style */
4167 font->style = font_extract_style(&tokens, font->style, &style_name);
4169 /* extract stretch */
4170 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
4172 /* extract weight */
4173 weight = font_extract_weight(&tokens, font->weight, &weight_name);
4175 /* resolve weight */
4176 if (weight != font->weight)
4178 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
4179 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
4180 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
4181 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
4182 !(abs((int)weight - (int)font->weight) <= 150 &&
4183 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
4184 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
4185 font->weight != DWRITE_FONT_WEIGHT_BOLD))
4187 font->weight = weight;
4191 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
4192 it's leaning in opposite direction from normal comparing to specified stretch or if specified
4193 stretch itself is normal (extracted stretch is never normal). */
4194 if (stretch != font->stretch) {
4195 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
4196 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
4197 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
4199 font->stretch = stretch;
4203 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
4205 /* get final combined string from what's left in token list, list is released */
4206 fontname_tokens_to_str(&tokens, finalW);
4208 if (!wcscmp(familyW, finalW))
4209 return FALSE;
4211 /* construct face name */
4212 wcscpy(familyW, finalW);
4214 /* resolved weight name */
4215 if (weight_name.ptr)
4216 font_name_token_to_str(&weight_name, weightW);
4217 /* ignore normal weight */
4218 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
4219 weightW[0] = 0;
4220 /* for known weight values use appropriate names */
4221 else if (is_known_weight_value(font->weight, weightW)) {
4223 /* use Wnnn format as a fallback in case weight is not one of known values */
4224 else
4225 swprintf(weightW, ARRAY_SIZE(weightW), L"W%d", font->weight);
4227 /* resolved stretch name */
4228 if (stretch_name.ptr)
4229 font_name_token_to_str(&stretch_name, stretchW);
4230 /* ignore normal stretch */
4231 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
4232 stretchW[0] = 0;
4233 /* use predefined stretch names */
4234 else
4236 static const WCHAR *stretchnamesW[] =
4238 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
4239 L"Ultra Condensed",
4240 L"Extra Condensed",
4241 L"Condensed",
4242 L"Semi Condensed",
4243 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
4244 L"Semi Expanded",
4245 L"Expanded",
4246 L"Extra Expanded",
4247 L"Ultra Expanded"
4249 wcscpy(stretchW, stretchnamesW[font->stretch]);
4252 /* resolved style name */
4253 if (style_name.ptr)
4254 font_name_token_to_str(&style_name, styleW);
4255 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
4256 styleW[0] = 0;
4257 /* use predefined names */
4258 else
4259 wcscpy(styleW, font->style == DWRITE_FONT_STYLE_ITALIC ? L"Italic" : L"Oblique");
4261 /* use Regular match if it was found initially */
4262 if (!*weightW && !*stretchW && !*styleW)
4263 wcscpy(faceW, regular_ptr ? regular_ptr : L"Regular");
4264 else
4266 faceW[0] = 0;
4268 if (*stretchW) wcscpy(faceW, stretchW);
4270 if (*weightW)
4272 if (*faceW) wcscat(faceW, L" ");
4273 wcscat(faceW, weightW);
4276 if (*styleW)
4278 if (*faceW) wcscat(faceW, L" ");
4279 wcscat(faceW, styleW);
4283 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
4284 return TRUE;
4287 static HRESULT init_font_data(const struct fontface_desc *desc, DWRITE_FONT_FAMILY_MODEL family_model,
4288 struct dwrite_font_data **ret)
4290 static const float width_axis_values[] =
4292 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
4293 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
4294 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
4295 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
4296 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
4297 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
4298 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
4299 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
4300 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
4301 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
4304 struct file_stream_desc stream_desc;
4305 struct dwrite_font_props props;
4306 struct dwrite_font_data *data;
4307 WCHAR familyW[255], faceW[255];
4308 HRESULT hr;
4310 *ret = NULL;
4312 if (!(data = calloc(1, sizeof(*data))))
4313 return E_OUTOFMEMORY;
4315 data->refcount = 1;
4316 data->file = desc->file;
4317 data->face_index = desc->index;
4318 data->face_type = desc->face_type;
4319 IDWriteFontFile_AddRef(data->file);
4321 stream_desc.stream = desc->stream;
4322 stream_desc.face_type = desc->face_type;
4323 stream_desc.face_index = desc->index;
4324 opentype_get_font_properties(&stream_desc, &props);
4325 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4326 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4328 if (FAILED(hr = opentype_get_font_familyname(&stream_desc, family_model, &data->family_names)))
4330 WARN("Unable to get family name from the font file, hr %#lx.\n", hr);
4331 release_font_data(data);
4332 return hr;
4335 data->style = props.style;
4336 data->stretch = props.stretch;
4337 data->weight = props.weight;
4338 data->panose = props.panose;
4339 data->fontsig = props.fontsig;
4340 data->lf = props.lf;
4341 data->flags = props.flags;
4343 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4344 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4346 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE
4347 && font_apply_differentiation_rules(data, familyW, faceW))
4349 set_en_localizedstring(data->family_names, familyW);
4350 set_en_localizedstring(data->names, faceW);
4353 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4355 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4356 data->axis[0].value = props.weight;
4357 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4358 data->axis[1].value = width_axis_values[props.stretch];
4359 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4360 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4362 *ret = data;
4363 return S_OK;
4366 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4367 const WCHAR *facenameW, struct dwrite_font_data **ret)
4369 struct dwrite_font_data *data;
4371 *ret = NULL;
4373 if (!(data = calloc(1, sizeof(*data))))
4374 return E_OUTOFMEMORY;
4376 *data = *src;
4377 data->refcount = 1;
4378 data->simulations |= simulations;
4379 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4380 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4381 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4382 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4383 memset(data->info_strings, 0, sizeof(data->info_strings));
4384 data->names = NULL;
4385 IDWriteFontFile_AddRef(data->file);
4386 IDWriteLocalizedStrings_AddRef(data->family_names);
4388 create_localizedstrings(&data->names);
4389 add_localizedstring(data->names, L"en-us", facenameW);
4391 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4393 *ret = data;
4394 return S_OK;
4397 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4399 struct dwrite_fontfamily_data *data;
4401 if (!(data = calloc(1, sizeof(*data))))
4402 return E_OUTOFMEMORY;
4404 data->refcount = 1;
4405 data->familyname = familyname;
4406 IDWriteLocalizedStrings_AddRef(familyname);
4408 *ret = data;
4410 return S_OK;
4413 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4415 size_t i, j, heaviest;
4417 for (i = 0; i < family->count; ++i)
4419 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4420 heaviest = i;
4422 if (family->fonts[i]->bold_sim_tested)
4423 continue;
4425 family->fonts[i]->bold_sim_tested = 1;
4426 for (j = i; j < family->count; ++j)
4428 if (family->fonts[j]->bold_sim_tested)
4429 continue;
4431 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4432 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4433 if (family->fonts[j]->weight > weight) {
4434 weight = family->fonts[j]->weight;
4435 heaviest = j;
4437 family->fonts[j]->bold_sim_tested = 1;
4441 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550)
4443 static const struct name_pattern weightsim_patterns[] =
4445 { L"extra", L"light" },
4446 { L"ext", L"light" },
4447 { L"ultra", L"light" },
4448 { L"semi", L"light" },
4449 { L"semi", L"bold" },
4450 { L"demi", L"bold" },
4451 { L"bold" },
4452 { L"thin" },
4453 { L"light" },
4454 { L"medium" },
4455 { L"demi" },
4456 { NULL }
4459 WCHAR facenameW[255], initialW[255];
4460 struct dwrite_font_data *boldface;
4461 struct list tokens;
4463 /* add Bold simulation based on heaviest face data */
4465 /* Simulated face name should only contain Bold as weight term,
4466 so remove existing regular and weight terms. */
4467 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4468 facename_remove_regular_term(initialW, -1);
4470 /* remove current weight pattern */
4471 fontname_tokenize(&tokens, initialW);
4472 match_pattern_list(&tokens, weightsim_patterns, NULL);
4473 fontname_tokens_to_str(&tokens, facenameW);
4475 /* Bold suffix for new name */
4476 if (*facenameW) wcscat(facenameW, L" ");
4477 wcscat(facenameW, L"Bold");
4479 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4480 boldface->bold_sim_tested = 1;
4481 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4482 fontfamily_add_font(family, boldface);
4488 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4490 size_t i, j;
4492 for (i = 0; i < family->count; ++i)
4494 UINT32 regular = ~0u, oblique = ~0u;
4495 struct dwrite_font_data *obliqueface;
4496 WCHAR facenameW[255];
4498 if (family->fonts[i]->oblique_sim_tested)
4499 continue;
4501 family->fonts[i]->oblique_sim_tested = 1;
4502 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4503 regular = i;
4504 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4505 oblique = i;
4507 /* find regular style with same weight/stretch values */
4508 for (j = i; j < family->count; ++j)
4510 if (family->fonts[j]->oblique_sim_tested)
4511 continue;
4513 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4514 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4516 family->fonts[j]->oblique_sim_tested = 1;
4517 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4518 regular = j;
4520 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4521 oblique = j;
4524 if (regular != ~0u && oblique != ~0u)
4525 break;
4528 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4529 if (regular == ~0u)
4530 continue;
4532 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4533 if (oblique != ~0u)
4534 continue;
4536 /* add oblique simulation based on this regular face */
4538 /* remove regular term if any, append 'Oblique' */
4539 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4540 facename_remove_regular_term(facenameW, -1);
4542 if (*facenameW) wcscat(facenameW, L" ");
4543 wcscat(facenameW, L"Oblique");
4545 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4546 obliqueface->oblique_sim_tested = 1;
4547 obliqueface->lf.lfItalic = 1;
4548 fontfamily_add_font(family, obliqueface);
4553 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4554 const WCHAR *replacement_name)
4556 UINT32 i = collection_find_family(collection, replacement_name);
4557 struct dwrite_fontfamily_data *target;
4558 IDWriteLocalizedStrings *strings;
4559 HRESULT hr;
4561 /* replacement does not exist */
4562 if (i == ~0u)
4563 return FALSE;
4565 hr = create_localizedstrings(&strings);
4566 if (FAILED(hr))
4567 return FALSE;
4569 /* add a new family with target name, reuse font data from replacement */
4570 add_localizedstring(strings, L"en-us", target_name);
4571 hr = init_fontfamily_data(strings, &target);
4572 if (hr == S_OK) {
4573 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4574 WCHAR nameW[255];
4576 for (i = 0; i < replacement->count; ++i)
4578 fontfamily_add_font(target, replacement->fonts[i]);
4579 addref_font_data(replacement->fonts[i]);
4582 fontcollection_add_family(collection, target);
4583 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4584 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4586 IDWriteLocalizedStrings_Release(strings);
4587 return TRUE;
4590 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4591 system font collections. */
4592 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4594 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4595 WCHAR *name;
4596 void *data;
4597 HKEY hkey;
4599 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4600 return;
4602 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4603 RegCloseKey(hkey);
4604 return;
4607 max_namelen++; /* returned value doesn't include room for '\0' */
4608 name = malloc(max_namelen * sizeof(WCHAR));
4609 data = malloc(max_datalen);
4611 datalen = max_datalen;
4612 namelen = max_namelen;
4613 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4614 if (collection_find_family(collection, name) == ~0u) {
4615 if (type == REG_MULTI_SZ) {
4616 WCHAR *replacement = data;
4617 while (*replacement) {
4618 if (fontcollection_add_replacement(collection, name, replacement))
4619 break;
4620 replacement += wcslen(replacement) + 1;
4623 else if (type == REG_SZ)
4624 fontcollection_add_replacement(collection, name, data);
4626 else
4627 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4629 datalen = max_datalen;
4630 namelen = max_namelen;
4633 free(data);
4634 free(name);
4635 RegCloseKey(hkey);
4638 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4639 IDWriteFontCollection3 **ret)
4641 struct fontfile_enum {
4642 struct list entry;
4643 IDWriteFontFile *file;
4645 struct fontfile_enum *fileenum, *fileenum2;
4646 struct dwrite_fontcollection *collection;
4647 struct list scannedfiles;
4648 BOOL current = FALSE;
4649 HRESULT hr = S_OK;
4650 size_t i;
4652 *ret = NULL;
4654 if (!(collection = calloc(1, sizeof(*collection))))
4655 return E_OUTOFMEMORY;
4657 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, is_system);
4658 if (FAILED(hr))
4660 free(collection);
4661 return hr;
4664 *ret = &collection->IDWriteFontCollection3_iface;
4666 TRACE("building font collection:\n");
4668 list_init(&scannedfiles);
4669 while (hr == S_OK) {
4670 DWRITE_FONT_FACE_TYPE face_type;
4671 DWRITE_FONT_FILE_TYPE file_type;
4672 BOOL supported, same = FALSE;
4673 IDWriteFontFileStream *stream;
4674 IDWriteFontFile *file;
4675 UINT32 face_count;
4677 current = FALSE;
4678 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4679 if (FAILED(hr) || !current)
4680 break;
4682 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4683 if (FAILED(hr))
4684 break;
4686 /* check if we've scanned this file already */
4687 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4688 if ((same = is_same_fontfile(fileenum->file, file)))
4689 break;
4692 if (same) {
4693 IDWriteFontFile_Release(file);
4694 continue;
4697 if (FAILED(get_filestream_from_file(file, &stream))) {
4698 IDWriteFontFile_Release(file);
4699 continue;
4702 /* Unsupported formats are skipped. */
4703 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4704 if (FAILED(hr) || !supported || face_count == 0) {
4705 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
4706 IDWriteFontFileStream_Release(stream);
4707 IDWriteFontFile_Release(file);
4708 hr = S_OK;
4709 continue;
4712 /* add to scanned list */
4713 fileenum = malloc(sizeof(*fileenum));
4714 fileenum->file = file;
4715 list_add_tail(&scannedfiles, &fileenum->entry);
4717 for (i = 0; i < face_count; ++i)
4719 struct dwrite_font_data *font_data;
4720 struct fontface_desc desc;
4721 WCHAR familyW[255];
4722 UINT32 index;
4724 desc.factory = factory;
4725 desc.face_type = face_type;
4726 desc.file = file;
4727 desc.stream = stream;
4728 desc.index = i;
4729 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4730 desc.font_data = NULL;
4732 /* Allocate an initialize new font data structure. */
4733 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
4734 if (FAILED(hr))
4736 /* move to next one */
4737 hr = S_OK;
4738 continue;
4741 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4743 /* ignore dot named faces */
4744 if (familyW[0] == '.')
4746 WARN("Ignoring face %s\n", debugstr_w(familyW));
4747 release_font_data(font_data);
4748 continue;
4751 index = collection_find_family(collection, familyW);
4752 if (index != ~0u)
4753 hr = fontfamily_add_font(collection->family_data[index], font_data);
4754 else {
4755 struct dwrite_fontfamily_data *family_data;
4757 /* create and init new family */
4758 hr = init_fontfamily_data(font_data->family_names, &family_data);
4759 if (hr == S_OK) {
4760 /* add font to family, family - to collection */
4761 hr = fontfamily_add_font(family_data, font_data);
4762 if (hr == S_OK)
4763 hr = fontcollection_add_family(collection, family_data);
4765 if (FAILED(hr))
4766 release_fontfamily_data(family_data);
4770 if (FAILED(hr))
4772 release_font_data(font_data);
4773 break;
4777 IDWriteFontFileStream_Release(stream);
4780 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry)
4782 IDWriteFontFile_Release(fileenum->file);
4783 list_remove(&fileenum->entry);
4784 free(fileenum);
4787 for (i = 0; i < collection->count; ++i)
4789 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4790 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4793 if (is_system)
4794 fontcollection_add_replacements(collection);
4796 return hr;
4799 static HRESULT collection_add_font_entry(struct dwrite_fontcollection *collection, const struct fontface_desc *desc)
4801 struct dwrite_font_data *font_data;
4802 WCHAR familyW[255];
4803 UINT32 index;
4804 HRESULT hr;
4806 if (FAILED(hr = init_font_data(desc, collection->family_model, &font_data)))
4807 return hr;
4809 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4811 /* ignore dot named faces */
4812 if (familyW[0] == '.')
4814 WARN("Ignoring face %s\n", debugstr_w(familyW));
4815 release_font_data(font_data);
4816 return S_OK;
4819 index = collection_find_family(collection, familyW);
4820 if (index != ~0u)
4821 hr = fontfamily_add_font(collection->family_data[index], font_data);
4822 else
4824 struct dwrite_fontfamily_data *family_data;
4826 /* Create and initialize new family */
4827 hr = init_fontfamily_data(font_data->family_names, &family_data);
4828 if (hr == S_OK)
4830 /* add font to family, family - to collection */
4831 hr = fontfamily_add_font(family_data, font_data);
4832 if (hr == S_OK)
4833 hr = fontcollection_add_family(collection, family_data);
4835 if (FAILED(hr))
4836 release_fontfamily_data(family_data);
4840 if (FAILED(hr))
4841 release_font_data(font_data);
4843 return hr;
4846 HRESULT create_font_collection_from_set(IDWriteFactory7 *factory, IDWriteFontSet *fontset,
4847 DWRITE_FONT_FAMILY_MODEL family_model, REFGUID riid, void **ret)
4849 struct dwrite_fontset *set = unsafe_impl_from_IDWriteFontSet(fontset);
4850 struct dwrite_fontcollection *collection;
4851 HRESULT hr = S_OK;
4852 size_t i;
4854 *ret = NULL;
4856 if (!(collection = calloc(1, sizeof(*collection))))
4857 return E_OUTOFMEMORY;
4859 if (FAILED(hr = init_font_collection(collection, factory, family_model, FALSE)))
4861 free(collection);
4862 return hr;
4865 for (i = 0; i < set->count; ++i)
4867 const struct dwrite_fontset_entry *entry = set->entries[i];
4868 IDWriteFontFileStream *stream;
4869 struct fontface_desc desc;
4871 if (FAILED(get_filestream_from_file(entry->desc.file, &stream)))
4873 WARN("Failed to get file stream.\n");
4874 continue;
4877 desc.factory = factory;
4878 desc.face_type = entry->desc.face_type;
4879 desc.file = entry->desc.file;
4880 desc.stream = stream;
4881 desc.index = entry->desc.face_index;
4882 desc.simulations = entry->desc.simulations;
4883 desc.font_data = NULL;
4885 if (FAILED(hr = collection_add_font_entry(collection, &desc)))
4886 WARN("Failed to add font collection element, hr %#lx.\n", hr);
4888 IDWriteFontFileStream_Release(stream);
4891 if (family_model == DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE)
4893 for (i = 0; i < collection->count; ++i)
4895 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4896 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4900 hr = IDWriteFontCollection3_QueryInterface(&collection->IDWriteFontCollection3_iface, riid, ret);
4901 IDWriteFontCollection3_Release(&collection->IDWriteFontCollection3_iface);
4903 return hr;
4906 struct system_fontfile_enumerator
4908 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4909 LONG refcount;
4911 IDWriteFactory7 *factory;
4912 HKEY hkey;
4913 int index;
4915 WCHAR *filename;
4916 DWORD filename_size;
4919 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4921 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4924 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4926 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4927 IDWriteFontFileEnumerator_AddRef(iface);
4928 *obj = iface;
4929 return S_OK;
4932 WARN("%s not implemented.\n", debugstr_guid(riid));
4934 *obj = NULL;
4936 return E_NOINTERFACE;
4939 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4941 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4942 return InterlockedIncrement(&enumerator->refcount);
4945 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4947 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4948 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4950 if (!refcount)
4952 IDWriteFactory7_Release(enumerator->factory);
4953 RegCloseKey(enumerator->hkey);
4954 free(enumerator->filename);
4955 free(enumerator);
4958 return refcount;
4961 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4963 HRESULT hr;
4965 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4966 if (!wcschr(filename, '\\'))
4968 WCHAR fullpathW[MAX_PATH];
4970 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4971 wcscat(fullpathW, L"\\fonts\\");
4972 wcscat(fullpathW, filename);
4974 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4976 else
4977 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4979 return hr;
4982 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4984 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4986 *file = NULL;
4988 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4989 return E_FAIL;
4991 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4994 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4996 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4997 WCHAR name_buf[256], *name = name_buf;
4998 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4999 HRESULT hr = S_OK;
5000 LONG r;
5002 *current = FALSE;
5003 enumerator->index++;
5005 /* iterate until we find next string value */
5006 for (;;) {
5007 do {
5008 name_count = max_name_count;
5009 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
5011 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
5012 NULL, &type, (BYTE *)enumerator->filename, &data_size);
5013 if (r == ERROR_MORE_DATA) {
5014 if (name_count >= max_name_count) {
5015 if (name != name_buf) free(name);
5016 max_name_count *= 2;
5017 name = malloc(max_name_count * sizeof(*name));
5018 if (!name) return E_OUTOFMEMORY;
5020 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename))
5022 free(enumerator->filename);
5023 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
5024 if (!(enumerator->filename = malloc(enumerator->filename_size)))
5026 hr = E_OUTOFMEMORY;
5027 goto err;
5031 } while (r == ERROR_MORE_DATA);
5033 if (r != ERROR_SUCCESS) {
5034 enumerator->filename[0] = 0;
5035 break;
5037 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
5038 if (type == REG_SZ && *name != '@') {
5039 *current = TRUE;
5040 break;
5042 enumerator->index++;
5044 TRACE("index = %d, current = %d\n", enumerator->index, *current);
5046 err:
5047 if (name != name_buf) free(name);
5048 return hr;
5051 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
5053 systemfontfileenumerator_QueryInterface,
5054 systemfontfileenumerator_AddRef,
5055 systemfontfileenumerator_Release,
5056 systemfontfileenumerator_MoveNext,
5057 systemfontfileenumerator_GetCurrentFontFile
5060 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
5062 struct system_fontfile_enumerator *enumerator;
5064 *ret = NULL;
5066 if (!(enumerator = calloc(1, sizeof(*enumerator))))
5067 return E_OUTOFMEMORY;
5069 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
5070 enumerator->refcount = 1;
5071 enumerator->factory = factory;
5072 enumerator->index = -1;
5073 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
5074 enumerator->filename = malloc(enumerator->filename_size);
5075 if (!enumerator->filename)
5077 free(enumerator);
5078 return E_OUTOFMEMORY;
5081 IDWriteFactory7_AddRef(factory);
5083 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0,
5084 GENERIC_READ, &enumerator->hkey))
5086 ERR("failed to open fonts list key\n");
5087 IDWriteFactory7_Release(factory);
5088 free(enumerator->filename);
5089 free(enumerator);
5090 return E_FAIL;
5093 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
5095 return S_OK;
5098 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, DWRITE_FONT_FAMILY_MODEL family_model,
5099 IDWriteFontCollection **collection)
5101 IDWriteFontFileEnumerator *enumerator;
5102 IDWriteFontSet *fontset;
5103 HRESULT hr;
5105 *collection = NULL;
5107 if (family_model == DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC)
5109 if (SUCCEEDED(hr = create_system_fontset(factory, &IID_IDWriteFontSet, (void **)&fontset)))
5111 hr = create_font_collection_from_set(factory, fontset, family_model,
5112 &IID_IDWriteFontCollection, (void **)collection);
5113 IDWriteFontSet_Release(fontset);
5116 else
5118 if (SUCCEEDED(hr = create_system_fontfile_enumerator(factory, &enumerator)))
5120 TRACE("Building system font collection for factory %p.\n", factory);
5121 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
5122 IDWriteFontFileEnumerator_Release(enumerator);
5126 return hr;
5129 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
5130 const WCHAR *keynameW, const WCHAR *pathW)
5132 struct dwrite_fontfamily_data *family_data;
5133 IDWriteLocalizedStrings *names;
5134 DWRITE_FONT_FACE_TYPE face_type;
5135 DWRITE_FONT_FILE_TYPE file_type;
5136 IDWriteFontFileStream *stream;
5137 IDWriteFontFile *file;
5138 UINT32 face_count, i;
5139 BOOL supported;
5140 HRESULT hr;
5142 /* create font file from this path */
5143 hr = create_local_file_reference(factory, pathW, &file);
5144 if (FAILED(hr))
5145 return S_FALSE;
5147 if (FAILED(get_filestream_from_file(file, &stream))) {
5148 IDWriteFontFile_Release(file);
5149 return S_FALSE;
5152 /* Unsupported formats are skipped. */
5153 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
5154 if (FAILED(hr) || !supported || face_count == 0) {
5155 TRACE("Unsupported font (%p, 0x%08lx, %d, %u)\n", file, hr, supported, face_count);
5156 IDWriteFontFileStream_Release(stream);
5157 IDWriteFontFile_Release(file);
5158 return S_FALSE;
5161 /* create and init new family */
5163 /* Family names are added for non-specific locale, represented with empty string.
5164 Default family appears with empty family name. */
5165 create_localizedstrings(&names);
5166 if (!wcsicmp(keynameW, L"SystemDefaultEUDCFont"))
5167 add_localizedstring(names, L"", L"");
5168 else
5169 add_localizedstring(names, L"", keynameW);
5171 hr = init_fontfamily_data(names, &family_data);
5172 IDWriteLocalizedStrings_Release(names);
5173 if (hr != S_OK) {
5174 IDWriteFontFile_Release(file);
5175 return hr;
5178 /* fill with faces */
5179 for (i = 0; i < face_count; i++) {
5180 struct dwrite_font_data *font_data;
5181 struct fontface_desc desc;
5183 /* Allocate new font data structure. */
5184 desc.factory = factory;
5185 desc.face_type = face_type;
5186 desc.index = i;
5187 desc.file = file;
5188 desc.stream = stream;
5189 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
5190 desc.font_data = NULL;
5192 hr = init_font_data(&desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5193 if (FAILED(hr))
5194 continue;
5196 /* add font to family */
5197 hr = fontfamily_add_font(family_data, font_data);
5198 if (hr != S_OK)
5199 release_font_data(font_data);
5202 /* add family to collection */
5203 hr = fontcollection_add_family(collection, family_data);
5204 if (FAILED(hr))
5205 release_fontfamily_data(family_data);
5206 IDWriteFontFileStream_Release(stream);
5207 IDWriteFontFile_Release(file);
5209 return hr;
5212 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
5214 struct dwrite_fontcollection *collection;
5215 WCHAR eudckeypathW[16];
5216 HKEY eudckey;
5217 UINT32 index;
5218 BOOL exists;
5219 LONG retval;
5220 HRESULT hr;
5221 size_t i;
5223 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
5225 *ret = NULL;
5227 if (!(collection = calloc(1, sizeof(*collection))))
5228 return E_OUTOFMEMORY;
5230 hr = init_font_collection(collection, factory, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, FALSE);
5231 if (FAILED(hr))
5233 free(collection);
5234 return hr;
5237 *ret = &collection->IDWriteFontCollection3_iface;
5239 /* return empty collection if EUDC fonts are not configured */
5240 swprintf(eudckeypathW, ARRAY_SIZE(eudckeypathW), L"EUDC\\%u", GetACP());
5241 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
5242 return S_OK;
5244 retval = ERROR_SUCCESS;
5245 index = 0;
5246 while (retval != ERROR_NO_MORE_ITEMS) {
5247 WCHAR keynameW[64], pathW[MAX_PATH];
5248 DWORD type, path_len, name_len;
5250 path_len = ARRAY_SIZE(pathW);
5251 name_len = ARRAY_SIZE(keynameW);
5252 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
5253 if (retval || type != REG_SZ)
5254 continue;
5256 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
5257 if (hr != S_OK)
5258 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
5260 RegCloseKey(eudckey);
5262 /* try to add global default if not defined for specific codepage */
5263 exists = FALSE;
5264 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, L"",
5265 &index, &exists);
5266 if (FAILED(hr) || !exists)
5268 hr = eudc_collection_add_family(factory, collection, L"", L"EUDC.TTE");
5269 if (hr != S_OK)
5270 WARN("failed to add global default EUDC font, 0x%08lx\n", hr);
5273 /* EUDC collection offers simulated faces too */
5274 for (i = 0; i < collection->count; ++i)
5276 fontfamily_add_bold_simulated_face(collection->family_data[i]);
5277 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
5280 return S_OK;
5283 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
5285 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5287 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
5289 *obj = iface;
5290 IDWriteFontFile_AddRef(iface);
5291 return S_OK;
5294 WARN("%s not implemented.\n", debugstr_guid(riid));
5296 *obj = NULL;
5297 return E_NOINTERFACE;
5300 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
5302 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5303 ULONG refcount = InterlockedIncrement(&file->refcount);
5305 TRACE("%p, refcount %ld.\n", iface, refcount);
5307 return refcount;
5310 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
5312 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5313 ULONG refcount = InterlockedDecrement(&file->refcount);
5315 TRACE("%p, refcount %ld.\n", iface, refcount);
5317 if (!refcount)
5319 IDWriteFontFileLoader_Release(file->loader);
5320 if (file->stream)
5321 IDWriteFontFileStream_Release(file->stream);
5322 free(file->reference_key);
5323 free(file);
5326 return refcount;
5329 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
5331 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5333 TRACE("%p, %p, %p.\n", iface, key, key_size);
5335 *key = file->reference_key;
5336 *key_size = file->key_size;
5338 return S_OK;
5341 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
5343 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5345 TRACE("%p, %p.\n", iface, loader);
5347 *loader = file->loader;
5348 IDWriteFontFileLoader_AddRef(*loader);
5350 return S_OK;
5353 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
5354 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
5356 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5357 IDWriteFontFileStream *stream;
5358 HRESULT hr;
5360 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
5362 *is_supported = FALSE;
5363 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
5364 if (face_type)
5365 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
5366 *face_count = 0;
5368 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
5369 if (FAILED(hr))
5370 return hr;
5372 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
5374 /* TODO: Further Analysis */
5375 IDWriteFontFileStream_Release(stream);
5376 return S_OK;
5379 static const IDWriteFontFileVtbl dwritefontfilevtbl =
5381 dwritefontfile_QueryInterface,
5382 dwritefontfile_AddRef,
5383 dwritefontfile_Release,
5384 dwritefontfile_GetReferenceKey,
5385 dwritefontfile_GetLoader,
5386 dwritefontfile_Analyze,
5389 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
5390 IDWriteFontFile **ret)
5392 struct dwrite_fontfile *file;
5393 void *key;
5395 *ret = NULL;
5397 file = calloc(1, sizeof(*file));
5398 key = malloc(key_size);
5399 if (!file || !key)
5401 free(file);
5402 free(key);
5403 return E_OUTOFMEMORY;
5406 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
5407 file->refcount = 1;
5408 IDWriteFontFileLoader_AddRef(loader);
5409 file->loader = loader;
5410 file->stream = NULL;
5411 file->reference_key = key;
5412 memcpy(file->reference_key, reference_key, key_size);
5413 file->key_size = key_size;
5415 *ret = &file->IDWriteFontFile_iface;
5417 return S_OK;
5420 static UINT64 dwrite_fontface_get_font_object(struct dwrite_fontface *fontface)
5422 struct create_font_object_params create_params;
5423 struct release_font_object_params release_params;
5424 UINT64 font_object, size;
5425 const void *data_ptr;
5426 void *data_context;
5428 if (!fontface->font_object && SUCCEEDED(IDWriteFontFileStream_GetFileSize(fontface->stream, &size)))
5430 if (SUCCEEDED(IDWriteFontFileStream_ReadFileFragment(fontface->stream, &data_ptr, 0, size, &data_context)))
5432 create_params.data = data_ptr;
5433 create_params.size = size;
5434 create_params.index = fontface->index;
5435 create_params.object = &font_object;
5437 UNIX_CALL(create_font_object, &create_params);
5439 if (!font_object)
5441 WARN("Backend failed to create font object.\n");
5442 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5443 return 0;
5446 if (!InterlockedCompareExchange64((LONGLONG *)&fontface->font_object, font_object, 0))
5448 fontface->data_context = data_context;
5450 else
5452 release_params.object = font_object;
5453 UNIX_CALL(release_font_object, &release_params);
5454 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5459 return fontface->font_object;
5462 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5464 struct file_stream_desc stream_desc;
5465 struct dwrite_font_data *font_data;
5466 struct dwrite_fontface *fontface;
5467 HRESULT hr;
5468 int i;
5470 *ret = NULL;
5472 if (!(fontface = calloc(1, sizeof(*fontface))))
5473 return E_OUTOFMEMORY;
5475 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5476 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5477 fontface->refcount = 1;
5478 fontface->type = desc->face_type;
5479 fontface->vdmx.exists = TRUE;
5480 fontface->gasp.exists = TRUE;
5481 fontface->cpal.exists = TRUE;
5482 fontface->colr.exists = TRUE;
5483 fontface->kern.exists = TRUE;
5484 fontface->index = desc->index;
5485 fontface->simulations = desc->simulations;
5486 fontface->factory = desc->factory;
5487 IDWriteFactory7_AddRef(fontface->factory);
5488 fontface->file = desc->file;
5489 IDWriteFontFile_AddRef(fontface->file);
5490 fontface->stream = desc->stream;
5491 IDWriteFontFileStream_AddRef(fontface->stream);
5492 InitializeCriticalSection(&fontface->cs);
5493 fontface_cache_init(fontface);
5495 stream_desc.stream = fontface->stream;
5496 stream_desc.face_type = desc->face_type;
5497 stream_desc.face_index = desc->index;
5498 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5499 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5500 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5501 /* TODO: test what happens if caret is already slanted */
5502 if (fontface->caret.slopeRise == 1) {
5503 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5504 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5507 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5509 /* Font properties are reused from font object when 'normal' face creation path is used:
5510 collection -> family -> matching font -> fontface.
5512 If face is created directly from factory we have to go through properties resolution.
5514 if (desc->font_data)
5516 font_data = addref_font_data(desc->font_data);
5518 else
5520 hr = init_font_data(desc, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE, &font_data);
5521 if (FAILED(hr))
5523 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5524 return hr;
5528 fontface->weight = font_data->weight;
5529 fontface->style = font_data->style;
5530 fontface->stretch = font_data->stretch;
5531 fontface->panose = font_data->panose;
5532 fontface->fontsig = font_data->fontsig;
5533 fontface->lf = font_data->lf;
5534 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5535 fontface->names = font_data->names;
5536 if (fontface->names)
5537 IDWriteLocalizedStrings_AddRef(fontface->names);
5538 fontface->family_names = font_data->family_names;
5539 if (fontface->family_names)
5540 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5541 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5542 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5544 if (fontface->info_strings[i])
5545 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5547 fontface->cmap.stream = fontface->stream;
5548 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5549 release_font_data(font_data);
5551 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5552 fontface->get_font_object = dwrite_fontface_get_font_object;
5554 *ret = &fontface->IDWriteFontFace5_iface;
5556 return S_OK;
5559 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5560 struct local_refkey
5562 FILETIME writetime;
5563 WCHAR name[1];
5566 struct local_cached_stream
5568 struct list entry;
5569 IDWriteFontFileStream *stream;
5570 struct local_refkey *key;
5571 UINT32 key_size;
5574 struct dwrite_localfontfilestream
5576 IDWriteFontFileStream IDWriteFontFileStream_iface;
5577 LONG refcount;
5579 struct local_cached_stream *entry;
5580 const void *file_ptr;
5581 UINT64 size;
5584 struct dwrite_localfontfileloader
5586 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5587 LONG refcount;
5589 struct list streams;
5590 CRITICAL_SECTION cs;
5593 static struct dwrite_localfontfileloader local_fontfile_loader;
5595 struct dwrite_inmemory_stream_data
5597 LONG refcount;
5598 IUnknown *owner;
5599 void *data;
5600 UINT32 size;
5603 struct dwrite_inmemory_filestream
5605 IDWriteFontFileStream IDWriteFontFileStream_iface;
5606 LONG refcount;
5608 struct dwrite_inmemory_stream_data *data;
5611 struct dwrite_inmemory_fileloader
5613 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5614 LONG refcount;
5616 struct dwrite_inmemory_stream_data **streams;
5617 size_t size;
5618 size_t count;
5621 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5623 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5626 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5628 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5631 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5633 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5636 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5638 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5641 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5643 if (InterlockedDecrement(&stream->refcount) == 0)
5645 if (stream->owner)
5646 IUnknown_Release(stream->owner);
5647 else
5648 free(stream->data);
5649 free(stream);
5653 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5655 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5657 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5659 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5660 IsEqualIID(riid, &IID_IUnknown))
5662 *obj = iface;
5663 if (InterlockedIncrement(&stream->refcount) == 1)
5665 InterlockedDecrement(&stream->refcount);
5666 *obj = NULL;
5667 return E_FAIL;
5669 return S_OK;
5672 WARN("%s not implemented.\n", debugstr_guid(riid));
5674 *obj = NULL;
5675 return E_NOINTERFACE;
5678 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5680 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5681 ULONG refcount = InterlockedIncrement(&stream->refcount);
5683 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5685 return refcount;
5688 static inline void release_cached_stream(struct local_cached_stream *stream)
5690 list_remove(&stream->entry);
5691 free(stream->key);
5692 free(stream);
5695 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5697 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5698 ULONG refcount = InterlockedDecrement(&stream->refcount);
5700 TRACE_(dwrite_file)("%p, refcount %ld.\n", iface, refcount);
5702 if (!refcount)
5704 UnmapViewOfFile(stream->file_ptr);
5706 EnterCriticalSection(&local_fontfile_loader.cs);
5707 release_cached_stream(stream->entry);
5708 LeaveCriticalSection(&local_fontfile_loader.cs);
5710 free(stream);
5713 return refcount;
5716 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5717 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5719 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5721 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5722 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5724 *fragment_context = NULL;
5726 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5728 *fragment_start = NULL;
5729 return E_FAIL;
5732 *fragment_start = (char *)stream->file_ptr + offset;
5733 return S_OK;
5736 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5738 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5741 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5743 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5745 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5747 *size = stream->size;
5748 return S_OK;
5751 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5753 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5754 ULARGE_INTEGER li;
5756 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5758 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5759 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5760 *last_writetime = li.QuadPart;
5762 return S_OK;
5765 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5767 localfontfilestream_QueryInterface,
5768 localfontfilestream_AddRef,
5769 localfontfilestream_Release,
5770 localfontfilestream_ReadFileFragment,
5771 localfontfilestream_ReleaseFileFragment,
5772 localfontfilestream_GetFileSize,
5773 localfontfilestream_GetLastWriteTime
5776 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5777 IDWriteFontFileStream **ret)
5779 struct dwrite_localfontfilestream *object;
5781 *ret = NULL;
5783 if (!(object = calloc(1, sizeof(*object))))
5784 return E_OUTOFMEMORY;
5786 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5787 object->refcount = 1;
5789 object->file_ptr = file_ptr;
5790 object->size = size;
5791 object->entry = entry;
5793 *ret = &object->IDWriteFontFileStream_iface;
5795 return S_OK;
5798 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5800 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5802 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5803 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5804 IsEqualIID(riid, &IID_IUnknown))
5806 *obj = iface;
5807 IDWriteLocalFontFileLoader_AddRef(iface);
5808 return S_OK;
5811 WARN("%s not implemented.\n", debugstr_guid(riid));
5813 *obj = NULL;
5814 return E_NOINTERFACE;
5817 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5819 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5820 ULONG refcount = InterlockedIncrement(&loader->refcount);
5822 TRACE("%p, refcount %ld.\n", iface, refcount);
5824 return refcount;
5827 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5829 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5830 ULONG refcount = InterlockedDecrement(&loader->refcount);
5832 TRACE("%p, refcount %ld.\n", iface, refcount);
5834 return refcount;
5837 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5839 const struct local_refkey *refkey = key;
5840 struct local_cached_stream *stream;
5841 IDWriteFontFileStream *filestream;
5842 HANDLE file, mapping;
5843 LARGE_INTEGER size;
5844 void *file_ptr;
5845 HRESULT hr = S_OK;
5847 *ret = NULL;
5849 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5850 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5851 if (file == INVALID_HANDLE_VALUE) {
5852 WARN_(dwrite_file)("Failed to open the file %s, error %ld.\n", debugstr_w(refkey->name), GetLastError());
5853 return E_FAIL;
5856 GetFileSizeEx(file, &size);
5857 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5858 CloseHandle(file);
5859 if (!mapping)
5860 return E_FAIL;
5862 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5863 CloseHandle(mapping);
5864 if (!file_ptr) {
5865 ERR("mapping failed, file size %s, error %ld\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5866 return E_FAIL;
5869 if (!(stream = malloc(sizeof(*stream))))
5871 UnmapViewOfFile(file_ptr);
5872 return E_OUTOFMEMORY;
5875 if (!(stream->key = malloc(key_size)))
5877 UnmapViewOfFile(file_ptr);
5878 free(stream);
5879 return E_OUTOFMEMORY;
5882 stream->key_size = key_size;
5883 memcpy(stream->key, key, key_size);
5885 if (FAILED(hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream)))
5887 UnmapViewOfFile(file_ptr);
5888 free(stream->key);
5889 free(stream);
5890 return hr;
5893 stream->stream = filestream;
5895 *ret = stream;
5897 return S_OK;
5900 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5901 UINT32 key_size, IDWriteFontFileStream **ret)
5903 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5904 struct local_cached_stream *stream;
5905 HRESULT hr = S_OK;
5907 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5909 EnterCriticalSection(&loader->cs);
5911 *ret = NULL;
5913 /* search cache first */
5914 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5916 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5917 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5918 break;
5922 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5924 list_add_head(&loader->streams, &stream->entry);
5925 *ret = stream->stream;
5928 LeaveCriticalSection(&loader->cs);
5930 return hr;
5933 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5934 UINT32 key_size, UINT32 *length)
5936 const struct local_refkey *refkey = key;
5938 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5940 *length = wcslen(refkey->name);
5941 return S_OK;
5944 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5945 UINT32 key_size, WCHAR *path, UINT32 length)
5947 const struct local_refkey *refkey = key;
5949 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5951 if (length < wcslen(refkey->name))
5952 return E_INVALIDARG;
5954 wcscpy(path, refkey->name);
5955 return S_OK;
5958 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5959 UINT32 key_size, FILETIME *writetime)
5961 const struct local_refkey *refkey = key;
5963 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5965 *writetime = refkey->writetime;
5966 return S_OK;
5969 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5971 localfontfileloader_QueryInterface,
5972 localfontfileloader_AddRef,
5973 localfontfileloader_Release,
5974 localfontfileloader_CreateStreamFromKey,
5975 localfontfileloader_GetFilePathLengthFromKey,
5976 localfontfileloader_GetFilePathFromKey,
5977 localfontfileloader_GetLastWriteTimeFromKey
5980 void init_local_fontfile_loader(void)
5982 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5983 local_fontfile_loader.refcount = 1;
5984 list_init(&local_fontfile_loader.streams);
5985 InitializeCriticalSection(&local_fontfile_loader.cs);
5986 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5989 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5991 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5994 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5996 struct local_refkey *refkey;
5998 if (!path)
5999 return E_INVALIDARG;
6001 *size = FIELD_OFFSET(struct local_refkey, name) + (wcslen(path)+1)*sizeof(WCHAR);
6002 *key = NULL;
6004 if (!(refkey = malloc(*size)))
6005 return E_OUTOFMEMORY;
6007 if (writetime)
6008 refkey->writetime = *writetime;
6009 else {
6010 WIN32_FILE_ATTRIBUTE_DATA info;
6012 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
6013 refkey->writetime = info.ftLastWriteTime;
6014 else
6015 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
6017 wcscpy(refkey->name, path);
6019 *key = refkey;
6021 return S_OK;
6024 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
6026 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6028 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
6029 IsEqualIID(riid, &IID_IUnknown))
6031 *ppv = iface;
6032 IDWriteGlyphRunAnalysis_AddRef(iface);
6033 return S_OK;
6036 WARN("%s not implemented.\n", debugstr_guid(riid));
6038 *ppv = NULL;
6039 return E_NOINTERFACE;
6042 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
6044 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6045 ULONG refcount = InterlockedIncrement(&analysis->refcount);
6047 TRACE("%p, refcount %ld.\n", iface, refcount);
6049 return refcount;
6052 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
6054 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6055 ULONG refcount = InterlockedDecrement(&analysis->refcount);
6057 TRACE("%p, refcount %ld.\n", iface, refcount);
6059 if (!refcount)
6061 if (analysis->run.fontFace)
6062 IDWriteFontFace_Release(analysis->run.fontFace);
6063 free(analysis->glyphs);
6064 free(analysis->origins);
6065 free(analysis->bitmap);
6066 free(analysis);
6069 return refcount;
6072 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
6074 struct dwrite_glyphbitmap glyph_bitmap;
6075 UINT32 i;
6077 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
6078 *bounds = analysis->bounds;
6079 return;
6082 if (analysis->run.isSideways)
6083 FIXME("sideways runs are not supported.\n");
6085 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6086 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(analysis->run.fontFace);
6087 glyph_bitmap.emsize = analysis->run.fontEmSize;
6088 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6089 glyph_bitmap.m = &analysis->m;
6091 for (i = 0; i < analysis->run.glyphCount; i++) {
6092 RECT *bbox = &glyph_bitmap.bbox;
6093 UINT32 bitmap_size;
6095 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6096 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6098 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
6099 (bbox->bottom - bbox->top);
6100 if (bitmap_size > analysis->max_glyph_bitmap_size)
6101 analysis->max_glyph_bitmap_size = bitmap_size;
6103 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6104 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
6107 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
6108 *bounds = analysis->bounds;
6111 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
6112 DWRITE_TEXTURE_TYPE type, RECT *bounds)
6114 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6116 TRACE("%p, %d, %p.\n", iface, type, bounds);
6118 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
6119 SetRectEmpty(bounds);
6120 return E_INVALIDARG;
6123 if (type != analysis->texture_type)
6125 SetRectEmpty(bounds);
6126 return S_OK;
6129 glyphrunanalysis_get_texturebounds(analysis, bounds);
6130 return S_OK;
6133 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
6135 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6136 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
6137 (runbounds->left - bounds->left) * 3;
6138 else
6139 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
6140 runbounds->left - bounds->left;
6143 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
6145 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6146 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(analysis->run.fontFace);
6147 struct dwrite_glyphbitmap glyph_bitmap;
6148 D2D_POINT_2F origin;
6149 UINT32 i, size;
6150 RECT *bbox;
6152 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
6153 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6154 size *= 3;
6155 if (!(analysis->bitmap = calloc(1, size)))
6157 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
6158 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
6159 return E_OUTOFMEMORY;
6162 origin.x = origin.y = 0.0f;
6164 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6165 glyph_bitmap.simulations = fontface->simulations;
6166 glyph_bitmap.emsize = analysis->run.fontEmSize;
6167 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6168 glyph_bitmap.m = &analysis->m;
6169 if (!(glyph_bitmap.buf = malloc(analysis->max_glyph_bitmap_size)))
6170 return E_OUTOFMEMORY;
6172 bbox = &glyph_bitmap.bbox;
6174 for (i = 0; i < analysis->run.glyphCount; ++i)
6176 BYTE *src = glyph_bitmap.buf, *dst;
6177 int x, y, width, height;
6178 unsigned int is_1bpp;
6180 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6181 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6183 if (IsRectEmpty(bbox))
6184 continue;
6186 width = bbox->right - bbox->left;
6187 height = bbox->bottom - bbox->top;
6189 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
6190 memset(src, 0, height * glyph_bitmap.pitch);
6192 if (FAILED(dwrite_fontface_get_glyph_bitmap(fontface, analysis->rendering_mode, &is_1bpp, &glyph_bitmap)))
6194 WARN("Failed to render glyph[%u] = %#x.\n", i, glyph_bitmap.glyph);
6195 continue;
6198 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6200 /* blit to analysis bitmap */
6201 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
6203 if (is_1bpp) {
6204 /* convert 1bpp to 8bpp/24bpp */
6205 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6206 for (y = 0; y < height; y++) {
6207 for (x = 0; x < width; x++)
6208 if (src[x / 8] & masks[x % 8])
6209 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
6210 src += glyph_bitmap.pitch;
6211 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6214 else {
6215 for (y = 0; y < height; y++) {
6216 for (x = 0; x < width; x++)
6217 if (src[x / 8] & masks[x % 8])
6218 dst[x] = DWRITE_ALPHA_MAX;
6219 src += glyph_bitmap.pitch;
6220 dst += analysis->bounds.right - analysis->bounds.left;
6224 else {
6225 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6226 for (y = 0; y < height; y++) {
6227 for (x = 0; x < width; x++)
6228 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
6229 src += glyph_bitmap.pitch;
6230 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6233 else {
6234 for (y = 0; y < height; y++) {
6235 for (x = 0; x < width; x++)
6236 dst[x] |= src[x];
6237 src += glyph_bitmap.pitch;
6238 dst += analysis->bounds.right - analysis->bounds.left;
6243 free(glyph_bitmap.buf);
6245 analysis->flags |= RUNANALYSIS_BITMAP_READY;
6247 /* we don't need this anymore */
6248 free(analysis->glyphs);
6249 free(analysis->origins);
6250 IDWriteFontFace_Release(analysis->run.fontFace);
6252 analysis->glyphs = NULL;
6253 analysis->origins = NULL;
6254 analysis->run.glyphIndices = NULL;
6255 analysis->run.fontFace = NULL;
6257 return S_OK;
6260 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
6261 RECT const *bounds, BYTE *bitmap, UINT32 size)
6263 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6264 UINT32 required;
6265 RECT runbounds;
6267 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
6269 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
6270 return E_INVALIDARG;
6272 /* make sure buffer is large enough for requested texture type */
6273 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
6274 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6275 required *= 3;
6277 if (size < required)
6278 return E_NOT_SUFFICIENT_BUFFER;
6280 /* validate requested texture type */
6281 if (analysis->texture_type != type)
6282 return DWRITE_E_UNSUPPORTEDOPERATION;
6284 memset(bitmap, 0, size);
6285 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
6286 if (IntersectRect(&runbounds, &runbounds, bounds))
6288 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
6289 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
6290 int dst_width = (bounds->right - bounds->left) * pixel_size;
6291 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
6292 BYTE *src, *dst;
6293 int y;
6295 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
6297 HRESULT hr;
6299 if (FAILED(hr = glyphrunanalysis_render(analysis)))
6300 return hr;
6303 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
6304 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
6306 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
6307 memcpy(dst, src, draw_width);
6308 src += src_width;
6309 dst += dst_width;
6313 return S_OK;
6316 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
6317 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
6319 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6321 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
6323 if (!params)
6324 return E_INVALIDARG;
6326 switch (analysis->rendering_mode)
6328 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
6329 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
6331 UINT value = 0;
6332 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6333 *gamma = (FLOAT)value / 1000.0f;
6334 *contrast = 0.0f;
6335 *cleartypelevel = 1.0f;
6336 break;
6338 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
6339 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
6340 /* fallthrough */
6341 case DWRITE_RENDERING_MODE1_ALIASED:
6342 case DWRITE_RENDERING_MODE1_NATURAL:
6343 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
6344 *gamma = IDWriteRenderingParams_GetGamma(params);
6345 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
6346 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
6347 break;
6348 default:
6352 return S_OK;
6355 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
6357 glyphrunanalysis_QueryInterface,
6358 glyphrunanalysis_AddRef,
6359 glyphrunanalysis_Release,
6360 glyphrunanalysis_GetAlphaTextureBounds,
6361 glyphrunanalysis_CreateAlphaTexture,
6362 glyphrunanalysis_GetAlphaBlendParams
6365 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
6367 D2D_POINT_2F ret;
6368 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
6369 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
6370 *point = ret;
6373 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
6374 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
6376 unsigned int upem = fontface->metrics.designUnitsPerEm;
6377 int advance;
6379 if (is_sideways)
6380 FIXME("Sideways mode is not supported.\n");
6382 EnterCriticalSection(&fontface->cs);
6383 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
6384 LeaveCriticalSection(&fontface->cs);
6386 switch (measuring_mode)
6388 case DWRITE_MEASURING_MODE_NATURAL:
6389 return (float)advance * emsize / (float)upem;
6390 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6391 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6392 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
6393 default:
6394 WARN("Unknown measuring mode %u.\n", measuring_mode);
6395 return 0.0f;
6399 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
6401 struct dwrite_glyphrunanalysis *analysis;
6402 unsigned int i;
6404 *ret = NULL;
6406 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
6407 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
6408 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
6409 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
6410 return E_INVALIDARG;
6412 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6413 return E_INVALIDARG;
6415 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
6416 return E_INVALIDARG;
6418 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
6419 return E_INVALIDARG;
6421 if (!(analysis = calloc(1, sizeof(*analysis))))
6422 return E_OUTOFMEMORY;
6424 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
6425 analysis->refcount = 1;
6426 analysis->rendering_mode = desc->rendering_mode;
6428 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
6429 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6430 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6431 else
6432 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6434 analysis->run = *desc->run;
6435 IDWriteFontFace_AddRef(analysis->run.fontFace);
6436 analysis->glyphs = calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6437 analysis->origins = calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6439 if (!analysis->glyphs || !analysis->origins)
6441 free(analysis->glyphs);
6442 free(analysis->origins);
6444 analysis->glyphs = NULL;
6445 analysis->origins = NULL;
6447 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6448 return E_OUTOFMEMORY;
6451 /* check if transform is usable */
6452 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6453 analysis->m = *desc->transform;
6454 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6457 analysis->run.glyphIndices = analysis->glyphs;
6458 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6460 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6461 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6463 for (i = 0; i < desc->run->glyphCount; ++i)
6464 transform_point(&analysis->origins[i], &analysis->m);
6467 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6468 return S_OK;
6471 /* IDWriteColorGlyphRunEnumerator1 */
6472 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6474 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6476 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6477 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6478 IsEqualIID(riid, &IID_IUnknown))
6480 *ppv = iface;
6481 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6482 return S_OK;
6485 WARN("%s not implemented.\n", debugstr_guid(riid));
6487 *ppv = NULL;
6488 return E_NOINTERFACE;
6491 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6493 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6494 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6496 TRACE("%p, refcount %lu.\n", iface, refcount);
6498 return refcount;
6501 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6503 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6504 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6506 TRACE("%p, refcount %lu.\n", iface, refcount);
6508 if (!refcount)
6510 free(glyphenum->advances);
6511 free(glyphenum->color_advances);
6512 free(glyphenum->offsets);
6513 free(glyphenum->color_offsets);
6514 free(glyphenum->glyphindices);
6515 free(glyphenum->glyphs);
6516 if (glyphenum->colr.context)
6517 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6518 IDWriteFontFace5_Release(glyphenum->fontface);
6519 free(glyphenum);
6522 return refcount;
6525 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6527 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6528 FLOAT origin = 0.0f;
6530 if (g == 0)
6531 return 0.0f;
6533 while (g--)
6534 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6535 return origin;
6538 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6540 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6541 FLOAT advance_adj = 0.0f;
6542 BOOL got_palette_index;
6543 UINT32 g;
6545 /* start with regular glyphs */
6546 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6547 UINT32 first_glyph = 0;
6549 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6550 if (glyphenum->glyphs[g].num_layers == 0) {
6551 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6552 first_glyph = min(first_glyph, g);
6554 else
6555 glyphenum->glyphindices[g] = 1;
6556 glyphenum->color_advances[g] = glyphenum->advances[g];
6557 if (glyphenum->color_offsets)
6558 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6561 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, first_glyph);
6562 colorrun->baselineOriginY = glyphenum->origin.y;
6563 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6564 colorrun->paletteIndex = 0xffff;
6565 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6566 glyphenum->has_regular_glyphs = FALSE;
6567 return TRUE;
6569 else {
6570 colorrun->glyphRun.glyphCount = 0;
6571 got_palette_index = FALSE;
6574 advance_adj = 0.0f;
6575 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6577 glyphenum->glyphindices[g] = 1;
6579 /* all glyph layers were returned */
6580 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6581 advance_adj += glyphenum->advances[g];
6582 continue;
6585 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6586 UINT32 index = colorrun->glyphRun.glyphCount;
6587 if (!got_palette_index) {
6588 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6589 /* use foreground color or request one from the font */
6590 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6591 if (colorrun->paletteIndex != 0xffff)
6593 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6594 colorrun->paletteIndex, 1, &colorrun->runColor);
6595 if (FAILED(hr))
6596 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08lx\n", glyphenum->fontface,
6597 glyphenum->palette, colorrun->paletteIndex, hr);
6599 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6600 colorrun->baselineOriginX = glyphenum->origin.x + get_glyph_origin(glyphenum, g);
6601 colorrun->baselineOriginY = glyphenum->origin.y;
6602 glyphenum->color_advances[index] = glyphenum->advances[g];
6603 got_palette_index = TRUE;
6606 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6607 /* offsets are relative to glyph origin, nothing to fix up */
6608 if (glyphenum->color_offsets)
6609 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6610 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6611 if (index)
6612 glyphenum->color_advances[index-1] += advance_adj;
6613 colorrun->glyphRun.glyphCount++;
6614 advance_adj = 0.0f;
6616 else
6617 advance_adj += glyphenum->advances[g];
6620 /* reset last advance */
6621 if (colorrun->glyphRun.glyphCount)
6622 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6624 return colorrun->glyphRun.glyphCount > 0;
6627 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6629 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6631 TRACE("%p, %p.\n", iface, has_run);
6633 *has_run = FALSE;
6635 glyphenum->colorrun.glyphRun.glyphCount = 0;
6636 while (glyphenum->current_layer < glyphenum->max_layer_num)
6638 if (colorglyphenum_build_color_run(glyphenum))
6639 break;
6640 else
6641 glyphenum->current_layer++;
6644 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6646 return S_OK;
6649 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6650 DWRITE_COLOR_GLYPH_RUN1 const **run)
6652 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6654 *run = NULL;
6655 return E_NOT_VALID_STATE;
6658 *run = &glyphenum->colorrun;
6659 return S_OK;
6662 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6663 DWRITE_COLOR_GLYPH_RUN const **run)
6665 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6667 TRACE("%p, %p.\n", iface, run);
6669 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6672 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6673 DWRITE_COLOR_GLYPH_RUN1 const **run)
6675 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6677 TRACE("%p, %p.\n", iface, run);
6679 return colorglyphenum_get_current_run(glyphenum, run);
6682 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6684 colorglyphenum_QueryInterface,
6685 colorglyphenum_AddRef,
6686 colorglyphenum_Release,
6687 colorglyphenum_MoveNext,
6688 colorglyphenum_GetCurrentRun,
6689 colorglyphenum1_GetCurrentRun,
6692 HRESULT create_colorglyphenum(D2D1_POINT_2F origin, const DWRITE_GLYPH_RUN *run,
6693 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_GLYPH_IMAGE_FORMATS formats, DWRITE_MEASURING_MODE measuring_mode,
6694 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator1 **ret)
6696 struct dwrite_colorglyphenum *colorglyphenum;
6697 BOOL colorfont, has_colored_glyph;
6698 struct dwrite_fontface *fontface;
6699 unsigned int i;
6701 *ret = NULL;
6703 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6705 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6706 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6707 if (!colorfont)
6708 return DWRITE_E_NOCOLOR;
6710 if (!(formats & (DWRITE_GLYPH_IMAGE_FORMATS_COLR |
6711 DWRITE_GLYPH_IMAGE_FORMATS_SVG |
6712 DWRITE_GLYPH_IMAGE_FORMATS_PNG |
6713 DWRITE_GLYPH_IMAGE_FORMATS_JPEG |
6714 DWRITE_GLYPH_IMAGE_FORMATS_TIFF |
6715 DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8)))
6717 return DWRITE_E_NOCOLOR;
6720 if (formats & ~(DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_CFF | DWRITE_GLYPH_IMAGE_FORMATS_COLR))
6722 FIXME("Unimplemented formats requested %#x.\n", formats);
6723 return E_NOTIMPL;
6726 if (!(colorglyphenum = calloc(1, sizeof(*colorglyphenum))))
6727 return E_OUTOFMEMORY;
6729 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6730 colorglyphenum->refcount = 1;
6731 colorglyphenum->origin = origin;
6732 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6733 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6734 colorglyphenum->glyphs = NULL;
6735 colorglyphenum->run = *run;
6736 colorglyphenum->run.glyphIndices = NULL;
6737 colorglyphenum->run.glyphAdvances = NULL;
6738 colorglyphenum->run.glyphOffsets = NULL;
6739 colorglyphenum->palette = palette;
6740 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6741 colorglyphenum->colr.exists = TRUE;
6742 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6743 colorglyphenum->current_layer = 0;
6744 colorglyphenum->max_layer_num = 0;
6746 colorglyphenum->glyphs = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphs));
6748 has_colored_glyph = FALSE;
6749 colorglyphenum->has_regular_glyphs = FALSE;
6750 for (i = 0; i < run->glyphCount; i++) {
6751 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6752 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6753 has_colored_glyph = TRUE;
6755 if (colorglyphenum->glyphs[i].num_layers == 0)
6756 colorglyphenum->has_regular_glyphs = TRUE;
6759 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6760 is supposed to proceed normally, like if font had no color info at all. */
6761 if (!has_colored_glyph) {
6762 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6763 return DWRITE_E_NOCOLOR;
6766 colorglyphenum->advances = calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6767 colorglyphenum->color_advances = calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6768 colorglyphenum->glyphindices = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6769 if (run->glyphOffsets) {
6770 colorglyphenum->offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6771 colorglyphenum->color_offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6772 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6775 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6776 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6777 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6778 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6779 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6780 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6781 colorglyphenum->colorrun.measuringMode = measuring_mode;
6782 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6784 if (run->glyphAdvances)
6785 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6786 else
6788 for (i = 0; i < run->glyphCount; ++i)
6789 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6790 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6793 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6795 return S_OK;
6798 /* IDWriteFontFaceReference */
6799 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6801 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6803 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6804 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6805 IsEqualIID(riid, &IID_IUnknown))
6807 *obj = iface;
6808 IDWriteFontFaceReference1_AddRef(iface);
6809 return S_OK;
6812 WARN("%s not implemented.\n", debugstr_guid(riid));
6814 *obj = NULL;
6816 return E_NOINTERFACE;
6819 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6821 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6822 ULONG refcount = InterlockedIncrement(&reference->refcount);
6824 TRACE("%p, refcount %lu.\n", iface, refcount);
6826 return refcount;
6829 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6831 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6832 ULONG refcount = InterlockedDecrement(&reference->refcount);
6834 TRACE("%p, refcount %lu.\n", iface, refcount);
6836 if (!refcount)
6838 IDWriteFontFile_Release(reference->file);
6839 IDWriteFactory7_Release(reference->factory);
6840 free(reference->axis_values);
6841 free(reference);
6844 return refcount;
6847 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6849 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6851 TRACE("%p, %p.\n", iface, fontface);
6853 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6856 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6857 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6859 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6860 DWRITE_FONT_FILE_TYPE file_type;
6861 DWRITE_FONT_FACE_TYPE face_type;
6862 IDWriteFontFace *fontface;
6863 BOOL is_supported;
6864 UINT32 face_num;
6865 HRESULT hr;
6867 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6869 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6870 if (FAILED(hr))
6871 return hr;
6873 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6874 simulations, &fontface);
6875 if (SUCCEEDED(hr))
6877 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6878 IDWriteFontFace_Release(fontface);
6881 return hr;
6884 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6886 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6887 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6888 BOOL ret;
6890 TRACE("%p, %p.\n", iface, ref);
6892 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6893 reference->simulations == other->simulations;
6894 if (reference->axis_values_count)
6896 ret &= reference->axis_values_count == other->axis_values_count &&
6897 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6900 return ret;
6903 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6905 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6907 TRACE("%p.\n", iface);
6909 return reference->index;
6912 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6914 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6916 TRACE("%p.\n", iface);
6918 return reference->simulations;
6921 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6923 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6924 IDWriteFontFileLoader *loader;
6925 const void *key;
6926 UINT32 key_size;
6927 HRESULT hr;
6929 TRACE("%p, %p.\n", iface, file);
6931 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6932 if (FAILED(hr))
6933 return hr;
6935 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6936 if (FAILED(hr))
6937 return hr;
6939 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6940 IDWriteFontFileLoader_Release(loader);
6942 return hr;
6945 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6947 FIXME("%p.\n", iface);
6949 return 0;
6952 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6954 FIXME("%p.\n", iface);
6956 return 0;
6959 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6961 FIXME("%p, %p.\n", iface, writetime);
6963 return E_NOTIMPL;
6966 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6968 FIXME("%p.\n", iface);
6970 return DWRITE_LOCALITY_LOCAL;
6973 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6975 FIXME("%p.\n", iface);
6977 return E_NOTIMPL;
6980 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6981 WCHAR const *chars, UINT32 count)
6983 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6985 return E_NOTIMPL;
6988 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6989 UINT16 const *glyphs, UINT32 count)
6991 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6993 return E_NOTIMPL;
6996 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6997 UINT64 offset, UINT64 size)
6999 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
7001 return E_NOTIMPL;
7004 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
7006 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7007 IDWriteFontFace3 *fontface3;
7008 HRESULT hr;
7010 TRACE("%p, %p.\n", iface, fontface);
7012 /* FIXME: created instance should likely respect given axis. */
7013 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
7014 &fontface3)))
7016 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
7017 IDWriteFontFace3_Release(fontface3);
7020 return hr;
7023 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
7025 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7027 TRACE("%p.\n", iface);
7029 return reference->axis_values_count;
7032 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
7033 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
7035 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
7037 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
7039 if (value_count < reference->axis_values_count)
7040 return E_NOT_SUFFICIENT_BUFFER;
7042 memcpy(axis_values, reference->axis_values, reference->axis_values_count * sizeof(*axis_values));
7044 return S_OK;
7047 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
7049 fontfacereference_QueryInterface,
7050 fontfacereference_AddRef,
7051 fontfacereference_Release,
7052 fontfacereference_CreateFontFace,
7053 fontfacereference_CreateFontFaceWithSimulations,
7054 fontfacereference_Equals,
7055 fontfacereference_GetFontFaceIndex,
7056 fontfacereference_GetSimulations,
7057 fontfacereference_GetFontFile,
7058 fontfacereference_GetLocalFileSize,
7059 fontfacereference_GetFileSize,
7060 fontfacereference_GetFileTime,
7061 fontfacereference_GetLocality,
7062 fontfacereference_EnqueueFontDownloadRequest,
7063 fontfacereference_EnqueueCharacterDownloadRequest,
7064 fontfacereference_EnqueueGlyphDownloadRequest,
7065 fontfacereference_EnqueueFileFragmentDownloadRequest,
7066 fontfacereference1_CreateFontFace,
7067 fontfacereference1_GetFontAxisValueCount,
7068 fontfacereference1_GetFontAxisValues,
7071 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
7072 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
7073 IDWriteFontFaceReference1 **ret)
7075 struct dwrite_fontfacereference *object;
7077 *ret = NULL;
7079 if (!is_simulation_valid(simulations))
7080 return E_INVALIDARG;
7082 if (!(object = calloc(1, sizeof(*object))))
7083 return E_OUTOFMEMORY;
7085 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
7086 object->refcount = 1;
7088 object->factory = factory;
7089 IDWriteFactory7_AddRef(object->factory);
7090 object->file = file;
7091 IDWriteFontFile_AddRef(object->file);
7092 object->index = index;
7093 object->simulations = simulations;
7094 if (axis_values_count)
7096 if (!(object->axis_values = malloc(axis_values_count * sizeof(*axis_values))))
7098 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
7099 return E_OUTOFMEMORY;
7101 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
7102 object->axis_values_count = axis_values_count;
7105 *ret = &object->IDWriteFontFaceReference1_iface;
7107 return S_OK;
7110 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
7112 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7114 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
7115 *obj = iface;
7116 IDWriteFontFileStream_AddRef(iface);
7117 return S_OK;
7120 *obj = NULL;
7122 WARN("%s not implemented.\n", debugstr_guid(riid));
7123 return E_NOINTERFACE;
7126 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
7128 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7129 ULONG refcount = InterlockedIncrement(&stream->refcount);
7131 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7133 return refcount;
7136 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
7138 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7139 ULONG refcount = InterlockedDecrement(&stream->refcount);
7141 TRACE_(dwrite_file)("%p, refcount %lu.\n", iface, refcount);
7143 if (!refcount)
7145 release_inmemory_stream(stream->data);
7146 free(stream);
7149 return refcount;
7152 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
7153 UINT64 offset, UINT64 fragment_size, void **fragment_context)
7155 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7157 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
7158 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
7160 *fragment_context = NULL;
7162 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
7163 *fragment_start = NULL;
7164 return E_FAIL;
7167 *fragment_start = (char *)stream->data->data + offset;
7168 return S_OK;
7171 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
7173 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
7176 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
7178 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7180 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
7182 *size = stream->data->size;
7184 return S_OK;
7187 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
7189 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
7191 *last_writetime = 0;
7193 return E_NOTIMPL;
7196 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
7197 inmemoryfilestream_QueryInterface,
7198 inmemoryfilestream_AddRef,
7199 inmemoryfilestream_Release,
7200 inmemoryfilestream_ReadFileFragment,
7201 inmemoryfilestream_ReleaseFileFragment,
7202 inmemoryfilestream_GetFileSize,
7203 inmemoryfilestream_GetLastWriteTime,
7206 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
7207 REFIID riid, void **obj)
7209 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7211 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
7212 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
7213 IsEqualIID(riid, &IID_IUnknown))
7215 *obj = iface;
7216 IDWriteInMemoryFontFileLoader_AddRef(iface);
7217 return S_OK;
7220 WARN("%s not implemented.\n", debugstr_guid(riid));
7222 *obj = NULL;
7224 return E_NOINTERFACE;
7227 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
7229 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7230 ULONG refcount = InterlockedIncrement(&loader->refcount);
7232 TRACE("%p, refcount %lu.\n", iface, refcount);
7234 return refcount;
7237 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
7239 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7240 ULONG refcount = InterlockedDecrement(&loader->refcount);
7241 size_t i;
7243 TRACE("%p, refcount %lu.\n", iface, refcount);
7245 if (!refcount)
7247 for (i = 0; i < loader->count; ++i)
7248 release_inmemory_stream(loader->streams[i]);
7249 free(loader->streams);
7250 free(loader);
7253 return refcount;
7256 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
7257 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
7259 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7260 struct dwrite_inmemory_filestream *stream;
7261 DWORD index;
7263 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
7265 *ret = NULL;
7267 if (key_size != sizeof(DWORD))
7268 return E_INVALIDARG;
7270 index = *(DWORD *)key;
7272 if (index >= loader->count)
7273 return E_INVALIDARG;
7275 if (!(stream = malloc(sizeof(*stream))))
7276 return E_OUTOFMEMORY;
7278 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
7279 stream->refcount = 1;
7280 stream->data = loader->streams[index];
7281 InterlockedIncrement(&stream->data->refcount);
7283 *ret = &stream->IDWriteFontFileStream_iface;
7285 return S_OK;
7288 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
7289 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
7291 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7292 struct dwrite_inmemory_stream_data *stream;
7293 DWORD key;
7295 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
7297 *fontfile = NULL;
7299 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
7300 return E_OUTOFMEMORY;
7302 if (!(stream = malloc(sizeof(*stream))))
7303 return E_OUTOFMEMORY;
7305 stream->refcount = 1;
7306 stream->size = data_size;
7307 stream->owner = owner;
7308 if (stream->owner) {
7309 IUnknown_AddRef(stream->owner);
7310 stream->data = (void *)data;
7312 else {
7313 if (!(stream->data = malloc(data_size)))
7315 free(stream);
7316 return E_OUTOFMEMORY;
7318 memcpy(stream->data, data, data_size);
7321 key = loader->count;
7322 loader->streams[loader->count++] = stream;
7324 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
7325 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
7328 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
7330 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7332 TRACE("%p.\n", iface);
7334 return loader->count;
7337 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
7339 inmemoryfontfileloader_QueryInterface,
7340 inmemoryfontfileloader_AddRef,
7341 inmemoryfontfileloader_Release,
7342 inmemoryfontfileloader_CreateStreamFromKey,
7343 inmemoryfontfileloader_CreateInMemoryFontFileReference,
7344 inmemoryfontfileloader_GetFileCount,
7347 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
7349 struct dwrite_inmemory_fileloader *loader;
7351 *ret = NULL;
7353 if (!(loader = calloc(1, sizeof(*loader))))
7354 return E_OUTOFMEMORY;
7356 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
7357 loader->refcount = 1;
7359 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
7361 return S_OK;
7364 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
7366 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7368 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
7369 IsEqualIID(riid, &IID_IUnknown))
7371 *obj = iface;
7372 IDWriteFontResource_AddRef(iface);
7373 return S_OK;
7376 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7378 return E_NOINTERFACE;
7381 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
7383 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7384 ULONG refcount = InterlockedIncrement(&resource->refcount);
7386 TRACE("%p, refcount %lu.\n", iface, refcount);
7388 return refcount;
7391 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
7393 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7394 ULONG refcount = InterlockedDecrement(&resource->refcount);
7396 TRACE("%p, refcount %lu.\n", iface, refcount);
7398 if (!refcount)
7400 IDWriteFactory7_Release(resource->factory);
7401 IDWriteFontFile_Release(resource->file);
7402 free(resource->axis);
7403 free(resource);
7406 return refcount;
7409 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
7411 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7413 TRACE("%p, %p.\n", iface, fontfile);
7415 *fontfile = resource->file;
7416 IDWriteFontFile_AddRef(*fontfile);
7418 return S_OK;
7421 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
7423 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7425 TRACE("%p.\n", iface);
7427 return resource->face_index;
7430 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
7432 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7434 TRACE("%p.\n", iface);
7436 return resource->axis_count;
7439 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
7440 DWRITE_FONT_AXIS_VALUE *values, UINT32 count)
7442 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7443 unsigned int i;
7445 TRACE("%p, %p, %u.\n", iface, values, count);
7447 if (count < resource->axis_count)
7448 return E_NOT_SUFFICIENT_BUFFER;
7450 for (i = 0; i < resource->axis_count; ++i)
7452 values[i].axisTag = resource->axis[i].tag;
7453 values[i].value = resource->axis[i].default_value;
7456 return S_OK;
7459 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7460 DWRITE_FONT_AXIS_RANGE *ranges, UINT32 count)
7462 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7463 unsigned int i;
7465 TRACE("%p, %p, %u.\n", iface, ranges, count);
7467 if (count < resource->axis_count)
7468 return E_NOT_SUFFICIENT_BUFFER;
7470 for (i = 0; i < resource->axis_count; ++i)
7472 ranges[i].axisTag = resource->axis[i].tag;
7473 ranges[i].minValue = resource->axis[i].min_value;
7474 ranges[i].maxValue = resource->axis[i].max_value;
7477 return S_OK;
7480 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7481 UINT32 axis)
7483 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7485 TRACE("%p, %u.\n", iface, axis);
7487 return axis < resource->axis_count ? resource->axis[axis].attributes : 0;
7490 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7491 IDWriteLocalizedStrings **names)
7493 FIXME("%p, %u, %p.\n", iface, axis, names);
7495 return E_NOTIMPL;
7498 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7500 FIXME("%p, %u.\n", iface, axis);
7502 return 0;
7505 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7506 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7508 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7510 return E_NOTIMPL;
7513 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7515 FIXME("%p.\n", iface);
7517 return FALSE;
7520 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7521 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7522 IDWriteFontFace5 **fontface)
7524 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7525 IDWriteFontFaceReference1 *reference;
7526 HRESULT hr;
7528 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7530 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7531 simulations, axis_values, num_values, &reference);
7532 if (SUCCEEDED(hr))
7534 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7535 IDWriteFontFaceReference1_Release(reference);
7538 return hr;
7541 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7542 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7543 IDWriteFontFaceReference1 **reference)
7545 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7547 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7549 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7550 simulations, axis_values, num_values, reference);
7553 static const IDWriteFontResourceVtbl fontresourcevtbl =
7555 dwritefontresource_QueryInterface,
7556 dwritefontresource_AddRef,
7557 dwritefontresource_Release,
7558 dwritefontresource_GetFontFile,
7559 dwritefontresource_GetFontFaceIndex,
7560 dwritefontresource_GetFontAxisCount,
7561 dwritefontresource_GetDefaultFontAxisValues,
7562 dwritefontresource_GetFontAxisRanges,
7563 dwritefontresource_GetFontAxisAttributes,
7564 dwritefontresource_GetAxisNames,
7565 dwritefontresource_GetAxisValueNameCount,
7566 dwritefontresource_GetAxisValueNames,
7567 dwritefontresource_HasVariations,
7568 dwritefontresource_CreateFontFace,
7569 dwritefontresource_CreateFontFaceReference,
7572 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7573 IDWriteFontResource **ret)
7575 struct dwrite_fontresource *resource;
7576 struct file_stream_desc stream_desc;
7577 DWRITE_FONT_FILE_TYPE file_type;
7578 DWRITE_FONT_FACE_TYPE face_type;
7579 unsigned int face_count;
7580 BOOL supported = FALSE;
7581 HRESULT hr;
7583 *ret = NULL;
7585 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
7586 return hr;
7588 if (!supported)
7589 return DWRITE_E_FILEFORMAT;
7591 if (!(resource = calloc(1, sizeof(*resource))))
7592 return E_OUTOFMEMORY;
7594 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7595 resource->refcount = 1;
7596 resource->face_index = face_index;
7597 resource->file = file;
7598 IDWriteFontFile_AddRef(resource->file);
7599 resource->factory = factory;
7600 IDWriteFactory7_AddRef(resource->factory);
7602 get_filestream_from_file(file, &stream_desc.stream);
7603 stream_desc.face_type = face_type;
7604 stream_desc.face_index = face_index;
7606 opentype_get_font_var_axis(&stream_desc, &resource->axis, &resource->axis_count);
7608 if (stream_desc.stream)
7609 IDWriteFontFileStream_Release(stream_desc.stream);
7611 *ret = &resource->IDWriteFontResource_iface;
7613 return S_OK;
7616 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7618 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7620 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7621 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7622 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7623 IsEqualIID(riid, &IID_IDWriteFontSet))
7625 *obj = iface;
7626 IDWriteFontSet3_AddRef(iface);
7627 return S_OK;
7630 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7631 *obj = NULL;
7632 return E_NOINTERFACE;
7635 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7637 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7638 ULONG refcount = InterlockedIncrement(&set->refcount);
7640 TRACE("%p, refcount %lu.\n", iface, refcount);
7642 return refcount;
7645 #define MISSING_SET_PROP ((void *)0x1)
7647 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7649 unsigned int i;
7651 if (InterlockedDecrement(&entry->refcount) > 0)
7652 return;
7653 IDWriteFontFile_Release(entry->desc.file);
7654 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7656 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7657 IDWriteLocalizedStrings_Release(entry->props[i]);
7659 free(entry);
7662 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7664 InterlockedIncrement(&entry->refcount);
7665 return entry;
7668 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7669 DWRITE_FONT_PROPERTY_ID property)
7671 struct file_stream_desc stream_desc = { 0 };
7672 IDWriteLocalizedStrings *value;
7674 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7676 if (entry->props[property] == MISSING_SET_PROP)
7677 return NULL;
7679 if ((value = entry->props[property]))
7681 IDWriteLocalizedStrings_AddRef(value);
7682 return value;
7685 get_filestream_from_file(entry->desc.file, &stream_desc.stream);
7686 stream_desc.face_type = entry->desc.face_type;
7687 stream_desc.face_index = entry->desc.face_index;
7689 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7690 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7691 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7692 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7693 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7694 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7695 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7696 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7697 else if (property == DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME)
7698 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &value);
7699 else
7700 WARN("Unsupported property %u.\n", property);
7702 if (stream_desc.stream)
7703 IDWriteFontFileStream_Release(stream_desc.stream);
7705 if (value)
7707 entry->props[property] = value;
7708 IDWriteLocalizedStrings_AddRef(value);
7710 else
7711 entry->props[property] = MISSING_SET_PROP;
7713 return value;
7716 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7717 struct dwrite_fontset_entry **entries, unsigned int count);
7719 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7721 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7722 ULONG refcount = InterlockedDecrement(&set->refcount);
7723 unsigned int i;
7725 TRACE("%p, refcount %lu.\n", iface, refcount);
7727 if (!refcount)
7729 IDWriteFactory7_Release(set->factory);
7730 for (i = 0; i < set->count; ++i)
7731 release_fontset_entry(set->entries[i]);
7732 free(set->entries);
7733 free(set);
7736 return refcount;
7739 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7741 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7743 TRACE("%p.\n", iface);
7745 return set->count;
7748 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7749 IDWriteFontFaceReference **reference)
7751 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7753 TRACE("%p, %u, %p.\n", iface, index, reference);
7755 *reference = NULL;
7757 if (index >= set->count)
7758 return E_INVALIDARG;
7760 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->desc.file,
7761 set->entries[index]->desc.face_index, set->entries[index]->desc.simulations, reference);
7764 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7765 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7767 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7769 return E_NOTIMPL;
7772 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7773 UINT32 *index, BOOL *exists)
7775 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7777 return E_NOTIMPL;
7780 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7781 IDWriteStringList **values)
7783 FIXME("%p, %d, %p.\n", iface, id, values);
7785 return E_NOTIMPL;
7788 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7789 WCHAR const *preferred_locales, IDWriteStringList **values)
7791 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7793 return E_NOTIMPL;
7796 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7797 BOOL *exists, IDWriteLocalizedStrings **values)
7799 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7801 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7803 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7804 index >= set->count)
7806 *values = NULL;
7807 *exists = FALSE;
7808 return E_INVALIDARG;
7811 *values = fontset_entry_get_property(set->entries[index], id);
7812 *exists = !!*values;
7814 return S_OK;
7817 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7818 UINT32 *count)
7820 FIXME("%p, %p, %p.\n", iface, property, count);
7822 return E_NOTIMPL;
7825 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7826 unsigned int count)
7828 IDWriteLocalizedStrings *value;
7829 unsigned int i;
7830 BOOL ret;
7832 for (i = 0; i < count; ++i)
7834 switch (props[i].propertyId)
7836 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7837 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7838 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7839 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7840 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7841 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7842 return FALSE;
7844 ret = localizedstrings_contains(value, props[i].propertyValue);
7845 IDWriteLocalizedStrings_Release(value);
7846 if (!ret) return FALSE;
7847 break;
7848 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7849 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7850 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7851 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7852 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7853 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7854 case DWRITE_FONT_PROPERTY_ID_STYLE:
7855 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7856 FIXME("Unsupported property %d.\n", props[i].propertyId);
7857 /* fallthrough */
7858 default:
7859 return FALSE;
7863 return TRUE;
7866 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7867 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7869 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7871 return E_NOTIMPL;
7874 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7875 IDWriteFontSet **filtered_set)
7877 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7878 struct dwrite_fontset_entry **entries;
7879 unsigned int i, matched_count = 0;
7880 struct dwrite_fontset *object;
7882 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7884 if (!props && count)
7885 return E_INVALIDARG;
7887 if (!(object = calloc(1, sizeof(*object))))
7888 return E_OUTOFMEMORY;
7890 if (!(entries = calloc(set->count, sizeof(*entries))))
7892 free(object);
7893 return E_OUTOFMEMORY;
7896 for (i = 0; i < set->count; ++i)
7898 if (fontset_entry_is_matching(set->entries[i], props, count))
7900 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7904 if (!matched_count)
7906 free(entries);
7907 entries = NULL;
7910 init_fontset(object, set->factory, entries, matched_count);
7912 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7914 return S_OK;
7917 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7918 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7920 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7922 return E_NOTIMPL;
7925 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7927 FIXME("%p, %p.\n", iface, fontset);
7929 return E_NOTIMPL;
7932 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7933 UINT32 num_indices, IDWriteFontSet1 **fontset)
7935 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7937 return E_NOTIMPL;
7940 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7941 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7943 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7945 return E_NOTIMPL;
7948 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7949 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7951 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7953 return E_NOTIMPL;
7956 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7957 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7959 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7961 return E_NOTIMPL;
7964 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7965 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7967 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7968 num_indices, actual_num_indices);
7970 return E_NOTIMPL;
7973 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7974 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7976 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7978 return E_NOTIMPL;
7981 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7982 UINT32 num_ranges, UINT32 *actual_num_ranges)
7984 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7986 return E_NOTIMPL;
7989 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7990 IDWriteFontFaceReference1 **reference)
7992 FIXME("%p, %u, %p.\n", iface, index, reference);
7994 return E_NOTIMPL;
7997 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
7999 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
8001 TRACE("%p, %u, %p.\n", iface, index, resource);
8003 *resource = NULL;
8005 if (index >= set->count)
8006 return E_INVALIDARG;
8008 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->desc.file,
8009 set->entries[index]->desc.face_index, resource);
8012 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
8014 FIXME("%p, %u, %p.\n", iface, index, fontface);
8016 return E_NOTIMPL;
8019 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
8021 FIXME("%p, %u.\n", iface, index);
8023 return DWRITE_LOCALITY_LOCAL;
8026 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
8028 FIXME("%p.\n", iface);
8030 return NULL;
8033 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
8035 FIXME("%p, %u.\n", iface, index);
8037 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
8040 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
8042 FIXME("%p, %u.\n", iface, index);
8044 return 0;
8047 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
8049 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
8051 return E_NOTIMPL;
8054 static const IDWriteFontSet3Vtbl fontsetvtbl =
8056 dwritefontset_QueryInterface,
8057 dwritefontset_AddRef,
8058 dwritefontset_Release,
8059 dwritefontset_GetFontCount,
8060 dwritefontset_GetFontFaceReference,
8061 dwritefontset_FindFontFaceReference,
8062 dwritefontset_FindFontFace,
8063 dwritefontset_GetPropertyValues__,
8064 dwritefontset_GetPropertyValues_,
8065 dwritefontset_GetPropertyValues,
8066 dwritefontset_GetPropertyOccurrenceCount,
8067 dwritefontset_GetMatchingFonts_,
8068 dwritefontset_GetMatchingFonts,
8069 dwritefontset1_GetMatchingFonts,
8070 dwritefontset1_GetFirstFontResources,
8071 dwritefontset1_GetFilteredFonts__,
8072 dwritefontset1_GetFilteredFonts_,
8073 dwritefontset1_GetFilteredFonts,
8074 dwritefontset1_GetFilteredFontIndices_,
8075 dwritefontset1_GetFilteredFontIndices,
8076 dwritefontset1_GetFontAxisRanges_,
8077 dwritefontset1_GetFontAxisRanges,
8078 dwritefontset1_GetFontFaceReference,
8079 dwritefontset1_CreateFontResource,
8080 dwritefontset1_CreateFontFace,
8081 dwritefontset1_GetFontLocality,
8082 dwritefontset2_GetExpirationEvent,
8083 dwritefontset3_GetFontSourceType,
8084 dwritefontset3_GetFontSourceNameLength,
8085 dwritefontset3_GetFontSourceName,
8088 static struct dwrite_fontset *unsafe_impl_from_IDWriteFontSet(IDWriteFontSet *iface)
8090 if (!iface)
8091 return NULL;
8092 assert(iface->lpVtbl == (IDWriteFontSetVtbl *)&fontsetvtbl);
8093 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
8096 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
8097 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
8099 struct dwrite_fontset_entry *entry;
8101 if (!(entry = calloc(1, sizeof(*entry))))
8102 return E_OUTOFMEMORY;
8104 entry->refcount = 1;
8105 entry->desc.file = file;
8106 IDWriteFontFile_AddRef(entry->desc.file);
8107 entry->desc.face_type = face_type;
8108 entry->desc.face_index = face_index;
8109 entry->desc.simulations = simulations;
8111 *ret = entry;
8113 return S_OK;
8116 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
8117 struct dwrite_fontset_entry **entries, unsigned int count)
8119 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
8120 object->refcount = 1;
8121 object->factory = factory;
8122 IDWriteFactory7_AddRef(object->factory);
8123 object->entries = entries;
8124 object->count = count;
8127 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
8128 unsigned int count, IDWriteFontSet1 **ret)
8130 struct dwrite_fontset_entry **entries = NULL;
8131 struct dwrite_fontset *object;
8132 unsigned int i;
8134 if (!(object = calloc(1, sizeof(*object))))
8135 return E_OUTOFMEMORY;
8137 if (count)
8139 entries = calloc(count, sizeof(*entries));
8141 /* FIXME: set available properties too */
8143 for (i = 0; i < count; ++i)
8145 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
8146 fonts[i]->simulations, &entries[i]);
8149 init_fontset(object, factory, entries, count);
8151 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
8153 return S_OK;
8156 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
8157 unsigned int count, IDWriteFontSet **ret)
8159 struct dwrite_fontset_entry **entries = NULL;
8160 struct dwrite_fontset *object;
8161 unsigned int i;
8163 if (!(object = calloc(1, sizeof(*object))))
8164 return E_OUTOFMEMORY;
8166 if (count)
8168 entries = calloc(count, sizeof(*entries));
8170 for (i = 0; i < count; ++i)
8171 entries[i] = addref_fontset_entry(src_entries[i]);
8173 init_fontset(object, factory, entries, count);
8175 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
8177 return S_OK;
8180 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
8181 REFIID riid, void **obj)
8183 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
8185 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
8186 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
8187 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
8188 IsEqualIID(riid, &IID_IUnknown))
8190 *obj = iface;
8191 IDWriteFontSetBuilder2_AddRef(iface);
8192 return S_OK;
8195 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
8196 *obj = NULL;
8197 return E_NOINTERFACE;
8200 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
8202 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8203 ULONG refcount = InterlockedIncrement(&builder->refcount);
8205 TRACE("%p, refcount %lu.\n", iface, refcount);
8207 return refcount;
8210 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
8212 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8213 ULONG refcount = InterlockedDecrement(&builder->refcount);
8214 unsigned int i;
8216 TRACE("%p, refcount %lu.\n", iface, refcount);
8218 if (!refcount)
8220 IDWriteFactory7_Release(builder->factory);
8221 for (i = 0; i < builder->count; ++i)
8222 release_fontset_entry(builder->entries[i]);
8223 free(builder->entries);
8224 free(builder);
8227 return refcount;
8230 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, const struct dwrite_fontset_entry_desc *desc)
8232 struct dwrite_fontset_entry *entry;
8233 HRESULT hr;
8235 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
8236 sizeof(*builder->entries)))
8238 return E_OUTOFMEMORY;
8241 if (FAILED(hr = fontset_create_entry(desc->file, desc->face_type, desc->face_index, desc->simulations, &entry)))
8242 return hr;
8244 builder->entries[builder->count++] = entry;
8246 return S_OK;
8249 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
8251 struct dwrite_fontset_entry_desc desc = { 0 };
8252 DWRITE_FONT_FILE_TYPE filetype;
8253 unsigned int i, face_count;
8254 BOOL supported = FALSE;
8255 HRESULT hr;
8257 desc.file = file;
8258 if (FAILED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &filetype, &desc.face_type, &face_count)))
8259 return hr;
8261 if (!supported)
8262 return DWRITE_E_FILEFORMAT;
8264 for (i = 0; i < face_count; ++i)
8266 desc.face_index = i;
8267 if (FAILED(hr = fontset_builder_add_entry(builder, &desc)))
8268 break;
8271 return hr;
8274 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
8275 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
8277 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
8279 return E_NOTIMPL;
8282 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
8283 IDWriteFontFaceReference *reference)
8285 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8286 struct dwrite_fontset_entry_desc desc = { 0 };
8287 DWRITE_FONT_FILE_TYPE file_type;
8288 unsigned int face_count;
8289 BOOL supported;
8290 HRESULT hr;
8292 TRACE("%p, %p.\n", iface, reference);
8294 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(reference, &desc.file))) return hr;
8296 if (SUCCEEDED(hr = IDWriteFontFile_Analyze(desc.file, &supported, &file_type, &desc.face_type, &face_count)))
8298 if (!supported)
8299 hr = DWRITE_E_FILEFORMAT;
8301 if (SUCCEEDED(hr))
8303 desc.face_index = IDWriteFontFaceReference_GetFontFaceIndex(reference);
8304 desc.simulations = IDWriteFontFaceReference_GetSimulations(reference);
8305 hr = fontset_builder_add_entry(builder, &desc);
8309 IDWriteFontFile_Release(desc.file);
8311 return hr;
8314 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
8316 FIXME("%p, %p.\n", iface, fontset);
8318 return E_NOTIMPL;
8321 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
8323 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8325 TRACE("%p, %p.\n", iface, fontset);
8327 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
8330 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
8332 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8334 TRACE("%p, %p.\n", iface, file);
8336 return fontset_builder_add_file(builder, file);
8339 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
8340 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
8341 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
8342 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
8344 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
8345 axis_ranges, num_ranges, props, num_properties);
8347 return E_NOTIMPL;
8350 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
8352 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8353 IDWriteFontFile *file;
8354 HRESULT hr;
8356 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
8358 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
8359 return hr;
8361 hr = fontset_builder_add_file(builder, file);
8362 IDWriteFontFile_Release(file);
8363 return hr;
8366 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
8368 dwritefontsetbuilder_QueryInterface,
8369 dwritefontsetbuilder_AddRef,
8370 dwritefontsetbuilder_Release,
8371 dwritefontsetbuilder_AddFontFaceReference_,
8372 dwritefontsetbuilder_AddFontFaceReference,
8373 dwritefontsetbuilder_AddFontSet,
8374 dwritefontsetbuilder_CreateFontSet,
8375 dwritefontsetbuilder1_AddFontFile,
8376 dwritefontsetbuilder2_AddFont,
8377 dwritefontsetbuilder2_AddFontFile,
8380 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
8382 struct dwrite_fontset_builder *builder;
8384 *ret = NULL;
8386 if (!(builder = calloc(1, sizeof(*builder))))
8387 return E_OUTOFMEMORY;
8389 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
8390 builder->refcount = 1;
8391 builder->factory = factory;
8392 IDWriteFactory7_AddRef(builder->factory);
8394 *ret = &builder->IDWriteFontSetBuilder2_iface;
8396 return S_OK;