dwrite/tests: Add some tests for CreateFontCollectionFromFontSet().
[wine/zf.git] / dlls / dwrite / font.c
blob245a59d5f545029a03ab7f8af44c98ab3e7b013b
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
31 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
33 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
34 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
44 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
45 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
46 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
48 static const WCHAR extraW[] = {'e','x','t','r','a',0};
49 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
50 static const WCHAR semiW[] = {'s','e','m','i',0};
51 static const WCHAR extW[] = {'e','x','t',0};
52 static const WCHAR thinW[] = {'t','h','i','n',0};
53 static const WCHAR lightW[] = {'l','i','g','h','t',0};
54 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
55 static const WCHAR blackW[] = {'b','l','a','c','k',0};
56 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
57 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
58 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
59 static const WCHAR boldW[] = {'B','o','l','d',0};
60 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
61 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
62 static const WCHAR demiW[] = {'d','e','m','i',0};
63 static const WCHAR spaceW[] = {' ',0};
64 static const WCHAR enusW[] = {'e','n','-','u','s',0};
66 struct dwrite_font_propvec {
67 FLOAT stretch;
68 FLOAT style;
69 FLOAT weight;
72 struct dwrite_font_data
74 LONG refcount;
76 DWRITE_FONT_STYLE style;
77 DWRITE_FONT_STRETCH stretch;
78 DWRITE_FONT_WEIGHT weight;
79 DWRITE_PANOSE panose;
80 FONTSIGNATURE fontsig;
81 UINT32 flags; /* enum font_flags */
82 struct dwrite_font_propvec propvec;
83 struct dwrite_cmap cmap;
84 /* Static axis for weight/width/italic. */
85 DWRITE_FONT_AXIS_VALUE axis[3];
87 DWRITE_FONT_METRICS1 metrics;
88 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
89 IDWriteLocalizedStrings *family_names;
90 IDWriteLocalizedStrings *names;
92 /* data needed to create fontface instance */
93 DWRITE_FONT_FACE_TYPE face_type;
94 IDWriteFontFile *file;
95 UINT32 face_index;
97 WCHAR *facename;
99 USHORT simulations;
101 LOGFONTW lf;
103 /* used to mark font as tested when scanning for simulation candidate */
104 unsigned int bold_sim_tested : 1;
105 unsigned int oblique_sim_tested : 1;
108 struct dwrite_fontfamily_data
110 LONG refcount;
112 IDWriteLocalizedStrings *familyname;
114 struct dwrite_font_data **fonts;
115 size_t size;
116 size_t count;
118 unsigned int has_normal_face : 1;
119 unsigned int has_oblique_face : 1;
120 unsigned int has_italic_face : 1;
123 struct dwrite_fontcollection
125 IDWriteFontCollection3 IDWriteFontCollection3_iface;
126 LONG refcount;
128 IDWriteFactory7 *factory;
129 struct dwrite_fontfamily_data **family_data;
130 size_t size;
131 size_t count;
134 struct dwrite_fontfamily
136 IDWriteFontFamily2 IDWriteFontFamily2_iface;
137 IDWriteFontList2 IDWriteFontList2_iface;
138 LONG refcount;
140 struct dwrite_fontfamily_data *data;
141 struct dwrite_fontcollection *collection;
144 struct dwrite_fontlist
146 IDWriteFontList2 IDWriteFontList2_iface;
147 LONG refcount;
149 struct dwrite_font_data **fonts;
150 UINT32 font_count;
151 struct dwrite_fontfamily *family;
154 struct dwrite_font
156 IDWriteFont3 IDWriteFont3_iface;
157 LONG refcount;
159 DWRITE_FONT_STYLE style;
160 struct dwrite_font_data *data;
161 struct dwrite_fontfamily *family;
164 enum runanalysis_flags {
165 RUNANALYSIS_BOUNDS_READY = 1 << 0,
166 RUNANALYSIS_BITMAP_READY = 1 << 1,
167 RUNANALYSIS_USE_TRANSFORM = 1 << 2
170 struct dwrite_glyphrunanalysis
172 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
173 LONG refcount;
175 DWRITE_RENDERING_MODE1 rendering_mode;
176 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
177 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
178 DWRITE_MATRIX m;
179 UINT16 *glyphs;
180 D2D_POINT_2F *origins;
182 UINT8 flags;
183 RECT bounds;
184 BYTE *bitmap;
185 UINT32 max_glyph_bitmap_size;
188 struct dwrite_colorglyphenum
190 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
191 LONG refcount;
193 FLOAT origin_x; /* original run origin */
194 FLOAT origin_y;
196 IDWriteFontFace5 *fontface; /* for convenience */
197 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
198 DWRITE_GLYPH_RUN run; /* base run */
199 UINT32 palette; /* palette index to get layer color from */
200 FLOAT *advances; /* original or measured advances for base glyphs */
201 FLOAT *color_advances; /* returned color run points to this */
202 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
203 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
204 UINT16 *glyphindices; /* returned color run points to this */
205 struct dwrite_colorglyph *glyphs; /* current glyph color info */
206 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
207 UINT16 current_layer; /* enumerator position, updated with MoveNext */
208 UINT16 max_layer_num; /* max number of layers for this run */
209 struct dwrite_fonttable colr; /* used to access layers */
212 #define GLYPH_BLOCK_SHIFT 8
213 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
214 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
215 #define GLYPH_MAX 65536
217 struct dwrite_fontfile
219 IDWriteFontFile IDWriteFontFile_iface;
220 LONG refcount;
222 IDWriteFontFileLoader *loader;
223 void *reference_key;
224 UINT32 key_size;
225 IDWriteFontFileStream *stream;
228 struct dwrite_fontfacereference
230 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
231 LONG refcount;
233 IDWriteFontFile *file;
234 UINT32 index;
235 USHORT simulations;
236 DWRITE_FONT_AXIS_VALUE *axis_values;
237 UINT32 axis_values_count;
238 IDWriteFactory7 *factory;
241 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
243 struct dwrite_fontresource
245 IDWriteFontResource IDWriteFontResource_iface;
246 LONG refcount;
248 IDWriteFontFile *file;
249 UINT32 face_index;
250 IDWriteFactory7 *factory;
253 struct dwrite_fontset_entry
255 LONG refcount;
256 IDWriteFontFile *file;
257 DWRITE_FONT_FACE_TYPE face_type;
258 unsigned int face_index;
259 unsigned int simulations;
260 IDWriteLocalizedStrings *props[DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME + 1];
263 struct dwrite_fontset
265 IDWriteFontSet3 IDWriteFontSet3_iface;
266 LONG refcount;
267 IDWriteFactory7 *factory;
269 struct dwrite_fontset_entry **entries;
270 unsigned int count;
273 struct dwrite_fontset_builder
275 IDWriteFontSetBuilder2 IDWriteFontSetBuilder2_iface;
276 LONG refcount;
277 IDWriteFactory7 *factory;
279 struct dwrite_fontset_entry **entries;
280 size_t count;
281 size_t capacity;
284 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
285 unsigned int count, IDWriteFontSet1 **ret);
287 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
289 struct dwrite_fontface *fontface = context;
290 BOOL exists = FALSE;
292 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
293 size, data_context, &exists)) || !exists)
295 *data = NULL;
296 *size = 0;
297 *data_context = NULL;
301 static void dwrite_release_font_table(void *context, void *data_context)
303 struct dwrite_fontface *fontface = context;
304 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
307 static UINT16 dwrite_get_font_upem(void *context)
309 struct dwrite_fontface *fontface = context;
310 return fontface->metrics.designUnitsPerEm;
313 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
315 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
316 return opentype_cmap_get_glyph(&fontface->cmap, ch);
319 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
321 struct dwrite_fontface *fontface = context;
322 return !!dwritefontface_get_glyph(fontface, codepoint);
325 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
327 struct dwrite_fontface *fontface = context;
328 return dwritefontface_get_glyph(fontface, codepoint);
331 static const struct shaping_font_ops dwrite_font_ops =
333 dwrite_grab_font_table,
334 dwrite_release_font_table,
335 dwrite_get_font_upem,
336 dwrite_has_glyph,
337 dwrite_get_glyph,
340 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
342 if (fontface->shaping_cache)
343 return fontface->shaping_cache;
345 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
348 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
353 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
355 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
358 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
360 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
363 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
365 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
367 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
370 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
372 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
375 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
377 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
380 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
382 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
385 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
387 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
390 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
392 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
395 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
397 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
400 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
402 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
405 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
407 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
410 static struct dwrite_fontset_builder *impl_from_IDWriteFontSetBuilder2(IDWriteFontSetBuilder2 *iface)
412 return CONTAINING_RECORD(iface, struct dwrite_fontset_builder, IDWriteFontSetBuilder2_iface);
415 static struct dwrite_fontset *impl_from_IDWriteFontSet3(IDWriteFontSet3 *iface)
417 return CONTAINING_RECORD(iface, struct dwrite_fontset, IDWriteFontSet3_iface);
420 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
422 static const DWRITE_GLYPH_METRICS nil;
423 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
425 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
426 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
427 return S_OK;
430 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
432 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
434 if (!*block) {
435 /* start new block */
436 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
437 if (!*block)
438 return E_OUTOFMEMORY;
441 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
442 return S_OK;
445 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
447 HRESULT hr;
449 if (table->data || !table->exists)
450 return table->data;
452 table->exists = FALSE;
453 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
454 &table->exists);
455 if (FAILED(hr) || !table->exists) {
456 TRACE("Font does not have %s table\n", debugstr_tag(tag));
457 return NULL;
460 return table->data;
463 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
464 struct dwrite_font_propvec *vec)
466 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
467 vec->style = style * 7.0f;
468 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
471 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
473 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
476 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
478 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
481 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
483 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
484 return &fontface->vdmx;
487 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
489 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
490 return &fontface->gasp;
493 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
495 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
496 return &fontface->cpal;
499 static struct dwrite_font_data * addref_font_data(struct dwrite_font_data *data)
501 InterlockedIncrement(&data->refcount);
502 return data;
505 static void release_font_data(struct dwrite_font_data *data)
507 int i;
509 if (InterlockedDecrement(&data->refcount) > 0)
510 return;
512 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
514 if (data->info_strings[i])
515 IDWriteLocalizedStrings_Release(data->info_strings[i]);
517 if (data->names)
518 IDWriteLocalizedStrings_Release(data->names);
520 if (data->family_names)
521 IDWriteLocalizedStrings_Release(data->family_names);
523 dwrite_cmap_release(&data->cmap);
524 IDWriteFontFile_Release(data->file);
525 heap_free(data->facename);
526 heap_free(data);
529 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
531 size_t i;
533 if (InterlockedDecrement(&data->refcount) > 0)
534 return;
536 for (i = 0; i < data->count; ++i)
537 release_font_data(data->fonts[i]);
538 heap_free(data->fonts);
539 IDWriteLocalizedStrings_Release(data->familyname);
540 heap_free(data);
543 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
545 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
546 fontface->cached = NULL;
549 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
551 UINT32 left_key_size, right_key_size;
552 const void *left_key, *right_key;
553 HRESULT hr;
555 if (left == right)
556 return TRUE;
558 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
559 if (FAILED(hr))
560 return FALSE;
562 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
563 if (FAILED(hr))
564 return FALSE;
566 if (left_key_size != right_key_size)
567 return FALSE;
569 return !memcmp(left_key, right_key, left_key_size);
572 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
574 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
576 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
578 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
579 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
580 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
581 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
582 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
583 IsEqualIID(riid, &IID_IDWriteFontFace) ||
584 IsEqualIID(riid, &IID_IUnknown))
586 *obj = iface;
588 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
589 *obj = &fontface->IDWriteFontFaceReference_iface;
590 else
591 *obj = NULL;
593 if (*obj)
595 if (InterlockedIncrement(&fontface->refcount) == 1)
597 InterlockedDecrement(&fontface->refcount);
598 *obj = NULL;
599 return E_FAIL;
601 return S_OK;
604 WARN("%s not implemented.\n", debugstr_guid(riid));
606 return E_NOINTERFACE;
609 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
611 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
612 ULONG refcount = InterlockedIncrement(&fontface->refcount);
614 TRACE("%p, refcount %u.\n", iface, refcount);
616 return refcount;
619 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
621 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
622 ULONG refcount = InterlockedDecrement(&fontface->refcount);
624 TRACE("%p, refcount %u.\n", iface, refcount);
626 if (!refcount)
628 UINT32 i;
630 if (fontface->cached)
632 factory_lock(fontface->factory);
633 list_remove(&fontface->cached->entry);
634 factory_unlock(fontface->factory);
635 heap_free(fontface->cached);
637 release_scriptshaping_cache(fontface->shaping_cache);
638 if (fontface->vdmx.context)
639 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
640 if (fontface->gasp.context)
641 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
642 if (fontface->cpal.context)
643 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
644 if (fontface->colr.context)
645 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
646 if (fontface->kern.context)
647 IDWriteFontFace5_ReleaseFontTable(iface, fontface->kern.context);
648 if (fontface->file)
649 IDWriteFontFile_Release(fontface->file);
650 if (fontface->stream)
651 IDWriteFontFileStream_Release(fontface->stream);
652 if (fontface->names)
653 IDWriteLocalizedStrings_Release(fontface->names);
654 if (fontface->family_names)
655 IDWriteLocalizedStrings_Release(fontface->family_names);
656 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
658 if (fontface->info_strings[i])
659 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
662 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
663 heap_free(fontface->glyphs[i]);
665 freetype_notify_cacheremove(iface);
667 dwrite_cmap_release(&fontface->cmap);
668 IDWriteFactory7_Release(fontface->factory);
669 heap_free(fontface);
672 return refcount;
675 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
677 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
679 TRACE("%p.\n", iface);
681 return fontface->type;
684 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
685 IDWriteFontFile **fontfiles)
687 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
689 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
691 if (!fontfiles)
693 *number_of_files = 1;
694 return S_OK;
697 if (!*number_of_files)
698 return E_INVALIDARG;
700 IDWriteFontFile_AddRef(fontface->file);
701 *fontfiles = fontface->file;
703 return S_OK;
706 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
708 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
710 TRACE("%p.\n", iface);
712 return fontface->index;
715 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
717 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
719 TRACE("%p.\n", iface);
721 return fontface->simulations;
724 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
726 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
728 TRACE("%p.\n", iface);
730 return !!(fontface->flags & FONT_IS_SYMBOL);
733 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
735 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
737 TRACE("%p, %p.\n", iface, metrics);
739 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
742 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
744 TRACE("%p.\n", iface);
746 return freetype_get_glyphcount(iface);
749 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
750 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
752 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
753 unsigned int i;
754 HRESULT hr;
756 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
758 if (!glyphs)
759 return E_INVALIDARG;
761 if (is_sideways)
762 FIXME("sideways metrics are not supported.\n");
764 for (i = 0; i < glyph_count; i++) {
765 DWRITE_GLYPH_METRICS metrics;
767 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
768 if (hr != S_OK) {
769 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
770 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
771 if (FAILED(hr))
772 return hr;
774 ret[i] = metrics;
777 return S_OK;
780 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
781 UINT32 count, UINT16 *glyphs)
783 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
784 unsigned int i;
786 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
788 if (!glyphs)
789 return E_INVALIDARG;
791 if (!codepoints)
793 memset(glyphs, 0, count * sizeof(*glyphs));
794 return E_INVALIDARG;
797 for (i = 0; i < count; ++i)
798 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
800 return S_OK;
803 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
804 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
806 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
807 struct file_stream_desc stream_desc;
809 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
811 stream_desc.stream = fontface->stream;
812 stream_desc.face_type = fontface->type;
813 stream_desc.face_index = fontface->index;
814 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
817 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
819 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
821 TRACE("%p, %p.\n", iface, table_context);
823 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
826 int dwrite_outline_push_tag(struct dwrite_outline *outline, unsigned char tag)
828 if (!dwrite_array_reserve((void **)&outline->tags.values, &outline->tags.size, outline->tags.count + 1,
829 sizeof(*outline->tags.values)))
831 return 1;
834 outline->tags.values[outline->tags.count++] = tag;
836 return 0;
839 int dwrite_outline_push_points(struct dwrite_outline *outline, const D2D1_POINT_2F *points, unsigned int count)
841 if (!dwrite_array_reserve((void **)&outline->points.values, &outline->points.size, outline->points.count + count,
842 sizeof(*outline->points.values)))
844 return 1;
847 memcpy(&outline->points.values[outline->points.count], points, sizeof(*points) * count);
848 outline->points.count += count;
850 return 0;
853 static void apply_outline_point_offset(const D2D1_POINT_2F *src, const D2D1_POINT_2F *offset,
854 D2D1_POINT_2F *dst)
856 dst->x = src->x + offset->x;
857 dst->y = src->y + offset->y;
860 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
861 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
862 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
864 D2D1_POINT_2F *origins, baseline_origin = { 0 };
865 struct dwrite_outline outline = {{ 0 }};
866 D2D1_BEZIER_SEGMENT segment;
867 D2D1_POINT_2F point;
868 DWRITE_GLYPH_RUN run;
869 unsigned int i, j, p;
870 HRESULT hr;
872 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
873 count, is_sideways, is_rtl, sink);
875 if (!glyphs || !sink)
876 return E_INVALIDARG;
878 if (!count)
879 return S_OK;
881 run.fontFace = (IDWriteFontFace *)iface;
882 run.fontEmSize = emSize;
883 run.glyphCount = count;
884 run.glyphIndices = glyphs;
885 run.glyphAdvances = advances;
886 run.glyphOffsets = offsets;
887 run.isSideways = is_sideways;
888 run.bidiLevel = is_rtl ? 1 : 0;
890 if (!(origins = heap_alloc(sizeof(*origins) * count)))
891 return E_OUTOFMEMORY;
893 if (FAILED(hr = compute_glyph_origins(&run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins)))
895 heap_free(origins);
896 return hr;
899 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
901 for (i = 0; i < count; ++i)
903 outline.tags.count = outline.points.count = 0;
904 if (freetype_get_glyph_outline(iface, emSize, glyphs[i], &outline))
906 WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
907 continue;
910 for (j = 0, p = 0; j < outline.tags.count; ++j)
912 switch (outline.tags.values[j])
914 case OUTLINE_BEGIN_FIGURE:
915 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
916 ID2D1SimplifiedGeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
917 break;
918 case OUTLINE_END_FIGURE:
919 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
920 break;
921 case OUTLINE_LINE:
922 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
923 ID2D1SimplifiedGeometrySink_AddLines(sink, &point, 1);
924 break;
925 case OUTLINE_BEZIER:
926 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point1);
927 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point2);
928 apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point3);
929 ID2D1SimplifiedGeometrySink_AddBeziers(sink, &segment, 1);
930 break;
935 heap_free(outline.tags.values);
936 heap_free(outline.points.values);
937 heap_free(origins);
939 return S_OK;
942 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
943 float ppem, unsigned int gasp)
945 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
947 switch (measuring)
949 case DWRITE_MEASURING_MODE_NATURAL:
951 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
952 mode = DWRITE_RENDERING_MODE_NATURAL;
953 else
954 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
955 break;
957 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
958 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
959 break;
960 case DWRITE_MEASURING_MODE_GDI_NATURAL:
961 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
962 break;
963 default:
967 return mode;
970 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
971 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
973 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
974 unsigned int flags;
975 FLOAT ppem;
977 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
979 if (!params) {
980 *mode = DWRITE_RENDERING_MODE_DEFAULT;
981 return E_INVALIDARG;
984 *mode = IDWriteRenderingParams_GetRenderingMode(params);
985 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
986 return S_OK;
988 ppem = emSize * ppdip;
990 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
991 *mode = DWRITE_RENDERING_MODE_OUTLINE;
992 return S_OK;
995 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
996 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
997 return S_OK;
1000 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
1001 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
1003 DWRITE_FONT_METRICS1 metrics1;
1004 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
1005 memcpy(metrics, &metrics1, sizeof(*metrics));
1006 return hr;
1009 static inline int round_metric(FLOAT metric)
1011 return (int)floorf(metric + 0.5f);
1014 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
1016 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
1017 return 0;
1019 return (fontface->metrics.designUnitsPerEm + 49) / 50;
1022 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
1023 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
1024 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
1026 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1027 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
1028 DWRITE_MEASURING_MODE mode;
1029 FLOAT scale, size;
1030 HRESULT hr;
1031 UINT32 i;
1033 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
1034 glyph_count, metrics, is_sideways);
1036 if (m && memcmp(m, &identity, sizeof(*m)))
1037 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
1039 size = emSize * ppdip;
1040 scale = size / fontface->metrics.designUnitsPerEm;
1041 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1043 for (i = 0; i < glyph_count; i++) {
1044 DWRITE_GLYPH_METRICS *ret = metrics + i;
1045 DWRITE_GLYPH_METRICS design;
1046 BOOL has_contours;
1048 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
1049 if (FAILED(hr))
1050 return hr;
1052 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
1053 if (has_contours)
1054 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
1055 else
1056 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
1058 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
1059 SCALE_METRIC(leftSideBearing);
1060 SCALE_METRIC(rightSideBearing);
1061 SCALE_METRIC(topSideBearing);
1062 SCALE_METRIC(advanceHeight);
1063 SCALE_METRIC(bottomSideBearing);
1064 SCALE_METRIC(verticalOriginY);
1065 #undef SCALE_METRIC
1068 return S_OK;
1071 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
1073 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1075 TRACE("%p, %p.\n", iface, metrics);
1077 *metrics = fontface->metrics;
1080 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
1081 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
1083 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1084 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
1085 UINT16 ascent, descent;
1086 FLOAT scale;
1088 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
1090 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
1091 memset(metrics, 0, sizeof(*metrics));
1092 return E_INVALIDARG;
1095 em_size *= pixels_per_dip;
1096 if (m && m->m22 != 0.0f)
1097 em_size *= fabs(m->m22);
1099 scale = em_size / design->designUnitsPerEm;
1100 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
1102 ascent = round_metric(design->ascent * scale);
1103 descent = round_metric(design->descent * scale);
1106 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
1107 metrics->designUnitsPerEm = design->designUnitsPerEm;
1108 metrics->ascent = round_metric(ascent / scale);
1109 metrics->descent = round_metric(descent / scale);
1111 SCALE_METRIC(lineGap);
1112 SCALE_METRIC(capHeight);
1113 SCALE_METRIC(xHeight);
1114 SCALE_METRIC(underlinePosition);
1115 SCALE_METRIC(underlineThickness);
1116 SCALE_METRIC(strikethroughPosition);
1117 SCALE_METRIC(strikethroughThickness);
1118 SCALE_METRIC(glyphBoxLeft);
1119 SCALE_METRIC(glyphBoxTop);
1120 SCALE_METRIC(glyphBoxRight);
1121 SCALE_METRIC(glyphBoxBottom);
1122 SCALE_METRIC(subscriptPositionX);
1123 SCALE_METRIC(subscriptPositionY);
1124 SCALE_METRIC(subscriptSizeX);
1125 SCALE_METRIC(subscriptSizeY);
1126 SCALE_METRIC(superscriptPositionX);
1127 SCALE_METRIC(superscriptPositionY);
1128 SCALE_METRIC(superscriptSizeX);
1129 SCALE_METRIC(superscriptSizeY);
1131 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1132 #undef SCALE_METRIC
1134 return S_OK;
1137 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1139 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1141 TRACE("%p, %p.\n", iface, metrics);
1143 *metrics = fontface->caret;
1146 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1147 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1149 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1151 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1153 *count = 0;
1154 if (max_count && !ranges)
1155 return E_INVALIDARG;
1157 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1158 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1161 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1163 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1165 TRACE("%p.\n", iface);
1167 return !!(fontface->flags & FONT_IS_MONOSPACED);
1170 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1171 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1173 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1174 BOOL has_contours;
1175 int advance;
1177 if (is_sideways)
1178 FIXME("Sideways mode is not supported.\n");
1180 switch (measuring_mode)
1182 case DWRITE_MEASURING_MODE_NATURAL:
1183 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1184 glyph, measuring_mode, &has_contours);
1185 if (has_contours)
1186 advance += adjustment;
1188 return advance;
1189 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1190 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1191 emsize *= ppdip;
1192 if (emsize == 0.0f)
1193 return 0.0f;
1195 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1196 FIXME("Transform is not supported.\n");
1198 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1199 &has_contours);
1200 if (has_contours)
1201 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1202 else
1203 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1205 return advance;
1206 default:
1207 WARN("Unknown measuring mode %u.\n", measuring_mode);
1208 return 0;
1212 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1213 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1215 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1216 unsigned int i;
1218 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1220 if (is_sideways)
1221 FIXME("sideways mode not supported\n");
1223 for (i = 0; i < glyph_count; ++i)
1225 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1226 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1229 return S_OK;
1232 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1233 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1234 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1236 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1237 DWRITE_MEASURING_MODE measuring_mode;
1238 UINT32 i;
1240 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1241 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1243 if (em_size < 0.0f || ppdip <= 0.0f) {
1244 memset(advances, 0, sizeof(*advances) * glyph_count);
1245 return E_INVALIDARG;
1248 if (em_size == 0.0f) {
1249 memset(advances, 0, sizeof(*advances) * glyph_count);
1250 return S_OK;
1253 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1254 for (i = 0; i < glyph_count; ++i)
1256 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1257 glyphs[i], is_sideways);
1260 return S_OK;
1263 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1264 const UINT16 *glyphs, INT32 *values)
1266 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1268 TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
1270 if (!(glyphs || values) || !count)
1271 return E_INVALIDARG;
1273 if (!glyphs || count == 1)
1275 memset(values, 0, count * sizeof(*values));
1276 return E_INVALIDARG;
1279 return opentype_get_kerning_pairs(fontface, count, glyphs, values);
1282 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1284 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1286 TRACE("%p.\n", iface);
1288 return opentype_has_kerning_pairs(fontface);
1291 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1292 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1293 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1295 DWRITE_GRID_FIT_MODE gridfitmode;
1296 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1297 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1300 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1301 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1303 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1305 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1307 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1310 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1312 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1314 TRACE("%p.\n", iface);
1316 return opentype_has_vertical_variants(fontface);
1319 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1321 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1323 TRACE("%p.\n", iface);
1325 return !!(fontface->flags & FONT_IS_COLORED);
1328 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1330 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1332 TRACE("%p.\n", iface);
1334 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1337 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1339 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1341 TRACE("%p.\n", iface);
1343 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1346 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1347 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1349 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1351 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1353 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1356 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1357 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1358 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1359 DWRITE_GRID_FIT_MODE *gridfitmode)
1361 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1362 unsigned int flags;
1363 FLOAT emthreshold;
1365 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1366 measuringmode, params, renderingmode, gridfitmode);
1368 if (m && memcmp(m, &identity, sizeof(*m)))
1369 FIXME("transform not supported %s\n", debugstr_matrix(m));
1371 if (is_sideways)
1372 FIXME("sideways mode not supported\n");
1374 emSize *= max(dpiX, dpiY) / 96.0f;
1376 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1377 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1378 if (params) {
1379 IDWriteRenderingParams2 *params2;
1380 HRESULT hr;
1382 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1383 if (hr == S_OK) {
1384 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1385 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1386 IDWriteRenderingParams2_Release(params2);
1388 else
1389 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1392 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1394 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1396 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1397 if (emSize >= emthreshold)
1398 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1399 else
1400 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1403 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1404 if (emSize >= emthreshold)
1405 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1406 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1407 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1408 else
1409 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1410 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1413 return S_OK;
1416 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1417 IDWriteFontFaceReference **reference)
1419 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1421 TRACE("%p, %p.\n", iface, reference);
1423 *reference = &fontface->IDWriteFontFaceReference_iface;
1424 IDWriteFontFaceReference_AddRef(*reference);
1426 return S_OK;
1429 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1431 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1433 TRACE("%p, %p.\n", iface, panose);
1435 *panose = fontface->panose;
1438 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1440 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1442 TRACE("%p.\n", iface);
1444 return fontface->weight;
1447 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1449 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1451 TRACE("%p.\n", iface);
1453 return fontface->stretch;
1456 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1458 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1460 TRACE("%p.\n", iface);
1462 return fontface->style;
1465 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1467 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1469 TRACE("%p, %p.\n", iface, names);
1471 return clone_localizedstrings(fontface->family_names, names);
1474 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1476 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1478 TRACE("%p, %p.\n", iface, names);
1480 return clone_localizedstrings(fontface->names, names);
1483 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1484 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1485 IDWriteLocalizedStrings **ret, BOOL *exists)
1487 HRESULT hr = S_OK;
1489 *exists = FALSE;
1490 *ret = NULL;
1492 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1493 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1495 return S_OK;
1498 if (!strings_cache[stringid])
1500 struct file_stream_desc desc = *stream_desc;
1502 if (!desc.stream)
1503 hr = get_filestream_from_file(file, &desc.stream);
1504 if (SUCCEEDED(hr))
1505 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1507 if (!stream_desc->stream && desc.stream)
1508 IDWriteFontFileStream_Release(desc.stream);
1511 if (SUCCEEDED(hr) && strings_cache[stringid])
1513 hr = clone_localizedstrings(strings_cache[stringid], ret);
1514 if (SUCCEEDED(hr))
1515 *exists = TRUE;
1518 return hr;
1521 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1522 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1524 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1525 struct file_stream_desc stream_desc;
1527 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1529 stream_desc.stream = fontface->stream;
1530 stream_desc.face_index = fontface->index;
1531 stream_desc.face_type = fontface->type;
1532 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1535 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1537 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1539 TRACE("%p, %#x.\n", iface, ch);
1541 return !!dwritefontface_get_glyph(fontface, ch);
1544 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1545 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1546 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1548 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1549 unsigned int flags;
1550 FLOAT emthreshold;
1552 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1553 measuring_mode, params, rendering_mode, gridfit_mode);
1555 if (m && memcmp(m, &identity, sizeof(*m)))
1556 FIXME("transform not supported %s\n", debugstr_matrix(m));
1558 if (is_sideways)
1559 FIXME("sideways mode not supported\n");
1561 emSize *= max(dpiX, dpiY) / 96.0f;
1563 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1564 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1565 if (params) {
1566 IDWriteRenderingParams3 *params3;
1567 HRESULT hr;
1569 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1570 if (hr == S_OK) {
1571 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1572 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1573 IDWriteRenderingParams3_Release(params3);
1575 else
1576 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1579 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1581 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1583 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1584 if (emSize >= emthreshold)
1585 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1586 else
1587 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1590 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1591 if (emSize >= emthreshold)
1592 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1593 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1594 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1595 else
1596 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1597 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1600 return S_OK;
1603 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1605 FIXME("%p, %#x: stub\n", iface, ch);
1607 return FALSE;
1610 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1612 FIXME("%p, %u: stub\n", iface, glyph);
1614 return FALSE;
1617 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1618 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1620 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1622 return E_NOTIMPL;
1625 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1626 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1628 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1630 return E_NOTIMPL;
1633 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1634 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1636 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1638 return E_NOTIMPL;
1641 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1643 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1645 TRACE("%p.\n", iface);
1647 return fontface->glyph_image_formats;
1650 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1651 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1653 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1655 return E_NOTIMPL;
1658 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1660 FIXME("%p, %p: stub\n", iface, context);
1663 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1665 FIXME("%p: stub\n", iface);
1667 return 0;
1670 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1671 UINT32 value_count)
1673 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1675 return E_NOTIMPL;
1678 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1680 static int once;
1682 if (!once++)
1683 FIXME("%p: stub\n", iface);
1685 return FALSE;
1688 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1690 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1692 TRACE("%p, %p.\n", iface, resource);
1694 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1697 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1699 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1701 TRACE("%p, %p.\n", iface, other);
1703 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1704 return FALSE;
1706 /* TODO: add variations support */
1708 return fontface->index == other_face->index &&
1709 fontface->simulations == other_face->simulations &&
1710 is_same_fontfile(fontface->file, other_face->file);
1713 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1715 dwritefontface_QueryInterface,
1716 dwritefontface_AddRef,
1717 dwritefontface_Release,
1718 dwritefontface_GetType,
1719 dwritefontface_GetFiles,
1720 dwritefontface_GetIndex,
1721 dwritefontface_GetSimulations,
1722 dwritefontface_IsSymbolFont,
1723 dwritefontface_GetMetrics,
1724 dwritefontface_GetGlyphCount,
1725 dwritefontface_GetDesignGlyphMetrics,
1726 dwritefontface_GetGlyphIndices,
1727 dwritefontface_TryGetFontTable,
1728 dwritefontface_ReleaseFontTable,
1729 dwritefontface_GetGlyphRunOutline,
1730 dwritefontface_GetRecommendedRenderingMode,
1731 dwritefontface_GetGdiCompatibleMetrics,
1732 dwritefontface_GetGdiCompatibleGlyphMetrics,
1733 dwritefontface1_GetMetrics,
1734 dwritefontface1_GetGdiCompatibleMetrics,
1735 dwritefontface1_GetCaretMetrics,
1736 dwritefontface1_GetUnicodeRanges,
1737 dwritefontface1_IsMonospacedFont,
1738 dwritefontface1_GetDesignGlyphAdvances,
1739 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1740 dwritefontface1_GetKerningPairAdjustments,
1741 dwritefontface1_HasKerningPairs,
1742 dwritefontface1_GetRecommendedRenderingMode,
1743 dwritefontface1_GetVerticalGlyphVariants,
1744 dwritefontface1_HasVerticalGlyphVariants,
1745 dwritefontface2_IsColorFont,
1746 dwritefontface2_GetColorPaletteCount,
1747 dwritefontface2_GetPaletteEntryCount,
1748 dwritefontface2_GetPaletteEntries,
1749 dwritefontface2_GetRecommendedRenderingMode,
1750 dwritefontface3_GetFontFaceReference,
1751 dwritefontface3_GetPanose,
1752 dwritefontface3_GetWeight,
1753 dwritefontface3_GetStretch,
1754 dwritefontface3_GetStyle,
1755 dwritefontface3_GetFamilyNames,
1756 dwritefontface3_GetFaceNames,
1757 dwritefontface3_GetInformationalStrings,
1758 dwritefontface3_HasCharacter,
1759 dwritefontface3_GetRecommendedRenderingMode,
1760 dwritefontface3_IsCharacterLocal,
1761 dwritefontface3_IsGlyphLocal,
1762 dwritefontface3_AreCharactersLocal,
1763 dwritefontface3_AreGlyphsLocal,
1764 dwritefontface4_GetGlyphImageFormats_,
1765 dwritefontface4_GetGlyphImageFormats,
1766 dwritefontface4_GetGlyphImageData,
1767 dwritefontface4_ReleaseGlyphImageData,
1768 dwritefontface5_GetFontAxisValueCount,
1769 dwritefontface5_GetFontAxisValues,
1770 dwritefontface5_HasVariations,
1771 dwritefontface5_GetFontResource,
1772 dwritefontface5_Equals,
1775 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1777 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1778 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1781 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1783 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1784 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1787 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1789 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1790 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1793 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1794 IDWriteFontFace3 **ret)
1796 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1798 TRACE("%p, %p.\n", iface, ret);
1800 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1801 IDWriteFontFace3_AddRef(*ret);
1803 return S_OK;
1806 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1807 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1809 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1810 DWRITE_FONT_FILE_TYPE file_type;
1811 DWRITE_FONT_FACE_TYPE face_type;
1812 IDWriteFontFace *face;
1813 BOOL is_supported;
1814 UINT32 face_num;
1815 HRESULT hr;
1817 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1819 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
1820 if (FAILED(hr))
1821 return hr;
1823 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
1824 simulations, &face);
1825 if (SUCCEEDED(hr))
1827 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1828 IDWriteFontFace_Release(face);
1831 return hr;
1834 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1836 FIXME("%p, %p.\n", iface, ref);
1838 return E_NOTIMPL;
1841 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1843 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1845 TRACE("%p.\n", iface);
1847 return fontface->index;
1850 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1852 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1854 TRACE("%p.\n", iface);
1856 return fontface->simulations;
1859 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1861 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1863 TRACE("%p, %p.\n", iface, file);
1865 *file = fontface->file;
1866 IDWriteFontFile_AddRef(*file);
1868 return S_OK;
1871 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1873 FIXME("%p.\n", iface);
1875 return 0;
1878 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1880 FIXME("%p.\n", iface);
1882 return 0;
1885 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1887 FIXME("%p, %p.\n", iface, writetime);
1889 return E_NOTIMPL;
1892 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1894 FIXME("%p.\n", iface);
1896 return DWRITE_LOCALITY_LOCAL;
1899 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1901 FIXME("%p.\n", iface);
1903 return E_NOTIMPL;
1906 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1907 WCHAR const *chars, UINT32 count)
1909 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1911 return E_NOTIMPL;
1914 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1915 UINT16 const *glyphs, UINT32 count)
1917 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1919 return E_NOTIMPL;
1922 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1923 UINT64 offset, UINT64 size)
1925 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1927 return E_NOTIMPL;
1930 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1932 dwritefontface_reference_QueryInterface,
1933 dwritefontface_reference_AddRef,
1934 dwritefontface_reference_Release,
1935 dwritefontface_reference_CreateFontFace,
1936 dwritefontface_reference_CreateFontFaceWithSimulations,
1937 dwritefontface_reference_Equals,
1938 dwritefontface_reference_GetFontFaceIndex,
1939 dwritefontface_reference_GetSimulations,
1940 dwritefontface_reference_GetFontFile,
1941 dwritefontface_reference_GetLocalFileSize,
1942 dwritefontface_reference_GetFileSize,
1943 dwritefontface_reference_GetFileTime,
1944 dwritefontface_reference_GetLocality,
1945 dwritefontface_reference_EnqueueFontDownloadRequest,
1946 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1947 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1948 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1951 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1953 struct dwrite_font_data *data = font->data;
1954 struct fontface_desc desc;
1955 struct list *cached_list;
1956 HRESULT hr;
1958 *fontface = NULL;
1960 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1961 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1962 if (hr == S_OK)
1963 return hr;
1965 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1966 return hr;
1968 desc.factory = font->family->collection->factory;
1969 desc.face_type = data->face_type;
1970 desc.file = data->file;
1971 desc.index = data->face_index;
1972 desc.simulations = data->simulations;
1973 desc.font_data = data;
1974 hr = create_fontface(&desc, cached_list, fontface);
1976 IDWriteFontFileStream_Release(desc.stream);
1977 return hr;
1980 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1982 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1984 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1985 IsEqualIID(riid, &IID_IDWriteFont2) ||
1986 IsEqualIID(riid, &IID_IDWriteFont1) ||
1987 IsEqualIID(riid, &IID_IDWriteFont) ||
1988 IsEqualIID(riid, &IID_IUnknown))
1990 *obj = iface;
1991 IDWriteFont3_AddRef(iface);
1992 return S_OK;
1995 WARN("%s not implemented.\n", debugstr_guid(riid));
1997 *obj = NULL;
1998 return E_NOINTERFACE;
2001 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
2003 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2004 ULONG refcount = InterlockedIncrement(&font->refcount);
2006 TRACE("%p, refcount %d.\n", iface, refcount);
2008 return refcount;
2011 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
2013 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2014 ULONG refcount = InterlockedDecrement(&font->refcount);
2016 TRACE("%p, refcount %d.\n", iface, refcount);
2018 if (!refcount)
2020 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
2021 release_font_data(font->data);
2022 heap_free(font);
2025 return refcount;
2028 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
2030 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2032 TRACE("%p, %p.\n", iface, family);
2034 *family = (IDWriteFontFamily *)font->family;
2035 IDWriteFontFamily_AddRef(*family);
2036 return S_OK;
2039 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
2041 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2043 TRACE("%p.\n", iface);
2045 return font->data->weight;
2048 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
2050 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2052 TRACE("%p.\n", iface);
2054 return font->data->stretch;
2057 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
2059 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2061 TRACE("%p.\n", iface);
2063 return font->style;
2066 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2068 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2070 TRACE("%p.\n", iface);
2072 return !!(font->data->flags & FONT_IS_SYMBOL);
2075 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2077 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2079 TRACE("%p, %p.\n", iface, names);
2081 return clone_localizedstrings(font->data->names, names);
2084 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2085 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2087 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2088 struct dwrite_font_data *data = font->data;
2089 struct file_stream_desc stream_desc;
2091 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2093 /* Stream will be created if necessary. */
2094 stream_desc.stream = NULL;
2095 stream_desc.face_index = data->face_index;
2096 stream_desc.face_type = data->face_type;
2097 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2100 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2102 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2104 TRACE("%p.\n", iface);
2106 return font->data->simulations;
2109 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2111 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2113 TRACE("%p, %p.\n", iface, metrics);
2115 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2118 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2120 UINT16 glyph;
2121 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2122 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2123 return glyph != 0;
2126 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2128 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2130 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2132 *exists = dwritefont_has_character(font, ch);
2134 return S_OK;
2137 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2139 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2141 TRACE("%p, %p.\n", iface, fontface);
2143 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2146 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2148 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2150 TRACE("%p, %p.\n", iface, metrics);
2152 *metrics = font->data->metrics;
2155 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2157 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2159 TRACE("%p, %p.\n", iface, panose);
2161 *panose = font->data->panose;
2164 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2165 UINT32 *count)
2167 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2169 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2171 *count = 0;
2172 if (max_count && !ranges)
2173 return E_INVALIDARG;
2175 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2176 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2179 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2181 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2183 TRACE("%p.\n", iface);
2185 return !!(font->data->flags & FONT_IS_MONOSPACED);
2188 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2190 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2192 TRACE("%p.\n", iface);
2194 return !!(font->data->flags & FONT_IS_COLORED);
2197 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2199 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2201 TRACE("%p, %p.\n", iface, fontface);
2203 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2206 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2208 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2210 TRACE("%p, %p.\n", iface, other);
2212 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2213 return FALSE;
2215 return font->data->face_index == other_font->data->face_index
2216 && font->data->simulations == other_font->data->simulations
2217 && is_same_fontfile(font->data->file, other_font->data->file);
2220 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2222 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2224 TRACE("%p, %p.\n", iface, reference);
2226 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2227 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2228 (IDWriteFontFaceReference1 **)reference);
2231 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2233 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2235 TRACE("%p, %#x.\n", iface, ch);
2237 return dwritefont_has_character(font, ch);
2240 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2242 FIXME("%p: stub.\n", iface);
2244 return DWRITE_LOCALITY_LOCAL;
2247 static const IDWriteFont3Vtbl dwritefontvtbl = {
2248 dwritefont_QueryInterface,
2249 dwritefont_AddRef,
2250 dwritefont_Release,
2251 dwritefont_GetFontFamily,
2252 dwritefont_GetWeight,
2253 dwritefont_GetStretch,
2254 dwritefont_GetStyle,
2255 dwritefont_IsSymbolFont,
2256 dwritefont_GetFaceNames,
2257 dwritefont_GetInformationalStrings,
2258 dwritefont_GetSimulations,
2259 dwritefont_GetMetrics,
2260 dwritefont_HasCharacter,
2261 dwritefont_CreateFontFace,
2262 dwritefont1_GetMetrics,
2263 dwritefont1_GetPanose,
2264 dwritefont1_GetUnicodeRanges,
2265 dwritefont1_IsMonospacedFont,
2266 dwritefont2_IsColorFont,
2267 dwritefont3_CreateFontFace,
2268 dwritefont3_Equals,
2269 dwritefont3_GetFontFaceReference,
2270 dwritefont3_HasCharacter,
2271 dwritefont3_GetLocality
2274 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2276 if (!iface)
2277 return NULL;
2278 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2279 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2282 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2284 if (!iface)
2285 return NULL;
2286 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2287 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2290 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2292 if (!iface)
2293 return NULL;
2294 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2295 return NULL;
2296 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2297 IDWriteFontFaceReference1_iface);
2300 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2302 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2303 *lf = font->data->lf;
2306 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2308 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2309 *lf = fontface->lf;
2312 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2314 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2315 *fontsig = font->data->fontsig;
2316 return S_OK;
2319 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2321 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2322 *fontsig = fontface->fontsig;
2323 return S_OK;
2326 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2328 struct dwrite_font *object;
2330 *font = NULL;
2332 if (!(object = heap_alloc(sizeof(*object))))
2333 return E_OUTOFMEMORY;
2335 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2336 object->refcount = 1;
2337 object->family = family;
2338 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2339 object->data = family->data->fonts[index];
2340 object->style = object->data->style;
2341 addref_font_data(object->data);
2343 *font = &object->IDWriteFont3_iface;
2345 return S_OK;
2348 /* IDWriteFontList2 */
2349 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2351 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2353 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2354 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2355 IsEqualIID(riid, &IID_IDWriteFontList) ||
2356 IsEqualIID(riid, &IID_IUnknown))
2358 *obj = iface;
2359 IDWriteFontList2_AddRef(iface);
2360 return S_OK;
2363 WARN("%s not implemented.\n", debugstr_guid(riid));
2365 *obj = NULL;
2366 return E_NOINTERFACE;
2369 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2371 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2372 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2374 TRACE("%p, refcount %u.\n", iface, refcount);
2376 return refcount;
2379 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2381 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2382 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2384 TRACE("%p, refcount %u.\n", iface, refcount);
2386 if (!refcount)
2388 UINT32 i;
2390 for (i = 0; i < fontlist->font_count; i++)
2391 release_font_data(fontlist->fonts[i]);
2392 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2393 heap_free(fontlist->fonts);
2394 heap_free(fontlist);
2397 return refcount;
2400 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2402 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2403 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2406 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2408 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2410 TRACE("%p.\n", iface);
2412 return fontlist->font_count;
2415 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2417 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2419 TRACE("%p, %u, %p.\n", iface, index, font);
2421 *font = NULL;
2423 if (fontlist->font_count == 0)
2424 return S_FALSE;
2426 if (index >= fontlist->font_count)
2427 return E_INVALIDARG;
2429 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2432 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2434 FIXME("%p, %u.\n", iface, index);
2436 return DWRITE_LOCALITY_LOCAL;
2439 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2440 IDWriteFont3 **font)
2442 *font = NULL;
2444 if (fontlist->font_count == 0)
2445 return S_FALSE;
2447 if (index >= fontlist->font_count)
2448 return E_FAIL;
2450 return create_font(fontlist->family, index, font);
2453 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2455 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2457 TRACE("%p, %u, %p.\n", iface, index, font);
2459 return fontlist_get_font(fontlist, index, font);
2462 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2463 IDWriteFontFaceReference **reference)
2465 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2466 IDWriteFont3 *font;
2467 HRESULT hr;
2469 TRACE("%p, %u, %p.\n", iface, index, reference);
2471 *reference = NULL;
2473 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2475 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2476 IDWriteFont3_Release(font);
2479 return hr;
2482 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2484 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2486 TRACE("%p, %p.\n", iface, fontset);
2488 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2489 fontlist->font_count, fontset);
2492 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2494 dwritefontlist_QueryInterface,
2495 dwritefontlist_AddRef,
2496 dwritefontlist_Release,
2497 dwritefontlist_GetFontCollection,
2498 dwritefontlist_GetFontCount,
2499 dwritefontlist_GetFont,
2500 dwritefontlist1_GetFontLocality,
2501 dwritefontlist1_GetFont,
2502 dwritefontlist1_GetFontFaceReference,
2503 dwritefontlist2_GetFontSet,
2506 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2508 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2510 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2512 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2513 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2514 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2515 IsEqualIID(riid, &IID_IUnknown))
2517 *obj = iface;
2519 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2520 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2521 IsEqualIID(riid, &IID_IDWriteFontList))
2523 *obj = &family->IDWriteFontList2_iface;
2525 else
2527 WARN("%s not implemented.\n", debugstr_guid(riid));
2528 *obj = NULL;
2529 return E_NOINTERFACE;
2532 IUnknown_AddRef((IUnknown *)*obj);
2533 return S_OK;
2536 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2538 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2539 ULONG refcount = InterlockedIncrement(&family->refcount);
2541 TRACE("%p, %u.\n", iface, refcount);
2543 return refcount;
2546 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2548 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2549 ULONG refcount = InterlockedDecrement(&family->refcount);
2551 TRACE("%p, %u.\n", iface, refcount);
2553 if (!refcount)
2555 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2556 release_fontfamily_data(family->data);
2557 heap_free(family);
2560 return refcount;
2563 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2565 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2567 TRACE("%p, %p.\n", iface, collection);
2569 *collection = (IDWriteFontCollection *)family->collection;
2570 IDWriteFontCollection_AddRef(*collection);
2571 return S_OK;
2574 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2576 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2578 TRACE("%p.\n", iface);
2580 return family->data->count;
2583 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2585 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2587 TRACE("%p, %u, %p.\n", iface, index, font);
2589 *font = NULL;
2591 if (!family->data->count)
2592 return S_FALSE;
2594 if (index >= family->data->count)
2595 return E_INVALIDARG;
2597 return create_font(family, index, (IDWriteFont3 **)font);
2600 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2602 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2604 TRACE("%p, %p.\n", iface, names);
2606 return clone_localizedstrings(family->data->familyname, names);
2609 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2610 const struct dwrite_font_propvec *req)
2612 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2613 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2614 FLOAT cur_req_prod, next_req_prod;
2616 if (next_to_req < cur_to_req)
2617 return TRUE;
2619 if (next_to_req > cur_to_req)
2620 return FALSE;
2622 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2623 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2625 if (next_req_prod > cur_req_prod)
2626 return TRUE;
2628 if (next_req_prod < cur_req_prod)
2629 return FALSE;
2631 if (next->stretch > cur->stretch)
2632 return TRUE;
2633 if (next->stretch < cur->stretch)
2634 return FALSE;
2636 if (next->style > cur->style)
2637 return TRUE;
2638 if (next->style < cur->style)
2639 return FALSE;
2641 if (next->weight > cur->weight)
2642 return TRUE;
2643 if (next->weight < cur->weight)
2644 return FALSE;
2646 /* full match, no reason to prefer new variant */
2647 return FALSE;
2650 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2651 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2653 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2654 struct dwrite_font_propvec req;
2655 size_t i, match;
2657 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2659 if (!family->data->count)
2661 *font = NULL;
2662 return DWRITE_E_NOFONT;
2665 init_font_prop_vec(weight, stretch, style, &req);
2666 match = 0;
2668 for (i = 1; i < family->data->count; ++i)
2670 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2671 match = i;
2674 return create_font(family, match, (IDWriteFont3 **)font);
2677 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2679 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2681 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2684 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2686 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2689 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2691 UINT32 b = fonts->font_count - 1, j, t;
2693 while (1) {
2694 t = b;
2696 for (j = 0; j < b; j++) {
2697 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2698 struct dwrite_font_data *s = fonts->fonts[j];
2699 fonts->fonts[j] = fonts->fonts[j+1];
2700 fonts->fonts[j+1] = s;
2701 t = j;
2705 if (t == b)
2706 break;
2707 b = t;
2711 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2712 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2714 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2715 matching_filter_func func = NULL;
2716 struct dwrite_font_propvec req;
2717 struct dwrite_fontlist *fonts;
2718 size_t i;
2720 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2722 *ret = NULL;
2724 fonts = heap_alloc(sizeof(*fonts));
2725 if (!fonts)
2726 return E_OUTOFMEMORY;
2728 /* Allocate as many as family has, not all of them will be necessary used. */
2729 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2730 if (!fonts->fonts) {
2731 heap_free(fonts);
2732 return E_OUTOFMEMORY;
2735 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2736 fonts->refcount = 1;
2737 fonts->family = family;
2738 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2739 fonts->font_count = 0;
2741 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2742 if (style == DWRITE_FONT_STYLE_NORMAL) {
2743 if (family->data->has_normal_face || family->data->has_italic_face)
2744 func = is_font_acceptable_for_normal;
2746 else /* requested oblique or italic */ {
2747 if (family->data->has_oblique_face || family->data->has_italic_face)
2748 func = is_font_acceptable_for_oblique_italic;
2751 for (i = 0; i < family->data->count; ++i)
2753 if (!func || func(family->data->fonts[i]))
2755 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
2759 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2760 init_font_prop_vec(weight, stretch, style, &req);
2761 matchingfonts_sort(fonts, &req);
2763 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2764 return S_OK;
2767 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2769 FIXME("%p, %u.\n", iface, index);
2771 return DWRITE_LOCALITY_LOCAL;
2774 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2776 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2778 TRACE("%p, %u, %p.\n", iface, index, font);
2780 *font = NULL;
2782 if (!family->data->count)
2783 return S_FALSE;
2785 if (index >= family->data->count)
2786 return E_FAIL;
2788 return create_font(family, index, font);
2791 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2792 IDWriteFontFaceReference **reference)
2794 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2795 const struct dwrite_font_data *font;
2797 TRACE("%p, %u, %p.\n", iface, index, reference);
2799 *reference = NULL;
2801 if (index >= family->data->count)
2802 return E_FAIL;
2804 font = family->data->fonts[index];
2805 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2806 font->file, font->face_index, font->simulations, reference);
2809 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2810 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2812 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2814 return E_NOTIMPL;
2817 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2819 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2821 TRACE("%p, %p.\n", iface, fontset);
2823 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
2824 family->data->count, fontset);
2827 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2829 dwritefontfamily_QueryInterface,
2830 dwritefontfamily_AddRef,
2831 dwritefontfamily_Release,
2832 dwritefontfamily_GetFontCollection,
2833 dwritefontfamily_GetFontCount,
2834 dwritefontfamily_GetFont,
2835 dwritefontfamily_GetFamilyNames,
2836 dwritefontfamily_GetFirstMatchingFont,
2837 dwritefontfamily_GetMatchingFonts,
2838 dwritefontfamily1_GetFontLocality,
2839 dwritefontfamily1_GetFont,
2840 dwritefontfamily1_GetFontFaceReference,
2841 dwritefontfamily2_GetMatchingFonts,
2842 dwritefontfamily2_GetFontSet,
2845 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2847 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2848 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2851 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2853 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2854 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2857 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2859 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2860 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2863 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2864 IDWriteFontCollection **collection)
2866 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2867 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2870 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2872 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2873 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2876 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2878 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2879 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2882 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2884 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2885 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2888 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2890 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2891 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2894 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2895 IDWriteFontFaceReference **reference)
2897 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2898 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2901 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2903 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2905 TRACE("%p, %p.\n", iface, fontset);
2907 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
2908 family->data->count, fontset);
2911 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2913 dwritefontfamilylist_QueryInterface,
2914 dwritefontfamilylist_AddRef,
2915 dwritefontfamilylist_Release,
2916 dwritefontfamilylist_GetFontCollection,
2917 dwritefontfamilylist_GetFontCount,
2918 dwritefontfamilylist_GetFont,
2919 dwritefontfamilylist1_GetFontLocality,
2920 dwritefontfamilylist1_GetFont,
2921 dwritefontfamilylist1_GetFontFaceReference,
2922 dwritefontfamilylist2_GetFontSet,
2925 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2926 struct dwrite_fontfamily **family)
2928 struct dwrite_fontfamily *object;
2930 *family = NULL;
2932 object = heap_alloc(sizeof(*object));
2933 if (!object)
2934 return E_OUTOFMEMORY;
2936 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2937 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2938 object->refcount = 1;
2939 object->collection = collection;
2940 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2941 object->data = collection->family_data[index];
2942 InterlockedIncrement(&object->data->refcount);
2944 *family = object;
2946 return S_OK;
2949 BOOL is_system_collection(IDWriteFontCollection *collection)
2951 void *obj;
2952 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2955 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2957 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2959 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2961 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2962 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2963 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2964 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2965 IsEqualIID(riid, &IID_IUnknown))
2967 *obj = iface;
2968 IDWriteFontCollection3_AddRef(iface);
2969 return S_OK;
2972 *obj = NULL;
2974 if (IsEqualIID(riid, &IID_issystemcollection))
2975 return S_OK;
2977 WARN("%s not implemented.\n", debugstr_guid(riid));
2979 return E_NOINTERFACE;
2982 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2984 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2986 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2987 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2988 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2989 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2990 IsEqualIID(riid, &IID_IUnknown))
2992 *obj = iface;
2993 IDWriteFontCollection3_AddRef(iface);
2994 return S_OK;
2997 WARN("%s not implemented.\n", debugstr_guid(riid));
2999 *obj = NULL;
3001 return E_NOINTERFACE;
3004 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
3006 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3007 ULONG refcount = InterlockedIncrement(&collection->refcount);
3009 TRACE("%p, refcount %d.\n", collection, refcount);
3011 return refcount;
3014 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
3016 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3017 ULONG refcount = InterlockedDecrement(&collection->refcount);
3018 size_t i;
3020 TRACE("%p, refcount %d.\n", iface, refcount);
3022 if (!refcount)
3024 factory_detach_fontcollection(collection->factory, iface);
3025 for (i = 0; i < collection->count; ++i)
3026 release_fontfamily_data(collection->family_data[i]);
3027 heap_free(collection->family_data);
3028 heap_free(collection);
3031 return refcount;
3034 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
3036 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3038 TRACE("%p.\n", iface);
3040 return collection->count;
3043 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3044 IDWriteFontFamily **ret)
3046 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3047 struct dwrite_fontfamily *family;
3048 HRESULT hr;
3050 TRACE("%p, %u, %p.\n", iface, index, ret);
3052 *ret = NULL;
3054 if (index >= collection->count)
3055 return E_FAIL;
3057 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3058 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
3060 return hr;
3063 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
3065 size_t i;
3067 for (i = 0; i < collection->count; ++i)
3069 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3070 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3071 HRESULT hr;
3073 for (j = 0; j < count; j++) {
3074 WCHAR buffer[255];
3075 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3076 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
3077 return i;
3081 return ~0u;
3084 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3085 UINT32 *index, BOOL *exists)
3087 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3089 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3091 *index = collection_find_family(collection, name);
3092 *exists = *index != ~0u;
3093 return S_OK;
3096 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3097 IDWriteFont **font)
3099 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3100 struct dwrite_fontfamily *family;
3101 BOOL found_font = FALSE;
3102 IDWriteFontFile *file;
3103 UINT32 face_index, count;
3104 size_t i, j;
3105 HRESULT hr;
3107 TRACE("%p, %p, %p.\n", iface, face, font);
3109 *font = NULL;
3111 if (!face)
3112 return E_INVALIDARG;
3114 count = 1;
3115 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3116 if (FAILED(hr))
3117 return hr;
3118 face_index = IDWriteFontFace_GetIndex(face);
3120 found_font = FALSE;
3121 for (i = 0; i < collection->count; ++i)
3123 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3125 for (j = 0; j < family_data->count; ++j)
3127 struct dwrite_font_data *font_data = family_data->fonts[j];
3129 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3130 found_font = TRUE;
3131 break;
3135 if (found_font)
3136 break;
3138 IDWriteFontFile_Release(file);
3140 if (!found_font)
3141 return DWRITE_E_NOFONT;
3143 hr = create_fontfamily(collection, i, &family);
3144 if (FAILED(hr))
3145 return hr;
3147 hr = create_font(family, j, (IDWriteFont3 **)font);
3148 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3149 return hr;
3152 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3154 FIXME("%p, %p.\n", iface, fontset);
3156 return E_NOTIMPL;
3159 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3160 IDWriteFontFamily1 **ret)
3162 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3163 struct dwrite_fontfamily *family;
3164 HRESULT hr;
3166 TRACE("%p, %u, %p.\n", iface, index, ret);
3168 *ret = NULL;
3170 if (index >= collection->count)
3171 return E_FAIL;
3173 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3174 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3176 return hr;
3179 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3180 UINT32 index, IDWriteFontFamily2 **ret)
3182 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3183 struct dwrite_fontfamily *family;
3184 HRESULT hr;
3186 TRACE("%p, %u, %p.\n", iface, index, ret);
3188 *ret = NULL;
3190 if (index >= collection->count)
3191 return E_FAIL;
3193 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3194 *ret = &family->IDWriteFontFamily2_iface;
3196 return hr;
3199 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3200 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3201 IDWriteFontList2 **fontlist)
3203 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3205 return E_NOTIMPL;
3208 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3210 FIXME("%p.\n", iface);
3212 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3215 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3217 FIXME("%p, %p.\n", iface, fontset);
3219 return E_NOTIMPL;
3222 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3224 FIXME("%p.\n", iface);
3226 return NULL;
3229 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3231 dwritefontcollection_QueryInterface,
3232 dwritefontcollection_AddRef,
3233 dwritefontcollection_Release,
3234 dwritefontcollection_GetFontFamilyCount,
3235 dwritefontcollection_GetFontFamily,
3236 dwritefontcollection_FindFamilyName,
3237 dwritefontcollection_GetFontFromFontFace,
3238 dwritefontcollection1_GetFontSet,
3239 dwritefontcollection1_GetFontFamily,
3240 dwritefontcollection2_GetFontFamily,
3241 dwritefontcollection2_GetMatchingFonts,
3242 dwritefontcollection2_GetFontFamilyModel,
3243 dwritefontcollection2_GetFontSet,
3244 dwritefontcollection3_GetExpirationEvent,
3247 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3249 dwritesystemfontcollection_QueryInterface,
3250 dwritefontcollection_AddRef,
3251 dwritefontcollection_Release,
3252 dwritefontcollection_GetFontFamilyCount,
3253 dwritefontcollection_GetFontFamily,
3254 dwritefontcollection_FindFamilyName,
3255 dwritefontcollection_GetFontFromFontFace,
3256 dwritefontcollection1_GetFontSet,
3257 dwritefontcollection1_GetFontFamily,
3258 dwritefontcollection2_GetFontFamily,
3259 dwritefontcollection2_GetMatchingFonts,
3260 dwritefontcollection2_GetFontFamilyModel,
3261 dwritefontcollection2_GetFontSet,
3262 dwritefontcollection3_GetExpirationEvent,
3265 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3267 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3268 sizeof(*family_data->fonts)))
3270 return E_OUTOFMEMORY;
3273 family_data->fonts[family_data->count++] = font_data;
3274 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3275 family_data->has_normal_face = 1;
3276 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3277 family_data->has_oblique_face = 1;
3278 else
3279 family_data->has_italic_face = 1;
3280 return S_OK;
3283 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3284 struct dwrite_fontfamily_data *family)
3286 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3287 sizeof(*collection->family_data)))
3289 return E_OUTOFMEMORY;
3292 collection->family_data[collection->count++] = family;
3293 return S_OK;
3296 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3298 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3299 collection->refcount = 1;
3300 collection->count = 0;
3301 collection->size = 0;
3302 collection->family_data = NULL;
3304 return S_OK;
3307 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3309 IDWriteFontFileLoader *loader;
3310 const void *key;
3311 UINT32 key_size;
3312 HRESULT hr;
3314 *stream = NULL;
3316 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3317 if (FAILED(hr))
3318 return hr;
3320 hr = IDWriteFontFile_GetLoader(file, &loader);
3321 if (FAILED(hr))
3322 return hr;
3324 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3325 IDWriteFontFileLoader_Release(loader);
3326 if (FAILED(hr))
3327 return hr;
3329 return hr;
3332 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3334 BOOL exists = FALSE;
3335 UINT32 index;
3336 HRESULT hr;
3338 buffer[0] = 0;
3339 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3340 if (FAILED(hr) || !exists)
3341 return;
3343 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3346 static int trim_spaces(WCHAR *in, WCHAR *ret)
3348 int len;
3350 while (isspaceW(*in))
3351 in++;
3353 ret[0] = 0;
3354 if (!(len = strlenW(in)))
3355 return 0;
3357 while (isspaceW(in[len-1]))
3358 len--;
3360 memcpy(ret, in, len*sizeof(WCHAR));
3361 ret[len] = 0;
3363 return len;
3366 struct name_token {
3367 struct list entry;
3368 const WCHAR *ptr;
3369 INT len; /* token length */
3370 INT fulllen; /* full length including following separators */
3373 static inline BOOL is_name_separator_char(WCHAR ch)
3375 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3378 struct name_pattern {
3379 const WCHAR *part1; /* NULL indicates end of list */
3380 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3383 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3385 const struct name_pattern *pattern;
3386 struct name_token *token;
3387 int i = 0;
3389 while ((pattern = &patterns[i++])->part1) {
3390 int len_part1 = strlenW(pattern->part1);
3391 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3393 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3394 if (len_part2 == 0) {
3395 /* simple case with single part pattern */
3396 if (token->len != len_part1)
3397 continue;
3399 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3400 if (match) *match = *token;
3401 list_remove(&token->entry);
3402 heap_free(token);
3403 return TRUE;
3406 else {
3407 struct name_token *next_token;
3408 struct list *next_entry;
3410 /* pattern parts are stored in reading order, tokens list is reversed */
3411 if (token->len < len_part2)
3412 continue;
3414 /* it's possible to have combined string as a token, like ExtraCondensed */
3415 if (token->len == len_part1 + len_part2) {
3416 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3417 continue;
3419 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3420 continue;
3422 /* combined string match */
3423 if (match) *match = *token;
3424 list_remove(&token->entry);
3425 heap_free(token);
3426 return TRUE;
3429 /* now it's only possible to have two tokens matched to respective pattern parts */
3430 if (token->len != len_part2)
3431 continue;
3433 next_entry = list_next(tokens, &token->entry);
3434 if (next_entry) {
3435 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3436 if (next_token->len != len_part1)
3437 continue;
3439 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3440 continue;
3442 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3443 continue;
3445 /* both parts matched, remove tokens */
3446 if (match) {
3447 match->ptr = next_token->ptr;
3448 match->len = (token->ptr - next_token->ptr) + token->len;
3450 list_remove(&token->entry);
3451 list_remove(&next_token->entry);
3452 heap_free(next_token);
3453 heap_free(token);
3454 return TRUE;
3460 if (match) {
3461 match->ptr = NULL;
3462 match->len = 0;
3464 return FALSE;
3467 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3469 static const WCHAR itaW[] = {'i','t','a',0};
3470 static const WCHAR italW[] = {'i','t','a','l',0};
3471 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3472 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3474 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3475 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3476 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3477 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3479 static const struct name_pattern italic_patterns[] = {
3480 { itaW },
3481 { italW },
3482 { italicW },
3483 { cursiveW },
3484 { kursivW },
3485 { NULL }
3488 static const struct name_pattern oblique_patterns[] = {
3489 { inclinedW },
3490 { obliqueW },
3491 { backslantedW },
3492 { backslantW },
3493 { slantedW },
3494 { NULL }
3497 /* italic patterns first */
3498 if (match_pattern_list(tokens, italic_patterns, match))
3499 return DWRITE_FONT_STYLE_ITALIC;
3501 /* oblique patterns */
3502 if (match_pattern_list(tokens, oblique_patterns, match))
3503 return DWRITE_FONT_STYLE_OBLIQUE;
3505 return style;
3508 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3509 struct name_token *match)
3511 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3512 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3513 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3514 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3515 static const WCHAR wideW[] = {'w','i','d','e',0};
3516 static const WCHAR condW[] = {'c','o','n','d',0};
3518 static const struct name_pattern ultracondensed_patterns[] = {
3519 { extraW, compressedW },
3520 { extW, compressedW },
3521 { ultraW, compressedW },
3522 { ultraW, condensedW },
3523 { ultraW, condW },
3524 { NULL }
3527 static const struct name_pattern extracondensed_patterns[] = {
3528 { compressedW },
3529 { extraW, condensedW },
3530 { extW, condensedW },
3531 { extraW, condW },
3532 { extW, condW },
3533 { NULL }
3536 static const struct name_pattern semicondensed_patterns[] = {
3537 { narrowW },
3538 { compactW },
3539 { semiW, condensedW },
3540 { semiW, condW },
3541 { NULL }
3544 static const struct name_pattern semiexpanded_patterns[] = {
3545 { wideW },
3546 { semiW, expandedW },
3547 { semiW, extendedW },
3548 { NULL }
3551 static const struct name_pattern extraexpanded_patterns[] = {
3552 { extraW, expandedW },
3553 { extW, expandedW },
3554 { extraW, extendedW },
3555 { extW, extendedW },
3556 { NULL }
3559 static const struct name_pattern ultraexpanded_patterns[] = {
3560 { ultraW, expandedW },
3561 { ultraW, extendedW },
3562 { NULL }
3565 static const struct name_pattern condensed_patterns[] = {
3566 { condensedW },
3567 { condW },
3568 { NULL }
3571 static const struct name_pattern expanded_patterns[] = {
3572 { expandedW },
3573 { extendedW },
3574 { NULL }
3577 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3578 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3580 if (match_pattern_list(tokens, extracondensed_patterns, match))
3581 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3583 if (match_pattern_list(tokens, semicondensed_patterns, match))
3584 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3586 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3587 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3589 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3590 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3592 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3593 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3595 if (match_pattern_list(tokens, condensed_patterns, match))
3596 return DWRITE_FONT_STRETCH_CONDENSED;
3598 if (match_pattern_list(tokens, expanded_patterns, match))
3599 return DWRITE_FONT_STRETCH_EXPANDED;
3601 return stretch;
3604 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3605 struct name_token *match)
3607 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3608 static const WCHAR nordW[] = {'n','o','r','d',0};
3610 static const struct name_pattern thin_patterns[] = {
3611 { extraW, thinW },
3612 { extW, thinW },
3613 { ultraW, thinW },
3614 { NULL }
3617 static const struct name_pattern extralight_patterns[] = {
3618 { extraW, lightW },
3619 { extW, lightW },
3620 { ultraW, lightW },
3621 { NULL }
3624 static const struct name_pattern semilight_patterns[] = {
3625 { semiW, lightW },
3626 { NULL }
3629 static const struct name_pattern demibold_patterns[] = {
3630 { semiW, boldW },
3631 { demiW, boldW },
3632 { NULL }
3635 static const struct name_pattern extrabold_patterns[] = {
3636 { extraW, boldW },
3637 { extW, boldW },
3638 { ultraW, boldW },
3639 { NULL }
3642 static const struct name_pattern extrablack_patterns[] = {
3643 { extraW, blackW },
3644 { extW, blackW },
3645 { ultraW, blackW },
3646 { NULL }
3649 static const struct name_pattern bold_patterns[] = {
3650 { boldW },
3651 { NULL }
3654 static const struct name_pattern thin2_patterns[] = {
3655 { thinW },
3656 { NULL }
3659 static const struct name_pattern light_patterns[] = {
3660 { lightW },
3661 { NULL }
3664 static const struct name_pattern medium_patterns[] = {
3665 { mediumW },
3666 { NULL }
3669 static const struct name_pattern black_patterns[] = {
3670 { blackW },
3671 { heavyW },
3672 { nordW },
3673 { NULL }
3676 static const struct name_pattern demibold2_patterns[] = {
3677 { demiW },
3678 { NULL }
3681 static const struct name_pattern extrabold2_patterns[] = {
3682 { ultraW },
3683 { NULL }
3686 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3687 matching pattern. */
3689 if (match_pattern_list(tokens, thin_patterns, match))
3690 return DWRITE_FONT_WEIGHT_THIN;
3692 if (match_pattern_list(tokens, extralight_patterns, match))
3693 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3695 if (match_pattern_list(tokens, semilight_patterns, match))
3696 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3698 if (match_pattern_list(tokens, demibold_patterns, match))
3699 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3701 if (match_pattern_list(tokens, extrabold_patterns, match))
3702 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3704 if (match_pattern_list(tokens, extrablack_patterns, match))
3705 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3707 if (match_pattern_list(tokens, bold_patterns, match))
3708 return DWRITE_FONT_WEIGHT_BOLD;
3710 if (match_pattern_list(tokens, thin2_patterns, match))
3711 return DWRITE_FONT_WEIGHT_THIN;
3713 if (match_pattern_list(tokens, light_patterns, match))
3714 return DWRITE_FONT_WEIGHT_LIGHT;
3716 if (match_pattern_list(tokens, medium_patterns, match))
3717 return DWRITE_FONT_WEIGHT_MEDIUM;
3719 if (match_pattern_list(tokens, black_patterns, match))
3720 return DWRITE_FONT_WEIGHT_BLACK;
3722 if (match_pattern_list(tokens, black_patterns, match))
3723 return DWRITE_FONT_WEIGHT_BLACK;
3725 if (match_pattern_list(tokens, demibold2_patterns, match))
3726 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3728 if (match_pattern_list(tokens, extrabold2_patterns, match))
3729 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3731 /* FIXME: use abbreviated names to extract weight */
3733 return weight;
3736 struct knownweight_entry {
3737 const WCHAR *nameW;
3738 DWRITE_FONT_WEIGHT weight;
3741 static int compare_knownweights(const void *a, const void* b)
3743 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3744 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3745 int ret = 0;
3747 if (target > entry->weight)
3748 ret = 1;
3749 else if (target < entry->weight)
3750 ret = -1;
3752 return ret;
3755 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3757 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3758 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3759 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3760 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3761 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3762 static const WCHAR thinW[] = {'T','h','i','n',0};
3763 static const WCHAR lightW[] = {'L','i','g','h','t',0};
3764 static const WCHAR mediumW[] = {'M','e','d','i','u','m',0};
3765 static const WCHAR blackW[] = {'B','l','a','c','k',0};
3766 const struct knownweight_entry *ptr;
3768 static const struct knownweight_entry knownweights[] = {
3769 { thinW, DWRITE_FONT_WEIGHT_THIN },
3770 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3771 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3772 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3773 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3774 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3775 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3776 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3777 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3778 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3781 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3782 compare_knownweights);
3783 if (!ptr) {
3784 nameW[0] = 0;
3785 return FALSE;
3788 strcpyW(nameW, ptr->nameW);
3789 return TRUE;
3792 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3794 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3795 strW[name->len] = 0;
3798 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3799 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3801 static const WCHAR bookW[] = {'B','o','o','k',0};
3802 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3803 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3804 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3805 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3807 static const WCHAR *regular_patterns[] = {
3808 bookW,
3809 normalW,
3810 regularW,
3811 romanW,
3812 uprightW,
3813 NULL
3816 const WCHAR *regular_ptr = NULL, *ptr;
3817 int i = 0;
3819 if (len == -1)
3820 len = strlenW(facenameW);
3822 /* remove rightmost regular variant from face name */
3823 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3824 int pattern_len = strlenW(ptr);
3825 WCHAR *src;
3827 if (pattern_len > len)
3828 continue;
3830 src = facenameW + len - pattern_len;
3831 while (src >= facenameW) {
3832 if (!strncmpiW(src, ptr, pattern_len)) {
3833 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3834 len = strlenW(facenameW);
3835 regular_ptr = ptr;
3836 break;
3838 else
3839 src--;
3843 return regular_ptr;
3846 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3848 const WCHAR *ptr;
3850 list_init(tokens);
3851 ptr = nameW;
3853 while (*ptr) {
3854 struct name_token *token = heap_alloc(sizeof(*token));
3855 token->ptr = ptr;
3856 token->len = 0;
3857 token->fulllen = 0;
3859 while (*ptr && !is_name_separator_char(*ptr)) {
3860 token->len++;
3861 token->fulllen++;
3862 ptr++;
3865 /* skip separators */
3866 while (is_name_separator_char(*ptr)) {
3867 token->fulllen++;
3868 ptr++;
3871 list_add_head(tokens, &token->entry);
3875 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3877 struct name_token *token, *token2;
3878 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3879 int len;
3881 list_remove(&token->entry);
3883 /* don't include last separator */
3884 len = list_empty(tokens) ? token->len : token->fulllen;
3885 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3886 nameW += len;
3888 heap_free(token);
3890 *nameW = 0;
3893 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3895 struct name_token stretch_name, weight_name, style_name;
3896 WCHAR familynameW[255], facenameW[255], finalW[255];
3897 WCHAR weightW[32], stretchW[32], styleW[32];
3898 const WCHAR *regular_ptr = NULL;
3899 DWRITE_FONT_STRETCH stretch;
3900 DWRITE_FONT_WEIGHT weight;
3901 struct list tokens;
3902 int len;
3904 /* remove leading and trailing spaces from family and face name */
3905 trim_spaces(familyW, familynameW);
3906 len = trim_spaces(faceW, facenameW);
3908 /* remove rightmost regular variant from face name */
3909 regular_ptr = facename_remove_regular_term(facenameW, len);
3911 /* append face name to family name, FIXME check if face name is a substring of family name */
3912 if (*facenameW) {
3913 strcatW(familynameW, spaceW);
3914 strcatW(familynameW, facenameW);
3917 /* tokenize with " .-_" */
3918 fontname_tokenize(&tokens, familynameW);
3920 /* extract and resolve style */
3921 font->style = font_extract_style(&tokens, font->style, &style_name);
3923 /* extract stretch */
3924 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3926 /* extract weight */
3927 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3929 /* resolve weight */
3930 if (weight != font->weight) {
3931 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3932 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3933 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3934 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3935 !(abs(weight - font->weight) <= 150 &&
3936 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3937 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3938 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3940 font->weight = weight;
3944 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3945 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3946 stretch itself is normal (extracted stretch is never normal). */
3947 if (stretch != font->stretch) {
3948 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3949 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3950 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3952 font->stretch = stretch;
3956 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3958 /* get final combined string from what's left in token list, list is released */
3959 fontname_tokens_to_str(&tokens, finalW);
3961 if (!strcmpW(familyW, finalW))
3962 return FALSE;
3964 /* construct face name */
3965 strcpyW(familyW, finalW);
3967 /* resolved weight name */
3968 if (weight_name.ptr)
3969 font_name_token_to_str(&weight_name, weightW);
3970 /* ignore normal weight */
3971 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3972 weightW[0] = 0;
3973 /* for known weight values use appropriate names */
3974 else if (is_known_weight_value(font->weight, weightW)) {
3976 /* use Wnnn format as a fallback in case weight is not one of known values */
3977 else {
3978 static const WCHAR fmtW[] = {'W','%','d',0};
3979 sprintfW(weightW, fmtW, font->weight);
3982 /* resolved stretch name */
3983 if (stretch_name.ptr)
3984 font_name_token_to_str(&stretch_name, stretchW);
3985 /* ignore normal stretch */
3986 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3987 stretchW[0] = 0;
3988 /* use predefined stretch names */
3989 else {
3990 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3991 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3992 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3993 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3994 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3995 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3997 static const WCHAR *stretchnamesW[] = {
3998 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3999 ultracondensedW,
4000 extracondensedW,
4001 condensedW,
4002 semicondensedW,
4003 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
4004 semiexpandedW,
4005 expandedW,
4006 extraexpandedW,
4007 ultraexpandedW
4009 strcpyW(stretchW, stretchnamesW[font->stretch]);
4012 /* resolved style name */
4013 if (style_name.ptr)
4014 font_name_token_to_str(&style_name, styleW);
4015 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
4016 styleW[0] = 0;
4017 /* use predefined names */
4018 else {
4019 if (font->style == DWRITE_FONT_STYLE_ITALIC)
4020 strcpyW(styleW, italicW);
4021 else
4022 strcpyW(styleW, obliqueW);
4025 /* use Regular match if it was found initially */
4026 if (!*weightW && !*stretchW && !*styleW)
4027 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
4028 else {
4029 faceW[0] = 0;
4030 if (*stretchW)
4031 strcpyW(faceW, stretchW);
4032 if (*weightW) {
4033 if (*faceW)
4034 strcatW(faceW, spaceW);
4035 strcatW(faceW, weightW);
4037 if (*styleW) {
4038 if (*faceW)
4039 strcatW(faceW, spaceW);
4040 strcatW(faceW, styleW);
4044 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
4045 return TRUE;
4048 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
4050 static const float width_axis_values[] =
4052 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
4053 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
4054 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
4055 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
4056 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
4057 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
4058 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
4059 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
4060 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
4061 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
4064 struct file_stream_desc stream_desc;
4065 struct dwrite_font_props props;
4066 struct dwrite_font_data *data;
4067 WCHAR familyW[255], faceW[255];
4068 HRESULT hr;
4070 *ret = NULL;
4072 data = heap_alloc_zero(sizeof(*data));
4073 if (!data)
4074 return E_OUTOFMEMORY;
4076 data->refcount = 1;
4077 data->file = desc->file;
4078 data->face_index = desc->index;
4079 data->face_type = desc->face_type;
4080 IDWriteFontFile_AddRef(data->file);
4082 stream_desc.stream = desc->stream;
4083 stream_desc.face_type = desc->face_type;
4084 stream_desc.face_index = desc->index;
4085 opentype_get_font_properties(&stream_desc, &props);
4086 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4087 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4089 /* get family name from font file */
4090 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
4091 if (FAILED(hr)) {
4092 WARN("unable to get family name from font\n");
4093 release_font_data(data);
4094 return hr;
4097 data->style = props.style;
4098 data->stretch = props.stretch;
4099 data->weight = props.weight;
4100 data->panose = props.panose;
4101 data->fontsig = props.fontsig;
4102 data->lf = props.lf;
4103 data->flags = props.flags;
4105 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4106 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4107 if (font_apply_differentiation_rules(data, familyW, faceW)) {
4108 set_en_localizedstring(data->family_names, familyW);
4109 set_en_localizedstring(data->names, faceW);
4112 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4114 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4115 data->axis[0].value = props.weight;
4116 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4117 data->axis[1].value = width_axis_values[props.stretch];
4118 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4119 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4121 *ret = data;
4122 return S_OK;
4125 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4126 const WCHAR *facenameW, struct dwrite_font_data **ret)
4128 struct dwrite_font_data *data;
4130 *ret = NULL;
4132 data = heap_alloc_zero(sizeof(*data));
4133 if (!data)
4134 return E_OUTOFMEMORY;
4136 *data = *src;
4137 data->refcount = 1;
4138 data->simulations |= simulations;
4139 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4140 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4141 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4142 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4143 memset(data->info_strings, 0, sizeof(data->info_strings));
4144 data->names = NULL;
4145 IDWriteFontFile_AddRef(data->file);
4146 IDWriteLocalizedStrings_AddRef(data->family_names);
4148 create_localizedstrings(&data->names);
4149 add_localizedstring(data->names, enusW, facenameW);
4151 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4153 *ret = data;
4154 return S_OK;
4157 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4159 struct dwrite_fontfamily_data *data;
4161 data = heap_alloc_zero(sizeof(*data));
4162 if (!data)
4163 return E_OUTOFMEMORY;
4165 data->refcount = 1;
4166 data->familyname = familyname;
4167 IDWriteLocalizedStrings_AddRef(familyname);
4169 *ret = data;
4171 return S_OK;
4174 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4176 size_t i, j, heaviest;
4178 for (i = 0; i < family->count; ++i)
4180 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4181 heaviest = i;
4183 if (family->fonts[i]->bold_sim_tested)
4184 continue;
4186 family->fonts[i]->bold_sim_tested = 1;
4187 for (j = i; j < family->count; ++j)
4189 if (family->fonts[j]->bold_sim_tested)
4190 continue;
4192 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4193 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4194 if (family->fonts[j]->weight > weight) {
4195 weight = family->fonts[j]->weight;
4196 heaviest = j;
4198 family->fonts[j]->bold_sim_tested = 1;
4202 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4203 static const struct name_pattern weightsim_patterns[] = {
4204 { extraW, lightW },
4205 { extW, lightW },
4206 { ultraW, lightW },
4207 { semiW, lightW },
4208 { semiW, boldW },
4209 { demiW, boldW },
4210 { boldW },
4211 { thinW },
4212 { lightW },
4213 { mediumW },
4214 { demiW },
4215 { NULL }
4218 WCHAR facenameW[255], initialW[255];
4219 struct dwrite_font_data *boldface;
4220 struct list tokens;
4222 /* add Bold simulation based on heaviest face data */
4224 /* Simulated face name should only contain Bold as weight term,
4225 so remove existing regular and weight terms. */
4226 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4227 facename_remove_regular_term(initialW, -1);
4229 /* remove current weight pattern */
4230 fontname_tokenize(&tokens, initialW);
4231 match_pattern_list(&tokens, weightsim_patterns, NULL);
4232 fontname_tokens_to_str(&tokens, facenameW);
4234 /* Bold suffix for new name */
4235 if (*facenameW)
4236 strcatW(facenameW, spaceW);
4237 strcatW(facenameW, boldW);
4239 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4240 boldface->bold_sim_tested = 1;
4241 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4242 fontfamily_add_font(family, boldface);
4248 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4250 size_t i, j;
4252 for (i = 0; i < family->count; ++i)
4254 UINT32 regular = ~0u, oblique = ~0u;
4255 struct dwrite_font_data *obliqueface;
4256 WCHAR facenameW[255];
4258 if (family->fonts[i]->oblique_sim_tested)
4259 continue;
4261 family->fonts[i]->oblique_sim_tested = 1;
4262 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4263 regular = i;
4264 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4265 oblique = i;
4267 /* find regular style with same weight/stretch values */
4268 for (j = i; j < family->count; ++j)
4270 if (family->fonts[j]->oblique_sim_tested)
4271 continue;
4273 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4274 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4276 family->fonts[j]->oblique_sim_tested = 1;
4277 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4278 regular = j;
4280 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4281 oblique = j;
4284 if (regular != ~0u && oblique != ~0u)
4285 break;
4288 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4289 if (regular == ~0u)
4290 continue;
4292 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4293 if (oblique != ~0u)
4294 continue;
4296 /* add oblique simulation based on this regular face */
4298 /* remove regular term if any, append 'Oblique' */
4299 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4300 facename_remove_regular_term(facenameW, -1);
4302 if (*facenameW)
4303 strcatW(facenameW, spaceW);
4304 strcatW(facenameW, obliqueW);
4306 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4307 obliqueface->oblique_sim_tested = 1;
4308 obliqueface->lf.lfItalic = 1;
4309 fontfamily_add_font(family, obliqueface);
4314 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4315 const WCHAR *replacement_name)
4317 UINT32 i = collection_find_family(collection, replacement_name);
4318 struct dwrite_fontfamily_data *target;
4319 IDWriteLocalizedStrings *strings;
4320 HRESULT hr;
4322 /* replacement does not exist */
4323 if (i == ~0u)
4324 return FALSE;
4326 hr = create_localizedstrings(&strings);
4327 if (FAILED(hr))
4328 return FALSE;
4330 /* add a new family with target name, reuse font data from replacement */
4331 add_localizedstring(strings, enusW, target_name);
4332 hr = init_fontfamily_data(strings, &target);
4333 if (hr == S_OK) {
4334 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4335 WCHAR nameW[255];
4337 for (i = 0; i < replacement->count; ++i)
4339 fontfamily_add_font(target, replacement->fonts[i]);
4340 addref_font_data(replacement->fonts[i]);
4343 fontcollection_add_family(collection, target);
4344 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4345 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4347 IDWriteLocalizedStrings_Release(strings);
4348 return TRUE;
4351 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4352 system font collections. */
4353 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4355 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4356 WCHAR *name;
4357 void *data;
4358 HKEY hkey;
4360 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4361 return;
4363 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4364 RegCloseKey(hkey);
4365 return;
4368 max_namelen++; /* returned value doesn't include room for '\0' */
4369 name = heap_alloc(max_namelen * sizeof(WCHAR));
4370 data = heap_alloc(max_datalen);
4372 datalen = max_datalen;
4373 namelen = max_namelen;
4374 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4375 if (collection_find_family(collection, name) == ~0u) {
4376 if (type == REG_MULTI_SZ) {
4377 WCHAR *replacement = data;
4378 while (*replacement) {
4379 if (fontcollection_add_replacement(collection, name, replacement))
4380 break;
4381 replacement += strlenW(replacement) + 1;
4384 else if (type == REG_SZ)
4385 fontcollection_add_replacement(collection, name, data);
4387 else
4388 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4390 datalen = max_datalen;
4391 namelen = max_namelen;
4394 heap_free(data);
4395 heap_free(name);
4396 RegCloseKey(hkey);
4399 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4400 IDWriteFontCollection3 **ret)
4402 struct fontfile_enum {
4403 struct list entry;
4404 IDWriteFontFile *file;
4406 struct fontfile_enum *fileenum, *fileenum2;
4407 struct dwrite_fontcollection *collection;
4408 struct list scannedfiles;
4409 BOOL current = FALSE;
4410 HRESULT hr = S_OK;
4411 size_t i;
4413 *ret = NULL;
4415 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4416 if (!collection) return E_OUTOFMEMORY;
4418 hr = init_font_collection(collection, is_system);
4419 if (FAILED(hr)) {
4420 heap_free(collection);
4421 return hr;
4424 *ret = &collection->IDWriteFontCollection3_iface;
4426 TRACE("building font collection:\n");
4428 list_init(&scannedfiles);
4429 while (hr == S_OK) {
4430 DWRITE_FONT_FACE_TYPE face_type;
4431 DWRITE_FONT_FILE_TYPE file_type;
4432 BOOL supported, same = FALSE;
4433 IDWriteFontFileStream *stream;
4434 IDWriteFontFile *file;
4435 UINT32 face_count;
4437 current = FALSE;
4438 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4439 if (FAILED(hr) || !current)
4440 break;
4442 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4443 if (FAILED(hr))
4444 break;
4446 /* check if we've scanned this file already */
4447 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4448 if ((same = is_same_fontfile(fileenum->file, file)))
4449 break;
4452 if (same) {
4453 IDWriteFontFile_Release(file);
4454 continue;
4457 if (FAILED(get_filestream_from_file(file, &stream))) {
4458 IDWriteFontFile_Release(file);
4459 continue;
4462 /* Unsupported formats are skipped. */
4463 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4464 if (FAILED(hr) || !supported || face_count == 0) {
4465 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4466 IDWriteFontFileStream_Release(stream);
4467 IDWriteFontFile_Release(file);
4468 hr = S_OK;
4469 continue;
4472 /* add to scanned list */
4473 fileenum = heap_alloc(sizeof(*fileenum));
4474 fileenum->file = file;
4475 list_add_tail(&scannedfiles, &fileenum->entry);
4477 for (i = 0; i < face_count; ++i)
4479 struct dwrite_font_data *font_data;
4480 struct fontface_desc desc;
4481 WCHAR familyW[255];
4482 UINT32 index;
4484 desc.factory = factory;
4485 desc.face_type = face_type;
4486 desc.file = file;
4487 desc.stream = stream;
4488 desc.index = i;
4489 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4490 desc.font_data = NULL;
4492 /* Allocate an initialize new font data structure. */
4493 hr = init_font_data(&desc, &font_data);
4494 if (FAILED(hr))
4496 /* move to next one */
4497 hr = S_OK;
4498 continue;
4501 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4503 /* ignore dot named faces */
4504 if (familyW[0] == '.')
4506 WARN("Ignoring face %s\n", debugstr_w(familyW));
4507 release_font_data(font_data);
4508 continue;
4511 index = collection_find_family(collection, familyW);
4512 if (index != ~0u)
4513 hr = fontfamily_add_font(collection->family_data[index], font_data);
4514 else {
4515 struct dwrite_fontfamily_data *family_data;
4517 /* create and init new family */
4518 hr = init_fontfamily_data(font_data->family_names, &family_data);
4519 if (hr == S_OK) {
4520 /* add font to family, family - to collection */
4521 hr = fontfamily_add_font(family_data, font_data);
4522 if (hr == S_OK)
4523 hr = fontcollection_add_family(collection, family_data);
4525 if (FAILED(hr))
4526 release_fontfamily_data(family_data);
4530 if (FAILED(hr))
4531 break;
4534 IDWriteFontFileStream_Release(stream);
4537 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4538 IDWriteFontFile_Release(fileenum->file);
4539 list_remove(&fileenum->entry);
4540 heap_free(fileenum);
4543 for (i = 0; i < collection->count; ++i)
4545 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4546 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4549 if (is_system)
4550 fontcollection_add_replacements(collection);
4552 collection->factory = factory;
4553 IDWriteFactory7_AddRef(factory);
4555 return hr;
4558 struct system_fontfile_enumerator
4560 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4561 LONG refcount;
4563 IDWriteFactory7 *factory;
4564 HKEY hkey;
4565 int index;
4567 WCHAR *filename;
4568 DWORD filename_size;
4571 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4573 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4576 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4578 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4579 IDWriteFontFileEnumerator_AddRef(iface);
4580 *obj = iface;
4581 return S_OK;
4584 WARN("%s not implemented.\n", debugstr_guid(riid));
4586 *obj = NULL;
4588 return E_NOINTERFACE;
4591 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4593 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4594 return InterlockedIncrement(&enumerator->refcount);
4597 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4599 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4600 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4602 if (!refcount)
4604 IDWriteFactory7_Release(enumerator->factory);
4605 RegCloseKey(enumerator->hkey);
4606 heap_free(enumerator->filename);
4607 heap_free(enumerator);
4610 return refcount;
4613 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4615 HRESULT hr;
4617 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4618 if (!strchrW(filename, '\\')) {
4619 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4620 WCHAR fullpathW[MAX_PATH];
4622 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4623 strcatW(fullpathW, fontsW);
4624 strcatW(fullpathW, filename);
4626 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4628 else
4629 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4631 return hr;
4634 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4636 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4638 *file = NULL;
4640 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4641 return E_FAIL;
4643 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4646 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4648 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4649 WCHAR name_buf[256], *name = name_buf;
4650 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4651 HRESULT hr = S_OK;
4652 LONG r;
4654 *current = FALSE;
4655 enumerator->index++;
4657 /* iterate until we find next string value */
4658 for (;;) {
4659 do {
4660 name_count = max_name_count;
4661 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4663 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4664 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4665 if (r == ERROR_MORE_DATA) {
4666 if (name_count >= max_name_count) {
4667 if (name != name_buf) heap_free(name);
4668 max_name_count *= 2;
4669 name = heap_alloc(max_name_count * sizeof(*name));
4670 if (!name) return E_OUTOFMEMORY;
4672 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4673 heap_free(enumerator->filename);
4674 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4675 enumerator->filename = heap_alloc(enumerator->filename_size);
4676 if (!enumerator->filename) {
4677 hr = E_OUTOFMEMORY;
4678 goto err;
4682 } while (r == ERROR_MORE_DATA);
4684 if (r != ERROR_SUCCESS) {
4685 enumerator->filename[0] = 0;
4686 break;
4688 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4689 if (type == REG_SZ && *name != '@') {
4690 *current = TRUE;
4691 break;
4693 enumerator->index++;
4695 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4697 err:
4698 if (name != name_buf) heap_free(name);
4699 return hr;
4702 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4704 systemfontfileenumerator_QueryInterface,
4705 systemfontfileenumerator_AddRef,
4706 systemfontfileenumerator_Release,
4707 systemfontfileenumerator_MoveNext,
4708 systemfontfileenumerator_GetCurrentFontFile
4711 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4713 struct system_fontfile_enumerator *enumerator;
4714 static const WCHAR fontslistW[] = {
4715 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4716 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4717 'F','o','n','t','s',0
4720 *ret = NULL;
4722 enumerator = heap_alloc(sizeof(*enumerator));
4723 if (!enumerator)
4724 return E_OUTOFMEMORY;
4726 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4727 enumerator->refcount = 1;
4728 enumerator->factory = factory;
4729 enumerator->index = -1;
4730 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4731 enumerator->filename = heap_alloc(enumerator->filename_size);
4732 if (!enumerator->filename) {
4733 heap_free(enumerator);
4734 return E_OUTOFMEMORY;
4737 IDWriteFactory7_AddRef(factory);
4739 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4741 ERR("failed to open fonts list key\n");
4742 IDWriteFactory7_Release(factory);
4743 heap_free(enumerator->filename);
4744 heap_free(enumerator);
4745 return E_FAIL;
4748 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4750 return S_OK;
4753 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4755 IDWriteFontFileEnumerator *enumerator;
4756 HRESULT hr;
4758 *collection = NULL;
4760 hr = create_system_fontfile_enumerator(factory, &enumerator);
4761 if (FAILED(hr))
4762 return hr;
4764 TRACE("building system font collection for factory %p\n", factory);
4765 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4766 IDWriteFontFileEnumerator_Release(enumerator);
4767 return hr;
4770 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4771 const WCHAR *keynameW, const WCHAR *pathW)
4773 static const WCHAR defaultfontW[] = {'S','y','s','t','e','m','D','e','f','a','u','l','t','E','U','D','C','F','o','n','t',0};
4774 static const WCHAR emptyW[] = {0};
4775 struct dwrite_fontfamily_data *family_data;
4776 IDWriteLocalizedStrings *names;
4777 DWRITE_FONT_FACE_TYPE face_type;
4778 DWRITE_FONT_FILE_TYPE file_type;
4779 IDWriteFontFileStream *stream;
4780 IDWriteFontFile *file;
4781 UINT32 face_count, i;
4782 BOOL supported;
4783 HRESULT hr;
4785 /* create font file from this path */
4786 hr = create_local_file_reference(factory, pathW, &file);
4787 if (FAILED(hr))
4788 return S_FALSE;
4790 if (FAILED(get_filestream_from_file(file, &stream))) {
4791 IDWriteFontFile_Release(file);
4792 return S_FALSE;
4795 /* Unsupported formats are skipped. */
4796 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4797 if (FAILED(hr) || !supported || face_count == 0) {
4798 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4799 IDWriteFontFileStream_Release(stream);
4800 IDWriteFontFile_Release(file);
4801 return S_FALSE;
4804 /* create and init new family */
4806 /* Family names are added for non-specific locale, represented with empty string.
4807 Default family appears with empty family name. */
4808 create_localizedstrings(&names);
4809 if (!strcmpiW(keynameW, defaultfontW))
4810 add_localizedstring(names, emptyW, emptyW);
4811 else
4812 add_localizedstring(names, emptyW, keynameW);
4814 hr = init_fontfamily_data(names, &family_data);
4815 IDWriteLocalizedStrings_Release(names);
4816 if (hr != S_OK) {
4817 IDWriteFontFile_Release(file);
4818 return hr;
4821 /* fill with faces */
4822 for (i = 0; i < face_count; i++) {
4823 struct dwrite_font_data *font_data;
4824 struct fontface_desc desc;
4826 /* Allocate new font data structure. */
4827 desc.factory = factory;
4828 desc.face_type = face_type;
4829 desc.index = i;
4830 desc.file = file;
4831 desc.stream = stream;
4832 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4833 desc.font_data = NULL;
4835 hr = init_font_data(&desc, &font_data);
4836 if (FAILED(hr))
4837 continue;
4839 /* add font to family */
4840 hr = fontfamily_add_font(family_data, font_data);
4841 if (hr != S_OK)
4842 release_font_data(font_data);
4845 /* add family to collection */
4846 hr = fontcollection_add_family(collection, family_data);
4847 if (FAILED(hr))
4848 release_fontfamily_data(family_data);
4849 IDWriteFontFileStream_Release(stream);
4850 IDWriteFontFile_Release(file);
4852 return hr;
4855 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4857 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4858 struct dwrite_fontcollection *collection;
4859 static const WCHAR emptyW[] = {0};
4860 WCHAR eudckeypathW[16];
4861 HKEY eudckey;
4862 DWORD index;
4863 BOOL exists;
4864 LONG retval;
4865 HRESULT hr;
4866 size_t i;
4868 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4870 *ret = NULL;
4872 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4873 if (!collection) return E_OUTOFMEMORY;
4875 hr = init_font_collection(collection, FALSE);
4876 if (FAILED(hr)) {
4877 heap_free(collection);
4878 return hr;
4881 *ret = &collection->IDWriteFontCollection3_iface;
4882 collection->factory = factory;
4883 IDWriteFactory7_AddRef(factory);
4885 /* return empty collection if EUDC fonts are not configured */
4886 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4887 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4888 return S_OK;
4890 retval = ERROR_SUCCESS;
4891 index = 0;
4892 while (retval != ERROR_NO_MORE_ITEMS) {
4893 WCHAR keynameW[64], pathW[MAX_PATH];
4894 DWORD type, path_len, name_len;
4896 path_len = ARRAY_SIZE(pathW);
4897 name_len = ARRAY_SIZE(keynameW);
4898 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4899 if (retval || type != REG_SZ)
4900 continue;
4902 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4903 if (hr != S_OK)
4904 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4906 RegCloseKey(eudckey);
4908 /* try to add global default if not defined for specific codepage */
4909 exists = FALSE;
4910 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4911 &index, &exists);
4912 if (FAILED(hr) || !exists) {
4913 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4914 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4915 if (hr != S_OK)
4916 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4919 /* EUDC collection offers simulated faces too */
4920 for (i = 0; i < collection->count; ++i)
4922 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4923 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4926 return S_OK;
4929 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4931 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4933 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4935 *obj = iface;
4936 IDWriteFontFile_AddRef(iface);
4937 return S_OK;
4940 WARN("%s not implemented.\n", debugstr_guid(riid));
4942 *obj = NULL;
4943 return E_NOINTERFACE;
4946 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4948 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4949 ULONG refcount = InterlockedIncrement(&file->refcount);
4951 TRACE("%p, refcount %d.\n", iface, refcount);
4953 return refcount;
4956 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4958 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4959 ULONG refcount = InterlockedDecrement(&file->refcount);
4961 TRACE("%p, refcount %d.\n", iface, refcount);
4963 if (!refcount)
4965 IDWriteFontFileLoader_Release(file->loader);
4966 if (file->stream)
4967 IDWriteFontFileStream_Release(file->stream);
4968 heap_free(file->reference_key);
4969 heap_free(file);
4972 return refcount;
4975 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
4977 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4979 TRACE("%p, %p, %p.\n", iface, key, key_size);
4981 *key = file->reference_key;
4982 *key_size = file->key_size;
4984 return S_OK;
4987 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
4989 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4991 TRACE("%p, %p.\n", iface, loader);
4993 *loader = file->loader;
4994 IDWriteFontFileLoader_AddRef(*loader);
4996 return S_OK;
4999 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
5000 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
5002 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
5003 IDWriteFontFileStream *stream;
5004 HRESULT hr;
5006 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
5008 *is_supported = FALSE;
5009 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
5010 if (face_type)
5011 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
5012 *face_count = 0;
5014 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
5015 if (FAILED(hr))
5016 return hr;
5018 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
5020 /* TODO: Further Analysis */
5021 IDWriteFontFileStream_Release(stream);
5022 return S_OK;
5025 static const IDWriteFontFileVtbl dwritefontfilevtbl =
5027 dwritefontfile_QueryInterface,
5028 dwritefontfile_AddRef,
5029 dwritefontfile_Release,
5030 dwritefontfile_GetReferenceKey,
5031 dwritefontfile_GetLoader,
5032 dwritefontfile_Analyze,
5035 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
5036 IDWriteFontFile **ret)
5038 struct dwrite_fontfile *file;
5039 void *key;
5041 *ret = NULL;
5043 file = heap_alloc(sizeof(*file));
5044 key = heap_alloc(key_size);
5045 if (!file || !key) {
5046 heap_free(file);
5047 heap_free(key);
5048 return E_OUTOFMEMORY;
5051 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
5052 file->refcount = 1;
5053 IDWriteFontFileLoader_AddRef(loader);
5054 file->loader = loader;
5055 file->stream = NULL;
5056 file->reference_key = key;
5057 memcpy(file->reference_key, reference_key, key_size);
5058 file->key_size = key_size;
5060 *ret = &file->IDWriteFontFile_iface;
5062 return S_OK;
5065 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5067 struct file_stream_desc stream_desc;
5068 struct dwrite_font_data *font_data;
5069 struct dwrite_fontface *fontface;
5070 HRESULT hr;
5071 int i;
5073 *ret = NULL;
5075 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
5076 if (!fontface)
5077 return E_OUTOFMEMORY;
5079 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5080 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5081 fontface->refcount = 1;
5082 fontface->type = desc->face_type;
5083 fontface->vdmx.exists = TRUE;
5084 fontface->gasp.exists = TRUE;
5085 fontface->cpal.exists = TRUE;
5086 fontface->colr.exists = TRUE;
5087 fontface->kern.exists = TRUE;
5088 fontface->index = desc->index;
5089 fontface->simulations = desc->simulations;
5090 fontface->factory = desc->factory;
5091 IDWriteFactory7_AddRef(fontface->factory);
5092 fontface->file = desc->file;
5093 IDWriteFontFile_AddRef(fontface->file);
5094 fontface->stream = desc->stream;
5095 IDWriteFontFileStream_AddRef(fontface->stream);
5097 stream_desc.stream = fontface->stream;
5098 stream_desc.face_type = desc->face_type;
5099 stream_desc.face_index = desc->index;
5100 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5101 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5102 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5103 /* TODO: test what happens if caret is already slanted */
5104 if (fontface->caret.slopeRise == 1) {
5105 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5106 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5109 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5111 /* Font properties are reused from font object when 'normal' face creation path is used:
5112 collection -> family -> matching font -> fontface.
5114 If face is created directly from factory we have to go through properties resolution.
5116 if (desc->font_data)
5118 font_data = addref_font_data(desc->font_data);
5120 else
5122 hr = init_font_data(desc, &font_data);
5123 if (FAILED(hr))
5125 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5126 return hr;
5130 fontface->weight = font_data->weight;
5131 fontface->style = font_data->style;
5132 fontface->stretch = font_data->stretch;
5133 fontface->panose = font_data->panose;
5134 fontface->fontsig = font_data->fontsig;
5135 fontface->lf = font_data->lf;
5136 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5137 fontface->names = font_data->names;
5138 if (fontface->names)
5139 IDWriteLocalizedStrings_AddRef(fontface->names);
5140 fontface->family_names = font_data->family_names;
5141 if (fontface->family_names)
5142 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5143 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5144 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5146 if (fontface->info_strings[i])
5147 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5149 fontface->cmap.stream = fontface->stream;
5150 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5151 release_font_data(font_data);
5153 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5155 *ret = &fontface->IDWriteFontFace5_iface;
5157 return S_OK;
5160 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5161 struct local_refkey
5163 FILETIME writetime;
5164 WCHAR name[1];
5167 struct local_cached_stream
5169 struct list entry;
5170 IDWriteFontFileStream *stream;
5171 struct local_refkey *key;
5172 UINT32 key_size;
5175 struct dwrite_localfontfilestream
5177 IDWriteFontFileStream IDWriteFontFileStream_iface;
5178 LONG refcount;
5180 struct local_cached_stream *entry;
5181 const void *file_ptr;
5182 UINT64 size;
5185 struct dwrite_localfontfileloader
5187 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5188 LONG refcount;
5190 struct list streams;
5191 CRITICAL_SECTION cs;
5194 static struct dwrite_localfontfileloader local_fontfile_loader;
5196 struct dwrite_inmemory_stream_data
5198 LONG refcount;
5199 IUnknown *owner;
5200 void *data;
5201 UINT32 size;
5204 struct dwrite_inmemory_filestream
5206 IDWriteFontFileStream IDWriteFontFileStream_iface;
5207 LONG refcount;
5209 struct dwrite_inmemory_stream_data *data;
5212 struct dwrite_inmemory_fileloader
5214 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5215 LONG refcount;
5217 struct dwrite_inmemory_stream_data **streams;
5218 size_t size;
5219 size_t count;
5222 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5224 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5227 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5229 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5232 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5234 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5237 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5239 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5242 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5244 if (InterlockedDecrement(&stream->refcount) == 0)
5246 if (stream->owner)
5247 IUnknown_Release(stream->owner);
5248 else
5249 heap_free(stream->data);
5250 heap_free(stream);
5254 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5256 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5258 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5260 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5261 IsEqualIID(riid, &IID_IUnknown))
5263 *obj = iface;
5264 if (InterlockedIncrement(&stream->refcount) == 1)
5266 InterlockedDecrement(&stream->refcount);
5267 *obj = NULL;
5268 return E_FAIL;
5270 return S_OK;
5273 WARN("%s not implemented.\n", debugstr_guid(riid));
5275 *obj = NULL;
5276 return E_NOINTERFACE;
5279 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5281 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5282 ULONG refcount = InterlockedIncrement(&stream->refcount);
5284 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5286 return refcount;
5289 static inline void release_cached_stream(struct local_cached_stream *stream)
5291 list_remove(&stream->entry);
5292 heap_free(stream->key);
5293 heap_free(stream);
5296 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5298 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5299 ULONG refcount = InterlockedDecrement(&stream->refcount);
5301 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5303 if (!refcount)
5305 UnmapViewOfFile(stream->file_ptr);
5307 EnterCriticalSection(&local_fontfile_loader.cs);
5308 release_cached_stream(stream->entry);
5309 LeaveCriticalSection(&local_fontfile_loader.cs);
5311 heap_free(stream);
5314 return refcount;
5317 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5318 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5320 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5322 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5323 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5325 *fragment_context = NULL;
5327 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5329 *fragment_start = NULL;
5330 return E_FAIL;
5333 *fragment_start = (char *)stream->file_ptr + offset;
5334 return S_OK;
5337 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5339 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5342 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5344 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5346 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5348 *size = stream->size;
5349 return S_OK;
5352 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5354 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5355 ULARGE_INTEGER li;
5357 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5359 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5360 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5361 *last_writetime = li.QuadPart;
5363 return S_OK;
5366 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5368 localfontfilestream_QueryInterface,
5369 localfontfilestream_AddRef,
5370 localfontfilestream_Release,
5371 localfontfilestream_ReadFileFragment,
5372 localfontfilestream_ReleaseFileFragment,
5373 localfontfilestream_GetFileSize,
5374 localfontfilestream_GetLastWriteTime
5377 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5378 IDWriteFontFileStream **ret)
5380 struct dwrite_localfontfilestream *object;
5382 *ret = NULL;
5384 if (!(object = heap_alloc(sizeof(*object))))
5385 return E_OUTOFMEMORY;
5387 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5388 object->refcount = 1;
5390 object->file_ptr = file_ptr;
5391 object->size = size;
5392 object->entry = entry;
5394 *ret = &object->IDWriteFontFileStream_iface;
5396 return S_OK;
5399 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5401 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5403 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5404 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5405 IsEqualIID(riid, &IID_IUnknown))
5407 *obj = iface;
5408 IDWriteLocalFontFileLoader_AddRef(iface);
5409 return S_OK;
5412 WARN("%s not implemented.\n", debugstr_guid(riid));
5414 *obj = NULL;
5415 return E_NOINTERFACE;
5418 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5420 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5421 ULONG refcount = InterlockedIncrement(&loader->refcount);
5423 TRACE("%p, refcount %d.\n", iface, refcount);
5425 return refcount;
5428 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5430 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5431 ULONG refcount = InterlockedDecrement(&loader->refcount);
5433 TRACE("%p, refcount %d.\n", iface, refcount);
5435 return refcount;
5438 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5440 const struct local_refkey *refkey = key;
5441 struct local_cached_stream *stream;
5442 IDWriteFontFileStream *filestream;
5443 HANDLE file, mapping;
5444 LARGE_INTEGER size;
5445 void *file_ptr;
5446 HRESULT hr = S_OK;
5448 *ret = NULL;
5450 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5451 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5452 if (file == INVALID_HANDLE_VALUE) {
5453 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5454 return E_FAIL;
5457 GetFileSizeEx(file, &size);
5458 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5459 CloseHandle(file);
5460 if (!mapping)
5461 return E_FAIL;
5463 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5464 CloseHandle(mapping);
5465 if (!file_ptr) {
5466 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5467 return E_FAIL;
5470 stream = heap_alloc(sizeof(*stream));
5471 if (!stream) {
5472 UnmapViewOfFile(file_ptr);
5473 return E_OUTOFMEMORY;
5476 stream->key = heap_alloc(key_size);
5477 if (!stream->key) {
5478 UnmapViewOfFile(file_ptr);
5479 heap_free(stream);
5480 return E_OUTOFMEMORY;
5483 stream->key_size = key_size;
5484 memcpy(stream->key, key, key_size);
5486 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5487 if (FAILED(hr)) {
5488 UnmapViewOfFile(file_ptr);
5489 heap_free(stream->key);
5490 heap_free(stream);
5491 return hr;
5494 stream->stream = filestream;
5496 *ret = stream;
5498 return S_OK;
5501 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5502 UINT32 key_size, IDWriteFontFileStream **ret)
5504 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5505 struct local_cached_stream *stream;
5506 HRESULT hr = S_OK;
5508 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5510 EnterCriticalSection(&loader->cs);
5512 *ret = NULL;
5514 /* search cache first */
5515 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5517 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5518 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5519 break;
5523 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5525 list_add_head(&loader->streams, &stream->entry);
5526 *ret = stream->stream;
5529 LeaveCriticalSection(&loader->cs);
5531 return hr;
5534 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5535 UINT32 key_size, UINT32 *length)
5537 const struct local_refkey *refkey = key;
5539 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5541 *length = strlenW(refkey->name);
5542 return S_OK;
5545 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5546 UINT32 key_size, WCHAR *path, UINT32 length)
5548 const struct local_refkey *refkey = key;
5550 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5552 if (length < strlenW(refkey->name))
5553 return E_INVALIDARG;
5555 strcpyW(path, refkey->name);
5556 return S_OK;
5559 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5560 UINT32 key_size, FILETIME *writetime)
5562 const struct local_refkey *refkey = key;
5564 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5566 *writetime = refkey->writetime;
5567 return S_OK;
5570 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5572 localfontfileloader_QueryInterface,
5573 localfontfileloader_AddRef,
5574 localfontfileloader_Release,
5575 localfontfileloader_CreateStreamFromKey,
5576 localfontfileloader_GetFilePathLengthFromKey,
5577 localfontfileloader_GetFilePathFromKey,
5578 localfontfileloader_GetLastWriteTimeFromKey
5581 void init_local_fontfile_loader(void)
5583 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5584 local_fontfile_loader.refcount = 1;
5585 list_init(&local_fontfile_loader.streams);
5586 InitializeCriticalSection(&local_fontfile_loader.cs);
5587 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5590 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5592 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5595 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5597 struct local_refkey *refkey;
5599 if (!path)
5600 return E_INVALIDARG;
5602 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5603 *key = NULL;
5605 refkey = heap_alloc(*size);
5606 if (!refkey)
5607 return E_OUTOFMEMORY;
5609 if (writetime)
5610 refkey->writetime = *writetime;
5611 else {
5612 WIN32_FILE_ATTRIBUTE_DATA info;
5614 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5615 refkey->writetime = info.ftLastWriteTime;
5616 else
5617 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5619 strcpyW(refkey->name, path);
5621 *key = refkey;
5623 return S_OK;
5626 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5628 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5630 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5631 IsEqualIID(riid, &IID_IUnknown))
5633 *ppv = iface;
5634 IDWriteGlyphRunAnalysis_AddRef(iface);
5635 return S_OK;
5638 WARN("%s not implemented.\n", debugstr_guid(riid));
5640 *ppv = NULL;
5641 return E_NOINTERFACE;
5644 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5646 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5647 ULONG refcount = InterlockedIncrement(&analysis->refcount);
5649 TRACE("%p, refcount %d.\n", iface, refcount);
5651 return refcount;
5654 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5656 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5657 ULONG refcount = InterlockedDecrement(&analysis->refcount);
5659 TRACE("%p, refcount %d.\n", iface, refcount);
5661 if (!refcount)
5663 if (analysis->run.fontFace)
5664 IDWriteFontFace_Release(analysis->run.fontFace);
5665 heap_free(analysis->glyphs);
5666 heap_free(analysis->origins);
5667 heap_free(analysis->bitmap);
5668 heap_free(analysis);
5671 return refcount;
5674 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5676 switch (mode)
5678 case DWRITE_RENDERING_MODE1_NATURAL:
5679 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5680 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5681 return TRUE;
5682 default:
5683 return FALSE;
5687 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5689 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5692 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5694 struct dwrite_glyphbitmap glyph_bitmap;
5695 IDWriteFontFace4 *fontface;
5696 HRESULT hr;
5697 UINT32 i;
5699 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5700 *bounds = analysis->bounds;
5701 return;
5704 if (analysis->run.isSideways)
5705 FIXME("sideways runs are not supported.\n");
5707 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5708 if (FAILED(hr))
5709 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5711 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5712 glyph_bitmap.fontface = fontface;
5713 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5714 glyph_bitmap.emsize = analysis->run.fontEmSize;
5715 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5716 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5717 glyph_bitmap.m = &analysis->m;
5719 for (i = 0; i < analysis->run.glyphCount; i++) {
5720 RECT *bbox = &glyph_bitmap.bbox;
5721 UINT32 bitmap_size;
5723 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5724 freetype_get_glyph_bbox(&glyph_bitmap);
5726 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5727 (bbox->bottom - bbox->top);
5728 if (bitmap_size > analysis->max_glyph_bitmap_size)
5729 analysis->max_glyph_bitmap_size = bitmap_size;
5731 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5732 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5735 IDWriteFontFace4_Release(fontface);
5737 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5738 *bounds = analysis->bounds;
5741 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
5742 DWRITE_TEXTURE_TYPE type, RECT *bounds)
5744 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5746 TRACE("%p, %d, %p.\n", iface, type, bounds);
5748 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5749 SetRectEmpty(bounds);
5750 return E_INVALIDARG;
5753 if (type != analysis->texture_type)
5755 SetRectEmpty(bounds);
5756 return S_OK;
5759 glyphrunanalysis_get_texturebounds(analysis, bounds);
5760 return S_OK;
5763 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5765 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5766 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5767 (runbounds->left - bounds->left) * 3;
5768 else
5769 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5770 runbounds->left - bounds->left;
5773 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5775 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5776 struct dwrite_glyphbitmap glyph_bitmap;
5777 IDWriteFontFace4 *fontface;
5778 D2D_POINT_2F origin;
5779 UINT32 i, size;
5780 HRESULT hr;
5781 RECT *bbox;
5783 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5784 if (FAILED(hr)) {
5785 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5786 return hr;
5789 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5790 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5791 size *= 3;
5792 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5793 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5794 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5795 IDWriteFontFace4_Release(fontface);
5796 return E_OUTOFMEMORY;
5799 origin.x = origin.y = 0.0f;
5801 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5802 glyph_bitmap.fontface = fontface;
5803 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5804 glyph_bitmap.emsize = analysis->run.fontEmSize;
5805 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5806 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5807 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5808 glyph_bitmap.m = &analysis->m;
5809 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5810 IDWriteFontFace4_Release(fontface);
5811 return E_OUTOFMEMORY;
5814 bbox = &glyph_bitmap.bbox;
5816 for (i = 0; i < analysis->run.glyphCount; i++) {
5817 BYTE *src = glyph_bitmap.buf, *dst;
5818 int x, y, width, height;
5819 BOOL is_1bpp;
5821 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5822 freetype_get_glyph_bbox(&glyph_bitmap);
5824 if (IsRectEmpty(bbox))
5825 continue;
5827 width = bbox->right - bbox->left;
5828 height = bbox->bottom - bbox->top;
5830 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5831 memset(src, 0, height * glyph_bitmap.pitch);
5832 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5834 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5836 /* blit to analysis bitmap */
5837 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5839 if (is_1bpp) {
5840 /* convert 1bpp to 8bpp/24bpp */
5841 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5842 for (y = 0; y < height; y++) {
5843 for (x = 0; x < width; x++)
5844 if (src[x / 8] & masks[x % 8])
5845 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5846 src += glyph_bitmap.pitch;
5847 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5850 else {
5851 for (y = 0; y < height; y++) {
5852 for (x = 0; x < width; x++)
5853 if (src[x / 8] & masks[x % 8])
5854 dst[x] = DWRITE_ALPHA_MAX;
5855 src += glyph_bitmap.pitch;
5856 dst += analysis->bounds.right - analysis->bounds.left;
5860 else {
5861 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5862 for (y = 0; y < height; y++) {
5863 for (x = 0; x < width; x++)
5864 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5865 src += glyph_bitmap.pitch;
5866 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5869 else {
5870 for (y = 0; y < height; y++) {
5871 for (x = 0; x < width; x++)
5872 dst[x] |= src[x];
5873 src += glyph_bitmap.pitch;
5874 dst += analysis->bounds.right - analysis->bounds.left;
5879 heap_free(glyph_bitmap.buf);
5881 IDWriteFontFace4_Release(fontface);
5883 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5885 /* we don't need this anymore */
5886 heap_free(analysis->glyphs);
5887 heap_free(analysis->origins);
5888 IDWriteFontFace_Release(analysis->run.fontFace);
5890 analysis->glyphs = NULL;
5891 analysis->origins = NULL;
5892 analysis->run.glyphIndices = NULL;
5893 analysis->run.fontFace = NULL;
5895 return S_OK;
5898 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5899 RECT const *bounds, BYTE *bitmap, UINT32 size)
5901 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5902 UINT32 required;
5903 RECT runbounds;
5905 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
5907 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5908 return E_INVALIDARG;
5910 /* make sure buffer is large enough for requested texture type */
5911 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5912 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5913 required *= 3;
5915 if (size < required)
5916 return E_NOT_SUFFICIENT_BUFFER;
5918 /* validate requested texture type */
5919 if (analysis->texture_type != type)
5920 return DWRITE_E_UNSUPPORTEDOPERATION;
5922 memset(bitmap, 0, size);
5923 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
5924 if (IntersectRect(&runbounds, &runbounds, bounds))
5926 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5927 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
5928 int dst_width = (bounds->right - bounds->left) * pixel_size;
5929 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5930 BYTE *src, *dst;
5931 int y;
5933 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
5935 HRESULT hr;
5937 if (FAILED(hr = glyphrunanalysis_render(analysis)))
5938 return hr;
5941 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
5942 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5944 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5945 memcpy(dst, src, draw_width);
5946 src += src_width;
5947 dst += dst_width;
5951 return S_OK;
5954 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5955 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5957 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5959 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
5961 if (!params)
5962 return E_INVALIDARG;
5964 switch (analysis->rendering_mode)
5966 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5967 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5969 UINT value = 0;
5970 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5971 *gamma = (FLOAT)value / 1000.0f;
5972 *contrast = 0.0f;
5973 *cleartypelevel = 1.0f;
5974 break;
5976 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5977 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5978 /* fallthrough */
5979 case DWRITE_RENDERING_MODE1_ALIASED:
5980 case DWRITE_RENDERING_MODE1_NATURAL:
5981 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5982 *gamma = IDWriteRenderingParams_GetGamma(params);
5983 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5984 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5985 break;
5986 default:
5990 return S_OK;
5993 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
5995 glyphrunanalysis_QueryInterface,
5996 glyphrunanalysis_AddRef,
5997 glyphrunanalysis_Release,
5998 glyphrunanalysis_GetAlphaTextureBounds,
5999 glyphrunanalysis_CreateAlphaTexture,
6000 glyphrunanalysis_GetAlphaBlendParams
6003 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
6005 D2D_POINT_2F ret;
6006 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
6007 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
6008 *point = ret;
6011 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
6012 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
6014 unsigned int upem = fontface->metrics.designUnitsPerEm;
6015 int advance;
6017 if (is_sideways)
6018 FIXME("Sideways mode is not supported.\n");
6020 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
6022 switch (measuring_mode)
6024 case DWRITE_MEASURING_MODE_NATURAL:
6025 return (float)advance * emsize / (float)upem;
6026 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6027 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6028 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
6029 default:
6030 WARN("Unknown measuring mode %u.\n", measuring_mode);
6031 return 0.0f;
6035 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
6037 struct dwrite_glyphrunanalysis *analysis;
6038 unsigned int i;
6040 *ret = NULL;
6042 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
6043 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
6044 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
6045 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
6046 return E_INVALIDARG;
6048 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6049 return E_INVALIDARG;
6051 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
6052 return E_INVALIDARG;
6054 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
6055 return E_INVALIDARG;
6057 analysis = heap_alloc_zero(sizeof(*analysis));
6058 if (!analysis)
6059 return E_OUTOFMEMORY;
6061 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
6062 analysis->refcount = 1;
6063 analysis->rendering_mode = desc->rendering_mode;
6065 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
6066 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6067 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6068 else
6069 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6071 analysis->run = *desc->run;
6072 IDWriteFontFace_AddRef(analysis->run.fontFace);
6073 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6074 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6076 if (!analysis->glyphs || !analysis->origins) {
6077 heap_free(analysis->glyphs);
6078 heap_free(analysis->origins);
6080 analysis->glyphs = NULL;
6081 analysis->origins = NULL;
6083 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6084 return E_OUTOFMEMORY;
6087 /* check if transform is usable */
6088 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6089 analysis->m = *desc->transform;
6090 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6093 analysis->run.glyphIndices = analysis->glyphs;
6094 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6096 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6097 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6099 for (i = 0; i < desc->run->glyphCount; ++i)
6100 transform_point(&analysis->origins[i], &analysis->m);
6103 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6104 return S_OK;
6107 /* IDWriteColorGlyphRunEnumerator1 */
6108 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6110 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6112 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6113 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6114 IsEqualIID(riid, &IID_IUnknown))
6116 *ppv = iface;
6117 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6118 return S_OK;
6121 WARN("%s not implemented.\n", debugstr_guid(riid));
6123 *ppv = NULL;
6124 return E_NOINTERFACE;
6127 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6129 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6130 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6132 TRACE("%p, refcount %u.\n", iface, refcount);
6134 return refcount;
6137 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6139 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6140 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6142 TRACE("%p, refcount %u.\n", iface, refcount);
6144 if (!refcount)
6146 heap_free(glyphenum->advances);
6147 heap_free(glyphenum->color_advances);
6148 heap_free(glyphenum->offsets);
6149 heap_free(glyphenum->color_offsets);
6150 heap_free(glyphenum->glyphindices);
6151 heap_free(glyphenum->glyphs);
6152 if (glyphenum->colr.context)
6153 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6154 IDWriteFontFace5_Release(glyphenum->fontface);
6155 heap_free(glyphenum);
6158 return refcount;
6161 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6163 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6164 FLOAT origin = 0.0f;
6166 if (g == 0)
6167 return 0.0f;
6169 while (g--)
6170 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6171 return origin;
6174 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6176 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6177 FLOAT advance_adj = 0.0f;
6178 BOOL got_palette_index;
6179 UINT32 g;
6181 /* start with regular glyphs */
6182 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6183 UINT32 first_glyph = 0;
6185 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6186 if (glyphenum->glyphs[g].num_layers == 0) {
6187 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6188 first_glyph = min(first_glyph, g);
6190 else
6191 glyphenum->glyphindices[g] = 1;
6192 glyphenum->color_advances[g] = glyphenum->advances[g];
6193 if (glyphenum->color_offsets)
6194 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6197 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6198 colorrun->baselineOriginY = glyphenum->origin_y;
6199 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6200 colorrun->paletteIndex = 0xffff;
6201 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6202 glyphenum->has_regular_glyphs = FALSE;
6203 return TRUE;
6205 else {
6206 colorrun->glyphRun.glyphCount = 0;
6207 got_palette_index = FALSE;
6210 advance_adj = 0.0f;
6211 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6213 glyphenum->glyphindices[g] = 1;
6215 /* all glyph layers were returned */
6216 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6217 advance_adj += glyphenum->advances[g];
6218 continue;
6221 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6222 UINT32 index = colorrun->glyphRun.glyphCount;
6223 if (!got_palette_index) {
6224 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6225 /* use foreground color or request one from the font */
6226 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6227 if (colorrun->paletteIndex != 0xffff)
6229 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6230 colorrun->paletteIndex, 1, &colorrun->runColor);
6231 if (FAILED(hr))
6232 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6233 glyphenum->palette, colorrun->paletteIndex, hr);
6235 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6236 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6237 colorrun->baselineOriginY = glyphenum->origin_y;
6238 glyphenum->color_advances[index] = glyphenum->advances[g];
6239 got_palette_index = TRUE;
6242 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6243 /* offsets are relative to glyph origin, nothing to fix up */
6244 if (glyphenum->color_offsets)
6245 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6246 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6247 if (index)
6248 glyphenum->color_advances[index-1] += advance_adj;
6249 colorrun->glyphRun.glyphCount++;
6250 advance_adj = 0.0f;
6252 else
6253 advance_adj += glyphenum->advances[g];
6256 /* reset last advance */
6257 if (colorrun->glyphRun.glyphCount)
6258 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6260 return colorrun->glyphRun.glyphCount > 0;
6263 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6265 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6267 TRACE("%p, %p.\n", iface, has_run);
6269 *has_run = FALSE;
6271 glyphenum->colorrun.glyphRun.glyphCount = 0;
6272 while (glyphenum->current_layer < glyphenum->max_layer_num)
6274 if (colorglyphenum_build_color_run(glyphenum))
6275 break;
6276 else
6277 glyphenum->current_layer++;
6280 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6282 return S_OK;
6285 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6286 DWRITE_COLOR_GLYPH_RUN1 const **run)
6288 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6290 *run = NULL;
6291 return E_NOT_VALID_STATE;
6294 *run = &glyphenum->colorrun;
6295 return S_OK;
6298 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6299 DWRITE_COLOR_GLYPH_RUN const **run)
6301 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6303 TRACE("%p, %p.\n", iface, run);
6305 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6308 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6309 DWRITE_COLOR_GLYPH_RUN1 const **run)
6311 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6313 TRACE("%p, %p.\n", iface, run);
6315 return colorglyphenum_get_current_run(glyphenum, run);
6318 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6320 colorglyphenum_QueryInterface,
6321 colorglyphenum_AddRef,
6322 colorglyphenum_Release,
6323 colorglyphenum_MoveNext,
6324 colorglyphenum_GetCurrentRun,
6325 colorglyphenum1_GetCurrentRun,
6328 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6329 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6330 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6332 struct dwrite_colorglyphenum *colorglyphenum;
6333 BOOL colorfont, has_colored_glyph;
6334 struct dwrite_fontface *fontface;
6335 unsigned int i;
6337 *ret = NULL;
6339 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6341 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6342 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6343 if (!colorfont)
6344 return DWRITE_E_NOCOLOR;
6346 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6347 if (!colorglyphenum)
6348 return E_OUTOFMEMORY;
6350 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6351 colorglyphenum->refcount = 1;
6352 colorglyphenum->origin_x = originX;
6353 colorglyphenum->origin_y = originY;
6354 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6355 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6356 colorglyphenum->glyphs = NULL;
6357 colorglyphenum->run = *run;
6358 colorglyphenum->run.glyphIndices = NULL;
6359 colorglyphenum->run.glyphAdvances = NULL;
6360 colorglyphenum->run.glyphOffsets = NULL;
6361 colorglyphenum->palette = palette;
6362 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6363 colorglyphenum->colr.exists = TRUE;
6364 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6365 colorglyphenum->current_layer = 0;
6366 colorglyphenum->max_layer_num = 0;
6368 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6370 has_colored_glyph = FALSE;
6371 colorglyphenum->has_regular_glyphs = FALSE;
6372 for (i = 0; i < run->glyphCount; i++) {
6373 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6374 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6375 has_colored_glyph = TRUE;
6377 if (colorglyphenum->glyphs[i].num_layers == 0)
6378 colorglyphenum->has_regular_glyphs = TRUE;
6381 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6382 is supposed to proceed normally, like if font had no color info at all. */
6383 if (!has_colored_glyph) {
6384 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6385 return DWRITE_E_NOCOLOR;
6388 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6389 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6390 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6391 if (run->glyphOffsets) {
6392 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6393 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6394 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6397 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6398 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6399 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6400 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6401 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6402 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6403 colorglyphenum->colorrun.measuringMode = measuring_mode;
6404 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6406 if (run->glyphAdvances)
6407 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6408 else
6410 for (i = 0; i < run->glyphCount; ++i)
6411 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6412 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6415 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6417 return S_OK;
6420 /* IDWriteFontFaceReference */
6421 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6423 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6425 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6426 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6427 IsEqualIID(riid, &IID_IUnknown))
6429 *obj = iface;
6430 IDWriteFontFaceReference1_AddRef(iface);
6431 return S_OK;
6434 WARN("%s not implemented.\n", debugstr_guid(riid));
6436 *obj = NULL;
6438 return E_NOINTERFACE;
6441 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6443 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6444 ULONG refcount = InterlockedIncrement(&reference->refcount);
6446 TRACE("%p, refcount %u.\n", iface, refcount);
6448 return refcount;
6451 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6453 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6454 ULONG refcount = InterlockedDecrement(&reference->refcount);
6456 TRACE("%p, refcount %u.\n", iface, refcount);
6458 if (!refcount)
6460 IDWriteFontFile_Release(reference->file);
6461 IDWriteFactory7_Release(reference->factory);
6462 heap_free(reference->axis_values);
6463 heap_free(reference);
6466 return refcount;
6469 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6471 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6473 TRACE("%p, %p.\n", iface, fontface);
6475 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6478 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6479 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6481 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6482 DWRITE_FONT_FILE_TYPE file_type;
6483 DWRITE_FONT_FACE_TYPE face_type;
6484 IDWriteFontFace *fontface;
6485 BOOL is_supported;
6486 UINT32 face_num;
6487 HRESULT hr;
6489 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6491 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6492 if (FAILED(hr))
6493 return hr;
6495 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6496 simulations, &fontface);
6497 if (SUCCEEDED(hr))
6499 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6500 IDWriteFontFace_Release(fontface);
6503 return hr;
6506 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6508 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6509 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6510 BOOL ret;
6512 TRACE("%p, %p.\n", iface, ref);
6514 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6515 reference->simulations == other->simulations;
6516 if (reference->axis_values_count)
6518 ret &= reference->axis_values_count == other->axis_values_count &&
6519 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6522 return ret;
6525 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6527 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6529 TRACE("%p.\n", iface);
6531 return reference->index;
6534 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6536 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6538 TRACE("%p.\n", iface);
6540 return reference->simulations;
6543 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6545 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6546 IDWriteFontFileLoader *loader;
6547 const void *key;
6548 UINT32 key_size;
6549 HRESULT hr;
6551 TRACE("%p, %p.\n", iface, file);
6553 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6554 if (FAILED(hr))
6555 return hr;
6557 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6558 if (FAILED(hr))
6559 return hr;
6561 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6562 IDWriteFontFileLoader_Release(loader);
6564 return hr;
6567 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6569 FIXME("%p.\n", iface);
6571 return 0;
6574 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6576 FIXME("%p.\n", iface);
6578 return 0;
6581 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6583 FIXME("%p, %p.\n", iface, writetime);
6585 return E_NOTIMPL;
6588 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6590 FIXME("%p.\n", iface);
6592 return DWRITE_LOCALITY_LOCAL;
6595 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6597 FIXME("%p.\n", iface);
6599 return E_NOTIMPL;
6602 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6603 WCHAR const *chars, UINT32 count)
6605 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6607 return E_NOTIMPL;
6610 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6611 UINT16 const *glyphs, UINT32 count)
6613 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6615 return E_NOTIMPL;
6618 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6619 UINT64 offset, UINT64 size)
6621 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6623 return E_NOTIMPL;
6626 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6628 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6629 IDWriteFontFace3 *fontface3;
6630 HRESULT hr;
6632 TRACE("%p, %p.\n", iface, fontface);
6634 /* FIXME: created instance should likely respect given axis. */
6635 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6636 &fontface3)))
6638 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6639 IDWriteFontFace3_Release(fontface3);
6642 return hr;
6645 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6647 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6649 TRACE("%p.\n", iface);
6651 return reference->axis_values_count;
6654 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6655 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6657 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6659 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6661 if (value_count < reference->axis_values_count)
6662 return E_NOT_SUFFICIENT_BUFFER;
6664 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6666 return S_OK;
6669 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6671 fontfacereference_QueryInterface,
6672 fontfacereference_AddRef,
6673 fontfacereference_Release,
6674 fontfacereference_CreateFontFace,
6675 fontfacereference_CreateFontFaceWithSimulations,
6676 fontfacereference_Equals,
6677 fontfacereference_GetFontFaceIndex,
6678 fontfacereference_GetSimulations,
6679 fontfacereference_GetFontFile,
6680 fontfacereference_GetLocalFileSize,
6681 fontfacereference_GetFileSize,
6682 fontfacereference_GetFileTime,
6683 fontfacereference_GetLocality,
6684 fontfacereference_EnqueueFontDownloadRequest,
6685 fontfacereference_EnqueueCharacterDownloadRequest,
6686 fontfacereference_EnqueueGlyphDownloadRequest,
6687 fontfacereference_EnqueueFileFragmentDownloadRequest,
6688 fontfacereference1_CreateFontFace,
6689 fontfacereference1_GetFontAxisValueCount,
6690 fontfacereference1_GetFontAxisValues,
6693 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6694 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6695 IDWriteFontFaceReference1 **ret)
6697 struct dwrite_fontfacereference *object;
6699 *ret = NULL;
6701 if (!is_simulation_valid(simulations))
6702 return E_INVALIDARG;
6704 object = heap_alloc_zero(sizeof(*object));
6705 if (!object)
6706 return E_OUTOFMEMORY;
6708 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6709 object->refcount = 1;
6711 object->factory = factory;
6712 IDWriteFactory7_AddRef(object->factory);
6713 object->file = file;
6714 IDWriteFontFile_AddRef(object->file);
6715 object->index = index;
6716 object->simulations = simulations;
6717 if (axis_values_count)
6719 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6721 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6722 return E_OUTOFMEMORY;
6724 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6725 object->axis_values_count = axis_values_count;
6728 *ret = &object->IDWriteFontFaceReference1_iface;
6730 return S_OK;
6733 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6735 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6737 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6738 *obj = iface;
6739 IDWriteFontFileStream_AddRef(iface);
6740 return S_OK;
6743 *obj = NULL;
6745 WARN("%s not implemented.\n", debugstr_guid(riid));
6746 return E_NOINTERFACE;
6749 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6751 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6752 ULONG refcount = InterlockedIncrement(&stream->refcount);
6754 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6756 return refcount;
6759 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6761 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6762 ULONG refcount = InterlockedDecrement(&stream->refcount);
6764 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6766 if (!refcount)
6768 release_inmemory_stream(stream->data);
6769 heap_free(stream);
6772 return refcount;
6775 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6776 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6778 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6780 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
6781 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6783 *fragment_context = NULL;
6785 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6786 *fragment_start = NULL;
6787 return E_FAIL;
6790 *fragment_start = (char *)stream->data->data + offset;
6791 return S_OK;
6794 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6796 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
6799 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6801 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6803 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
6805 *size = stream->data->size;
6807 return S_OK;
6810 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6812 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
6814 *last_writetime = 0;
6816 return E_NOTIMPL;
6819 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6820 inmemoryfilestream_QueryInterface,
6821 inmemoryfilestream_AddRef,
6822 inmemoryfilestream_Release,
6823 inmemoryfilestream_ReadFileFragment,
6824 inmemoryfilestream_ReleaseFileFragment,
6825 inmemoryfilestream_GetFileSize,
6826 inmemoryfilestream_GetLastWriteTime,
6829 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6830 REFIID riid, void **obj)
6832 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6834 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6835 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6836 IsEqualIID(riid, &IID_IUnknown))
6838 *obj = iface;
6839 IDWriteInMemoryFontFileLoader_AddRef(iface);
6840 return S_OK;
6843 WARN("%s not implemented.\n", debugstr_guid(riid));
6845 *obj = NULL;
6847 return E_NOINTERFACE;
6850 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6852 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6853 ULONG refcount = InterlockedIncrement(&loader->refcount);
6855 TRACE("%p, refcount %u.\n", iface, refcount);
6857 return refcount;
6860 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6862 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6863 ULONG refcount = InterlockedDecrement(&loader->refcount);
6864 size_t i;
6866 TRACE("%p, refcount %u.\n", iface, refcount);
6868 if (!refcount)
6870 for (i = 0; i < loader->count; ++i)
6871 release_inmemory_stream(loader->streams[i]);
6872 heap_free(loader->streams);
6873 heap_free(loader);
6876 return refcount;
6879 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6880 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6882 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6883 struct dwrite_inmemory_filestream *stream;
6884 DWORD index;
6886 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
6888 *ret = NULL;
6890 if (key_size != sizeof(DWORD))
6891 return E_INVALIDARG;
6893 index = *(DWORD *)key;
6895 if (index >= loader->count)
6896 return E_INVALIDARG;
6898 if (!(stream = heap_alloc(sizeof(*stream))))
6899 return E_OUTOFMEMORY;
6901 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6902 stream->refcount = 1;
6903 stream->data = loader->streams[index];
6904 InterlockedIncrement(&stream->data->refcount);
6906 *ret = &stream->IDWriteFontFileStream_iface;
6908 return S_OK;
6911 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6912 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6914 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6915 struct dwrite_inmemory_stream_data *stream;
6916 DWORD key;
6918 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
6920 *fontfile = NULL;
6922 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6923 return E_OUTOFMEMORY;
6925 if (!(stream = heap_alloc(sizeof(*stream))))
6926 return E_OUTOFMEMORY;
6928 stream->refcount = 1;
6929 stream->size = data_size;
6930 stream->owner = owner;
6931 if (stream->owner) {
6932 IUnknown_AddRef(stream->owner);
6933 stream->data = (void *)data;
6935 else {
6936 if (!(stream->data = heap_alloc(data_size))) {
6937 heap_free(stream);
6938 return E_OUTOFMEMORY;
6940 memcpy(stream->data, data, data_size);
6943 key = loader->count;
6944 loader->streams[loader->count++] = stream;
6946 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6947 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6950 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6952 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6954 TRACE("%p.\n", iface);
6956 return loader->count;
6959 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6961 inmemoryfontfileloader_QueryInterface,
6962 inmemoryfontfileloader_AddRef,
6963 inmemoryfontfileloader_Release,
6964 inmemoryfontfileloader_CreateStreamFromKey,
6965 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6966 inmemoryfontfileloader_GetFileCount,
6969 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6971 struct dwrite_inmemory_fileloader *loader;
6973 *ret = NULL;
6975 loader = heap_alloc_zero(sizeof(*loader));
6976 if (!loader)
6977 return E_OUTOFMEMORY;
6979 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6980 loader->refcount = 1;
6982 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6984 return S_OK;
6987 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6989 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6991 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6992 IsEqualIID(riid, &IID_IUnknown))
6994 *obj = iface;
6995 IDWriteFontResource_AddRef(iface);
6996 return S_OK;
6999 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7001 return E_NOINTERFACE;
7004 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
7006 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7007 ULONG refcount = InterlockedIncrement(&resource->refcount);
7009 TRACE("%p, refcount %u.\n", iface, refcount);
7011 return refcount;
7014 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
7016 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7017 ULONG refcount = InterlockedDecrement(&resource->refcount);
7019 TRACE("%p, refcount %u.\n", iface, refcount);
7021 if (!refcount)
7023 IDWriteFactory7_Release(resource->factory);
7024 IDWriteFontFile_Release(resource->file);
7025 heap_free(resource);
7028 return refcount;
7031 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
7033 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7035 TRACE("%p, %p.\n", iface, fontfile);
7037 *fontfile = resource->file;
7038 IDWriteFontFile_AddRef(*fontfile);
7040 return S_OK;
7043 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
7045 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7047 TRACE("%p.\n", iface);
7049 return resource->face_index;
7052 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
7054 FIXME("%p.\n", iface);
7056 return 0;
7059 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
7060 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
7062 FIXME("%p, %p, %u.\n", iface, values, num_values);
7064 return E_NOTIMPL;
7067 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7068 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
7070 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
7072 return E_NOTIMPL;
7075 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7076 UINT32 axis)
7078 FIXME("%p, %u.\n", iface, axis);
7080 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
7083 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7084 IDWriteLocalizedStrings **names)
7086 FIXME("%p, %u, %p.\n", iface, axis, names);
7088 return E_NOTIMPL;
7091 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7093 FIXME("%p, %u.\n", iface, axis);
7095 return 0;
7098 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7099 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7101 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7103 return E_NOTIMPL;
7106 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7108 FIXME("%p.\n", iface);
7110 return FALSE;
7113 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7114 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7115 IDWriteFontFace5 **fontface)
7117 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7118 IDWriteFontFaceReference1 *reference;
7119 HRESULT hr;
7121 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7123 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7124 simulations, axis_values, num_values, &reference);
7125 if (SUCCEEDED(hr))
7127 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7128 IDWriteFontFaceReference1_Release(reference);
7131 return hr;
7134 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7135 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7136 IDWriteFontFaceReference1 **reference)
7138 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7140 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7142 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7143 simulations, axis_values, num_values, reference);
7146 static const IDWriteFontResourceVtbl fontresourcevtbl =
7148 dwritefontresource_QueryInterface,
7149 dwritefontresource_AddRef,
7150 dwritefontresource_Release,
7151 dwritefontresource_GetFontFile,
7152 dwritefontresource_GetFontFaceIndex,
7153 dwritefontresource_GetFontAxisCount,
7154 dwritefontresource_GetDefaultFontAxisValues,
7155 dwritefontresource_GetFontAxisRanges,
7156 dwritefontresource_GetFontAxisAttributes,
7157 dwritefontresource_GetAxisNames,
7158 dwritefontresource_GetAxisValueNameCount,
7159 dwritefontresource_GetAxisValueNames,
7160 dwritefontresource_HasVariations,
7161 dwritefontresource_CreateFontFace,
7162 dwritefontresource_CreateFontFaceReference,
7165 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7166 IDWriteFontResource **ret)
7168 struct dwrite_fontresource *resource;
7170 *ret = NULL;
7172 resource = heap_alloc_zero(sizeof(*resource));
7173 if (!resource)
7174 return E_OUTOFMEMORY;
7176 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7177 resource->refcount = 1;
7178 resource->face_index = face_index;
7179 resource->file = file;
7180 IDWriteFontFile_AddRef(resource->file);
7181 resource->factory = factory;
7182 IDWriteFactory7_AddRef(resource->factory);
7184 *ret = &resource->IDWriteFontResource_iface;
7186 return S_OK;
7189 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7191 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7193 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7194 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7195 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7196 IsEqualIID(riid, &IID_IDWriteFontSet))
7198 *obj = iface;
7199 IDWriteFontSet3_AddRef(iface);
7200 return S_OK;
7203 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7204 *obj = NULL;
7205 return E_NOINTERFACE;
7208 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7210 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7211 ULONG refcount = InterlockedIncrement(&set->refcount);
7213 TRACE("%p, refcount %u.\n", iface, refcount);
7215 return refcount;
7218 #define MISSING_SET_PROP ((void *)0x1)
7220 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7222 unsigned int i;
7224 if (InterlockedDecrement(&entry->refcount) > 0)
7225 return;
7226 IDWriteFontFile_Release(entry->file);
7227 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7229 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7230 IDWriteLocalizedStrings_Release(entry->props[i]);
7232 heap_free(entry);
7235 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7237 InterlockedIncrement(&entry->refcount);
7238 return entry;
7241 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7242 DWRITE_FONT_PROPERTY_ID property)
7244 struct file_stream_desc stream_desc = { 0 };
7245 IDWriteLocalizedStrings *value;
7247 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7249 if (entry->props[property] == MISSING_SET_PROP)
7250 return NULL;
7252 if ((value = entry->props[property]))
7254 IDWriteLocalizedStrings_AddRef(value);
7255 return value;
7258 get_filestream_from_file(entry->file, &stream_desc.stream);
7259 stream_desc.face_type = entry->face_type;
7260 stream_desc.face_index = entry->face_index;
7262 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7263 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7264 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7265 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7266 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7267 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7268 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7269 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7270 else
7271 WARN("Unsupported property %u.\n", property);
7273 if (stream_desc.stream)
7274 IDWriteFontFileStream_Release(stream_desc.stream);
7276 if (value)
7278 entry->props[property] = value;
7279 IDWriteLocalizedStrings_AddRef(value);
7281 else
7282 entry->props[property] = MISSING_SET_PROP;
7284 return value;
7287 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7288 struct dwrite_fontset_entry **entries, unsigned int count);
7290 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7292 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7293 ULONG refcount = InterlockedDecrement(&set->refcount);
7294 unsigned int i;
7296 TRACE("%p, refcount %u.\n", iface, refcount);
7298 if (!refcount)
7300 IDWriteFactory7_Release(set->factory);
7301 for (i = 0; i < set->count; ++i)
7302 release_fontset_entry(set->entries[i]);
7303 heap_free(set->entries);
7304 heap_free(set);
7307 return refcount;
7310 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7312 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7314 TRACE("%p.\n", iface);
7316 return set->count;
7319 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7320 IDWriteFontFaceReference **reference)
7322 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7324 TRACE("%p, %u, %p.\n", iface, index, reference);
7326 *reference = NULL;
7328 if (index >= set->count)
7329 return E_INVALIDARG;
7331 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->file,
7332 set->entries[index]->face_index, set->entries[index]->simulations, reference);
7335 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7336 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7338 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7340 return E_NOTIMPL;
7343 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7344 UINT32 *index, BOOL *exists)
7346 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7348 return E_NOTIMPL;
7351 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7352 IDWriteStringList **values)
7354 FIXME("%p, %d, %p.\n", iface, id, values);
7356 return E_NOTIMPL;
7359 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7360 WCHAR const *preferred_locales, IDWriteStringList **values)
7362 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7364 return E_NOTIMPL;
7367 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7368 BOOL *exists, IDWriteLocalizedStrings **values)
7370 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7372 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7374 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7375 index >= set->count)
7377 *values = NULL;
7378 *exists = FALSE;
7379 return E_INVALIDARG;
7382 *values = fontset_entry_get_property(set->entries[index], id);
7383 *exists = !!*values;
7385 return S_OK;
7388 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7389 UINT32 *count)
7391 FIXME("%p, %p, %p.\n", iface, property, count);
7393 return E_NOTIMPL;
7396 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7397 unsigned int count)
7399 IDWriteLocalizedStrings *value;
7400 unsigned int i;
7401 BOOL ret;
7403 for (i = 0; i < count; ++i)
7405 switch (props[i].propertyId)
7407 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7408 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7409 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7410 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7411 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7412 return FALSE;
7414 ret = localizedstrings_contains(value, props[i].propertyValue);
7415 IDWriteLocalizedStrings_Release(value);
7416 if (!ret) return FALSE;
7417 break;
7418 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7419 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7420 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7421 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7422 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7423 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7424 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7425 case DWRITE_FONT_PROPERTY_ID_STYLE:
7426 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7427 FIXME("Unsupported property %d.\n", props[i].propertyId);
7428 /* fallthrough */
7429 default:
7430 return FALSE;
7434 return TRUE;
7437 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7438 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7440 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7442 return E_NOTIMPL;
7445 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7446 IDWriteFontSet **filtered_set)
7448 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7449 struct dwrite_fontset_entry **entries;
7450 unsigned int i, matched_count = 0;
7451 struct dwrite_fontset *object;
7453 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7455 if (!props && count)
7456 return E_INVALIDARG;
7458 if (!(object = heap_alloc_zero(sizeof(*object))))
7459 return E_OUTOFMEMORY;
7461 if (!(entries = heap_calloc(set->count, sizeof(*entries))))
7463 heap_free(object);
7464 return E_OUTOFMEMORY;
7467 for (i = 0; i < set->count; ++i)
7469 if (fontset_entry_is_matching(set->entries[i], props, count))
7471 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7475 if (!matched_count)
7477 heap_free(entries);
7478 entries = NULL;
7481 init_fontset(object, set->factory, entries, matched_count);
7483 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7485 return S_OK;
7488 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7489 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7491 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7493 return E_NOTIMPL;
7496 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7498 FIXME("%p, %p.\n", iface, fontset);
7500 return E_NOTIMPL;
7503 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7504 UINT32 num_indices, IDWriteFontSet1 **fontset)
7506 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7508 return E_NOTIMPL;
7511 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7512 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7514 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7516 return E_NOTIMPL;
7519 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7520 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7522 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7524 return E_NOTIMPL;
7527 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7528 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7530 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7532 return E_NOTIMPL;
7535 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7536 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7538 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7539 num_indices, actual_num_indices);
7541 return E_NOTIMPL;
7544 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7545 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7547 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7549 return E_NOTIMPL;
7552 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7553 UINT32 num_ranges, UINT32 *actual_num_ranges)
7555 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7557 return E_NOTIMPL;
7560 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7561 IDWriteFontFaceReference1 **reference)
7563 FIXME("%p, %u, %p.\n", iface, index, reference);
7565 return E_NOTIMPL;
7568 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
7570 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7572 TRACE("%p, %u, %p.\n", iface, index, resource);
7574 *resource = NULL;
7576 if (index >= set->count)
7577 return E_INVALIDARG;
7579 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->file,
7580 set->entries[index]->face_index, resource);
7583 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
7585 FIXME("%p, %u, %p.\n", iface, index, fontface);
7587 return E_NOTIMPL;
7590 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
7592 FIXME("%p, %u.\n", iface, index);
7594 return DWRITE_LOCALITY_LOCAL;
7597 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
7599 FIXME("%p.\n", iface);
7601 return NULL;
7604 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
7606 FIXME("%p, %u.\n", iface, index);
7608 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
7611 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
7613 FIXME("%p, %u.\n", iface, index);
7615 return 0;
7618 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
7620 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
7622 return E_NOTIMPL;
7625 static const IDWriteFontSet3Vtbl fontsetvtbl =
7627 dwritefontset_QueryInterface,
7628 dwritefontset_AddRef,
7629 dwritefontset_Release,
7630 dwritefontset_GetFontCount,
7631 dwritefontset_GetFontFaceReference,
7632 dwritefontset_FindFontFaceReference,
7633 dwritefontset_FindFontFace,
7634 dwritefontset_GetPropertyValues__,
7635 dwritefontset_GetPropertyValues_,
7636 dwritefontset_GetPropertyValues,
7637 dwritefontset_GetPropertyOccurrenceCount,
7638 dwritefontset_GetMatchingFonts_,
7639 dwritefontset_GetMatchingFonts,
7640 dwritefontset1_GetMatchingFonts,
7641 dwritefontset1_GetFirstFontResources,
7642 dwritefontset1_GetFilteredFonts__,
7643 dwritefontset1_GetFilteredFonts_,
7644 dwritefontset1_GetFilteredFonts,
7645 dwritefontset1_GetFilteredFontIndices_,
7646 dwritefontset1_GetFilteredFontIndices,
7647 dwritefontset1_GetFontAxisRanges_,
7648 dwritefontset1_GetFontAxisRanges,
7649 dwritefontset1_GetFontFaceReference,
7650 dwritefontset1_CreateFontResource,
7651 dwritefontset1_CreateFontFace,
7652 dwritefontset1_GetFontLocality,
7653 dwritefontset2_GetExpirationEvent,
7654 dwritefontset3_GetFontSourceType,
7655 dwritefontset3_GetFontSourceNameLength,
7656 dwritefontset3_GetFontSourceName,
7659 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
7660 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
7662 struct dwrite_fontset_entry *entry;
7664 if (!(entry = heap_alloc_zero(sizeof(*entry))))
7665 return E_OUTOFMEMORY;
7667 entry->refcount = 1;
7668 entry->file = file;
7669 IDWriteFontFile_AddRef(entry->file);
7670 entry->face_type = face_type;
7671 entry->face_index = face_index;
7672 entry->simulations = simulations;
7674 *ret = entry;
7676 return S_OK;
7679 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7680 struct dwrite_fontset_entry **entries, unsigned int count)
7682 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
7683 object->refcount = 1;
7684 object->factory = factory;
7685 IDWriteFactory7_AddRef(object->factory);
7686 object->entries = entries;
7687 object->count = count;
7690 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
7691 unsigned int count, IDWriteFontSet1 **ret)
7693 struct dwrite_fontset_entry **entries = NULL;
7694 struct dwrite_fontset *object;
7695 unsigned int i;
7697 if (!(object = heap_alloc_zero(sizeof(*object))))
7698 return E_OUTOFMEMORY;
7700 if (count)
7702 entries = heap_calloc(count, sizeof(*entries));
7704 /* FIXME: set available properties too */
7706 for (i = 0; i < count; ++i)
7708 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
7709 fonts[i]->simulations, &entries[i]);
7712 init_fontset(object, factory, entries, count);
7714 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
7716 return S_OK;
7719 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
7720 unsigned int count, IDWriteFontSet **ret)
7722 struct dwrite_fontset_entry **entries = NULL;
7723 struct dwrite_fontset *object;
7724 unsigned int i;
7726 if (!(object = heap_alloc_zero(sizeof(*object))))
7727 return E_OUTOFMEMORY;
7729 if (count)
7731 entries = heap_calloc(count, sizeof(*entries));
7733 for (i = 0; i < count; ++i)
7734 entries[i] = addref_fontset_entry(src_entries[i]);
7736 init_fontset(object, factory, entries, count);
7738 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7740 return S_OK;
7743 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
7744 REFIID riid, void **obj)
7746 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7748 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
7749 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
7750 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
7751 IsEqualIID(riid, &IID_IUnknown))
7753 *obj = iface;
7754 IDWriteFontSetBuilder2_AddRef(iface);
7755 return S_OK;
7758 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7759 *obj = NULL;
7760 return E_NOINTERFACE;
7763 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
7765 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7766 ULONG refcount = InterlockedIncrement(&builder->refcount);
7768 TRACE("%p, refcount %u.\n", iface, refcount);
7770 return refcount;
7773 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
7775 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7776 ULONG refcount = InterlockedDecrement(&builder->refcount);
7777 unsigned int i;
7779 TRACE("%p, refcount %u.\n", iface, refcount);
7781 if (!refcount)
7783 IDWriteFactory7_Release(builder->factory);
7784 for (i = 0; i < builder->count; ++i)
7785 release_fontset_entry(builder->entries[i]);
7786 heap_free(builder->entries);
7787 heap_free(builder);
7790 return refcount;
7793 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, IDWriteFontFile *file,
7794 DWRITE_FONT_FACE_TYPE face_type, unsigned int face_index, unsigned int simulations)
7796 struct dwrite_fontset_entry *entry;
7797 HRESULT hr;
7799 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
7800 sizeof(*builder->entries)))
7802 return E_OUTOFMEMORY;
7805 if (FAILED(hr = fontset_create_entry(file, face_type, face_index, simulations, &entry)))
7806 return hr;
7808 builder->entries[builder->count++] = entry;
7810 return S_OK;
7813 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
7815 DWRITE_FONT_FILE_TYPE filetype;
7816 DWRITE_FONT_FACE_TYPE facetype;
7817 unsigned int i, face_count;
7818 BOOL supported = FALSE;
7819 HRESULT hr;
7821 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &filetype, &facetype, &face_count)))
7822 return hr;
7824 if (!supported)
7825 return DWRITE_E_FILEFORMAT;
7827 for (i = 0; i < face_count; ++i)
7829 if (FAILED(hr = fontset_builder_add_entry(builder, file, facetype, i, DWRITE_FONT_SIMULATIONS_NONE)))
7830 break;
7833 return hr;
7836 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
7837 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
7839 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
7841 return E_NOTIMPL;
7844 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
7845 IDWriteFontFaceReference *ref)
7847 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7848 unsigned int face_count, face_index, simulations;
7849 DWRITE_FONT_FILE_TYPE file_type;
7850 DWRITE_FONT_FACE_TYPE face_type;
7851 IDWriteFontFile *file;
7852 BOOL supported;
7853 HRESULT hr;
7855 TRACE("%p, %p.\n", iface, ref);
7857 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(ref, &file))) return hr;
7858 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
7859 goto done;
7861 if (!supported)
7863 hr = DWRITE_E_FILEFORMAT;
7864 goto done;
7867 face_index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
7868 simulations = IDWriteFontFaceReference_GetSimulations(ref);
7869 hr = fontset_builder_add_entry(builder, file, face_type, face_index, simulations);
7871 done:
7872 IDWriteFontFile_Release(file);
7874 return hr;
7877 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
7879 FIXME("%p, %p.\n", iface, fontset);
7881 return E_NOTIMPL;
7884 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
7886 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7888 TRACE("%p, %p.\n", iface, fontset);
7890 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
7893 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
7895 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7897 TRACE("%p, %p.\n", iface, file);
7899 return fontset_builder_add_file(builder, file);
7902 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
7903 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
7904 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
7905 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
7907 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
7908 axis_ranges, num_ranges, props, num_properties);
7910 return E_NOTIMPL;
7913 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
7915 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7916 IDWriteFontFile *file;
7917 HRESULT hr;
7919 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
7921 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
7922 return hr;
7924 hr = fontset_builder_add_file(builder, file);
7925 IDWriteFontFile_Release(file);
7926 return hr;
7929 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
7931 dwritefontsetbuilder_QueryInterface,
7932 dwritefontsetbuilder_AddRef,
7933 dwritefontsetbuilder_Release,
7934 dwritefontsetbuilder_AddFontFaceReference_,
7935 dwritefontsetbuilder_AddFontFaceReference,
7936 dwritefontsetbuilder_AddFontSet,
7937 dwritefontsetbuilder_CreateFontSet,
7938 dwritefontsetbuilder1_AddFontFile,
7939 dwritefontsetbuilder2_AddFont,
7940 dwritefontsetbuilder2_AddFontFile,
7943 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
7945 struct dwrite_fontset_builder *builder;
7947 *ret = NULL;
7949 if (!(builder = heap_alloc_zero(sizeof(*builder))))
7950 return E_OUTOFMEMORY;
7952 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
7953 builder->refcount = 1;
7954 builder->factory = factory;
7955 IDWriteFactory7_AddRef(builder->factory);
7957 *ret = &builder->IDWriteFontSetBuilder2_iface;
7959 return S_OK;