dwrite: Remove some unused fields.
[wine.git] / dlls / dwrite / font.c
blob5815c09e8ae1b4a1bca4904fb8c4ce5e8f006132
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
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 struct dwrite_fontfamily_data **family_data;
337 size_t size;
338 size_t count;
341 struct dwrite_fontfamily
343 IDWriteFontFamily2 IDWriteFontFamily2_iface;
344 IDWriteFontList2 IDWriteFontList2_iface;
345 LONG refcount;
347 struct dwrite_fontfamily_data *data;
348 struct dwrite_fontcollection *collection;
351 struct dwrite_fontlist
353 IDWriteFontList2 IDWriteFontList2_iface;
354 LONG refcount;
356 struct dwrite_font_data **fonts;
357 UINT32 font_count;
358 struct dwrite_fontfamily *family;
361 struct dwrite_font
363 IDWriteFont3 IDWriteFont3_iface;
364 LONG refcount;
366 DWRITE_FONT_STYLE style;
367 struct dwrite_font_data *data;
368 struct dwrite_fontfamily *family;
371 enum runanalysis_flags {
372 RUNANALYSIS_BOUNDS_READY = 1 << 0,
373 RUNANALYSIS_BITMAP_READY = 1 << 1,
374 RUNANALYSIS_USE_TRANSFORM = 1 << 2
377 struct dwrite_glyphrunanalysis
379 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
380 LONG refcount;
382 DWRITE_RENDERING_MODE1 rendering_mode;
383 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
384 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
385 DWRITE_MATRIX m;
386 UINT16 *glyphs;
387 D2D_POINT_2F *origins;
389 UINT8 flags;
390 RECT bounds;
391 BYTE *bitmap;
392 UINT32 max_glyph_bitmap_size;
395 struct dwrite_colorglyphenum
397 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
398 LONG refcount;
400 FLOAT origin_x; /* original run origin */
401 FLOAT origin_y;
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 #define GLYPH_BLOCK_SHIFT 8
420 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
421 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
422 #define GLYPH_MAX 65536
424 struct dwrite_fontfile
426 IDWriteFontFile IDWriteFontFile_iface;
427 LONG refcount;
429 IDWriteFontFileLoader *loader;
430 void *reference_key;
431 UINT32 key_size;
432 IDWriteFontFileStream *stream;
435 struct dwrite_fontfacereference
437 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
438 LONG refcount;
440 IDWriteFontFile *file;
441 UINT32 index;
442 USHORT simulations;
443 DWRITE_FONT_AXIS_VALUE *axis_values;
444 UINT32 axis_values_count;
445 IDWriteFactory7 *factory;
448 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
450 struct dwrite_fontresource
452 IDWriteFontResource IDWriteFontResource_iface;
453 LONG refcount;
455 IDWriteFontFile *file;
456 UINT32 face_index;
457 IDWriteFactory7 *factory;
460 struct dwrite_fontset_entry
462 LONG refcount;
463 IDWriteFontFile *file;
464 DWRITE_FONT_FACE_TYPE face_type;
465 unsigned int face_index;
466 unsigned int simulations;
467 IDWriteLocalizedStrings *props[DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME + 1];
470 struct dwrite_fontset
472 IDWriteFontSet3 IDWriteFontSet3_iface;
473 LONG refcount;
474 IDWriteFactory7 *factory;
476 struct dwrite_fontset_entry **entries;
477 unsigned int count;
480 struct dwrite_fontset_builder
482 IDWriteFontSetBuilder2 IDWriteFontSetBuilder2_iface;
483 LONG refcount;
484 IDWriteFactory7 *factory;
486 struct dwrite_fontset_entry **entries;
487 size_t count;
488 size_t capacity;
491 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
492 unsigned int count, IDWriteFontSet1 **ret);
494 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
496 struct dwrite_fontface *fontface = context;
497 BOOL exists = FALSE;
499 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
500 size, data_context, &exists)) || !exists)
502 *data = NULL;
503 *size = 0;
504 *data_context = NULL;
508 static void dwrite_release_font_table(void *context, void *data_context)
510 struct dwrite_fontface *fontface = context;
511 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
514 static UINT16 dwrite_get_font_upem(void *context)
516 struct dwrite_fontface *fontface = context;
517 return fontface->metrics.designUnitsPerEm;
520 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
522 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
523 return opentype_cmap_get_glyph(&fontface->cmap, ch);
526 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
528 struct dwrite_fontface *fontface = context;
529 return !!dwritefontface_get_glyph(fontface, codepoint);
532 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
534 struct dwrite_fontface *fontface = context;
535 return dwritefontface_get_glyph(fontface, codepoint);
538 static const struct shaping_font_ops dwrite_font_ops =
540 dwrite_grab_font_table,
541 dwrite_release_font_table,
542 dwrite_get_font_upem,
543 dwrite_has_glyph,
544 dwrite_get_glyph,
547 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
549 if (fontface->shaping_cache)
550 return fontface->shaping_cache;
552 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
555 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
557 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
560 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
562 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
565 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
567 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
570 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
572 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
574 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
577 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
579 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
582 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
584 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
587 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
589 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
592 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
594 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
597 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
599 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
602 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
604 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
607 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
609 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
612 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
614 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
617 static struct dwrite_fontset_builder *impl_from_IDWriteFontSetBuilder2(IDWriteFontSetBuilder2 *iface)
619 return CONTAINING_RECORD(iface, struct dwrite_fontset_builder, IDWriteFontSetBuilder2_iface);
622 static struct dwrite_fontset *impl_from_IDWriteFontSet3(IDWriteFontSet3 *iface)
624 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
627 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
629 static const DWRITE_GLYPH_METRICS nil;
630 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
632 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
633 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
634 return S_OK;
637 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
639 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
641 if (!*block)
643 /* start new block */
644 if (!(*block = calloc(GLYPH_BLOCK_SIZE, sizeof(*metrics))))
645 return E_OUTOFMEMORY;
648 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
649 return S_OK;
652 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
654 HRESULT hr;
656 if (table->data || !table->exists)
657 return table->data;
659 table->exists = FALSE;
660 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
661 &table->exists);
662 if (FAILED(hr) || !table->exists) {
663 TRACE("Font does not have %s table\n", debugstr_tag(tag));
664 return NULL;
667 return table->data;
670 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
671 struct dwrite_font_propvec *vec)
673 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
674 vec->style = style * 7.0f;
675 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
678 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
680 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
683 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
685 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
688 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
690 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
691 return &fontface->vdmx;
694 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
696 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
697 return &fontface->gasp;
700 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
702 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
703 return &fontface->cpal;
706 static struct dwrite_font_data * addref_font_data(struct dwrite_font_data *data)
708 InterlockedIncrement(&data->refcount);
709 return data;
712 static void release_font_data(struct dwrite_font_data *data)
714 int i;
716 if (InterlockedDecrement(&data->refcount) > 0)
717 return;
719 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
721 if (data->info_strings[i])
722 IDWriteLocalizedStrings_Release(data->info_strings[i]);
724 if (data->names)
725 IDWriteLocalizedStrings_Release(data->names);
727 if (data->family_names)
728 IDWriteLocalizedStrings_Release(data->family_names);
730 dwrite_cmap_release(&data->cmap);
731 IDWriteFontFile_Release(data->file);
732 free(data->facename);
733 free(data);
736 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
738 size_t i;
740 if (InterlockedDecrement(&data->refcount) > 0)
741 return;
743 for (i = 0; i < data->count; ++i)
744 release_font_data(data->fonts[i]);
745 free(data->fonts);
746 IDWriteLocalizedStrings_Release(data->familyname);
747 free(data);
750 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
752 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
753 fontface->cached = NULL;
756 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
758 UINT32 left_key_size, right_key_size;
759 const void *left_key, *right_key;
760 HRESULT hr;
762 if (left == right)
763 return TRUE;
765 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
766 if (FAILED(hr))
767 return FALSE;
769 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
770 if (FAILED(hr))
771 return FALSE;
773 if (left_key_size != right_key_size)
774 return FALSE;
776 return !memcmp(left_key, right_key, left_key_size);
779 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
781 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
783 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
785 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
786 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
787 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
788 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
789 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
790 IsEqualIID(riid, &IID_IDWriteFontFace) ||
791 IsEqualIID(riid, &IID_IUnknown))
793 *obj = iface;
795 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
796 *obj = &fontface->IDWriteFontFaceReference_iface;
797 else
798 *obj = NULL;
800 if (*obj)
802 if (InterlockedIncrement(&fontface->refcount) == 1)
804 InterlockedDecrement(&fontface->refcount);
805 *obj = NULL;
806 return E_FAIL;
808 return S_OK;
811 WARN("%s not implemented.\n", debugstr_guid(riid));
813 return E_NOINTERFACE;
816 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
818 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
819 ULONG refcount = InterlockedIncrement(&fontface->refcount);
821 TRACE("%p, refcount %u.\n", iface, refcount);
823 return refcount;
826 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
828 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
829 ULONG refcount = InterlockedDecrement(&fontface->refcount);
830 struct release_font_object_params params = { fontface->font_object };
832 TRACE("%p, refcount %u.\n", iface, refcount);
834 if (!refcount)
836 UINT32 i;
838 if (fontface->cached)
840 factory_lock(fontface->factory);
841 list_remove(&fontface->cached->entry);
842 factory_unlock(fontface->factory);
843 free(fontface->cached);
845 release_scriptshaping_cache(fontface->shaping_cache);
846 if (fontface->vdmx.context)
847 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
848 if (fontface->gasp.context)
849 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
850 if (fontface->cpal.context)
851 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
852 if (fontface->colr.context)
853 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
854 if (fontface->kern.context)
855 IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
856 if (fontface->file)
857 IDWriteFontFile_Release(fontface->file);
858 if (fontface->names)
859 IDWriteLocalizedStrings_Release(fontface->names);
860 if (fontface->family_names)
861 IDWriteLocalizedStrings_Release(fontface->family_names);
862 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
864 if (fontface->info_strings[i])
865 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
868 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
869 free(fontface->glyphs[i]);
871 UNIX_CALL(release_font_object, &params);
872 if (fontface->stream)
874 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, fontface->data_context);
875 IDWriteFontFileStream_Release(fontface->stream);
877 fontface_cache_clear(fontface);
879 dwrite_cmap_release(&fontface->cmap);
880 IDWriteFactory7_Release(fontface->factory);
881 DeleteCriticalSection(&fontface->cs);
882 free(fontface);
885 return refcount;
888 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
890 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
892 TRACE("%p.\n", iface);
894 return fontface->type;
897 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
898 IDWriteFontFile **fontfiles)
900 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
902 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
904 if (!fontfiles)
906 *number_of_files = 1;
907 return S_OK;
910 if (!*number_of_files)
911 return E_INVALIDARG;
913 IDWriteFontFile_AddRef(fontface->file);
914 *fontfiles = fontface->file;
916 return S_OK;
919 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
921 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
923 TRACE("%p.\n", iface);
925 return fontface->index;
928 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
930 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
932 TRACE("%p.\n", iface);
934 return fontface->simulations;
937 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
939 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
941 TRACE("%p.\n", iface);
943 return !!(fontface->flags & FONT_IS_SYMBOL);
946 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
948 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
950 TRACE("%p, %p.\n", iface, metrics);
952 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
955 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
957 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
958 struct get_glyph_count_params params;
959 unsigned int count;
961 TRACE("%p.\n", iface);
963 params.object = fontface->get_font_object(fontface);
964 params.count = &count;
965 UNIX_CALL(get_glyph_count, &params);
967 return count;
970 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
971 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
973 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
974 struct get_design_glyph_metrics_params params;
975 DWRITE_GLYPH_METRICS metrics;
976 HRESULT hr = S_OK;
977 unsigned int i;
979 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
981 if (!glyphs)
982 return E_INVALIDARG;
984 if (is_sideways)
985 FIXME("sideways metrics are not supported.\n");
987 params.object = fontface->get_font_object(fontface);
988 params.simulations = fontface->simulations;
989 params.upem = fontface->metrics.designUnitsPerEm;
990 params.ascent = fontface->typo_metrics.ascent;
991 params.metrics = &metrics;
993 EnterCriticalSection(&fontface->cs);
994 for (i = 0; i < glyph_count; ++i)
997 if (get_cached_glyph_metrics(fontface, glyphs[i], &metrics) != S_OK)
999 params.glyph = glyphs[i];
1000 UNIX_CALL(get_design_glyph_metrics, &params);
1001 if (FAILED(hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics))) break;
1003 ret[i] = metrics;
1005 LeaveCriticalSection(&fontface->cs);
1007 return hr;
1010 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
1011 UINT32 count, UINT16 *glyphs)
1013 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1014 unsigned int i;
1016 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
1018 if (!glyphs)
1019 return E_INVALIDARG;
1021 if (!codepoints)
1023 memset(glyphs, 0, count * sizeof(*glyphs));
1024 return E_INVALIDARG;
1027 for (i = 0; i < count; ++i)
1028 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
1030 return S_OK;
1033 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
1034 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
1036 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1037 struct file_stream_desc stream_desc;
1039 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
1041 stream_desc.stream = fontface->stream;
1042 stream_desc.face_type = fontface->type;
1043 stream_desc.face_index = fontface->index;
1044 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
1047 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
1049 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1051 TRACE("%p, %p.\n", iface, table_context);
1053 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
1056 static void apply_outline_point_offset(const D2D1_POINT_2F *src, const D2D1_POINT_2F *offset,
1057 D2D1_POINT_2F *dst)
1059 dst->x = src->x + offset->x;
1060 dst->y = src->y + offset->y;
1063 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
1064 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
1065 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
1067 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1068 D2D1_POINT_2F *origins, baseline_origin = { 0 };
1069 struct dwrite_outline outline, outline_size;
1070 struct get_glyph_outline_params params;
1071 D2D1_BEZIER_SEGMENT segment;
1072 D2D1_POINT_2F point;
1073 DWRITE_GLYPH_RUN run;
1074 unsigned int i, j, p;
1075 NTSTATUS status;
1076 HRESULT hr;
1078 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
1079 count, is_sideways, is_rtl, sink);
1081 if (!glyphs || !sink)
1082 return E_INVALIDARG;
1084 if (!count)
1085 return S_OK;
1087 run.fontFace = (IDWriteFontFace *)iface;
1088 run.fontEmSize = emSize;
1089 run.glyphCount = count;
1090 run.glyphIndices = glyphs;
1091 run.glyphAdvances = advances;
1092 run.glyphOffsets = offsets;
1093 run.isSideways = is_sideways;
1094 run.bidiLevel = is_rtl ? 1 : 0;
1096 if (!(origins = malloc(sizeof(*origins) * count)))
1097 return E_OUTOFMEMORY;
1099 if (FAILED(hr = compute_glyph_origins(&run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins)))
1101 free(origins);
1102 return hr;
1105 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
1107 memset(&outline_size, 0, sizeof(outline_size));
1108 memset(&outline, 0, sizeof(outline));
1110 params.object = fontface->get_font_object(fontface);
1111 params.simulations = fontface->simulations;
1112 params.emsize = emSize;
1114 for (i = 0; i < count; ++i)
1116 outline.tags.count = outline.points.count = 0;
1118 EnterCriticalSection(&fontface->cs);
1120 params.glyph = glyphs[i];
1121 params.outline = &outline_size;
1123 if (!(status = UNIX_CALL(get_glyph_outline, &params)))
1125 dwrite_array_reserve((void **)&outline.tags.values, &outline.tags.size, outline_size.tags.count,
1126 sizeof(*outline.tags.values));
1127 dwrite_array_reserve((void **)&outline.points.values, &outline.points.size, outline_size.points.count,
1128 sizeof(*outline.points.values));
1130 params.outline = &outline;
1131 if ((status = UNIX_CALL(get_glyph_outline, &params)))
1133 WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
1136 LeaveCriticalSection(&fontface->cs);
1138 if (status)
1139 continue;
1141 for (j = 0, p = 0; j < outline.tags.count; ++j)
1143 switch (outline.tags.values[j])
1145 case OUTLINE_BEGIN_FIGURE:
1146 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1147 ID2D1SimplifiedGeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
1148 break;
1149 case OUTLINE_END_FIGURE:
1150 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
1151 break;
1152 case OUTLINE_LINE:
1153 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
1154 ID2D1SimplifiedGeometrySink_AddLines(sink, &point, 1);
1155 break;
1156 case OUTLINE_BEZIER:
1157 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point1);
1158 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point2);
1159 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point3);
1160 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &segment, 1);
1161 break;
1166 free(outline.tags.values);
1167 free(outline.points.values);
1168 free(origins);
1170 return S_OK;
1173 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
1174 float ppem, unsigned int gasp)
1176 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
1178 switch (measuring)
1180 case DWRITE_MEASURING_MODE_NATURAL:
1182 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
1183 mode = DWRITE_RENDERING_MODE_NATURAL;
1184 else
1185 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
1186 break;
1188 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1189 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
1190 break;
1191 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1192 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
1193 break;
1194 default:
1198 return mode;
1201 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1202 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
1204 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1205 unsigned int flags;
1206 FLOAT ppem;
1208 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
1210 if (!params) {
1211 *mode = DWRITE_RENDERING_MODE_DEFAULT;
1212 return E_INVALIDARG;
1215 *mode = IDWriteRenderingParams_GetRenderingMode(params);
1216 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
1217 return S_OK;
1219 ppem = emSize * ppdip;
1221 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
1222 *mode = DWRITE_RENDERING_MODE_OUTLINE;
1223 return S_OK;
1226 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
1227 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
1228 return S_OK;
1231 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
1232 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
1234 DWRITE_FONT_METRICS1 metrics1;
1235 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
1236 memcpy(metrics, &metrics1, sizeof(*metrics));
1237 return hr;
1240 static inline int round_metric(FLOAT metric)
1242 return (int)floorf(metric + 0.5f);
1245 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
1247 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
1248 return 0;
1250 return (fontface->metrics.designUnitsPerEm + 49) / 50;
1253 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
1254 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
1255 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
1257 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1258 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
1259 DWRITE_MEASURING_MODE mode;
1260 FLOAT scale, size;
1261 HRESULT hr = S_OK;
1262 UINT32 i;
1264 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
1265 glyph_count, metrics, is_sideways);
1267 if (m && memcmp(m, &identity, sizeof(*m)))
1268 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
1270 size = emSize * ppdip;
1271 scale = size / fontface->metrics.designUnitsPerEm;
1272 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1274 EnterCriticalSection(&fontface->cs);
1275 for (i = 0; i < glyph_count; ++i)
1277 DWRITE_GLYPH_METRICS *ret = metrics + i;
1278 DWRITE_GLYPH_METRICS design;
1279 BOOL has_contours;
1281 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
1282 if (FAILED(hr))
1283 break;
1285 ret->advanceWidth = fontface_get_glyph_advance(fontface, size, glyphs[i], mode, &has_contours);
1286 if (has_contours)
1287 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
1288 else
1289 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
1291 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
1292 SCALE_METRIC(leftSideBearing);
1293 SCALE_METRIC(rightSideBearing);
1294 SCALE_METRIC(topSideBearing);
1295 SCALE_METRIC(advanceHeight);
1296 SCALE_METRIC(bottomSideBearing);
1297 SCALE_METRIC(verticalOriginY);
1298 #undef SCALE_METRIC
1300 LeaveCriticalSection(&fontface->cs);
1302 return S_OK;
1305 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
1307 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1309 TRACE("%p, %p.\n", iface, metrics);
1311 *metrics = fontface->metrics;
1314 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
1315 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
1317 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1318 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
1319 UINT16 ascent, descent;
1320 FLOAT scale;
1322 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
1324 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
1325 memset(metrics, 0, sizeof(*metrics));
1326 return E_INVALIDARG;
1329 em_size *= pixels_per_dip;
1330 if (m && m->m22 != 0.0f)
1331 em_size *= fabs(m->m22);
1333 scale = em_size / design->designUnitsPerEm;
1334 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
1336 ascent = round_metric(design->ascent * scale);
1337 descent = round_metric(design->descent * scale);
1340 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
1341 metrics->designUnitsPerEm = design->designUnitsPerEm;
1342 metrics->ascent = round_metric(ascent / scale);
1343 metrics->descent = round_metric(descent / scale);
1345 SCALE_METRIC(lineGap);
1346 SCALE_METRIC(capHeight);
1347 SCALE_METRIC(xHeight);
1348 SCALE_METRIC(underlinePosition);
1349 SCALE_METRIC(underlineThickness);
1350 SCALE_METRIC(strikethroughPosition);
1351 SCALE_METRIC(strikethroughThickness);
1352 SCALE_METRIC(glyphBoxLeft);
1353 SCALE_METRIC(glyphBoxTop);
1354 SCALE_METRIC(glyphBoxRight);
1355 SCALE_METRIC(glyphBoxBottom);
1356 SCALE_METRIC(subscriptPositionX);
1357 SCALE_METRIC(subscriptPositionY);
1358 SCALE_METRIC(subscriptSizeX);
1359 SCALE_METRIC(subscriptSizeY);
1360 SCALE_METRIC(superscriptPositionX);
1361 SCALE_METRIC(superscriptPositionY);
1362 SCALE_METRIC(superscriptSizeX);
1363 SCALE_METRIC(superscriptSizeY);
1365 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1366 #undef SCALE_METRIC
1368 return S_OK;
1371 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1373 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1375 TRACE("%p, %p.\n", iface, metrics);
1377 *metrics = fontface->caret;
1380 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1381 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1383 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1385 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1387 *count = 0;
1388 if (max_count && !ranges)
1389 return E_INVALIDARG;
1391 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1392 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1395 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1397 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1399 TRACE("%p.\n", iface);
1401 return !!(fontface->flags & FONT_IS_MONOSPACED);
1404 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1405 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1407 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1408 BOOL has_contours;
1409 int advance;
1411 if (is_sideways)
1412 FIXME("Sideways mode is not supported.\n");
1414 switch (measuring_mode)
1416 case DWRITE_MEASURING_MODE_NATURAL:
1417 advance = fontface_get_glyph_advance(fontface, fontface->metrics.designUnitsPerEm, glyph,
1418 measuring_mode, &has_contours);
1419 if (has_contours)
1420 advance += adjustment;
1422 return advance;
1423 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1424 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1425 emsize *= ppdip;
1426 if (emsize == 0.0f)
1427 return 0.0f;
1429 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1430 FIXME("Transform is not supported.\n");
1432 advance = fontface_get_glyph_advance(fontface, emsize, glyph, measuring_mode, &has_contours);
1433 if (has_contours)
1434 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1435 else
1436 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1438 return advance;
1439 default:
1440 WARN("Unknown measuring mode %u.\n", measuring_mode);
1441 return 0;
1445 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1446 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1448 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1449 unsigned int i;
1451 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1453 if (is_sideways)
1454 FIXME("sideways mode not supported\n");
1456 EnterCriticalSection(&fontface->cs);
1457 for (i = 0; i < glyph_count; ++i)
1459 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1460 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1462 LeaveCriticalSection(&fontface->cs);
1464 return S_OK;
1467 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1468 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1469 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1471 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1472 DWRITE_MEASURING_MODE measuring_mode;
1473 UINT32 i;
1475 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1476 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1478 if (em_size < 0.0f || ppdip <= 0.0f) {
1479 memset(advances, 0, sizeof(*advances) * glyph_count);
1480 return E_INVALIDARG;
1483 if (em_size == 0.0f) {
1484 memset(advances, 0, sizeof(*advances) * glyph_count);
1485 return S_OK;
1488 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1490 EnterCriticalSection(&fontface->cs);
1491 for (i = 0; i < glyph_count; ++i)
1493 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1494 glyphs[i], is_sideways);
1496 LeaveCriticalSection(&fontface->cs);
1498 return S_OK;
1501 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1502 const UINT16 *glyphs, INT32 *values)
1504 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1506 TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
1508 if (!(glyphs || values) || !count)
1509 return E_INVALIDARG;
1511 if (!glyphs || count == 1)
1513 memset(values, 0, count * sizeof(*values));
1514 return E_INVALIDARG;
1517 return opentype_get_kerning_pairs(fontface, count, glyphs, values);
1520 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1522 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1524 TRACE("%p.\n", iface);
1526 return opentype_has_kerning_pairs(fontface);
1529 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1530 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1531 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1533 DWRITE_GRID_FIT_MODE gridfitmode;
1534 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1535 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1538 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1539 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1541 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1543 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1545 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1548 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1550 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1552 TRACE("%p.\n", iface);
1554 return opentype_has_vertical_variants(fontface);
1557 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1559 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1561 TRACE("%p.\n", iface);
1563 return !!(fontface->flags & FONT_IS_COLORED);
1566 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1568 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1570 TRACE("%p.\n", iface);
1572 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1575 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1577 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1579 TRACE("%p.\n", iface);
1581 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1584 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1585 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1587 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1589 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1591 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1594 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1595 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1596 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1597 DWRITE_GRID_FIT_MODE *gridfitmode)
1599 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1600 unsigned int flags;
1601 FLOAT emthreshold;
1603 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1604 measuringmode, params, renderingmode, gridfitmode);
1606 if (m && memcmp(m, &identity, sizeof(*m)))
1607 FIXME("transform not supported %s\n", debugstr_matrix(m));
1609 if (is_sideways)
1610 FIXME("sideways mode not supported\n");
1612 emSize *= max(dpiX, dpiY) / 96.0f;
1614 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1615 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1616 if (params) {
1617 IDWriteRenderingParams2 *params2;
1618 HRESULT hr;
1620 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1621 if (hr == S_OK) {
1622 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1623 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1624 IDWriteRenderingParams2_Release(params2);
1626 else
1627 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1630 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1632 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1634 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1635 if (emSize >= emthreshold)
1636 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1637 else
1638 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1641 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1642 if (emSize >= emthreshold)
1643 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1644 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1645 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1646 else
1647 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1648 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1651 return S_OK;
1654 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1655 IDWriteFontFaceReference **reference)
1657 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1659 TRACE("%p, %p.\n", iface, reference);
1661 *reference = &fontface->IDWriteFontFaceReference_iface;
1662 IDWriteFontFaceReference_AddRef(*reference);
1664 return S_OK;
1667 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1669 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1671 TRACE("%p, %p.\n", iface, panose);
1673 *panose = fontface->panose;
1676 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1678 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1680 TRACE("%p.\n", iface);
1682 return fontface->weight;
1685 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1687 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1689 TRACE("%p.\n", iface);
1691 return fontface->stretch;
1694 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1696 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1698 TRACE("%p.\n", iface);
1700 return fontface->style;
1703 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1705 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1707 TRACE("%p, %p.\n", iface, names);
1709 return clone_localizedstrings(fontface->family_names, names);
1712 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1714 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1716 TRACE("%p, %p.\n", iface, names);
1718 return clone_localizedstrings(fontface->names, names);
1721 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1722 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1723 IDWriteLocalizedStrings **ret, BOOL *exists)
1725 HRESULT hr = S_OK;
1727 *exists = FALSE;
1728 *ret = NULL;
1730 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1731 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1733 return S_OK;
1736 if (!strings_cache[stringid])
1738 struct file_stream_desc desc = *stream_desc;
1740 if (!desc.stream)
1741 hr = get_filestream_from_file(file, &desc.stream);
1742 if (SUCCEEDED(hr))
1743 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1745 if (!stream_desc->stream && desc.stream)
1746 IDWriteFontFileStream_Release(desc.stream);
1749 if (SUCCEEDED(hr) && strings_cache[stringid])
1751 hr = clone_localizedstrings(strings_cache[stringid], ret);
1752 if (SUCCEEDED(hr))
1753 *exists = TRUE;
1756 return hr;
1759 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1760 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1762 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1763 struct file_stream_desc stream_desc;
1765 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1767 stream_desc.stream = fontface->stream;
1768 stream_desc.face_index = fontface->index;
1769 stream_desc.face_type = fontface->type;
1770 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1773 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1775 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1777 TRACE("%p, %#x.\n", iface, ch);
1779 return !!dwritefontface_get_glyph(fontface, ch);
1782 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1783 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1784 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1786 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1787 unsigned int flags;
1788 FLOAT emthreshold;
1790 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1791 measuring_mode, params, rendering_mode, gridfit_mode);
1793 if (m && memcmp(m, &identity, sizeof(*m)))
1794 FIXME("transform not supported %s\n", debugstr_matrix(m));
1796 if (is_sideways)
1797 FIXME("sideways mode not supported\n");
1799 emSize *= max(dpiX, dpiY) / 96.0f;
1801 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1802 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1803 if (params) {
1804 IDWriteRenderingParams3 *params3;
1805 HRESULT hr;
1807 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1808 if (hr == S_OK) {
1809 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1810 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1811 IDWriteRenderingParams3_Release(params3);
1813 else
1814 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1817 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1819 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1821 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1822 if (emSize >= emthreshold)
1823 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1824 else
1825 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1828 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1829 if (emSize >= emthreshold)
1830 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1831 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1832 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1833 else
1834 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1835 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1838 return S_OK;
1841 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1843 FIXME("%p, %#x: stub\n", iface, ch);
1845 return FALSE;
1848 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1850 FIXME("%p, %u: stub\n", iface, glyph);
1852 return FALSE;
1855 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1856 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1858 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1860 return E_NOTIMPL;
1863 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1864 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1866 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1868 return E_NOTIMPL;
1871 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1872 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1874 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1876 return E_NOTIMPL;
1879 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1881 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1883 TRACE("%p.\n", iface);
1885 return fontface->glyph_image_formats;
1888 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1889 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1891 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1893 return E_NOTIMPL;
1896 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1898 FIXME("%p, %p: stub\n", iface, context);
1901 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1903 FIXME("%p: stub\n", iface);
1905 return 0;
1908 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1909 UINT32 value_count)
1911 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1913 return E_NOTIMPL;
1916 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1918 static int once;
1920 if (!once++)
1921 FIXME("%p: stub\n", iface);
1923 return FALSE;
1926 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1928 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1930 TRACE("%p, %p.\n", iface, resource);
1932 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1935 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1937 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1939 TRACE("%p, %p.\n", iface, other);
1941 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1942 return FALSE;
1944 /* TODO: add variations support */
1946 return fontface->index == other_face->index &&
1947 fontface->simulations == other_face->simulations &&
1948 is_same_fontfile(fontface->file, other_face->file);
1951 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1953 dwritefontface_QueryInterface,
1954 dwritefontface_AddRef,
1955 dwritefontface_Release,
1956 dwritefontface_GetType,
1957 dwritefontface_GetFiles,
1958 dwritefontface_GetIndex,
1959 dwritefontface_GetSimulations,
1960 dwritefontface_IsSymbolFont,
1961 dwritefontface_GetMetrics,
1962 dwritefontface_GetGlyphCount,
1963 dwritefontface_GetDesignGlyphMetrics,
1964 dwritefontface_GetGlyphIndices,
1965 dwritefontface_TryGetFontTable,
1966 dwritefontface_ReleaseFontTable,
1967 dwritefontface_GetGlyphRunOutline,
1968 dwritefontface_GetRecommendedRenderingMode,
1969 dwritefontface_GetGdiCompatibleMetrics,
1970 dwritefontface_GetGdiCompatibleGlyphMetrics,
1971 dwritefontface1_GetMetrics,
1972 dwritefontface1_GetGdiCompatibleMetrics,
1973 dwritefontface1_GetCaretMetrics,
1974 dwritefontface1_GetUnicodeRanges,
1975 dwritefontface1_IsMonospacedFont,
1976 dwritefontface1_GetDesignGlyphAdvances,
1977 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1978 dwritefontface1_GetKerningPairAdjustments,
1979 dwritefontface1_HasKerningPairs,
1980 dwritefontface1_GetRecommendedRenderingMode,
1981 dwritefontface1_GetVerticalGlyphVariants,
1982 dwritefontface1_HasVerticalGlyphVariants,
1983 dwritefontface2_IsColorFont,
1984 dwritefontface2_GetColorPaletteCount,
1985 dwritefontface2_GetPaletteEntryCount,
1986 dwritefontface2_GetPaletteEntries,
1987 dwritefontface2_GetRecommendedRenderingMode,
1988 dwritefontface3_GetFontFaceReference,
1989 dwritefontface3_GetPanose,
1990 dwritefontface3_GetWeight,
1991 dwritefontface3_GetStretch,
1992 dwritefontface3_GetStyle,
1993 dwritefontface3_GetFamilyNames,
1994 dwritefontface3_GetFaceNames,
1995 dwritefontface3_GetInformationalStrings,
1996 dwritefontface3_HasCharacter,
1997 dwritefontface3_GetRecommendedRenderingMode,
1998 dwritefontface3_IsCharacterLocal,
1999 dwritefontface3_IsGlyphLocal,
2000 dwritefontface3_AreCharactersLocal,
2001 dwritefontface3_AreGlyphsLocal,
2002 dwritefontface4_GetGlyphImageFormats_,
2003 dwritefontface4_GetGlyphImageFormats,
2004 dwritefontface4_GetGlyphImageData,
2005 dwritefontface4_ReleaseGlyphImageData,
2006 dwritefontface5_GetFontAxisValueCount,
2007 dwritefontface5_GetFontAxisValues,
2008 dwritefontface5_HasVariations,
2009 dwritefontface5_GetFontResource,
2010 dwritefontface5_Equals,
2013 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
2015 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2016 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
2019 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
2021 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2022 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
2025 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
2027 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2028 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
2031 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
2032 IDWriteFontFace3 **ret)
2034 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2036 TRACE("%p, %p.\n", iface, ret);
2038 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
2039 IDWriteFontFace3_AddRef(*ret);
2041 return S_OK;
2044 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
2045 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
2047 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2048 DWRITE_FONT_FILE_TYPE file_type;
2049 DWRITE_FONT_FACE_TYPE face_type;
2050 IDWriteFontFace *face;
2051 BOOL is_supported;
2052 UINT32 face_num;
2053 HRESULT hr;
2055 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
2057 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
2058 if (FAILED(hr))
2059 return hr;
2061 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
2062 simulations, &face);
2063 if (SUCCEEDED(hr))
2065 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
2066 IDWriteFontFace_Release(face);
2069 return hr;
2072 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
2074 FIXME("%p, %p.\n", iface, ref);
2076 return E_NOTIMPL;
2079 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
2081 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2083 TRACE("%p.\n", iface);
2085 return fontface->index;
2088 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
2090 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2092 TRACE("%p.\n", iface);
2094 return fontface->simulations;
2097 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
2099 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
2101 TRACE("%p, %p.\n", iface, file);
2103 *file = fontface->file;
2104 IDWriteFontFile_AddRef(*file);
2106 return S_OK;
2109 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
2111 FIXME("%p.\n", iface);
2113 return 0;
2116 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
2118 FIXME("%p.\n", iface);
2120 return 0;
2123 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
2125 FIXME("%p, %p.\n", iface, writetime);
2127 return E_NOTIMPL;
2130 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
2132 FIXME("%p.\n", iface);
2134 return DWRITE_LOCALITY_LOCAL;
2137 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
2139 FIXME("%p.\n", iface);
2141 return E_NOTIMPL;
2144 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
2145 WCHAR const *chars, UINT32 count)
2147 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
2149 return E_NOTIMPL;
2152 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
2153 UINT16 const *glyphs, UINT32 count)
2155 FIXME("%p, %p, %u.\n", iface, glyphs, count);
2157 return E_NOTIMPL;
2160 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
2161 UINT64 offset, UINT64 size)
2163 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
2165 return E_NOTIMPL;
2168 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
2170 dwritefontface_reference_QueryInterface,
2171 dwritefontface_reference_AddRef,
2172 dwritefontface_reference_Release,
2173 dwritefontface_reference_CreateFontFace,
2174 dwritefontface_reference_CreateFontFaceWithSimulations,
2175 dwritefontface_reference_Equals,
2176 dwritefontface_reference_GetFontFaceIndex,
2177 dwritefontface_reference_GetSimulations,
2178 dwritefontface_reference_GetFontFile,
2179 dwritefontface_reference_GetLocalFileSize,
2180 dwritefontface_reference_GetFileSize,
2181 dwritefontface_reference_GetFileTime,
2182 dwritefontface_reference_GetLocality,
2183 dwritefontface_reference_EnqueueFontDownloadRequest,
2184 dwritefontface_reference_EnqueueCharacterDownloadRequest,
2185 dwritefontface_reference_EnqueueGlyphDownloadRequest,
2186 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
2189 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
2191 struct dwrite_font_data *data = font->data;
2192 struct fontface_desc desc;
2193 struct list *cached_list;
2194 HRESULT hr;
2196 *fontface = NULL;
2198 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
2199 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
2200 if (hr == S_OK)
2201 return hr;
2203 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
2204 return hr;
2206 desc.factory = font->family->collection->factory;
2207 desc.face_type = data->face_type;
2208 desc.file = data->file;
2209 desc.index = data->face_index;
2210 desc.simulations = data->simulations;
2211 desc.font_data = data;
2212 hr = create_fontface(&desc, cached_list, fontface);
2214 IDWriteFontFileStream_Release(desc.stream);
2215 return hr;
2218 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
2220 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2222 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
2223 IsEqualIID(riid, &IID_IDWriteFont2) ||
2224 IsEqualIID(riid, &IID_IDWriteFont1) ||
2225 IsEqualIID(riid, &IID_IDWriteFont) ||
2226 IsEqualIID(riid, &IID_IUnknown))
2228 *obj = iface;
2229 IDWriteFont3_AddRef(iface);
2230 return S_OK;
2233 WARN("%s not implemented.\n", debugstr_guid(riid));
2235 *obj = NULL;
2236 return E_NOINTERFACE;
2239 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
2241 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2242 ULONG refcount = InterlockedIncrement(&font->refcount);
2244 TRACE("%p, refcount %d.\n", iface, refcount);
2246 return refcount;
2249 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
2251 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2252 ULONG refcount = InterlockedDecrement(&font->refcount);
2254 TRACE("%p, refcount %d.\n", iface, refcount);
2256 if (!refcount)
2258 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
2259 release_font_data(font->data);
2260 free(font);
2263 return refcount;
2266 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
2268 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2270 TRACE("%p, %p.\n", iface, family);
2272 *family = (IDWriteFontFamily *)&font->family->IDWriteFontFamily2_iface;
2273 IDWriteFontFamily_AddRef(*family);
2274 return S_OK;
2277 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
2279 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2281 TRACE("%p.\n", iface);
2283 return font->data->weight;
2286 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
2288 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2290 TRACE("%p.\n", iface);
2292 return font->data->stretch;
2295 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
2297 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2299 TRACE("%p.\n", iface);
2301 return font->style;
2304 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2306 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2308 TRACE("%p.\n", iface);
2310 return !!(font->data->flags & FONT_IS_SYMBOL);
2313 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2315 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2317 TRACE("%p, %p.\n", iface, names);
2319 return clone_localizedstrings(font->data->names, names);
2322 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2323 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2325 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2326 struct dwrite_font_data *data = font->data;
2327 struct file_stream_desc stream_desc;
2329 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2331 /* Stream will be created if necessary. */
2332 stream_desc.stream = NULL;
2333 stream_desc.face_index = data->face_index;
2334 stream_desc.face_type = data->face_type;
2335 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2338 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2340 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2342 TRACE("%p.\n", iface);
2344 return font->data->simulations;
2347 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2349 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2351 TRACE("%p, %p.\n", iface, metrics);
2353 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2356 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2358 UINT16 glyph;
2359 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2360 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2361 return glyph != 0;
2364 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2366 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2368 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2370 *exists = dwritefont_has_character(font, ch);
2372 return S_OK;
2375 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2377 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2379 TRACE("%p, %p.\n", iface, fontface);
2381 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2384 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2386 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2388 TRACE("%p, %p.\n", iface, metrics);
2390 *metrics = font->data->metrics;
2393 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2395 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2397 TRACE("%p, %p.\n", iface, panose);
2399 *panose = font->data->panose;
2402 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2403 UINT32 *count)
2405 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2407 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2409 *count = 0;
2410 if (max_count && !ranges)
2411 return E_INVALIDARG;
2413 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2414 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2417 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2419 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2421 TRACE("%p.\n", iface);
2423 return !!(font->data->flags & FONT_IS_MONOSPACED);
2426 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2428 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2430 TRACE("%p.\n", iface);
2432 return !!(font->data->flags & FONT_IS_COLORED);
2435 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2437 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2439 TRACE("%p, %p.\n", iface, fontface);
2441 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2444 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2446 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2448 TRACE("%p, %p.\n", iface, other);
2450 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2451 return FALSE;
2453 return font->data->face_index == other_font->data->face_index
2454 && font->data->simulations == other_font->data->simulations
2455 && is_same_fontfile(font->data->file, other_font->data->file);
2458 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2460 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2462 TRACE("%p, %p.\n", iface, reference);
2464 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2465 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2466 (IDWriteFontFaceReference1 **)reference);
2469 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2471 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2473 TRACE("%p, %#x.\n", iface, ch);
2475 return dwritefont_has_character(font, ch);
2478 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2480 FIXME("%p: stub.\n", iface);
2482 return DWRITE_LOCALITY_LOCAL;
2485 static const IDWriteFont3Vtbl dwritefontvtbl = {
2486 dwritefont_QueryInterface,
2487 dwritefont_AddRef,
2488 dwritefont_Release,
2489 dwritefont_GetFontFamily,
2490 dwritefont_GetWeight,
2491 dwritefont_GetStretch,
2492 dwritefont_GetStyle,
2493 dwritefont_IsSymbolFont,
2494 dwritefont_GetFaceNames,
2495 dwritefont_GetInformationalStrings,
2496 dwritefont_GetSimulations,
2497 dwritefont_GetMetrics,
2498 dwritefont_HasCharacter,
2499 dwritefont_CreateFontFace,
2500 dwritefont1_GetMetrics,
2501 dwritefont1_GetPanose,
2502 dwritefont1_GetUnicodeRanges,
2503 dwritefont1_IsMonospacedFont,
2504 dwritefont2_IsColorFont,
2505 dwritefont3_CreateFontFace,
2506 dwritefont3_Equals,
2507 dwritefont3_GetFontFaceReference,
2508 dwritefont3_HasCharacter,
2509 dwritefont3_GetLocality
2512 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2514 if (!iface)
2515 return NULL;
2516 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2517 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2520 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2522 if (!iface)
2523 return NULL;
2524 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2525 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2528 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2530 if (!iface)
2531 return NULL;
2532 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2533 return NULL;
2534 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2535 IDWriteFontFaceReference1_iface);
2538 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2540 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2541 *lf = font->data->lf;
2544 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2546 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2547 *lf = fontface->lf;
2550 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2552 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2553 *fontsig = font->data->fontsig;
2554 return S_OK;
2557 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2559 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2560 *fontsig = fontface->fontsig;
2561 return S_OK;
2564 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2566 struct dwrite_font *object;
2568 *font = NULL;
2570 if (!(object = calloc(1, sizeof(*object))))
2571 return E_OUTOFMEMORY;
2573 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2574 object->refcount = 1;
2575 object->family = family;
2576 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2577 object->data = family->data->fonts[index];
2578 object->style = object->data->style;
2579 addref_font_data(object->data);
2581 *font = &object->IDWriteFont3_iface;
2583 return S_OK;
2586 /* IDWriteFontList2 */
2587 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2589 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2591 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2592 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2593 IsEqualIID(riid, &IID_IDWriteFontList) ||
2594 IsEqualIID(riid, &IID_IUnknown))
2596 *obj = iface;
2597 IDWriteFontList2_AddRef(iface);
2598 return S_OK;
2601 WARN("%s not implemented.\n", debugstr_guid(riid));
2603 *obj = NULL;
2604 return E_NOINTERFACE;
2607 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2609 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2610 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2612 TRACE("%p, refcount %u.\n", iface, refcount);
2614 return refcount;
2617 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2619 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2620 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2622 TRACE("%p, refcount %u.\n", iface, refcount);
2624 if (!refcount)
2626 unsigned int i;
2628 for (i = 0; i < fontlist->font_count; i++)
2629 release_font_data(fontlist->fonts[i]);
2630 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2631 free(fontlist->fonts);
2632 free(fontlist);
2635 return refcount;
2638 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2640 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2641 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2644 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2646 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2648 TRACE("%p.\n", iface);
2650 return fontlist->font_count;
2653 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2655 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2657 TRACE("%p, %u, %p.\n", iface, index, font);
2659 *font = NULL;
2661 if (fontlist->font_count == 0)
2662 return S_FALSE;
2664 if (index >= fontlist->font_count)
2665 return E_INVALIDARG;
2667 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2670 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2672 FIXME("%p, %u.\n", iface, index);
2674 return DWRITE_LOCALITY_LOCAL;
2677 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2678 IDWriteFont3 **font)
2680 *font = NULL;
2682 if (fontlist->font_count == 0)
2683 return S_FALSE;
2685 if (index >= fontlist->font_count)
2686 return E_FAIL;
2688 return create_font(fontlist->family, index, font);
2691 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2693 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2695 TRACE("%p, %u, %p.\n", iface, index, font);
2697 return fontlist_get_font(fontlist, index, font);
2700 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2701 IDWriteFontFaceReference **reference)
2703 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2704 IDWriteFont3 *font;
2705 HRESULT hr;
2707 TRACE("%p, %u, %p.\n", iface, index, reference);
2709 *reference = NULL;
2711 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2713 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2714 IDWriteFont3_Release(font);
2717 return hr;
2720 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2722 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2724 TRACE("%p, %p.\n", iface, fontset);
2726 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2727 fontlist->font_count, fontset);
2730 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2732 dwritefontlist_QueryInterface,
2733 dwritefontlist_AddRef,
2734 dwritefontlist_Release,
2735 dwritefontlist_GetFontCollection,
2736 dwritefontlist_GetFontCount,
2737 dwritefontlist_GetFont,
2738 dwritefontlist1_GetFontLocality,
2739 dwritefontlist1_GetFont,
2740 dwritefontlist1_GetFontFaceReference,
2741 dwritefontlist2_GetFontSet,
2744 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2746 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2748 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2750 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2751 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2752 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2753 IsEqualIID(riid, &IID_IUnknown))
2755 *obj = iface;
2757 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2758 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2759 IsEqualIID(riid, &IID_IDWriteFontList))
2761 *obj = &family->IDWriteFontList2_iface;
2763 else
2765 WARN("%s not implemented.\n", debugstr_guid(riid));
2766 *obj = NULL;
2767 return E_NOINTERFACE;
2770 IUnknown_AddRef((IUnknown *)*obj);
2771 return S_OK;
2774 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2776 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2777 ULONG refcount = InterlockedIncrement(&family->refcount);
2779 TRACE("%p, %u.\n", iface, refcount);
2781 return refcount;
2784 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2786 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2787 ULONG refcount = InterlockedDecrement(&family->refcount);
2789 TRACE("%p, %u.\n", iface, refcount);
2791 if (!refcount)
2793 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2794 release_fontfamily_data(family->data);
2795 free(family);
2798 return refcount;
2801 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2803 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2805 TRACE("%p, %p.\n", iface, collection);
2807 *collection = (IDWriteFontCollection *)&family->collection->IDWriteFontCollection3_iface;
2808 IDWriteFontCollection_AddRef(*collection);
2809 return S_OK;
2812 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2814 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2816 TRACE("%p.\n", iface);
2818 return family->data->count;
2821 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2823 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2825 TRACE("%p, %u, %p.\n", iface, index, font);
2827 *font = NULL;
2829 if (!family->data->count)
2830 return S_FALSE;
2832 if (index >= family->data->count)
2833 return E_INVALIDARG;
2835 return create_font(family, index, (IDWriteFont3 **)font);
2838 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2840 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2842 TRACE("%p, %p.\n", iface, names);
2844 return clone_localizedstrings(family->data->familyname, names);
2847 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2848 const struct dwrite_font_propvec *req)
2850 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2851 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2852 FLOAT cur_req_prod, next_req_prod;
2854 if (next_to_req < cur_to_req)
2855 return TRUE;
2857 if (next_to_req > cur_to_req)
2858 return FALSE;
2860 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2861 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2863 if (next_req_prod > cur_req_prod)
2864 return TRUE;
2866 if (next_req_prod < cur_req_prod)
2867 return FALSE;
2869 if (next->stretch > cur->stretch)
2870 return TRUE;
2871 if (next->stretch < cur->stretch)
2872 return FALSE;
2874 if (next->style > cur->style)
2875 return TRUE;
2876 if (next->style < cur->style)
2877 return FALSE;
2879 if (next->weight > cur->weight)
2880 return TRUE;
2881 if (next->weight < cur->weight)
2882 return FALSE;
2884 /* full match, no reason to prefer new variant */
2885 return FALSE;
2888 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2889 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2891 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2892 struct dwrite_font_propvec req;
2893 size_t i, match;
2895 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2897 if (!family->data->count)
2899 *font = NULL;
2900 return DWRITE_E_NOFONT;
2903 init_font_prop_vec(weight, stretch, style, &req);
2904 match = 0;
2906 for (i = 1; i < family->data->count; ++i)
2908 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2909 match = i;
2912 return create_font(family, match, (IDWriteFont3 **)font);
2915 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2917 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2919 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2922 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2924 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2927 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2929 UINT32 b = fonts->font_count - 1, j, t;
2931 while (1) {
2932 t = b;
2934 for (j = 0; j < b; j++) {
2935 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2936 struct dwrite_font_data *s = fonts->fonts[j];
2937 fonts->fonts[j] = fonts->fonts[j+1];
2938 fonts->fonts[j+1] = s;
2939 t = j;
2943 if (t == b)
2944 break;
2945 b = t;
2949 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2950 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2952 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2953 matching_filter_func func = NULL;
2954 struct dwrite_font_propvec req;
2955 struct dwrite_fontlist *fonts;
2956 size_t i;
2958 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2960 *ret = NULL;
2962 if (!(fonts = malloc(sizeof(*fonts))))
2963 return E_OUTOFMEMORY;
2965 /* Allocate as many as family has, not all of them will be necessary used. */
2966 if (!(fonts->fonts = calloc(family->data->count, sizeof(*fonts->fonts))))
2968 free(fonts);
2969 return E_OUTOFMEMORY;
2972 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2973 fonts->refcount = 1;
2974 fonts->family = family;
2975 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2976 fonts->font_count = 0;
2978 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2979 if (style == DWRITE_FONT_STYLE_NORMAL) {
2980 if (family->data->has_normal_face || family->data->has_italic_face)
2981 func = is_font_acceptable_for_normal;
2983 else /* requested oblique or italic */ {
2984 if (family->data->has_oblique_face || family->data->has_italic_face)
2985 func = is_font_acceptable_for_oblique_italic;
2988 for (i = 0; i < family->data->count; ++i)
2990 if (!func || func(family->data->fonts[i]))
2992 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
2996 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2997 init_font_prop_vec(weight, stretch, style, &req);
2998 matchingfonts_sort(fonts, &req);
3000 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
3001 return S_OK;
3004 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
3006 FIXME("%p, %u.\n", iface, index);
3008 return DWRITE_LOCALITY_LOCAL;
3011 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
3013 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3015 TRACE("%p, %u, %p.\n", iface, index, font);
3017 *font = NULL;
3019 if (!family->data->count)
3020 return S_FALSE;
3022 if (index >= family->data->count)
3023 return E_FAIL;
3025 return create_font(family, index, font);
3028 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
3029 IDWriteFontFaceReference **reference)
3031 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3032 const struct dwrite_font_data *font;
3034 TRACE("%p, %u, %p.\n", iface, index, reference);
3036 *reference = NULL;
3038 if (index >= family->data->count)
3039 return E_FAIL;
3041 font = family->data->fonts[index];
3042 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
3043 font->file, font->face_index, font->simulations, reference);
3046 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
3047 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
3049 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
3051 return E_NOTIMPL;
3054 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
3056 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
3058 TRACE("%p, %p.\n", iface, fontset);
3060 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3061 family->data->count, fontset);
3064 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
3066 dwritefontfamily_QueryInterface,
3067 dwritefontfamily_AddRef,
3068 dwritefontfamily_Release,
3069 dwritefontfamily_GetFontCollection,
3070 dwritefontfamily_GetFontCount,
3071 dwritefontfamily_GetFont,
3072 dwritefontfamily_GetFamilyNames,
3073 dwritefontfamily_GetFirstMatchingFont,
3074 dwritefontfamily_GetMatchingFonts,
3075 dwritefontfamily1_GetFontLocality,
3076 dwritefontfamily1_GetFont,
3077 dwritefontfamily1_GetFontFaceReference,
3078 dwritefontfamily2_GetMatchingFonts,
3079 dwritefontfamily2_GetFontSet,
3082 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
3084 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3085 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
3088 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
3090 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3091 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
3094 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
3096 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3097 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
3100 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
3101 IDWriteFontCollection **collection)
3103 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3104 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
3107 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
3109 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3110 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
3113 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
3115 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3116 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3119 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
3121 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3122 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
3125 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
3127 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3128 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
3131 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
3132 IDWriteFontFaceReference **reference)
3134 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3135 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
3138 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
3140 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
3142 TRACE("%p, %p.\n", iface, fontset);
3144 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
3145 family->data->count, fontset);
3148 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
3150 dwritefontfamilylist_QueryInterface,
3151 dwritefontfamilylist_AddRef,
3152 dwritefontfamilylist_Release,
3153 dwritefontfamilylist_GetFontCollection,
3154 dwritefontfamilylist_GetFontCount,
3155 dwritefontfamilylist_GetFont,
3156 dwritefontfamilylist1_GetFontLocality,
3157 dwritefontfamilylist1_GetFont,
3158 dwritefontfamilylist1_GetFontFaceReference,
3159 dwritefontfamilylist2_GetFontSet,
3162 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
3163 struct dwrite_fontfamily **family)
3165 struct dwrite_fontfamily *object;
3167 *family = NULL;
3169 if (!(object = calloc(1, sizeof(*object))))
3170 return E_OUTOFMEMORY;
3172 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
3173 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
3174 object->refcount = 1;
3175 object->collection = collection;
3176 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
3177 object->data = collection->family_data[index];
3178 InterlockedIncrement(&object->data->refcount);
3180 *family = object;
3182 return S_OK;
3185 BOOL is_system_collection(IDWriteFontCollection *collection)
3187 void *obj;
3188 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
3191 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3193 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3195 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
3197 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3198 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3199 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3200 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3201 IsEqualIID(riid, &IID_IUnknown))
3203 *obj = iface;
3204 IDWriteFontCollection3_AddRef(iface);
3205 return S_OK;
3208 *obj = NULL;
3210 if (IsEqualIID(riid, &IID_issystemcollection))
3211 return S_OK;
3213 WARN("%s not implemented.\n", debugstr_guid(riid));
3215 return E_NOINTERFACE;
3218 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
3220 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
3222 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
3223 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
3224 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
3225 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
3226 IsEqualIID(riid, &IID_IUnknown))
3228 *obj = iface;
3229 IDWriteFontCollection3_AddRef(iface);
3230 return S_OK;
3233 WARN("%s not implemented.\n", debugstr_guid(riid));
3235 *obj = NULL;
3237 return E_NOINTERFACE;
3240 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
3242 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3243 ULONG refcount = InterlockedIncrement(&collection->refcount);
3245 TRACE("%p, refcount %d.\n", collection, refcount);
3247 return refcount;
3250 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
3252 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3253 ULONG refcount = InterlockedDecrement(&collection->refcount);
3254 size_t i;
3256 TRACE("%p, refcount %d.\n", iface, refcount);
3258 if (!refcount)
3260 factory_detach_fontcollection(collection->factory, iface);
3261 for (i = 0; i < collection->count; ++i)
3262 release_fontfamily_data(collection->family_data[i]);
3263 free(collection->family_data);
3264 free(collection);
3267 return refcount;
3270 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
3272 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3274 TRACE("%p.\n", iface);
3276 return collection->count;
3279 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3280 IDWriteFontFamily **ret)
3282 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3283 struct dwrite_fontfamily *family;
3284 HRESULT hr;
3286 TRACE("%p, %u, %p.\n", iface, index, ret);
3288 *ret = NULL;
3290 if (index >= collection->count)
3291 return E_FAIL;
3293 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3294 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
3296 return hr;
3299 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
3301 size_t i;
3303 for (i = 0; i < collection->count; ++i)
3305 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3306 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3307 HRESULT hr;
3309 for (j = 0; j < count; j++)
3311 WCHAR buffer[255];
3312 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3313 if (SUCCEEDED(hr) && !wcsicmp(buffer, name))
3314 return i;
3318 return ~0u;
3321 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3322 UINT32 *index, BOOL *exists)
3324 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3326 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3328 *index = collection_find_family(collection, name);
3329 *exists = *index != ~0u;
3330 return S_OK;
3333 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3334 IDWriteFont **font)
3336 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3337 struct dwrite_fontfamily *family;
3338 BOOL found_font = FALSE;
3339 IDWriteFontFile *file;
3340 UINT32 face_index, count;
3341 size_t i, j;
3342 HRESULT hr;
3344 TRACE("%p, %p, %p.\n", iface, face, font);
3346 *font = NULL;
3348 if (!face)
3349 return E_INVALIDARG;
3351 count = 1;
3352 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3353 if (FAILED(hr))
3354 return hr;
3355 face_index = IDWriteFontFace_GetIndex(face);
3357 found_font = FALSE;
3358 for (i = 0; i < collection->count; ++i)
3360 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3362 for (j = 0; j < family_data->count; ++j)
3364 struct dwrite_font_data *font_data = family_data->fonts[j];
3366 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3367 found_font = TRUE;
3368 break;
3372 if (found_font)
3373 break;
3375 IDWriteFontFile_Release(file);
3377 if (!found_font)
3378 return DWRITE_E_NOFONT;
3380 hr = create_fontfamily(collection, i, &family);
3381 if (FAILED(hr))
3382 return hr;
3384 hr = create_font(family, j, (IDWriteFont3 **)font);
3385 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3386 return hr;
3389 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3391 FIXME("%p, %p.\n", iface, fontset);
3393 return E_NOTIMPL;
3396 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3397 IDWriteFontFamily1 **ret)
3399 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3400 struct dwrite_fontfamily *family;
3401 HRESULT hr;
3403 TRACE("%p, %u, %p.\n", iface, index, ret);
3405 *ret = NULL;
3407 if (index >= collection->count)
3408 return E_FAIL;
3410 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3411 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3413 return hr;
3416 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3417 UINT32 index, IDWriteFontFamily2 **ret)
3419 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3420 struct dwrite_fontfamily *family;
3421 HRESULT hr;
3423 TRACE("%p, %u, %p.\n", iface, index, ret);
3425 *ret = NULL;
3427 if (index >= collection->count)
3428 return E_FAIL;
3430 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3431 *ret = &family->IDWriteFontFamily2_iface;
3433 return hr;
3436 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3437 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3438 IDWriteFontList2 **fontlist)
3440 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3442 return E_NOTIMPL;
3445 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3447 FIXME("%p.\n", iface);
3449 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3452 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3454 FIXME("%p, %p.\n", iface, fontset);
3456 return E_NOTIMPL;
3459 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3461 FIXME("%p.\n", iface);
3463 return NULL;
3466 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3468 dwritefontcollection_QueryInterface,
3469 dwritefontcollection_AddRef,
3470 dwritefontcollection_Release,
3471 dwritefontcollection_GetFontFamilyCount,
3472 dwritefontcollection_GetFontFamily,
3473 dwritefontcollection_FindFamilyName,
3474 dwritefontcollection_GetFontFromFontFace,
3475 dwritefontcollection1_GetFontSet,
3476 dwritefontcollection1_GetFontFamily,
3477 dwritefontcollection2_GetFontFamily,
3478 dwritefontcollection2_GetMatchingFonts,
3479 dwritefontcollection2_GetFontFamilyModel,
3480 dwritefontcollection2_GetFontSet,
3481 dwritefontcollection3_GetExpirationEvent,
3484 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3486 dwritesystemfontcollection_QueryInterface,
3487 dwritefontcollection_AddRef,
3488 dwritefontcollection_Release,
3489 dwritefontcollection_GetFontFamilyCount,
3490 dwritefontcollection_GetFontFamily,
3491 dwritefontcollection_FindFamilyName,
3492 dwritefontcollection_GetFontFromFontFace,
3493 dwritefontcollection1_GetFontSet,
3494 dwritefontcollection1_GetFontFamily,
3495 dwritefontcollection2_GetFontFamily,
3496 dwritefontcollection2_GetMatchingFonts,
3497 dwritefontcollection2_GetFontFamilyModel,
3498 dwritefontcollection2_GetFontSet,
3499 dwritefontcollection3_GetExpirationEvent,
3502 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3504 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3505 sizeof(*family_data->fonts)))
3507 return E_OUTOFMEMORY;
3510 family_data->fonts[family_data->count++] = font_data;
3511 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3512 family_data->has_normal_face = 1;
3513 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3514 family_data->has_oblique_face = 1;
3515 else
3516 family_data->has_italic_face = 1;
3517 return S_OK;
3520 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3521 struct dwrite_fontfamily_data *family)
3523 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3524 sizeof(*collection->family_data)))
3526 return E_OUTOFMEMORY;
3529 collection->family_data[collection->count++] = family;
3530 return S_OK;
3533 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3535 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3536 collection->refcount = 1;
3537 collection->count = 0;
3538 collection->size = 0;
3539 collection->family_data = NULL;
3541 return S_OK;
3544 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3546 IDWriteFontFileLoader *loader;
3547 const void *key;
3548 UINT32 key_size;
3549 HRESULT hr;
3551 *stream = NULL;
3553 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3554 if (FAILED(hr))
3555 return hr;
3557 hr = IDWriteFontFile_GetLoader(file, &loader);
3558 if (FAILED(hr))
3559 return hr;
3561 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3562 IDWriteFontFileLoader_Release(loader);
3563 if (FAILED(hr))
3564 return hr;
3566 return hr;
3569 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3571 BOOL exists = FALSE;
3572 UINT32 index;
3573 HRESULT hr;
3575 buffer[0] = 0;
3576 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
3577 if (FAILED(hr) || !exists)
3578 return;
3580 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3583 static int trim_spaces(WCHAR *in, WCHAR *ret)
3585 int len;
3587 while (iswspace(*in))
3588 in++;
3590 ret[0] = 0;
3591 if (!(len = wcslen(in)))
3592 return 0;
3594 while (iswspace(in[len-1]))
3595 len--;
3597 memcpy(ret, in, len*sizeof(WCHAR));
3598 ret[len] = 0;
3600 return len;
3603 struct name_token {
3604 struct list entry;
3605 const WCHAR *ptr;
3606 INT len; /* token length */
3607 INT fulllen; /* full length including following separators */
3610 static inline BOOL is_name_separator_char(WCHAR ch)
3612 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3615 struct name_pattern {
3616 const WCHAR *part1; /* NULL indicates end of list */
3617 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3620 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3622 const struct name_pattern *pattern;
3623 struct name_token *token;
3624 int i = 0;
3626 while ((pattern = &patterns[i++])->part1)
3628 int len_part1 = wcslen(pattern->part1);
3629 int len_part2 = pattern->part2 ? wcslen(pattern->part2) : 0;
3631 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry)
3633 if (!len_part2)
3635 /* simple case with single part pattern */
3636 if (token->len != len_part1)
3637 continue;
3639 if (!wcsnicmp(token->ptr, pattern->part1, len_part1))
3641 if (match) *match = *token;
3642 list_remove(&token->entry);
3643 free(token);
3644 return TRUE;
3647 else
3649 struct name_token *next_token;
3650 struct list *next_entry;
3652 /* pattern parts are stored in reading order, tokens list is reversed */
3653 if (token->len < len_part2)
3654 continue;
3656 /* it's possible to have combined string as a token, like ExtraCondensed */
3657 if (token->len == len_part1 + len_part2)
3659 if (wcsnicmp(token->ptr, pattern->part1, len_part1))
3660 continue;
3662 if (wcsnicmp(&token->ptr[len_part1], pattern->part2, len_part2))
3663 continue;
3665 /* combined string match */
3666 if (match) *match = *token;
3667 list_remove(&token->entry);
3668 free(token);
3669 return TRUE;
3672 /* now it's only possible to have two tokens matched to respective pattern parts */
3673 if (token->len != len_part2)
3674 continue;
3676 next_entry = list_next(tokens, &token->entry);
3677 if (next_entry) {
3678 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3679 if (next_token->len != len_part1)
3680 continue;
3682 if (wcsnicmp(token->ptr, pattern->part2, len_part2))
3683 continue;
3685 if (wcsnicmp(next_token->ptr, pattern->part1, len_part1))
3686 continue;
3688 /* both parts matched, remove tokens */
3689 if (match) {
3690 match->ptr = next_token->ptr;
3691 match->len = (token->ptr - next_token->ptr) + token->len;
3693 list_remove(&token->entry);
3694 list_remove(&next_token->entry);
3695 free(next_token);
3696 free(token);
3697 return TRUE;
3703 if (match) {
3704 match->ptr = NULL;
3705 match->len = 0;
3707 return FALSE;
3710 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3712 static const struct name_pattern italic_patterns[] =
3714 { L"ita" },
3715 { L"ital" },
3716 { L"italic" },
3717 { L"cursive" },
3718 { L"kursiv" },
3719 { NULL }
3722 static const struct name_pattern oblique_patterns[] =
3724 { L"inclined" },
3725 { L"oblique" },
3726 { L"backslanted" },
3727 { L"backslant" },
3728 { L"slanted" },
3729 { NULL }
3732 /* italic patterns first */
3733 if (match_pattern_list(tokens, italic_patterns, match))
3734 return DWRITE_FONT_STYLE_ITALIC;
3736 /* oblique patterns */
3737 if (match_pattern_list(tokens, oblique_patterns, match))
3738 return DWRITE_FONT_STYLE_OBLIQUE;
3740 return style;
3743 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3744 struct name_token *match)
3746 static const struct name_pattern ultracondensed_patterns[] =
3748 { L"extra", L"compressed" },
3749 { L"ext", L"compressed" },
3750 { L"ultra", L"compressed" },
3751 { L"ultra", L"condensed" },
3752 { L"ultra", L"cond" },
3753 { NULL }
3756 static const struct name_pattern extracondensed_patterns[] =
3758 { L"compressed" },
3759 { L"extra", L"condensed" },
3760 { L"ext", L"condensed" },
3761 { L"extra", L"cond" },
3762 { L"ext", L"cond" },
3763 { NULL }
3766 static const struct name_pattern semicondensed_patterns[] =
3768 { L"narrow" },
3769 { L"compact" },
3770 { L"semi", L"condensed" },
3771 { L"semi", L"cond" },
3772 { NULL }
3775 static const struct name_pattern semiexpanded_patterns[] =
3777 { L"wide" },
3778 { L"semi", L"expanded" },
3779 { L"semi", L"extended" },
3780 { NULL }
3783 static const struct name_pattern extraexpanded_patterns[] =
3785 { L"extra", L"expanded" },
3786 { L"ext", L"expanded" },
3787 { L"extra", L"extended" },
3788 { L"ext", L"extended" },
3789 { NULL }
3792 static const struct name_pattern ultraexpanded_patterns[] =
3794 { L"ultra", L"expanded" },
3795 { L"ultra", L"extended" },
3796 { NULL }
3799 static const struct name_pattern condensed_patterns[] =
3801 { L"condensed" },
3802 { L"cond" },
3803 { NULL }
3806 static const struct name_pattern expanded_patterns[] =
3808 { L"expanded" },
3809 { L"extended" },
3810 { NULL }
3813 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3814 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3816 if (match_pattern_list(tokens, extracondensed_patterns, match))
3817 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3819 if (match_pattern_list(tokens, semicondensed_patterns, match))
3820 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3822 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3823 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3825 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3826 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3828 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3829 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3831 if (match_pattern_list(tokens, condensed_patterns, match))
3832 return DWRITE_FONT_STRETCH_CONDENSED;
3834 if (match_pattern_list(tokens, expanded_patterns, match))
3835 return DWRITE_FONT_STRETCH_EXPANDED;
3837 return stretch;
3840 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3841 struct name_token *match)
3843 static const struct name_pattern thin_patterns[] =
3845 { L"extra", L"thin" },
3846 { L"ext", L"thin" },
3847 { L"ultra", L"thin" },
3848 { NULL }
3851 static const struct name_pattern extralight_patterns[] =
3853 { L"extra", L"light" },
3854 { L"ext", L"light" },
3855 { L"ultra", L"light" },
3856 { NULL }
3859 static const struct name_pattern semilight_patterns[] =
3861 { L"semi", L"light" },
3862 { NULL }
3865 static const struct name_pattern demibold_patterns[] =
3867 { L"semi", L"bold" },
3868 { L"demi", L"bold" },
3869 { NULL }
3872 static const struct name_pattern extrabold_patterns[] =
3874 { L"extra", L"bold" },
3875 { L"ext", L"bold" },
3876 { L"ultra", L"bold" },
3877 { NULL }
3880 static const struct name_pattern extrablack_patterns[] =
3882 { L"extra", L"black" },
3883 { L"ext", L"black" },
3884 { L"ultra", L"black" },
3885 { NULL }
3888 static const struct name_pattern bold_patterns[] =
3890 { L"bold" },
3891 { NULL }
3894 static const struct name_pattern thin2_patterns[] =
3896 { L"thin" },
3897 { NULL }
3900 static const struct name_pattern light_patterns[] =
3902 { L"light" },
3903 { NULL }
3906 static const struct name_pattern medium_patterns[] =
3908 { L"medium" },
3909 { NULL }
3912 static const struct name_pattern black_patterns[] =
3914 { L"black" },
3915 { L"heavy" },
3916 { L"nord" },
3917 { NULL }
3920 static const struct name_pattern demibold2_patterns[] =
3922 { L"demi" },
3923 { NULL }
3926 static const struct name_pattern extrabold2_patterns[] =
3928 { L"ultra" },
3929 { NULL }
3932 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3933 matching pattern. */
3935 if (match_pattern_list(tokens, thin_patterns, match))
3936 return DWRITE_FONT_WEIGHT_THIN;
3938 if (match_pattern_list(tokens, extralight_patterns, match))
3939 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3941 if (match_pattern_list(tokens, semilight_patterns, match))
3942 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3944 if (match_pattern_list(tokens, demibold_patterns, match))
3945 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3947 if (match_pattern_list(tokens, extrabold_patterns, match))
3948 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3950 if (match_pattern_list(tokens, extrablack_patterns, match))
3951 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3953 if (match_pattern_list(tokens, bold_patterns, match))
3954 return DWRITE_FONT_WEIGHT_BOLD;
3956 if (match_pattern_list(tokens, thin2_patterns, match))
3957 return DWRITE_FONT_WEIGHT_THIN;
3959 if (match_pattern_list(tokens, light_patterns, match))
3960 return DWRITE_FONT_WEIGHT_LIGHT;
3962 if (match_pattern_list(tokens, medium_patterns, match))
3963 return DWRITE_FONT_WEIGHT_MEDIUM;
3965 if (match_pattern_list(tokens, black_patterns, match))
3966 return DWRITE_FONT_WEIGHT_BLACK;
3968 if (match_pattern_list(tokens, black_patterns, match))
3969 return DWRITE_FONT_WEIGHT_BLACK;
3971 if (match_pattern_list(tokens, demibold2_patterns, match))
3972 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3974 if (match_pattern_list(tokens, extrabold2_patterns, match))
3975 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3977 /* FIXME: use abbreviated names to extract weight */
3979 return weight;
3982 struct knownweight_entry
3984 const WCHAR *nameW;
3985 DWRITE_FONT_WEIGHT weight;
3988 static int __cdecl compare_knownweights(const void *a, const void* b)
3990 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3991 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3992 int ret = 0;
3994 if (target > entry->weight)
3995 ret = 1;
3996 else if (target < entry->weight)
3997 ret = -1;
3999 return ret;
4002 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
4004 static const struct knownweight_entry knownweights[] =
4006 { L"Thin", DWRITE_FONT_WEIGHT_THIN },
4007 { L"Extra Light", DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
4008 { L"Light", DWRITE_FONT_WEIGHT_LIGHT },
4009 { L"Semi Light", DWRITE_FONT_WEIGHT_SEMI_LIGHT },
4010 { L"Medium", DWRITE_FONT_WEIGHT_MEDIUM },
4011 { L"Demi Bold", DWRITE_FONT_WEIGHT_DEMI_BOLD },
4012 { L"Bold", DWRITE_FONT_WEIGHT_BOLD },
4013 { L"Extra Bold", DWRITE_FONT_WEIGHT_EXTRA_BOLD },
4014 { L"Black", DWRITE_FONT_WEIGHT_BLACK },
4015 { L"Extra Black", DWRITE_FONT_WEIGHT_EXTRA_BLACK }
4017 const struct knownweight_entry *ptr;
4019 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(*knownweights),
4020 compare_knownweights);
4021 if (!ptr) {
4022 nameW[0] = 0;
4023 return FALSE;
4026 wcscpy(nameW, ptr->nameW);
4027 return TRUE;
4030 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
4032 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
4033 strW[name->len] = 0;
4036 /* Modifies facenameW string, and returns pointer to regular term that was removed */
4037 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
4039 static const WCHAR *regular_patterns[] =
4041 L"Book",
4042 L"Normal",
4043 L"Regular",
4044 L"Roman",
4045 L"Upright",
4046 NULL
4049 const WCHAR *regular_ptr = NULL, *ptr;
4050 int i = 0;
4052 if (len == -1)
4053 len = wcslen(facenameW);
4055 /* remove rightmost regular variant from face name */
4056 while (!regular_ptr && (ptr = regular_patterns[i++]))
4058 int pattern_len = wcslen(ptr);
4059 WCHAR *src;
4061 if (pattern_len > len)
4062 continue;
4064 src = facenameW + len - pattern_len;
4065 while (src >= facenameW)
4067 if (!wcsnicmp(src, ptr, pattern_len))
4069 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
4070 len = wcslen(facenameW);
4071 regular_ptr = ptr;
4072 break;
4074 else
4075 src--;
4079 return regular_ptr;
4082 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
4084 const WCHAR *ptr;
4086 list_init(tokens);
4087 ptr = nameW;
4089 while (*ptr)
4091 struct name_token *token = malloc(sizeof(*token));
4092 token->ptr = ptr;
4093 token->len = 0;
4094 token->fulllen = 0;
4096 while (*ptr && !is_name_separator_char(*ptr)) {
4097 token->len++;
4098 token->fulllen++;
4099 ptr++;
4102 /* skip separators */
4103 while (is_name_separator_char(*ptr)) {
4104 token->fulllen++;
4105 ptr++;
4108 list_add_head(tokens, &token->entry);
4112 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
4114 struct name_token *token, *token2;
4115 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
4116 int len;
4118 list_remove(&token->entry);
4120 /* don't include last separator */
4121 len = list_empty(tokens) ? token->len : token->fulllen;
4122 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
4123 nameW += len;
4125 free(token);
4127 *nameW = 0;
4130 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
4132 struct name_token stretch_name, weight_name, style_name;
4133 WCHAR familynameW[255], facenameW[255], finalW[255];
4134 WCHAR weightW[32], stretchW[32], styleW[32];
4135 const WCHAR *regular_ptr = NULL;
4136 DWRITE_FONT_STRETCH stretch;
4137 DWRITE_FONT_WEIGHT weight;
4138 struct list tokens;
4139 int len;
4141 /* remove leading and trailing spaces from family and face name */
4142 trim_spaces(familyW, familynameW);
4143 len = trim_spaces(faceW, facenameW);
4145 /* remove rightmost regular variant from face name */
4146 regular_ptr = facename_remove_regular_term(facenameW, len);
4148 /* append face name to family name, FIXME check if face name is a substring of family name */
4149 if (*facenameW)
4151 wcscat(familynameW, L" ");
4152 wcscat(familynameW, facenameW);
4155 /* tokenize with " .-_" */
4156 fontname_tokenize(&tokens, familynameW);
4158 /* extract and resolve style */
4159 font->style = font_extract_style(&tokens, font->style, &style_name);
4161 /* extract stretch */
4162 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
4164 /* extract weight */
4165 weight = font_extract_weight(&tokens, font->weight, &weight_name);
4167 /* resolve weight */
4168 if (weight != font->weight)
4170 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
4171 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
4172 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
4173 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
4174 !(abs((int)weight - (int)font->weight) <= 150 &&
4175 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
4176 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
4177 font->weight != DWRITE_FONT_WEIGHT_BOLD))
4179 font->weight = weight;
4183 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
4184 it's leaning in opposite direction from normal comparing to specified stretch or if specified
4185 stretch itself is normal (extracted stretch is never normal). */
4186 if (stretch != font->stretch) {
4187 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
4188 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
4189 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
4191 font->stretch = stretch;
4195 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
4197 /* get final combined string from what's left in token list, list is released */
4198 fontname_tokens_to_str(&tokens, finalW);
4200 if (!wcscmp(familyW, finalW))
4201 return FALSE;
4203 /* construct face name */
4204 wcscpy(familyW, finalW);
4206 /* resolved weight name */
4207 if (weight_name.ptr)
4208 font_name_token_to_str(&weight_name, weightW);
4209 /* ignore normal weight */
4210 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
4211 weightW[0] = 0;
4212 /* for known weight values use appropriate names */
4213 else if (is_known_weight_value(font->weight, weightW)) {
4215 /* use Wnnn format as a fallback in case weight is not one of known values */
4216 else
4217 swprintf(weightW, ARRAY_SIZE(weightW), L"W%d", font->weight);
4219 /* resolved stretch name */
4220 if (stretch_name.ptr)
4221 font_name_token_to_str(&stretch_name, stretchW);
4222 /* ignore normal stretch */
4223 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
4224 stretchW[0] = 0;
4225 /* use predefined stretch names */
4226 else
4228 static const WCHAR *stretchnamesW[] =
4230 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
4231 L"Ultra Condensed",
4232 L"Extra Condensed",
4233 L"Condensed",
4234 L"Semi Condensed",
4235 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
4236 L"Semi Expanded",
4237 L"Expanded",
4238 L"Extra Expanded",
4239 L"Ultra Expanded"
4241 wcscpy(stretchW, stretchnamesW[font->stretch]);
4244 /* resolved style name */
4245 if (style_name.ptr)
4246 font_name_token_to_str(&style_name, styleW);
4247 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
4248 styleW[0] = 0;
4249 /* use predefined names */
4250 else
4251 wcscpy(styleW, font->style == DWRITE_FONT_STYLE_ITALIC ? L"Italic" : L"Oblique");
4253 /* use Regular match if it was found initially */
4254 if (!*weightW && !*stretchW && !*styleW)
4255 wcscpy(faceW, regular_ptr ? regular_ptr : L"Regular");
4256 else
4258 faceW[0] = 0;
4260 if (*stretchW) wcscpy(faceW, stretchW);
4262 if (*weightW)
4264 if (*faceW) wcscat(faceW, L" ");
4265 wcscat(faceW, weightW);
4268 if (*styleW)
4270 if (*faceW) wcscat(faceW, L" ");
4271 wcscat(faceW, styleW);
4275 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
4276 return TRUE;
4279 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
4281 static const float width_axis_values[] =
4283 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
4284 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
4285 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
4286 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
4287 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
4288 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
4289 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
4290 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
4291 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
4292 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
4295 struct file_stream_desc stream_desc;
4296 struct dwrite_font_props props;
4297 struct dwrite_font_data *data;
4298 WCHAR familyW[255], faceW[255];
4299 HRESULT hr;
4301 *ret = NULL;
4303 if (!(data = calloc(1, sizeof(*data))))
4304 return E_OUTOFMEMORY;
4306 data->refcount = 1;
4307 data->file = desc->file;
4308 data->face_index = desc->index;
4309 data->face_type = desc->face_type;
4310 IDWriteFontFile_AddRef(data->file);
4312 stream_desc.stream = desc->stream;
4313 stream_desc.face_type = desc->face_type;
4314 stream_desc.face_index = desc->index;
4315 opentype_get_font_properties(&stream_desc, &props);
4316 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4317 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4319 /* get family name from font file */
4320 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
4321 if (FAILED(hr)) {
4322 WARN("unable to get family name from font\n");
4323 release_font_data(data);
4324 return hr;
4327 data->style = props.style;
4328 data->stretch = props.stretch;
4329 data->weight = props.weight;
4330 data->panose = props.panose;
4331 data->fontsig = props.fontsig;
4332 data->lf = props.lf;
4333 data->flags = props.flags;
4335 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4336 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4337 if (font_apply_differentiation_rules(data, familyW, faceW)) {
4338 set_en_localizedstring(data->family_names, familyW);
4339 set_en_localizedstring(data->names, faceW);
4342 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4344 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4345 data->axis[0].value = props.weight;
4346 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4347 data->axis[1].value = width_axis_values[props.stretch];
4348 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4349 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4351 *ret = data;
4352 return S_OK;
4355 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4356 const WCHAR *facenameW, struct dwrite_font_data **ret)
4358 struct dwrite_font_data *data;
4360 *ret = NULL;
4362 if (!(data = calloc(1, sizeof(*data))))
4363 return E_OUTOFMEMORY;
4365 *data = *src;
4366 data->refcount = 1;
4367 data->simulations |= simulations;
4368 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4369 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4370 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4371 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4372 memset(data->info_strings, 0, sizeof(data->info_strings));
4373 data->names = NULL;
4374 IDWriteFontFile_AddRef(data->file);
4375 IDWriteLocalizedStrings_AddRef(data->family_names);
4377 create_localizedstrings(&data->names);
4378 add_localizedstring(data->names, L"en-us", facenameW);
4380 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4382 *ret = data;
4383 return S_OK;
4386 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4388 struct dwrite_fontfamily_data *data;
4390 if (!(data = calloc(1, sizeof(*data))))
4391 return E_OUTOFMEMORY;
4393 data->refcount = 1;
4394 data->familyname = familyname;
4395 IDWriteLocalizedStrings_AddRef(familyname);
4397 *ret = data;
4399 return S_OK;
4402 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4404 size_t i, j, heaviest;
4406 for (i = 0; i < family->count; ++i)
4408 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4409 heaviest = i;
4411 if (family->fonts[i]->bold_sim_tested)
4412 continue;
4414 family->fonts[i]->bold_sim_tested = 1;
4415 for (j = i; j < family->count; ++j)
4417 if (family->fonts[j]->bold_sim_tested)
4418 continue;
4420 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4421 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4422 if (family->fonts[j]->weight > weight) {
4423 weight = family->fonts[j]->weight;
4424 heaviest = j;
4426 family->fonts[j]->bold_sim_tested = 1;
4430 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550)
4432 static const struct name_pattern weightsim_patterns[] =
4434 { L"extra", L"light" },
4435 { L"ext", L"light" },
4436 { L"ultra", L"light" },
4437 { L"semi", L"light" },
4438 { L"semi", L"bold" },
4439 { L"demi", L"bold" },
4440 { L"bold" },
4441 { L"thin" },
4442 { L"light" },
4443 { L"medium" },
4444 { L"demi" },
4445 { NULL }
4448 WCHAR facenameW[255], initialW[255];
4449 struct dwrite_font_data *boldface;
4450 struct list tokens;
4452 /* add Bold simulation based on heaviest face data */
4454 /* Simulated face name should only contain Bold as weight term,
4455 so remove existing regular and weight terms. */
4456 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4457 facename_remove_regular_term(initialW, -1);
4459 /* remove current weight pattern */
4460 fontname_tokenize(&tokens, initialW);
4461 match_pattern_list(&tokens, weightsim_patterns, NULL);
4462 fontname_tokens_to_str(&tokens, facenameW);
4464 /* Bold suffix for new name */
4465 if (*facenameW) wcscat(facenameW, L" ");
4466 wcscat(facenameW, L"Bold");
4468 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4469 boldface->bold_sim_tested = 1;
4470 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4471 fontfamily_add_font(family, boldface);
4477 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4479 size_t i, j;
4481 for (i = 0; i < family->count; ++i)
4483 UINT32 regular = ~0u, oblique = ~0u;
4484 struct dwrite_font_data *obliqueface;
4485 WCHAR facenameW[255];
4487 if (family->fonts[i]->oblique_sim_tested)
4488 continue;
4490 family->fonts[i]->oblique_sim_tested = 1;
4491 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4492 regular = i;
4493 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4494 oblique = i;
4496 /* find regular style with same weight/stretch values */
4497 for (j = i; j < family->count; ++j)
4499 if (family->fonts[j]->oblique_sim_tested)
4500 continue;
4502 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4503 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4505 family->fonts[j]->oblique_sim_tested = 1;
4506 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4507 regular = j;
4509 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4510 oblique = j;
4513 if (regular != ~0u && oblique != ~0u)
4514 break;
4517 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4518 if (regular == ~0u)
4519 continue;
4521 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4522 if (oblique != ~0u)
4523 continue;
4525 /* add oblique simulation based on this regular face */
4527 /* remove regular term if any, append 'Oblique' */
4528 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4529 facename_remove_regular_term(facenameW, -1);
4531 if (*facenameW) wcscat(facenameW, L" ");
4532 wcscat(facenameW, L"Oblique");
4534 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4535 obliqueface->oblique_sim_tested = 1;
4536 obliqueface->lf.lfItalic = 1;
4537 fontfamily_add_font(family, obliqueface);
4542 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4543 const WCHAR *replacement_name)
4545 UINT32 i = collection_find_family(collection, replacement_name);
4546 struct dwrite_fontfamily_data *target;
4547 IDWriteLocalizedStrings *strings;
4548 HRESULT hr;
4550 /* replacement does not exist */
4551 if (i == ~0u)
4552 return FALSE;
4554 hr = create_localizedstrings(&strings);
4555 if (FAILED(hr))
4556 return FALSE;
4558 /* add a new family with target name, reuse font data from replacement */
4559 add_localizedstring(strings, L"en-us", target_name);
4560 hr = init_fontfamily_data(strings, &target);
4561 if (hr == S_OK) {
4562 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4563 WCHAR nameW[255];
4565 for (i = 0; i < replacement->count; ++i)
4567 fontfamily_add_font(target, replacement->fonts[i]);
4568 addref_font_data(replacement->fonts[i]);
4571 fontcollection_add_family(collection, target);
4572 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4573 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4575 IDWriteLocalizedStrings_Release(strings);
4576 return TRUE;
4579 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4580 system font collections. */
4581 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4583 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4584 WCHAR *name;
4585 void *data;
4586 HKEY hkey;
4588 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4589 return;
4591 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4592 RegCloseKey(hkey);
4593 return;
4596 max_namelen++; /* returned value doesn't include room for '\0' */
4597 name = malloc(max_namelen * sizeof(WCHAR));
4598 data = malloc(max_datalen);
4600 datalen = max_datalen;
4601 namelen = max_namelen;
4602 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4603 if (collection_find_family(collection, name) == ~0u) {
4604 if (type == REG_MULTI_SZ) {
4605 WCHAR *replacement = data;
4606 while (*replacement) {
4607 if (fontcollection_add_replacement(collection, name, replacement))
4608 break;
4609 replacement += wcslen(replacement) + 1;
4612 else if (type == REG_SZ)
4613 fontcollection_add_replacement(collection, name, data);
4615 else
4616 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4618 datalen = max_datalen;
4619 namelen = max_namelen;
4622 free(data);
4623 free(name);
4624 RegCloseKey(hkey);
4627 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4628 IDWriteFontCollection3 **ret)
4630 struct fontfile_enum {
4631 struct list entry;
4632 IDWriteFontFile *file;
4634 struct fontfile_enum *fileenum, *fileenum2;
4635 struct dwrite_fontcollection *collection;
4636 struct list scannedfiles;
4637 BOOL current = FALSE;
4638 HRESULT hr = S_OK;
4639 size_t i;
4641 *ret = NULL;
4643 if (!(collection = calloc(1, sizeof(*collection))))
4644 return E_OUTOFMEMORY;
4646 hr = init_font_collection(collection, is_system);
4647 if (FAILED(hr))
4649 free(collection);
4650 return hr;
4653 *ret = &collection->IDWriteFontCollection3_iface;
4655 TRACE("building font collection:\n");
4657 list_init(&scannedfiles);
4658 while (hr == S_OK) {
4659 DWRITE_FONT_FACE_TYPE face_type;
4660 DWRITE_FONT_FILE_TYPE file_type;
4661 BOOL supported, same = FALSE;
4662 IDWriteFontFileStream *stream;
4663 IDWriteFontFile *file;
4664 UINT32 face_count;
4666 current = FALSE;
4667 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4668 if (FAILED(hr) || !current)
4669 break;
4671 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4672 if (FAILED(hr))
4673 break;
4675 /* check if we've scanned this file already */
4676 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4677 if ((same = is_same_fontfile(fileenum->file, file)))
4678 break;
4681 if (same) {
4682 IDWriteFontFile_Release(file);
4683 continue;
4686 if (FAILED(get_filestream_from_file(file, &stream))) {
4687 IDWriteFontFile_Release(file);
4688 continue;
4691 /* Unsupported formats are skipped. */
4692 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4693 if (FAILED(hr) || !supported || face_count == 0) {
4694 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4695 IDWriteFontFileStream_Release(stream);
4696 IDWriteFontFile_Release(file);
4697 hr = S_OK;
4698 continue;
4701 /* add to scanned list */
4702 fileenum = malloc(sizeof(*fileenum));
4703 fileenum->file = file;
4704 list_add_tail(&scannedfiles, &fileenum->entry);
4706 for (i = 0; i < face_count; ++i)
4708 struct dwrite_font_data *font_data;
4709 struct fontface_desc desc;
4710 WCHAR familyW[255];
4711 UINT32 index;
4713 desc.factory = factory;
4714 desc.face_type = face_type;
4715 desc.file = file;
4716 desc.stream = stream;
4717 desc.index = i;
4718 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4719 desc.font_data = NULL;
4721 /* Allocate an initialize new font data structure. */
4722 hr = init_font_data(&desc, &font_data);
4723 if (FAILED(hr))
4725 /* move to next one */
4726 hr = S_OK;
4727 continue;
4730 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4732 /* ignore dot named faces */
4733 if (familyW[0] == '.')
4735 WARN("Ignoring face %s\n", debugstr_w(familyW));
4736 release_font_data(font_data);
4737 continue;
4740 index = collection_find_family(collection, familyW);
4741 if (index != ~0u)
4742 hr = fontfamily_add_font(collection->family_data[index], font_data);
4743 else {
4744 struct dwrite_fontfamily_data *family_data;
4746 /* create and init new family */
4747 hr = init_fontfamily_data(font_data->family_names, &family_data);
4748 if (hr == S_OK) {
4749 /* add font to family, family - to collection */
4750 hr = fontfamily_add_font(family_data, font_data);
4751 if (hr == S_OK)
4752 hr = fontcollection_add_family(collection, family_data);
4754 if (FAILED(hr))
4755 release_fontfamily_data(family_data);
4759 if (FAILED(hr))
4761 release_font_data(font_data);
4762 break;
4766 IDWriteFontFileStream_Release(stream);
4769 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry)
4771 IDWriteFontFile_Release(fileenum->file);
4772 list_remove(&fileenum->entry);
4773 free(fileenum);
4776 for (i = 0; i < collection->count; ++i)
4778 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4779 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4782 if (is_system)
4783 fontcollection_add_replacements(collection);
4785 collection->factory = factory;
4786 IDWriteFactory7_AddRef(factory);
4788 return hr;
4791 struct system_fontfile_enumerator
4793 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4794 LONG refcount;
4796 IDWriteFactory7 *factory;
4797 HKEY hkey;
4798 int index;
4800 WCHAR *filename;
4801 DWORD filename_size;
4804 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4806 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4809 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4811 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4812 IDWriteFontFileEnumerator_AddRef(iface);
4813 *obj = iface;
4814 return S_OK;
4817 WARN("%s not implemented.\n", debugstr_guid(riid));
4819 *obj = NULL;
4821 return E_NOINTERFACE;
4824 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4826 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4827 return InterlockedIncrement(&enumerator->refcount);
4830 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4832 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4833 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4835 if (!refcount)
4837 IDWriteFactory7_Release(enumerator->factory);
4838 RegCloseKey(enumerator->hkey);
4839 free(enumerator->filename);
4840 free(enumerator);
4843 return refcount;
4846 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4848 HRESULT hr;
4850 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4851 if (!wcschr(filename, '\\'))
4853 WCHAR fullpathW[MAX_PATH];
4855 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4856 wcscat(fullpathW, L"\\fonts\\");
4857 wcscat(fullpathW, filename);
4859 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4861 else
4862 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4864 return hr;
4867 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4869 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4871 *file = NULL;
4873 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4874 return E_FAIL;
4876 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4879 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4881 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4882 WCHAR name_buf[256], *name = name_buf;
4883 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4884 HRESULT hr = S_OK;
4885 LONG r;
4887 *current = FALSE;
4888 enumerator->index++;
4890 /* iterate until we find next string value */
4891 for (;;) {
4892 do {
4893 name_count = max_name_count;
4894 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4896 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4897 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4898 if (r == ERROR_MORE_DATA) {
4899 if (name_count >= max_name_count) {
4900 if (name != name_buf) free(name);
4901 max_name_count *= 2;
4902 name = malloc(max_name_count * sizeof(*name));
4903 if (!name) return E_OUTOFMEMORY;
4905 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename))
4907 free(enumerator->filename);
4908 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4909 if (!(enumerator->filename = malloc(enumerator->filename_size)))
4911 hr = E_OUTOFMEMORY;
4912 goto err;
4916 } while (r == ERROR_MORE_DATA);
4918 if (r != ERROR_SUCCESS) {
4919 enumerator->filename[0] = 0;
4920 break;
4922 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4923 if (type == REG_SZ && *name != '@') {
4924 *current = TRUE;
4925 break;
4927 enumerator->index++;
4929 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4931 err:
4932 if (name != name_buf) free(name);
4933 return hr;
4936 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4938 systemfontfileenumerator_QueryInterface,
4939 systemfontfileenumerator_AddRef,
4940 systemfontfileenumerator_Release,
4941 systemfontfileenumerator_MoveNext,
4942 systemfontfileenumerator_GetCurrentFontFile
4945 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4947 struct system_fontfile_enumerator *enumerator;
4949 *ret = NULL;
4951 if (!(enumerator = calloc(1, sizeof(*enumerator))))
4952 return E_OUTOFMEMORY;
4954 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4955 enumerator->refcount = 1;
4956 enumerator->factory = factory;
4957 enumerator->index = -1;
4958 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4959 enumerator->filename = malloc(enumerator->filename_size);
4960 if (!enumerator->filename)
4962 free(enumerator);
4963 return E_OUTOFMEMORY;
4966 IDWriteFactory7_AddRef(factory);
4968 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0,
4969 GENERIC_READ, &enumerator->hkey))
4971 ERR("failed to open fonts list key\n");
4972 IDWriteFactory7_Release(factory);
4973 free(enumerator->filename);
4974 free(enumerator);
4975 return E_FAIL;
4978 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4980 return S_OK;
4983 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4985 IDWriteFontFileEnumerator *enumerator;
4986 HRESULT hr;
4988 *collection = NULL;
4990 hr = create_system_fontfile_enumerator(factory, &enumerator);
4991 if (FAILED(hr))
4992 return hr;
4994 TRACE("building system font collection for factory %p\n", factory);
4995 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4996 IDWriteFontFileEnumerator_Release(enumerator);
4997 return hr;
5000 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
5001 const WCHAR *keynameW, const WCHAR *pathW)
5003 struct dwrite_fontfamily_data *family_data;
5004 IDWriteLocalizedStrings *names;
5005 DWRITE_FONT_FACE_TYPE face_type;
5006 DWRITE_FONT_FILE_TYPE file_type;
5007 IDWriteFontFileStream *stream;
5008 IDWriteFontFile *file;
5009 UINT32 face_count, i;
5010 BOOL supported;
5011 HRESULT hr;
5013 /* create font file from this path */
5014 hr = create_local_file_reference(factory, pathW, &file);
5015 if (FAILED(hr))
5016 return S_FALSE;
5018 if (FAILED(get_filestream_from_file(file, &stream))) {
5019 IDWriteFontFile_Release(file);
5020 return S_FALSE;
5023 /* Unsupported formats are skipped. */
5024 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
5025 if (FAILED(hr) || !supported || face_count == 0) {
5026 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
5027 IDWriteFontFileStream_Release(stream);
5028 IDWriteFontFile_Release(file);
5029 return S_FALSE;
5032 /* create and init new family */
5034 /* Family names are added for non-specific locale, represented with empty string.
5035 Default family appears with empty family name. */
5036 create_localizedstrings(&names);
5037 if (!wcsicmp(keynameW, L"SystemDefaultEUDCFont"))
5038 add_localizedstring(names, L"", L"");
5039 else
5040 add_localizedstring(names, L"", keynameW);
5042 hr = init_fontfamily_data(names, &family_data);
5043 IDWriteLocalizedStrings_Release(names);
5044 if (hr != S_OK) {
5045 IDWriteFontFile_Release(file);
5046 return hr;
5049 /* fill with faces */
5050 for (i = 0; i < face_count; i++) {
5051 struct dwrite_font_data *font_data;
5052 struct fontface_desc desc;
5054 /* Allocate new font data structure. */
5055 desc.factory = factory;
5056 desc.face_type = face_type;
5057 desc.index = i;
5058 desc.file = file;
5059 desc.stream = stream;
5060 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
5061 desc.font_data = NULL;
5063 hr = init_font_data(&desc, &font_data);
5064 if (FAILED(hr))
5065 continue;
5067 /* add font to family */
5068 hr = fontfamily_add_font(family_data, font_data);
5069 if (hr != S_OK)
5070 release_font_data(font_data);
5073 /* add family to collection */
5074 hr = fontcollection_add_family(collection, family_data);
5075 if (FAILED(hr))
5076 release_fontfamily_data(family_data);
5077 IDWriteFontFileStream_Release(stream);
5078 IDWriteFontFile_Release(file);
5080 return hr;
5083 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
5085 struct dwrite_fontcollection *collection;
5086 WCHAR eudckeypathW[16];
5087 HKEY eudckey;
5088 DWORD index;
5089 BOOL exists;
5090 LONG retval;
5091 HRESULT hr;
5092 size_t i;
5094 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
5096 *ret = NULL;
5098 if (!(collection = calloc(1, sizeof(*collection))))
5099 return E_OUTOFMEMORY;
5101 hr = init_font_collection(collection, FALSE);
5102 if (FAILED(hr))
5104 free(collection);
5105 return hr;
5108 *ret = &collection->IDWriteFontCollection3_iface;
5109 collection->factory = factory;
5110 IDWriteFactory7_AddRef(factory);
5112 /* return empty collection if EUDC fonts are not configured */
5113 swprintf(eudckeypathW, ARRAY_SIZE(eudckeypathW), L"EUDC\\%u", GetACP());
5114 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
5115 return S_OK;
5117 retval = ERROR_SUCCESS;
5118 index = 0;
5119 while (retval != ERROR_NO_MORE_ITEMS) {
5120 WCHAR keynameW[64], pathW[MAX_PATH];
5121 DWORD type, path_len, name_len;
5123 path_len = ARRAY_SIZE(pathW);
5124 name_len = ARRAY_SIZE(keynameW);
5125 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
5126 if (retval || type != REG_SZ)
5127 continue;
5129 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
5130 if (hr != S_OK)
5131 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
5133 RegCloseKey(eudckey);
5135 /* try to add global default if not defined for specific codepage */
5136 exists = FALSE;
5137 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, L"",
5138 &index, &exists);
5139 if (FAILED(hr) || !exists)
5141 hr = eudc_collection_add_family(factory, collection, L"", L"EUDC.TTE");
5142 if (hr != S_OK)
5143 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
5146 /* EUDC collection offers simulated faces too */
5147 for (i = 0; i < collection->count; ++i)
5149 fontfamily_add_bold_simulated_face(collection->family_data[i]);
5150 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
5153 return S_OK;
5156 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
5158 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5160 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
5162 *obj = iface;
5163 IDWriteFontFile_AddRef(iface);
5164 return S_OK;
5167 WARN("%s not implemented.\n", debugstr_guid(riid));
5169 *obj = NULL;
5170 return E_NOINTERFACE;
5173 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
5175 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5176 ULONG refcount = InterlockedIncrement(&file->refcount);
5178 TRACE("%p, refcount %d.\n", iface, refcount);
5180 return refcount;
5183 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
5185 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5186 ULONG refcount = InterlockedDecrement(&file->refcount);
5188 TRACE("%p, refcount %d.\n", iface, refcount);
5190 if (!refcount)
5192 IDWriteFontFileLoader_Release(file->loader);
5193 if (file->stream)
5194 IDWriteFontFileStream_Release(file->stream);
5195 free(file->reference_key);
5196 free(file);
5199 return refcount;
5202 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
5204 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5206 TRACE("%p, %p, %p.\n", iface, key, key_size);
5208 *key = file->reference_key;
5209 *key_size = file->key_size;
5211 return S_OK;
5214 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
5216 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5218 TRACE("%p, %p.\n", iface, loader);
5220 *loader = file->loader;
5221 IDWriteFontFileLoader_AddRef(*loader);
5223 return S_OK;
5226 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
5227 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
5229 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5230 IDWriteFontFileStream *stream;
5231 HRESULT hr;
5233 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
5235 *is_supported = FALSE;
5236 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
5237 if (face_type)
5238 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
5239 *face_count = 0;
5241 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
5242 if (FAILED(hr))
5243 return hr;
5245 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
5247 /* TODO: Further Analysis */
5248 IDWriteFontFileStream_Release(stream);
5249 return S_OK;
5252 static const IDWriteFontFileVtbl dwritefontfilevtbl =
5254 dwritefontfile_QueryInterface,
5255 dwritefontfile_AddRef,
5256 dwritefontfile_Release,
5257 dwritefontfile_GetReferenceKey,
5258 dwritefontfile_GetLoader,
5259 dwritefontfile_Analyze,
5262 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
5263 IDWriteFontFile **ret)
5265 struct dwrite_fontfile *file;
5266 void *key;
5268 *ret = NULL;
5270 file = calloc(1, sizeof(*file));
5271 key = malloc(key_size);
5272 if (!file || !key)
5274 free(file);
5275 free(key);
5276 return E_OUTOFMEMORY;
5279 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
5280 file->refcount = 1;
5281 IDWriteFontFileLoader_AddRef(loader);
5282 file->loader = loader;
5283 file->stream = NULL;
5284 file->reference_key = key;
5285 memcpy(file->reference_key, reference_key, key_size);
5286 file->key_size = key_size;
5288 *ret = &file->IDWriteFontFile_iface;
5290 return S_OK;
5293 static UINT64 dwrite_fontface_get_font_object(struct dwrite_fontface *fontface)
5295 struct create_font_object_params create_params;
5296 struct release_font_object_params release_params;
5297 UINT64 font_object, size;
5298 const void *data_ptr;
5299 void *data_context;
5301 if (!fontface->font_object && SUCCEEDED(IDWriteFontFileStream_GetFileSize(fontface->stream, &size)))
5303 if (SUCCEEDED(IDWriteFontFileStream_ReadFileFragment(fontface->stream, &data_ptr, 0, size, &data_context)))
5305 create_params.data = data_ptr;
5306 create_params.size = size;
5307 create_params.index = fontface->index;
5308 create_params.object = &font_object;
5310 UNIX_CALL(create_font_object, &create_params);
5312 if (!font_object)
5314 WARN("Backend failed to create font object.\n");
5315 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5316 return 0;
5319 if (!InterlockedCompareExchange64((LONGLONG *)&fontface->font_object, font_object, 0))
5321 fontface->data_context = data_context;
5323 else
5325 release_params.object = font_object;
5326 UNIX_CALL(release_font_object, &release_params);
5327 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, data_context);
5332 return fontface->font_object;
5335 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5337 struct file_stream_desc stream_desc;
5338 struct dwrite_font_data *font_data;
5339 struct dwrite_fontface *fontface;
5340 HRESULT hr;
5341 int i;
5343 *ret = NULL;
5345 if (!(fontface = calloc(1, sizeof(*fontface))))
5346 return E_OUTOFMEMORY;
5348 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5349 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5350 fontface->refcount = 1;
5351 fontface->type = desc->face_type;
5352 fontface->vdmx.exists = TRUE;
5353 fontface->gasp.exists = TRUE;
5354 fontface->cpal.exists = TRUE;
5355 fontface->colr.exists = TRUE;
5356 fontface->kern.exists = TRUE;
5357 fontface->index = desc->index;
5358 fontface->simulations = desc->simulations;
5359 fontface->factory = desc->factory;
5360 IDWriteFactory7_AddRef(fontface->factory);
5361 fontface->file = desc->file;
5362 IDWriteFontFile_AddRef(fontface->file);
5363 fontface->stream = desc->stream;
5364 IDWriteFontFileStream_AddRef(fontface->stream);
5365 InitializeCriticalSection(&fontface->cs);
5366 fontface_cache_init(fontface);
5368 stream_desc.stream = fontface->stream;
5369 stream_desc.face_type = desc->face_type;
5370 stream_desc.face_index = desc->index;
5371 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5372 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5373 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5374 /* TODO: test what happens if caret is already slanted */
5375 if (fontface->caret.slopeRise == 1) {
5376 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5377 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5380 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5382 /* Font properties are reused from font object when 'normal' face creation path is used:
5383 collection -> family -> matching font -> fontface.
5385 If face is created directly from factory we have to go through properties resolution.
5387 if (desc->font_data)
5389 font_data = addref_font_data(desc->font_data);
5391 else
5393 hr = init_font_data(desc, &font_data);
5394 if (FAILED(hr))
5396 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5397 return hr;
5401 fontface->weight = font_data->weight;
5402 fontface->style = font_data->style;
5403 fontface->stretch = font_data->stretch;
5404 fontface->panose = font_data->panose;
5405 fontface->fontsig = font_data->fontsig;
5406 fontface->lf = font_data->lf;
5407 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5408 fontface->names = font_data->names;
5409 if (fontface->names)
5410 IDWriteLocalizedStrings_AddRef(fontface->names);
5411 fontface->family_names = font_data->family_names;
5412 if (fontface->family_names)
5413 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5414 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5415 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5417 if (fontface->info_strings[i])
5418 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5420 fontface->cmap.stream = fontface->stream;
5421 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5422 release_font_data(font_data);
5424 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5425 fontface->get_font_object = dwrite_fontface_get_font_object;
5427 *ret = &fontface->IDWriteFontFace5_iface;
5429 return S_OK;
5432 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5433 struct local_refkey
5435 FILETIME writetime;
5436 WCHAR name[1];
5439 struct local_cached_stream
5441 struct list entry;
5442 IDWriteFontFileStream *stream;
5443 struct local_refkey *key;
5444 UINT32 key_size;
5447 struct dwrite_localfontfilestream
5449 IDWriteFontFileStream IDWriteFontFileStream_iface;
5450 LONG refcount;
5452 struct local_cached_stream *entry;
5453 const void *file_ptr;
5454 UINT64 size;
5457 struct dwrite_localfontfileloader
5459 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5460 LONG refcount;
5462 struct list streams;
5463 CRITICAL_SECTION cs;
5466 static struct dwrite_localfontfileloader local_fontfile_loader;
5468 struct dwrite_inmemory_stream_data
5470 LONG refcount;
5471 IUnknown *owner;
5472 void *data;
5473 UINT32 size;
5476 struct dwrite_inmemory_filestream
5478 IDWriteFontFileStream IDWriteFontFileStream_iface;
5479 LONG refcount;
5481 struct dwrite_inmemory_stream_data *data;
5484 struct dwrite_inmemory_fileloader
5486 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5487 LONG refcount;
5489 struct dwrite_inmemory_stream_data **streams;
5490 size_t size;
5491 size_t count;
5494 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5496 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5499 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5501 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5504 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5506 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5509 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5511 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5514 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5516 if (InterlockedDecrement(&stream->refcount) == 0)
5518 if (stream->owner)
5519 IUnknown_Release(stream->owner);
5520 else
5521 free(stream->data);
5522 free(stream);
5526 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5528 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5530 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5532 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5533 IsEqualIID(riid, &IID_IUnknown))
5535 *obj = iface;
5536 if (InterlockedIncrement(&stream->refcount) == 1)
5538 InterlockedDecrement(&stream->refcount);
5539 *obj = NULL;
5540 return E_FAIL;
5542 return S_OK;
5545 WARN("%s not implemented.\n", debugstr_guid(riid));
5547 *obj = NULL;
5548 return E_NOINTERFACE;
5551 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5553 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5554 ULONG refcount = InterlockedIncrement(&stream->refcount);
5556 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5558 return refcount;
5561 static inline void release_cached_stream(struct local_cached_stream *stream)
5563 list_remove(&stream->entry);
5564 free(stream->key);
5565 free(stream);
5568 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5570 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5571 ULONG refcount = InterlockedDecrement(&stream->refcount);
5573 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5575 if (!refcount)
5577 UnmapViewOfFile(stream->file_ptr);
5579 EnterCriticalSection(&local_fontfile_loader.cs);
5580 release_cached_stream(stream->entry);
5581 LeaveCriticalSection(&local_fontfile_loader.cs);
5583 free(stream);
5586 return refcount;
5589 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5590 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5592 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5594 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5595 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5597 *fragment_context = NULL;
5599 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5601 *fragment_start = NULL;
5602 return E_FAIL;
5605 *fragment_start = (char *)stream->file_ptr + offset;
5606 return S_OK;
5609 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5611 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5614 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5616 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5618 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5620 *size = stream->size;
5621 return S_OK;
5624 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5626 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5627 ULARGE_INTEGER li;
5629 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5631 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5632 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5633 *last_writetime = li.QuadPart;
5635 return S_OK;
5638 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5640 localfontfilestream_QueryInterface,
5641 localfontfilestream_AddRef,
5642 localfontfilestream_Release,
5643 localfontfilestream_ReadFileFragment,
5644 localfontfilestream_ReleaseFileFragment,
5645 localfontfilestream_GetFileSize,
5646 localfontfilestream_GetLastWriteTime
5649 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5650 IDWriteFontFileStream **ret)
5652 struct dwrite_localfontfilestream *object;
5654 *ret = NULL;
5656 if (!(object = calloc(1, sizeof(*object))))
5657 return E_OUTOFMEMORY;
5659 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5660 object->refcount = 1;
5662 object->file_ptr = file_ptr;
5663 object->size = size;
5664 object->entry = entry;
5666 *ret = &object->IDWriteFontFileStream_iface;
5668 return S_OK;
5671 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5673 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5675 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5676 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5677 IsEqualIID(riid, &IID_IUnknown))
5679 *obj = iface;
5680 IDWriteLocalFontFileLoader_AddRef(iface);
5681 return S_OK;
5684 WARN("%s not implemented.\n", debugstr_guid(riid));
5686 *obj = NULL;
5687 return E_NOINTERFACE;
5690 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5692 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5693 ULONG refcount = InterlockedIncrement(&loader->refcount);
5695 TRACE("%p, refcount %d.\n", iface, refcount);
5697 return refcount;
5700 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5702 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5703 ULONG refcount = InterlockedDecrement(&loader->refcount);
5705 TRACE("%p, refcount %d.\n", iface, refcount);
5707 return refcount;
5710 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5712 const struct local_refkey *refkey = key;
5713 struct local_cached_stream *stream;
5714 IDWriteFontFileStream *filestream;
5715 HANDLE file, mapping;
5716 LARGE_INTEGER size;
5717 void *file_ptr;
5718 HRESULT hr = S_OK;
5720 *ret = NULL;
5722 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5723 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5724 if (file == INVALID_HANDLE_VALUE) {
5725 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5726 return E_FAIL;
5729 GetFileSizeEx(file, &size);
5730 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5731 CloseHandle(file);
5732 if (!mapping)
5733 return E_FAIL;
5735 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5736 CloseHandle(mapping);
5737 if (!file_ptr) {
5738 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5739 return E_FAIL;
5742 if (!(stream = malloc(sizeof(*stream))))
5744 UnmapViewOfFile(file_ptr);
5745 return E_OUTOFMEMORY;
5748 if (!(stream->key = malloc(key_size)))
5750 UnmapViewOfFile(file_ptr);
5751 free(stream);
5752 return E_OUTOFMEMORY;
5755 stream->key_size = key_size;
5756 memcpy(stream->key, key, key_size);
5758 if (FAILED(hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream)))
5760 UnmapViewOfFile(file_ptr);
5761 free(stream->key);
5762 free(stream);
5763 return hr;
5766 stream->stream = filestream;
5768 *ret = stream;
5770 return S_OK;
5773 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5774 UINT32 key_size, IDWriteFontFileStream **ret)
5776 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5777 struct local_cached_stream *stream;
5778 HRESULT hr = S_OK;
5780 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5782 EnterCriticalSection(&loader->cs);
5784 *ret = NULL;
5786 /* search cache first */
5787 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5789 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5790 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5791 break;
5795 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5797 list_add_head(&loader->streams, &stream->entry);
5798 *ret = stream->stream;
5801 LeaveCriticalSection(&loader->cs);
5803 return hr;
5806 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5807 UINT32 key_size, UINT32 *length)
5809 const struct local_refkey *refkey = key;
5811 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5813 *length = wcslen(refkey->name);
5814 return S_OK;
5817 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5818 UINT32 key_size, WCHAR *path, UINT32 length)
5820 const struct local_refkey *refkey = key;
5822 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5824 if (length < wcslen(refkey->name))
5825 return E_INVALIDARG;
5827 wcscpy(path, refkey->name);
5828 return S_OK;
5831 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5832 UINT32 key_size, FILETIME *writetime)
5834 const struct local_refkey *refkey = key;
5836 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5838 *writetime = refkey->writetime;
5839 return S_OK;
5842 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5844 localfontfileloader_QueryInterface,
5845 localfontfileloader_AddRef,
5846 localfontfileloader_Release,
5847 localfontfileloader_CreateStreamFromKey,
5848 localfontfileloader_GetFilePathLengthFromKey,
5849 localfontfileloader_GetFilePathFromKey,
5850 localfontfileloader_GetLastWriteTimeFromKey
5853 void init_local_fontfile_loader(void)
5855 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5856 local_fontfile_loader.refcount = 1;
5857 list_init(&local_fontfile_loader.streams);
5858 InitializeCriticalSection(&local_fontfile_loader.cs);
5859 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5862 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5864 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5867 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5869 struct local_refkey *refkey;
5871 if (!path)
5872 return E_INVALIDARG;
5874 *size = FIELD_OFFSET(struct local_refkey, name) + (wcslen(path)+1)*sizeof(WCHAR);
5875 *key = NULL;
5877 if (!(refkey = malloc(*size)))
5878 return E_OUTOFMEMORY;
5880 if (writetime)
5881 refkey->writetime = *writetime;
5882 else {
5883 WIN32_FILE_ATTRIBUTE_DATA info;
5885 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5886 refkey->writetime = info.ftLastWriteTime;
5887 else
5888 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5890 wcscpy(refkey->name, path);
5892 *key = refkey;
5894 return S_OK;
5897 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5899 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5901 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5902 IsEqualIID(riid, &IID_IUnknown))
5904 *ppv = iface;
5905 IDWriteGlyphRunAnalysis_AddRef(iface);
5906 return S_OK;
5909 WARN("%s not implemented.\n", debugstr_guid(riid));
5911 *ppv = NULL;
5912 return E_NOINTERFACE;
5915 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5917 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5918 ULONG refcount = InterlockedIncrement(&analysis->refcount);
5920 TRACE("%p, refcount %d.\n", iface, refcount);
5922 return refcount;
5925 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5927 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5928 ULONG refcount = InterlockedDecrement(&analysis->refcount);
5930 TRACE("%p, refcount %d.\n", iface, refcount);
5932 if (!refcount)
5934 if (analysis->run.fontFace)
5935 IDWriteFontFace_Release(analysis->run.fontFace);
5936 free(analysis->glyphs);
5937 free(analysis->origins);
5938 free(analysis->bitmap);
5939 free(analysis);
5942 return refcount;
5945 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5947 struct dwrite_glyphbitmap glyph_bitmap;
5948 UINT32 i;
5950 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5951 *bounds = analysis->bounds;
5952 return;
5955 if (analysis->run.isSideways)
5956 FIXME("sideways runs are not supported.\n");
5958 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5959 glyph_bitmap.simulations = IDWriteFontFace_GetSimulations(analysis->run.fontFace);
5960 glyph_bitmap.emsize = analysis->run.fontEmSize;
5961 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5962 glyph_bitmap.m = &analysis->m;
5964 for (i = 0; i < analysis->run.glyphCount; i++) {
5965 RECT *bbox = &glyph_bitmap.bbox;
5966 UINT32 bitmap_size;
5968 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5969 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
5971 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5972 (bbox->bottom - bbox->top);
5973 if (bitmap_size > analysis->max_glyph_bitmap_size)
5974 analysis->max_glyph_bitmap_size = bitmap_size;
5976 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5977 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5980 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5981 *bounds = analysis->bounds;
5984 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
5985 DWRITE_TEXTURE_TYPE type, RECT *bounds)
5987 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5989 TRACE("%p, %d, %p.\n", iface, type, bounds);
5991 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5992 SetRectEmpty(bounds);
5993 return E_INVALIDARG;
5996 if (type != analysis->texture_type)
5998 SetRectEmpty(bounds);
5999 return S_OK;
6002 glyphrunanalysis_get_texturebounds(analysis, bounds);
6003 return S_OK;
6006 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
6008 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6009 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
6010 (runbounds->left - bounds->left) * 3;
6011 else
6012 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
6013 runbounds->left - bounds->left;
6016 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
6018 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
6019 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(analysis->run.fontFace);
6020 struct dwrite_glyphbitmap glyph_bitmap;
6021 D2D_POINT_2F origin;
6022 UINT32 i, size;
6023 RECT *bbox;
6025 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
6026 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6027 size *= 3;
6028 if (!(analysis->bitmap = calloc(1, size)))
6030 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
6031 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
6032 return E_OUTOFMEMORY;
6035 origin.x = origin.y = 0.0f;
6037 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
6038 glyph_bitmap.simulations = fontface->simulations;
6039 glyph_bitmap.emsize = analysis->run.fontEmSize;
6040 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6041 glyph_bitmap.m = &analysis->m;
6042 if (!(glyph_bitmap.buf = malloc(analysis->max_glyph_bitmap_size)))
6043 return E_OUTOFMEMORY;
6045 bbox = &glyph_bitmap.bbox;
6047 for (i = 0; i < analysis->run.glyphCount; ++i)
6049 BYTE *src = glyph_bitmap.buf, *dst;
6050 int x, y, width, height;
6051 unsigned int is_1bpp;
6053 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
6054 dwrite_fontface_get_glyph_bbox(analysis->run.fontFace, &glyph_bitmap);
6056 if (IsRectEmpty(bbox))
6057 continue;
6059 width = bbox->right - bbox->left;
6060 height = bbox->bottom - bbox->top;
6062 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
6063 memset(src, 0, height * glyph_bitmap.pitch);
6065 if (FAILED(dwrite_fontface_get_glyph_bitmap(fontface, analysis->rendering_mode, &is_1bpp, &glyph_bitmap)))
6067 WARN("Failed to render glyph[%u] = %#x.\n", i, glyph_bitmap.glyph);
6068 continue;
6071 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
6073 /* blit to analysis bitmap */
6074 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
6076 if (is_1bpp) {
6077 /* convert 1bpp to 8bpp/24bpp */
6078 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6079 for (y = 0; y < height; y++) {
6080 for (x = 0; x < width; x++)
6081 if (src[x / 8] & masks[x % 8])
6082 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
6083 src += glyph_bitmap.pitch;
6084 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6087 else {
6088 for (y = 0; y < height; y++) {
6089 for (x = 0; x < width; x++)
6090 if (src[x / 8] & masks[x % 8])
6091 dst[x] = DWRITE_ALPHA_MAX;
6092 src += glyph_bitmap.pitch;
6093 dst += analysis->bounds.right - analysis->bounds.left;
6097 else {
6098 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
6099 for (y = 0; y < height; y++) {
6100 for (x = 0; x < width; x++)
6101 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
6102 src += glyph_bitmap.pitch;
6103 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
6106 else {
6107 for (y = 0; y < height; y++) {
6108 for (x = 0; x < width; x++)
6109 dst[x] |= src[x];
6110 src += glyph_bitmap.pitch;
6111 dst += analysis->bounds.right - analysis->bounds.left;
6116 free(glyph_bitmap.buf);
6118 analysis->flags |= RUNANALYSIS_BITMAP_READY;
6120 /* we don't need this anymore */
6121 free(analysis->glyphs);
6122 free(analysis->origins);
6123 IDWriteFontFace_Release(analysis->run.fontFace);
6125 analysis->glyphs = NULL;
6126 analysis->origins = NULL;
6127 analysis->run.glyphIndices = NULL;
6128 analysis->run.fontFace = NULL;
6130 return S_OK;
6133 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
6134 RECT const *bounds, BYTE *bitmap, UINT32 size)
6136 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6137 UINT32 required;
6138 RECT runbounds;
6140 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
6142 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
6143 return E_INVALIDARG;
6145 /* make sure buffer is large enough for requested texture type */
6146 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
6147 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
6148 required *= 3;
6150 if (size < required)
6151 return E_NOT_SUFFICIENT_BUFFER;
6153 /* validate requested texture type */
6154 if (analysis->texture_type != type)
6155 return DWRITE_E_UNSUPPORTEDOPERATION;
6157 memset(bitmap, 0, size);
6158 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
6159 if (IntersectRect(&runbounds, &runbounds, bounds))
6161 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
6162 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
6163 int dst_width = (bounds->right - bounds->left) * pixel_size;
6164 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
6165 BYTE *src, *dst;
6166 int y;
6168 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
6170 HRESULT hr;
6172 if (FAILED(hr = glyphrunanalysis_render(analysis)))
6173 return hr;
6176 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
6177 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
6179 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
6180 memcpy(dst, src, draw_width);
6181 src += src_width;
6182 dst += dst_width;
6186 return S_OK;
6189 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
6190 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
6192 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
6194 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
6196 if (!params)
6197 return E_INVALIDARG;
6199 switch (analysis->rendering_mode)
6201 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
6202 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
6204 UINT value = 0;
6205 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6206 *gamma = (FLOAT)value / 1000.0f;
6207 *contrast = 0.0f;
6208 *cleartypelevel = 1.0f;
6209 break;
6211 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
6212 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
6213 /* fallthrough */
6214 case DWRITE_RENDERING_MODE1_ALIASED:
6215 case DWRITE_RENDERING_MODE1_NATURAL:
6216 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
6217 *gamma = IDWriteRenderingParams_GetGamma(params);
6218 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
6219 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
6220 break;
6221 default:
6225 return S_OK;
6228 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
6230 glyphrunanalysis_QueryInterface,
6231 glyphrunanalysis_AddRef,
6232 glyphrunanalysis_Release,
6233 glyphrunanalysis_GetAlphaTextureBounds,
6234 glyphrunanalysis_CreateAlphaTexture,
6235 glyphrunanalysis_GetAlphaBlendParams
6238 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
6240 D2D_POINT_2F ret;
6241 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
6242 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
6243 *point = ret;
6246 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
6247 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
6249 unsigned int upem = fontface->metrics.designUnitsPerEm;
6250 int advance;
6252 if (is_sideways)
6253 FIXME("Sideways mode is not supported.\n");
6255 EnterCriticalSection(&fontface->cs);
6256 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
6257 LeaveCriticalSection(&fontface->cs);
6259 switch (measuring_mode)
6261 case DWRITE_MEASURING_MODE_NATURAL:
6262 return (float)advance * emsize / (float)upem;
6263 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6264 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6265 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
6266 default:
6267 WARN("Unknown measuring mode %u.\n", measuring_mode);
6268 return 0.0f;
6272 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
6274 struct dwrite_glyphrunanalysis *analysis;
6275 unsigned int i;
6277 *ret = NULL;
6279 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
6280 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
6281 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
6282 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
6283 return E_INVALIDARG;
6285 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6286 return E_INVALIDARG;
6288 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
6289 return E_INVALIDARG;
6291 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
6292 return E_INVALIDARG;
6294 if (!(analysis = calloc(1, sizeof(*analysis))))
6295 return E_OUTOFMEMORY;
6297 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
6298 analysis->refcount = 1;
6299 analysis->rendering_mode = desc->rendering_mode;
6301 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
6302 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6303 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6304 else
6305 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6307 analysis->run = *desc->run;
6308 IDWriteFontFace_AddRef(analysis->run.fontFace);
6309 analysis->glyphs = calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6310 analysis->origins = calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6312 if (!analysis->glyphs || !analysis->origins)
6314 free(analysis->glyphs);
6315 free(analysis->origins);
6317 analysis->glyphs = NULL;
6318 analysis->origins = NULL;
6320 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6321 return E_OUTOFMEMORY;
6324 /* check if transform is usable */
6325 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6326 analysis->m = *desc->transform;
6327 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6330 analysis->run.glyphIndices = analysis->glyphs;
6331 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6333 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6334 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6336 for (i = 0; i < desc->run->glyphCount; ++i)
6337 transform_point(&analysis->origins[i], &analysis->m);
6340 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6341 return S_OK;
6344 /* IDWriteColorGlyphRunEnumerator1 */
6345 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6347 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6349 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6350 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6351 IsEqualIID(riid, &IID_IUnknown))
6353 *ppv = iface;
6354 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6355 return S_OK;
6358 WARN("%s not implemented.\n", debugstr_guid(riid));
6360 *ppv = NULL;
6361 return E_NOINTERFACE;
6364 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6366 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6367 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6369 TRACE("%p, refcount %u.\n", iface, refcount);
6371 return refcount;
6374 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6376 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6377 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6379 TRACE("%p, refcount %u.\n", iface, refcount);
6381 if (!refcount)
6383 free(glyphenum->advances);
6384 free(glyphenum->color_advances);
6385 free(glyphenum->offsets);
6386 free(glyphenum->color_offsets);
6387 free(glyphenum->glyphindices);
6388 free(glyphenum->glyphs);
6389 if (glyphenum->colr.context)
6390 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6391 IDWriteFontFace5_Release(glyphenum->fontface);
6392 free(glyphenum);
6395 return refcount;
6398 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6400 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6401 FLOAT origin = 0.0f;
6403 if (g == 0)
6404 return 0.0f;
6406 while (g--)
6407 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6408 return origin;
6411 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6413 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6414 FLOAT advance_adj = 0.0f;
6415 BOOL got_palette_index;
6416 UINT32 g;
6418 /* start with regular glyphs */
6419 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6420 UINT32 first_glyph = 0;
6422 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6423 if (glyphenum->glyphs[g].num_layers == 0) {
6424 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6425 first_glyph = min(first_glyph, g);
6427 else
6428 glyphenum->glyphindices[g] = 1;
6429 glyphenum->color_advances[g] = glyphenum->advances[g];
6430 if (glyphenum->color_offsets)
6431 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6434 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6435 colorrun->baselineOriginY = glyphenum->origin_y;
6436 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6437 colorrun->paletteIndex = 0xffff;
6438 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6439 glyphenum->has_regular_glyphs = FALSE;
6440 return TRUE;
6442 else {
6443 colorrun->glyphRun.glyphCount = 0;
6444 got_palette_index = FALSE;
6447 advance_adj = 0.0f;
6448 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6450 glyphenum->glyphindices[g] = 1;
6452 /* all glyph layers were returned */
6453 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6454 advance_adj += glyphenum->advances[g];
6455 continue;
6458 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6459 UINT32 index = colorrun->glyphRun.glyphCount;
6460 if (!got_palette_index) {
6461 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6462 /* use foreground color or request one from the font */
6463 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6464 if (colorrun->paletteIndex != 0xffff)
6466 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6467 colorrun->paletteIndex, 1, &colorrun->runColor);
6468 if (FAILED(hr))
6469 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6470 glyphenum->palette, colorrun->paletteIndex, hr);
6472 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6473 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6474 colorrun->baselineOriginY = glyphenum->origin_y;
6475 glyphenum->color_advances[index] = glyphenum->advances[g];
6476 got_palette_index = TRUE;
6479 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6480 /* offsets are relative to glyph origin, nothing to fix up */
6481 if (glyphenum->color_offsets)
6482 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6483 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6484 if (index)
6485 glyphenum->color_advances[index-1] += advance_adj;
6486 colorrun->glyphRun.glyphCount++;
6487 advance_adj = 0.0f;
6489 else
6490 advance_adj += glyphenum->advances[g];
6493 /* reset last advance */
6494 if (colorrun->glyphRun.glyphCount)
6495 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6497 return colorrun->glyphRun.glyphCount > 0;
6500 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6502 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6504 TRACE("%p, %p.\n", iface, has_run);
6506 *has_run = FALSE;
6508 glyphenum->colorrun.glyphRun.glyphCount = 0;
6509 while (glyphenum->current_layer < glyphenum->max_layer_num)
6511 if (colorglyphenum_build_color_run(glyphenum))
6512 break;
6513 else
6514 glyphenum->current_layer++;
6517 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6519 return S_OK;
6522 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6523 DWRITE_COLOR_GLYPH_RUN1 const **run)
6525 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6527 *run = NULL;
6528 return E_NOT_VALID_STATE;
6531 *run = &glyphenum->colorrun;
6532 return S_OK;
6535 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6536 DWRITE_COLOR_GLYPH_RUN const **run)
6538 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6540 TRACE("%p, %p.\n", iface, run);
6542 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6545 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6546 DWRITE_COLOR_GLYPH_RUN1 const **run)
6548 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6550 TRACE("%p, %p.\n", iface, run);
6552 return colorglyphenum_get_current_run(glyphenum, run);
6555 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6557 colorglyphenum_QueryInterface,
6558 colorglyphenum_AddRef,
6559 colorglyphenum_Release,
6560 colorglyphenum_MoveNext,
6561 colorglyphenum_GetCurrentRun,
6562 colorglyphenum1_GetCurrentRun,
6565 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6566 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6567 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6569 struct dwrite_colorglyphenum *colorglyphenum;
6570 BOOL colorfont, has_colored_glyph;
6571 struct dwrite_fontface *fontface;
6572 unsigned int i;
6574 *ret = NULL;
6576 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6578 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6579 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6580 if (!colorfont)
6581 return DWRITE_E_NOCOLOR;
6583 if (!(colorglyphenum = calloc(1, sizeof(*colorglyphenum))))
6584 return E_OUTOFMEMORY;
6586 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6587 colorglyphenum->refcount = 1;
6588 colorglyphenum->origin_x = originX;
6589 colorglyphenum->origin_y = originY;
6590 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6591 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6592 colorglyphenum->glyphs = NULL;
6593 colorglyphenum->run = *run;
6594 colorglyphenum->run.glyphIndices = NULL;
6595 colorglyphenum->run.glyphAdvances = NULL;
6596 colorglyphenum->run.glyphOffsets = NULL;
6597 colorglyphenum->palette = palette;
6598 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6599 colorglyphenum->colr.exists = TRUE;
6600 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6601 colorglyphenum->current_layer = 0;
6602 colorglyphenum->max_layer_num = 0;
6604 colorglyphenum->glyphs = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphs));
6606 has_colored_glyph = FALSE;
6607 colorglyphenum->has_regular_glyphs = FALSE;
6608 for (i = 0; i < run->glyphCount; i++) {
6609 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6610 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6611 has_colored_glyph = TRUE;
6613 if (colorglyphenum->glyphs[i].num_layers == 0)
6614 colorglyphenum->has_regular_glyphs = TRUE;
6617 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6618 is supposed to proceed normally, like if font had no color info at all. */
6619 if (!has_colored_glyph) {
6620 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6621 return DWRITE_E_NOCOLOR;
6624 colorglyphenum->advances = calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6625 colorglyphenum->color_advances = calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6626 colorglyphenum->glyphindices = calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6627 if (run->glyphOffsets) {
6628 colorglyphenum->offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6629 colorglyphenum->color_offsets = calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6630 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6633 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6634 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6635 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6636 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6637 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6638 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6639 colorglyphenum->colorrun.measuringMode = measuring_mode;
6640 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6642 if (run->glyphAdvances)
6643 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6644 else
6646 for (i = 0; i < run->glyphCount; ++i)
6647 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6648 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6651 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6653 return S_OK;
6656 /* IDWriteFontFaceReference */
6657 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6659 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6661 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6662 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6663 IsEqualIID(riid, &IID_IUnknown))
6665 *obj = iface;
6666 IDWriteFontFaceReference1_AddRef(iface);
6667 return S_OK;
6670 WARN("%s not implemented.\n", debugstr_guid(riid));
6672 *obj = NULL;
6674 return E_NOINTERFACE;
6677 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6679 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6680 ULONG refcount = InterlockedIncrement(&reference->refcount);
6682 TRACE("%p, refcount %u.\n", iface, refcount);
6684 return refcount;
6687 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6689 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6690 ULONG refcount = InterlockedDecrement(&reference->refcount);
6692 TRACE("%p, refcount %u.\n", iface, refcount);
6694 if (!refcount)
6696 IDWriteFontFile_Release(reference->file);
6697 IDWriteFactory7_Release(reference->factory);
6698 free(reference->axis_values);
6699 free(reference);
6702 return refcount;
6705 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6707 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6709 TRACE("%p, %p.\n", iface, fontface);
6711 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6714 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6715 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6717 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6718 DWRITE_FONT_FILE_TYPE file_type;
6719 DWRITE_FONT_FACE_TYPE face_type;
6720 IDWriteFontFace *fontface;
6721 BOOL is_supported;
6722 UINT32 face_num;
6723 HRESULT hr;
6725 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6727 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6728 if (FAILED(hr))
6729 return hr;
6731 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6732 simulations, &fontface);
6733 if (SUCCEEDED(hr))
6735 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6736 IDWriteFontFace_Release(fontface);
6739 return hr;
6742 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6744 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6745 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6746 BOOL ret;
6748 TRACE("%p, %p.\n", iface, ref);
6750 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6751 reference->simulations == other->simulations;
6752 if (reference->axis_values_count)
6754 ret &= reference->axis_values_count == other->axis_values_count &&
6755 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6758 return ret;
6761 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6763 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6765 TRACE("%p.\n", iface);
6767 return reference->index;
6770 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6772 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6774 TRACE("%p.\n", iface);
6776 return reference->simulations;
6779 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6781 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6782 IDWriteFontFileLoader *loader;
6783 const void *key;
6784 UINT32 key_size;
6785 HRESULT hr;
6787 TRACE("%p, %p.\n", iface, file);
6789 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6790 if (FAILED(hr))
6791 return hr;
6793 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6794 if (FAILED(hr))
6795 return hr;
6797 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6798 IDWriteFontFileLoader_Release(loader);
6800 return hr;
6803 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6805 FIXME("%p.\n", iface);
6807 return 0;
6810 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6812 FIXME("%p.\n", iface);
6814 return 0;
6817 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6819 FIXME("%p, %p.\n", iface, writetime);
6821 return E_NOTIMPL;
6824 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6826 FIXME("%p.\n", iface);
6828 return DWRITE_LOCALITY_LOCAL;
6831 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6833 FIXME("%p.\n", iface);
6835 return E_NOTIMPL;
6838 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6839 WCHAR const *chars, UINT32 count)
6841 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6843 return E_NOTIMPL;
6846 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6847 UINT16 const *glyphs, UINT32 count)
6849 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6851 return E_NOTIMPL;
6854 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6855 UINT64 offset, UINT64 size)
6857 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6859 return E_NOTIMPL;
6862 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6864 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6865 IDWriteFontFace3 *fontface3;
6866 HRESULT hr;
6868 TRACE("%p, %p.\n", iface, fontface);
6870 /* FIXME: created instance should likely respect given axis. */
6871 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6872 &fontface3)))
6874 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6875 IDWriteFontFace3_Release(fontface3);
6878 return hr;
6881 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6883 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6885 TRACE("%p.\n", iface);
6887 return reference->axis_values_count;
6890 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6891 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6893 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6895 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6897 if (value_count < reference->axis_values_count)
6898 return E_NOT_SUFFICIENT_BUFFER;
6900 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6902 return S_OK;
6905 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6907 fontfacereference_QueryInterface,
6908 fontfacereference_AddRef,
6909 fontfacereference_Release,
6910 fontfacereference_CreateFontFace,
6911 fontfacereference_CreateFontFaceWithSimulations,
6912 fontfacereference_Equals,
6913 fontfacereference_GetFontFaceIndex,
6914 fontfacereference_GetSimulations,
6915 fontfacereference_GetFontFile,
6916 fontfacereference_GetLocalFileSize,
6917 fontfacereference_GetFileSize,
6918 fontfacereference_GetFileTime,
6919 fontfacereference_GetLocality,
6920 fontfacereference_EnqueueFontDownloadRequest,
6921 fontfacereference_EnqueueCharacterDownloadRequest,
6922 fontfacereference_EnqueueGlyphDownloadRequest,
6923 fontfacereference_EnqueueFileFragmentDownloadRequest,
6924 fontfacereference1_CreateFontFace,
6925 fontfacereference1_GetFontAxisValueCount,
6926 fontfacereference1_GetFontAxisValues,
6929 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6930 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6931 IDWriteFontFaceReference1 **ret)
6933 struct dwrite_fontfacereference *object;
6935 *ret = NULL;
6937 if (!is_simulation_valid(simulations))
6938 return E_INVALIDARG;
6940 if (!(object = calloc(1, sizeof(*object))))
6941 return E_OUTOFMEMORY;
6943 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6944 object->refcount = 1;
6946 object->factory = factory;
6947 IDWriteFactory7_AddRef(object->factory);
6948 object->file = file;
6949 IDWriteFontFile_AddRef(object->file);
6950 object->index = index;
6951 object->simulations = simulations;
6952 if (axis_values_count)
6954 if (!(object->axis_values = malloc(axis_values_count * sizeof(*axis_values))))
6956 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6957 return E_OUTOFMEMORY;
6959 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6960 object->axis_values_count = axis_values_count;
6963 *ret = &object->IDWriteFontFaceReference1_iface;
6965 return S_OK;
6968 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6970 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6972 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6973 *obj = iface;
6974 IDWriteFontFileStream_AddRef(iface);
6975 return S_OK;
6978 *obj = NULL;
6980 WARN("%s not implemented.\n", debugstr_guid(riid));
6981 return E_NOINTERFACE;
6984 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6986 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6987 ULONG refcount = InterlockedIncrement(&stream->refcount);
6989 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6991 return refcount;
6994 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6996 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6997 ULONG refcount = InterlockedDecrement(&stream->refcount);
6999 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
7001 if (!refcount)
7003 release_inmemory_stream(stream->data);
7004 free(stream);
7007 return refcount;
7010 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
7011 UINT64 offset, UINT64 fragment_size, void **fragment_context)
7013 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7015 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
7016 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
7018 *fragment_context = NULL;
7020 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
7021 *fragment_start = NULL;
7022 return E_FAIL;
7025 *fragment_start = (char *)stream->data->data + offset;
7026 return S_OK;
7029 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
7031 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
7034 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
7036 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
7038 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
7040 *size = stream->data->size;
7042 return S_OK;
7045 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
7047 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
7049 *last_writetime = 0;
7051 return E_NOTIMPL;
7054 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
7055 inmemoryfilestream_QueryInterface,
7056 inmemoryfilestream_AddRef,
7057 inmemoryfilestream_Release,
7058 inmemoryfilestream_ReadFileFragment,
7059 inmemoryfilestream_ReleaseFileFragment,
7060 inmemoryfilestream_GetFileSize,
7061 inmemoryfilestream_GetLastWriteTime,
7064 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
7065 REFIID riid, void **obj)
7067 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7069 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
7070 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
7071 IsEqualIID(riid, &IID_IUnknown))
7073 *obj = iface;
7074 IDWriteInMemoryFontFileLoader_AddRef(iface);
7075 return S_OK;
7078 WARN("%s not implemented.\n", debugstr_guid(riid));
7080 *obj = NULL;
7082 return E_NOINTERFACE;
7085 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
7087 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7088 ULONG refcount = InterlockedIncrement(&loader->refcount);
7090 TRACE("%p, refcount %u.\n", iface, refcount);
7092 return refcount;
7095 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
7097 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7098 ULONG refcount = InterlockedDecrement(&loader->refcount);
7099 size_t i;
7101 TRACE("%p, refcount %u.\n", iface, refcount);
7103 if (!refcount)
7105 for (i = 0; i < loader->count; ++i)
7106 release_inmemory_stream(loader->streams[i]);
7107 free(loader->streams);
7108 free(loader);
7111 return refcount;
7114 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
7115 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
7117 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7118 struct dwrite_inmemory_filestream *stream;
7119 DWORD index;
7121 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
7123 *ret = NULL;
7125 if (key_size != sizeof(DWORD))
7126 return E_INVALIDARG;
7128 index = *(DWORD *)key;
7130 if (index >= loader->count)
7131 return E_INVALIDARG;
7133 if (!(stream = malloc(sizeof(*stream))))
7134 return E_OUTOFMEMORY;
7136 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
7137 stream->refcount = 1;
7138 stream->data = loader->streams[index];
7139 InterlockedIncrement(&stream->data->refcount);
7141 *ret = &stream->IDWriteFontFileStream_iface;
7143 return S_OK;
7146 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
7147 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
7149 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7150 struct dwrite_inmemory_stream_data *stream;
7151 DWORD key;
7153 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
7155 *fontfile = NULL;
7157 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
7158 return E_OUTOFMEMORY;
7160 if (!(stream = malloc(sizeof(*stream))))
7161 return E_OUTOFMEMORY;
7163 stream->refcount = 1;
7164 stream->size = data_size;
7165 stream->owner = owner;
7166 if (stream->owner) {
7167 IUnknown_AddRef(stream->owner);
7168 stream->data = (void *)data;
7170 else {
7171 if (!(stream->data = malloc(data_size)))
7173 free(stream);
7174 return E_OUTOFMEMORY;
7176 memcpy(stream->data, data, data_size);
7179 key = loader->count;
7180 loader->streams[loader->count++] = stream;
7182 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
7183 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
7186 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
7188 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
7190 TRACE("%p.\n", iface);
7192 return loader->count;
7195 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
7197 inmemoryfontfileloader_QueryInterface,
7198 inmemoryfontfileloader_AddRef,
7199 inmemoryfontfileloader_Release,
7200 inmemoryfontfileloader_CreateStreamFromKey,
7201 inmemoryfontfileloader_CreateInMemoryFontFileReference,
7202 inmemoryfontfileloader_GetFileCount,
7205 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
7207 struct dwrite_inmemory_fileloader *loader;
7209 *ret = NULL;
7211 if (!(loader = calloc(1, sizeof(*loader))))
7212 return E_OUTOFMEMORY;
7214 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
7215 loader->refcount = 1;
7217 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
7219 return S_OK;
7222 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
7224 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7226 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
7227 IsEqualIID(riid, &IID_IUnknown))
7229 *obj = iface;
7230 IDWriteFontResource_AddRef(iface);
7231 return S_OK;
7234 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7236 return E_NOINTERFACE;
7239 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
7241 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7242 ULONG refcount = InterlockedIncrement(&resource->refcount);
7244 TRACE("%p, refcount %u.\n", iface, refcount);
7246 return refcount;
7249 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
7251 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7252 ULONG refcount = InterlockedDecrement(&resource->refcount);
7254 TRACE("%p, refcount %u.\n", iface, refcount);
7256 if (!refcount)
7258 IDWriteFactory7_Release(resource->factory);
7259 IDWriteFontFile_Release(resource->file);
7260 free(resource);
7263 return refcount;
7266 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
7268 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7270 TRACE("%p, %p.\n", iface, fontfile);
7272 *fontfile = resource->file;
7273 IDWriteFontFile_AddRef(*fontfile);
7275 return S_OK;
7278 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
7280 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7282 TRACE("%p.\n", iface);
7284 return resource->face_index;
7287 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
7289 FIXME("%p.\n", iface);
7291 return 0;
7294 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
7295 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
7297 FIXME("%p, %p, %u.\n", iface, values, num_values);
7299 return E_NOTIMPL;
7302 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7303 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
7305 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
7307 return E_NOTIMPL;
7310 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7311 UINT32 axis)
7313 FIXME("%p, %u.\n", iface, axis);
7315 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
7318 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7319 IDWriteLocalizedStrings **names)
7321 FIXME("%p, %u, %p.\n", iface, axis, names);
7323 return E_NOTIMPL;
7326 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7328 FIXME("%p, %u.\n", iface, axis);
7330 return 0;
7333 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7334 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7336 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7338 return E_NOTIMPL;
7341 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7343 FIXME("%p.\n", iface);
7345 return FALSE;
7348 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7349 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7350 IDWriteFontFace5 **fontface)
7352 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7353 IDWriteFontFaceReference1 *reference;
7354 HRESULT hr;
7356 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7358 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7359 simulations, axis_values, num_values, &reference);
7360 if (SUCCEEDED(hr))
7362 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7363 IDWriteFontFaceReference1_Release(reference);
7366 return hr;
7369 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7370 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7371 IDWriteFontFaceReference1 **reference)
7373 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7375 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7377 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7378 simulations, axis_values, num_values, reference);
7381 static const IDWriteFontResourceVtbl fontresourcevtbl =
7383 dwritefontresource_QueryInterface,
7384 dwritefontresource_AddRef,
7385 dwritefontresource_Release,
7386 dwritefontresource_GetFontFile,
7387 dwritefontresource_GetFontFaceIndex,
7388 dwritefontresource_GetFontAxisCount,
7389 dwritefontresource_GetDefaultFontAxisValues,
7390 dwritefontresource_GetFontAxisRanges,
7391 dwritefontresource_GetFontAxisAttributes,
7392 dwritefontresource_GetAxisNames,
7393 dwritefontresource_GetAxisValueNameCount,
7394 dwritefontresource_GetAxisValueNames,
7395 dwritefontresource_HasVariations,
7396 dwritefontresource_CreateFontFace,
7397 dwritefontresource_CreateFontFaceReference,
7400 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7401 IDWriteFontResource **ret)
7403 struct dwrite_fontresource *resource;
7405 *ret = NULL;
7407 if (!(resource = calloc(1, sizeof(*resource))))
7408 return E_OUTOFMEMORY;
7410 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7411 resource->refcount = 1;
7412 resource->face_index = face_index;
7413 resource->file = file;
7414 IDWriteFontFile_AddRef(resource->file);
7415 resource->factory = factory;
7416 IDWriteFactory7_AddRef(resource->factory);
7418 *ret = &resource->IDWriteFontResource_iface;
7420 return S_OK;
7423 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7425 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7427 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7428 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7429 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7430 IsEqualIID(riid, &IID_IDWriteFontSet))
7432 *obj = iface;
7433 IDWriteFontSet3_AddRef(iface);
7434 return S_OK;
7437 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7438 *obj = NULL;
7439 return E_NOINTERFACE;
7442 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7444 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7445 ULONG refcount = InterlockedIncrement(&set->refcount);
7447 TRACE("%p, refcount %u.\n", iface, refcount);
7449 return refcount;
7452 #define MISSING_SET_PROP ((void *)0x1)
7454 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7456 unsigned int i;
7458 if (InterlockedDecrement(&entry->refcount) > 0)
7459 return;
7460 IDWriteFontFile_Release(entry->file);
7461 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7463 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7464 IDWriteLocalizedStrings_Release(entry->props[i]);
7466 free(entry);
7469 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7471 InterlockedIncrement(&entry->refcount);
7472 return entry;
7475 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7476 DWRITE_FONT_PROPERTY_ID property)
7478 struct file_stream_desc stream_desc = { 0 };
7479 IDWriteLocalizedStrings *value;
7481 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7483 if (entry->props[property] == MISSING_SET_PROP)
7484 return NULL;
7486 if ((value = entry->props[property]))
7488 IDWriteLocalizedStrings_AddRef(value);
7489 return value;
7492 get_filestream_from_file(entry->file, &stream_desc.stream);
7493 stream_desc.face_type = entry->face_type;
7494 stream_desc.face_index = entry->face_index;
7496 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7497 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7498 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7499 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7500 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7501 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7502 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7503 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7504 else
7505 WARN("Unsupported property %u.\n", property);
7507 if (stream_desc.stream)
7508 IDWriteFontFileStream_Release(stream_desc.stream);
7510 if (value)
7512 entry->props[property] = value;
7513 IDWriteLocalizedStrings_AddRef(value);
7515 else
7516 entry->props[property] = MISSING_SET_PROP;
7518 return value;
7521 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7522 struct dwrite_fontset_entry **entries, unsigned int count);
7524 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7526 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7527 ULONG refcount = InterlockedDecrement(&set->refcount);
7528 unsigned int i;
7530 TRACE("%p, refcount %u.\n", iface, refcount);
7532 if (!refcount)
7534 IDWriteFactory7_Release(set->factory);
7535 for (i = 0; i < set->count; ++i)
7536 release_fontset_entry(set->entries[i]);
7537 free(set->entries);
7538 free(set);
7541 return refcount;
7544 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7546 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7548 TRACE("%p.\n", iface);
7550 return set->count;
7553 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7554 IDWriteFontFaceReference **reference)
7556 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7558 TRACE("%p, %u, %p.\n", iface, index, reference);
7560 *reference = NULL;
7562 if (index >= set->count)
7563 return E_INVALIDARG;
7565 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->file,
7566 set->entries[index]->face_index, set->entries[index]->simulations, reference);
7569 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7570 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7572 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7574 return E_NOTIMPL;
7577 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7578 UINT32 *index, BOOL *exists)
7580 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7582 return E_NOTIMPL;
7585 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7586 IDWriteStringList **values)
7588 FIXME("%p, %d, %p.\n", iface, id, values);
7590 return E_NOTIMPL;
7593 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7594 WCHAR const *preferred_locales, IDWriteStringList **values)
7596 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7598 return E_NOTIMPL;
7601 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7602 BOOL *exists, IDWriteLocalizedStrings **values)
7604 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7606 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7608 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7609 index >= set->count)
7611 *values = NULL;
7612 *exists = FALSE;
7613 return E_INVALIDARG;
7616 *values = fontset_entry_get_property(set->entries[index], id);
7617 *exists = !!*values;
7619 return S_OK;
7622 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7623 UINT32 *count)
7625 FIXME("%p, %p, %p.\n", iface, property, count);
7627 return E_NOTIMPL;
7630 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7631 unsigned int count)
7633 IDWriteLocalizedStrings *value;
7634 unsigned int i;
7635 BOOL ret;
7637 for (i = 0; i < count; ++i)
7639 switch (props[i].propertyId)
7641 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7642 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7643 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7644 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7645 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7646 return FALSE;
7648 ret = localizedstrings_contains(value, props[i].propertyValue);
7649 IDWriteLocalizedStrings_Release(value);
7650 if (!ret) return FALSE;
7651 break;
7652 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7653 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7654 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7655 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7656 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7657 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7658 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7659 case DWRITE_FONT_PROPERTY_ID_STYLE:
7660 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7661 FIXME("Unsupported property %d.\n", props[i].propertyId);
7662 /* fallthrough */
7663 default:
7664 return FALSE;
7668 return TRUE;
7671 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7672 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7674 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7676 return E_NOTIMPL;
7679 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7680 IDWriteFontSet **filtered_set)
7682 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7683 struct dwrite_fontset_entry **entries;
7684 unsigned int i, matched_count = 0;
7685 struct dwrite_fontset *object;
7687 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7689 if (!props && count)
7690 return E_INVALIDARG;
7692 if (!(object = calloc(1, sizeof(*object))))
7693 return E_OUTOFMEMORY;
7695 if (!(entries = calloc(set->count, sizeof(*entries))))
7697 free(object);
7698 return E_OUTOFMEMORY;
7701 for (i = 0; i < set->count; ++i)
7703 if (fontset_entry_is_matching(set->entries[i], props, count))
7705 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7709 if (!matched_count)
7711 free(entries);
7712 entries = NULL;
7715 init_fontset(object, set->factory, entries, matched_count);
7717 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7719 return S_OK;
7722 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7723 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7725 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7727 return E_NOTIMPL;
7730 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7732 FIXME("%p, %p.\n", iface, fontset);
7734 return E_NOTIMPL;
7737 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7738 UINT32 num_indices, IDWriteFontSet1 **fontset)
7740 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7742 return E_NOTIMPL;
7745 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7746 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7748 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7750 return E_NOTIMPL;
7753 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7754 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7756 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7758 return E_NOTIMPL;
7761 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7762 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7764 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7766 return E_NOTIMPL;
7769 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7770 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7772 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7773 num_indices, actual_num_indices);
7775 return E_NOTIMPL;
7778 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7779 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7781 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7783 return E_NOTIMPL;
7786 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7787 UINT32 num_ranges, UINT32 *actual_num_ranges)
7789 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7791 return E_NOTIMPL;
7794 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7795 IDWriteFontFaceReference1 **reference)
7797 FIXME("%p, %u, %p.\n", iface, index, reference);
7799 return E_NOTIMPL;
7802 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
7804 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7806 TRACE("%p, %u, %p.\n", iface, index, resource);
7808 *resource = NULL;
7810 if (index >= set->count)
7811 return E_INVALIDARG;
7813 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->file,
7814 set->entries[index]->face_index, resource);
7817 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
7819 FIXME("%p, %u, %p.\n", iface, index, fontface);
7821 return E_NOTIMPL;
7824 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
7826 FIXME("%p, %u.\n", iface, index);
7828 return DWRITE_LOCALITY_LOCAL;
7831 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
7833 FIXME("%p.\n", iface);
7835 return NULL;
7838 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
7840 FIXME("%p, %u.\n", iface, index);
7842 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
7845 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
7847 FIXME("%p, %u.\n", iface, index);
7849 return 0;
7852 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
7854 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
7856 return E_NOTIMPL;
7859 static const IDWriteFontSet3Vtbl fontsetvtbl =
7861 dwritefontset_QueryInterface,
7862 dwritefontset_AddRef,
7863 dwritefontset_Release,
7864 dwritefontset_GetFontCount,
7865 dwritefontset_GetFontFaceReference,
7866 dwritefontset_FindFontFaceReference,
7867 dwritefontset_FindFontFace,
7868 dwritefontset_GetPropertyValues__,
7869 dwritefontset_GetPropertyValues_,
7870 dwritefontset_GetPropertyValues,
7871 dwritefontset_GetPropertyOccurrenceCount,
7872 dwritefontset_GetMatchingFonts_,
7873 dwritefontset_GetMatchingFonts,
7874 dwritefontset1_GetMatchingFonts,
7875 dwritefontset1_GetFirstFontResources,
7876 dwritefontset1_GetFilteredFonts__,
7877 dwritefontset1_GetFilteredFonts_,
7878 dwritefontset1_GetFilteredFonts,
7879 dwritefontset1_GetFilteredFontIndices_,
7880 dwritefontset1_GetFilteredFontIndices,
7881 dwritefontset1_GetFontAxisRanges_,
7882 dwritefontset1_GetFontAxisRanges,
7883 dwritefontset1_GetFontFaceReference,
7884 dwritefontset1_CreateFontResource,
7885 dwritefontset1_CreateFontFace,
7886 dwritefontset1_GetFontLocality,
7887 dwritefontset2_GetExpirationEvent,
7888 dwritefontset3_GetFontSourceType,
7889 dwritefontset3_GetFontSourceNameLength,
7890 dwritefontset3_GetFontSourceName,
7893 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
7894 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
7896 struct dwrite_fontset_entry *entry;
7898 if (!(entry = calloc(1, sizeof(*entry))))
7899 return E_OUTOFMEMORY;
7901 entry->refcount = 1;
7902 entry->file = file;
7903 IDWriteFontFile_AddRef(entry->file);
7904 entry->face_type = face_type;
7905 entry->face_index = face_index;
7906 entry->simulations = simulations;
7908 *ret = entry;
7910 return S_OK;
7913 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7914 struct dwrite_fontset_entry **entries, unsigned int count)
7916 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
7917 object->refcount = 1;
7918 object->factory = factory;
7919 IDWriteFactory7_AddRef(object->factory);
7920 object->entries = entries;
7921 object->count = count;
7924 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
7925 unsigned int count, IDWriteFontSet1 **ret)
7927 struct dwrite_fontset_entry **entries = NULL;
7928 struct dwrite_fontset *object;
7929 unsigned int i;
7931 if (!(object = calloc(1, sizeof(*object))))
7932 return E_OUTOFMEMORY;
7934 if (count)
7936 entries = calloc(count, sizeof(*entries));
7938 /* FIXME: set available properties too */
7940 for (i = 0; i < count; ++i)
7942 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
7943 fonts[i]->simulations, &entries[i]);
7946 init_fontset(object, factory, entries, count);
7948 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
7950 return S_OK;
7953 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
7954 unsigned int count, IDWriteFontSet **ret)
7956 struct dwrite_fontset_entry **entries = NULL;
7957 struct dwrite_fontset *object;
7958 unsigned int i;
7960 if (!(object = calloc(1, sizeof(*object))))
7961 return E_OUTOFMEMORY;
7963 if (count)
7965 entries = calloc(count, sizeof(*entries));
7967 for (i = 0; i < count; ++i)
7968 entries[i] = addref_fontset_entry(src_entries[i]);
7970 init_fontset(object, factory, entries, count);
7972 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7974 return S_OK;
7977 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
7978 REFIID riid, void **obj)
7980 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7982 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
7983 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
7984 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
7985 IsEqualIID(riid, &IID_IUnknown))
7987 *obj = iface;
7988 IDWriteFontSetBuilder2_AddRef(iface);
7989 return S_OK;
7992 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7993 *obj = NULL;
7994 return E_NOINTERFACE;
7997 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
7999 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8000 ULONG refcount = InterlockedIncrement(&builder->refcount);
8002 TRACE("%p, refcount %u.\n", iface, refcount);
8004 return refcount;
8007 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
8009 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8010 ULONG refcount = InterlockedDecrement(&builder->refcount);
8011 unsigned int i;
8013 TRACE("%p, refcount %u.\n", iface, refcount);
8015 if (!refcount)
8017 IDWriteFactory7_Release(builder->factory);
8018 for (i = 0; i < builder->count; ++i)
8019 release_fontset_entry(builder->entries[i]);
8020 free(builder->entries);
8021 free(builder);
8024 return refcount;
8027 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, IDWriteFontFile *file,
8028 DWRITE_FONT_FACE_TYPE face_type, unsigned int face_index, unsigned int simulations)
8030 struct dwrite_fontset_entry *entry;
8031 HRESULT hr;
8033 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
8034 sizeof(*builder->entries)))
8036 return E_OUTOFMEMORY;
8039 if (FAILED(hr = fontset_create_entry(file, face_type, face_index, simulations, &entry)))
8040 return hr;
8042 builder->entries[builder->count++] = entry;
8044 return S_OK;
8047 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
8049 DWRITE_FONT_FILE_TYPE filetype;
8050 DWRITE_FONT_FACE_TYPE facetype;
8051 unsigned int i, face_count;
8052 BOOL supported = FALSE;
8053 HRESULT hr;
8055 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &filetype, &facetype, &face_count)))
8056 return hr;
8058 if (!supported)
8059 return DWRITE_E_FILEFORMAT;
8061 for (i = 0; i < face_count; ++i)
8063 if (FAILED(hr = fontset_builder_add_entry(builder, file, facetype, i, DWRITE_FONT_SIMULATIONS_NONE)))
8064 break;
8067 return hr;
8070 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
8071 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
8073 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
8075 return E_NOTIMPL;
8078 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
8079 IDWriteFontFaceReference *ref)
8081 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8082 unsigned int face_count, face_index, simulations;
8083 DWRITE_FONT_FILE_TYPE file_type;
8084 DWRITE_FONT_FACE_TYPE face_type;
8085 IDWriteFontFile *file;
8086 BOOL supported;
8087 HRESULT hr;
8089 TRACE("%p, %p.\n", iface, ref);
8091 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(ref, &file))) return hr;
8092 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
8093 goto done;
8095 if (!supported)
8097 hr = DWRITE_E_FILEFORMAT;
8098 goto done;
8101 face_index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
8102 simulations = IDWriteFontFaceReference_GetSimulations(ref);
8103 hr = fontset_builder_add_entry(builder, file, face_type, face_index, simulations);
8105 done:
8106 IDWriteFontFile_Release(file);
8108 return hr;
8111 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
8113 FIXME("%p, %p.\n", iface, fontset);
8115 return E_NOTIMPL;
8118 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
8120 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8122 TRACE("%p, %p.\n", iface, fontset);
8124 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
8127 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
8129 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8131 TRACE("%p, %p.\n", iface, file);
8133 return fontset_builder_add_file(builder, file);
8136 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
8137 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
8138 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
8139 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
8141 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
8142 axis_ranges, num_ranges, props, num_properties);
8144 return E_NOTIMPL;
8147 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
8149 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
8150 IDWriteFontFile *file;
8151 HRESULT hr;
8153 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
8155 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
8156 return hr;
8158 hr = fontset_builder_add_file(builder, file);
8159 IDWriteFontFile_Release(file);
8160 return hr;
8163 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
8165 dwritefontsetbuilder_QueryInterface,
8166 dwritefontsetbuilder_AddRef,
8167 dwritefontsetbuilder_Release,
8168 dwritefontsetbuilder_AddFontFaceReference_,
8169 dwritefontsetbuilder_AddFontFaceReference,
8170 dwritefontsetbuilder_AddFontSet,
8171 dwritefontsetbuilder_CreateFontSet,
8172 dwritefontsetbuilder1_AddFontFile,
8173 dwritefontsetbuilder2_AddFont,
8174 dwritefontsetbuilder2_AddFontFile,
8177 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
8179 struct dwrite_fontset_builder *builder;
8181 *ret = NULL;
8183 if (!(builder = calloc(1, sizeof(*builder))))
8184 return E_OUTOFMEMORY;
8186 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
8187 builder->refcount = 1;
8188 builder->factory = factory;
8189 IDWriteFactory7_AddRef(builder->factory);
8191 *ret = &builder->IDWriteFontSetBuilder2_iface;
8193 return S_OK;