dwrite: Request one glyph outline at a time in GetGlyphRunOutline().
[wine.git] / dlls / dwrite / font.c
blob0167878e912d0e85e10f33dc31474b90eb226511
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 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
827 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
828 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
830 D2D1_POINT_2F *origins, baseline_origin = { 0 };
831 DWRITE_GLYPH_RUN run;
832 unsigned int i;
833 HRESULT hr;
835 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
836 count, is_sideways, is_rtl, sink);
838 if (!glyphs || !sink)
839 return E_INVALIDARG;
841 if (!count)
842 return S_OK;
844 run.fontFace = (IDWriteFontFace *)iface;
845 run.fontEmSize = emSize;
846 run.glyphCount = count;
847 run.glyphIndices = glyphs;
848 run.glyphAdvances = advances;
849 run.glyphOffsets = offsets;
850 run.isSideways = is_sideways;
851 run.bidiLevel = is_rtl ? 1 : 0;
853 if (!(origins = heap_alloc(sizeof(*origins) * count)))
854 return E_OUTOFMEMORY;
856 if (FAILED(hr = compute_glyph_origins(&run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins)))
858 heap_free(origins);
859 return hr;
862 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
864 for (i = 0; i < count; ++i)
866 if (FAILED(hr = freetype_get_glyph_outline(iface, emSize, glyphs[i], origins[i], sink)))
867 WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
870 heap_free(origins);
872 return S_OK;
875 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
876 float ppem, unsigned int gasp)
878 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
880 switch (measuring)
882 case DWRITE_MEASURING_MODE_NATURAL:
884 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
885 mode = DWRITE_RENDERING_MODE_NATURAL;
886 else
887 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
888 break;
890 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
891 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
892 break;
893 case DWRITE_MEASURING_MODE_GDI_NATURAL:
894 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
895 break;
896 default:
900 return mode;
903 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
904 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
906 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
907 unsigned int flags;
908 FLOAT ppem;
910 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
912 if (!params) {
913 *mode = DWRITE_RENDERING_MODE_DEFAULT;
914 return E_INVALIDARG;
917 *mode = IDWriteRenderingParams_GetRenderingMode(params);
918 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
919 return S_OK;
921 ppem = emSize * ppdip;
923 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
924 *mode = DWRITE_RENDERING_MODE_OUTLINE;
925 return S_OK;
928 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
929 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
930 return S_OK;
933 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
934 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
936 DWRITE_FONT_METRICS1 metrics1;
937 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
938 memcpy(metrics, &metrics1, sizeof(*metrics));
939 return hr;
942 static inline int round_metric(FLOAT metric)
944 return (int)floorf(metric + 0.5f);
947 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
949 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
950 return 0;
952 return (fontface->metrics.designUnitsPerEm + 49) / 50;
955 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
956 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
957 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
959 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
960 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
961 DWRITE_MEASURING_MODE mode;
962 FLOAT scale, size;
963 HRESULT hr;
964 UINT32 i;
966 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
967 glyph_count, metrics, is_sideways);
969 if (m && memcmp(m, &identity, sizeof(*m)))
970 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
972 size = emSize * ppdip;
973 scale = size / fontface->metrics.designUnitsPerEm;
974 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
976 for (i = 0; i < glyph_count; i++) {
977 DWRITE_GLYPH_METRICS *ret = metrics + i;
978 DWRITE_GLYPH_METRICS design;
979 BOOL has_contours;
981 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
982 if (FAILED(hr))
983 return hr;
985 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
986 if (has_contours)
987 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
988 else
989 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
991 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
992 SCALE_METRIC(leftSideBearing);
993 SCALE_METRIC(rightSideBearing);
994 SCALE_METRIC(topSideBearing);
995 SCALE_METRIC(advanceHeight);
996 SCALE_METRIC(bottomSideBearing);
997 SCALE_METRIC(verticalOriginY);
998 #undef SCALE_METRIC
1001 return S_OK;
1004 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
1006 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1008 TRACE("%p, %p.\n", iface, metrics);
1010 *metrics = fontface->metrics;
1013 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
1014 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
1016 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1017 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
1018 UINT16 ascent, descent;
1019 FLOAT scale;
1021 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
1023 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
1024 memset(metrics, 0, sizeof(*metrics));
1025 return E_INVALIDARG;
1028 em_size *= pixels_per_dip;
1029 if (m && m->m22 != 0.0f)
1030 em_size *= fabs(m->m22);
1032 scale = em_size / design->designUnitsPerEm;
1033 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
1035 ascent = round_metric(design->ascent * scale);
1036 descent = round_metric(design->descent * scale);
1039 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
1040 metrics->designUnitsPerEm = design->designUnitsPerEm;
1041 metrics->ascent = round_metric(ascent / scale);
1042 metrics->descent = round_metric(descent / scale);
1044 SCALE_METRIC(lineGap);
1045 SCALE_METRIC(capHeight);
1046 SCALE_METRIC(xHeight);
1047 SCALE_METRIC(underlinePosition);
1048 SCALE_METRIC(underlineThickness);
1049 SCALE_METRIC(strikethroughPosition);
1050 SCALE_METRIC(strikethroughThickness);
1051 SCALE_METRIC(glyphBoxLeft);
1052 SCALE_METRIC(glyphBoxTop);
1053 SCALE_METRIC(glyphBoxRight);
1054 SCALE_METRIC(glyphBoxBottom);
1055 SCALE_METRIC(subscriptPositionX);
1056 SCALE_METRIC(subscriptPositionY);
1057 SCALE_METRIC(subscriptSizeX);
1058 SCALE_METRIC(subscriptSizeY);
1059 SCALE_METRIC(superscriptPositionX);
1060 SCALE_METRIC(superscriptPositionY);
1061 SCALE_METRIC(superscriptSizeX);
1062 SCALE_METRIC(superscriptSizeY);
1064 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1065 #undef SCALE_METRIC
1067 return S_OK;
1070 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1072 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1074 TRACE("%p, %p.\n", iface, metrics);
1076 *metrics = fontface->caret;
1079 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1080 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1082 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1084 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1086 *count = 0;
1087 if (max_count && !ranges)
1088 return E_INVALIDARG;
1090 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1091 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1094 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1096 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1098 TRACE("%p.\n", iface);
1100 return !!(fontface->flags & FONT_IS_MONOSPACED);
1103 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1104 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1106 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1107 BOOL has_contours;
1108 int advance;
1110 if (is_sideways)
1111 FIXME("Sideways mode is not supported.\n");
1113 switch (measuring_mode)
1115 case DWRITE_MEASURING_MODE_NATURAL:
1116 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1117 glyph, measuring_mode, &has_contours);
1118 if (has_contours)
1119 advance += adjustment;
1121 return advance;
1122 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1123 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1124 emsize *= ppdip;
1125 if (emsize == 0.0f)
1126 return 0.0f;
1128 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1129 FIXME("Transform is not supported.\n");
1131 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1132 &has_contours);
1133 if (has_contours)
1134 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1135 else
1136 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1138 return advance;
1139 default:
1140 WARN("Unknown measuring mode %u.\n", measuring_mode);
1141 return 0;
1145 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1146 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1148 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1149 unsigned int i;
1151 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1153 if (is_sideways)
1154 FIXME("sideways mode not supported\n");
1156 for (i = 0; i < glyph_count; ++i)
1158 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1159 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1162 return S_OK;
1165 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1166 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1167 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1169 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1170 DWRITE_MEASURING_MODE measuring_mode;
1171 UINT32 i;
1173 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1174 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1176 if (em_size < 0.0f || ppdip <= 0.0f) {
1177 memset(advances, 0, sizeof(*advances) * glyph_count);
1178 return E_INVALIDARG;
1181 if (em_size == 0.0f) {
1182 memset(advances, 0, sizeof(*advances) * glyph_count);
1183 return S_OK;
1186 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1187 for (i = 0; i < glyph_count; ++i)
1189 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1190 glyphs[i], is_sideways);
1193 return S_OK;
1196 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1197 const UINT16 *glyphs, INT32 *values)
1199 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1201 TRACE("%p, %u, %p, %p.\n", iface, count, glyphs, values);
1203 if (!(glyphs || values) || !count)
1204 return E_INVALIDARG;
1206 if (!glyphs || count == 1)
1208 memset(values, 0, count * sizeof(*values));
1209 return E_INVALIDARG;
1212 return opentype_get_kerning_pairs(fontface, count, glyphs, values);
1215 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1217 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1219 TRACE("%p.\n", iface);
1221 return opentype_has_kerning_pairs(fontface);
1224 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1225 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1226 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1228 DWRITE_GRID_FIT_MODE gridfitmode;
1229 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1230 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1233 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1234 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1236 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1238 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1240 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1243 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1245 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1247 TRACE("%p.\n", iface);
1249 return opentype_has_vertical_variants(fontface);
1252 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1254 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1256 TRACE("%p.\n", iface);
1258 return !!(fontface->flags & FONT_IS_COLORED);
1261 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1263 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1265 TRACE("%p.\n", iface);
1267 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1270 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1272 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1274 TRACE("%p.\n", iface);
1276 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1279 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1280 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1282 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1284 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1286 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1289 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1290 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1291 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1292 DWRITE_GRID_FIT_MODE *gridfitmode)
1294 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1295 unsigned int flags;
1296 FLOAT emthreshold;
1298 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1299 measuringmode, params, renderingmode, gridfitmode);
1301 if (m && memcmp(m, &identity, sizeof(*m)))
1302 FIXME("transform not supported %s\n", debugstr_matrix(m));
1304 if (is_sideways)
1305 FIXME("sideways mode not supported\n");
1307 emSize *= max(dpiX, dpiY) / 96.0f;
1309 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1310 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1311 if (params) {
1312 IDWriteRenderingParams2 *params2;
1313 HRESULT hr;
1315 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1316 if (hr == S_OK) {
1317 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1318 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1319 IDWriteRenderingParams2_Release(params2);
1321 else
1322 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1325 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1327 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1329 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1330 if (emSize >= emthreshold)
1331 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1332 else
1333 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1336 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1337 if (emSize >= emthreshold)
1338 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1339 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1340 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1341 else
1342 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1343 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1346 return S_OK;
1349 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1350 IDWriteFontFaceReference **reference)
1352 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1354 TRACE("%p, %p.\n", iface, reference);
1356 *reference = &fontface->IDWriteFontFaceReference_iface;
1357 IDWriteFontFaceReference_AddRef(*reference);
1359 return S_OK;
1362 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1364 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1366 TRACE("%p, %p.\n", iface, panose);
1368 *panose = fontface->panose;
1371 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1373 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1375 TRACE("%p.\n", iface);
1377 return fontface->weight;
1380 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1382 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1384 TRACE("%p.\n", iface);
1386 return fontface->stretch;
1389 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1391 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1393 TRACE("%p.\n", iface);
1395 return fontface->style;
1398 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1400 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1402 TRACE("%p, %p.\n", iface, names);
1404 return clone_localizedstrings(fontface->family_names, names);
1407 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1409 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1411 TRACE("%p, %p.\n", iface, names);
1413 return clone_localizedstrings(fontface->names, names);
1416 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1417 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1418 IDWriteLocalizedStrings **ret, BOOL *exists)
1420 HRESULT hr = S_OK;
1422 *exists = FALSE;
1423 *ret = NULL;
1425 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1426 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1428 return S_OK;
1431 if (!strings_cache[stringid])
1433 struct file_stream_desc desc = *stream_desc;
1435 if (!desc.stream)
1436 hr = get_filestream_from_file(file, &desc.stream);
1437 if (SUCCEEDED(hr))
1438 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1440 if (!stream_desc->stream && desc.stream)
1441 IDWriteFontFileStream_Release(desc.stream);
1444 if (SUCCEEDED(hr) && strings_cache[stringid])
1446 hr = clone_localizedstrings(strings_cache[stringid], ret);
1447 if (SUCCEEDED(hr))
1448 *exists = TRUE;
1451 return hr;
1454 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1455 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1457 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1458 struct file_stream_desc stream_desc;
1460 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1462 stream_desc.stream = fontface->stream;
1463 stream_desc.face_index = fontface->index;
1464 stream_desc.face_type = fontface->type;
1465 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1468 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1470 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1472 TRACE("%p, %#x.\n", iface, ch);
1474 return !!dwritefontface_get_glyph(fontface, ch);
1477 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1478 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1479 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1481 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1482 unsigned int flags;
1483 FLOAT emthreshold;
1485 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1486 measuring_mode, params, rendering_mode, gridfit_mode);
1488 if (m && memcmp(m, &identity, sizeof(*m)))
1489 FIXME("transform not supported %s\n", debugstr_matrix(m));
1491 if (is_sideways)
1492 FIXME("sideways mode not supported\n");
1494 emSize *= max(dpiX, dpiY) / 96.0f;
1496 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1497 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1498 if (params) {
1499 IDWriteRenderingParams3 *params3;
1500 HRESULT hr;
1502 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1503 if (hr == S_OK) {
1504 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1505 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1506 IDWriteRenderingParams3_Release(params3);
1508 else
1509 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1512 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1514 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1516 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1517 if (emSize >= emthreshold)
1518 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1519 else
1520 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1523 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1524 if (emSize >= emthreshold)
1525 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1526 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1527 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1528 else
1529 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1530 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1533 return S_OK;
1536 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1538 FIXME("%p, %#x: stub\n", iface, ch);
1540 return FALSE;
1543 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1545 FIXME("%p, %u: stub\n", iface, glyph);
1547 return FALSE;
1550 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1551 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1553 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1555 return E_NOTIMPL;
1558 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1559 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1561 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1563 return E_NOTIMPL;
1566 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1567 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1569 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1571 return E_NOTIMPL;
1574 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1576 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1578 TRACE("%p.\n", iface);
1580 return fontface->glyph_image_formats;
1583 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1584 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1586 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1588 return E_NOTIMPL;
1591 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1593 FIXME("%p, %p: stub\n", iface, context);
1596 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1598 FIXME("%p: stub\n", iface);
1600 return 0;
1603 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1604 UINT32 value_count)
1606 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1608 return E_NOTIMPL;
1611 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1613 static int once;
1615 if (!once++)
1616 FIXME("%p: stub\n", iface);
1618 return FALSE;
1621 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1623 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1625 TRACE("%p, %p.\n", iface, resource);
1627 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->file, fontface->index, resource);
1630 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1632 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1634 TRACE("%p, %p.\n", iface, other);
1636 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1637 return FALSE;
1639 /* TODO: add variations support */
1641 return fontface->index == other_face->index &&
1642 fontface->simulations == other_face->simulations &&
1643 is_same_fontfile(fontface->file, other_face->file);
1646 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1648 dwritefontface_QueryInterface,
1649 dwritefontface_AddRef,
1650 dwritefontface_Release,
1651 dwritefontface_GetType,
1652 dwritefontface_GetFiles,
1653 dwritefontface_GetIndex,
1654 dwritefontface_GetSimulations,
1655 dwritefontface_IsSymbolFont,
1656 dwritefontface_GetMetrics,
1657 dwritefontface_GetGlyphCount,
1658 dwritefontface_GetDesignGlyphMetrics,
1659 dwritefontface_GetGlyphIndices,
1660 dwritefontface_TryGetFontTable,
1661 dwritefontface_ReleaseFontTable,
1662 dwritefontface_GetGlyphRunOutline,
1663 dwritefontface_GetRecommendedRenderingMode,
1664 dwritefontface_GetGdiCompatibleMetrics,
1665 dwritefontface_GetGdiCompatibleGlyphMetrics,
1666 dwritefontface1_GetMetrics,
1667 dwritefontface1_GetGdiCompatibleMetrics,
1668 dwritefontface1_GetCaretMetrics,
1669 dwritefontface1_GetUnicodeRanges,
1670 dwritefontface1_IsMonospacedFont,
1671 dwritefontface1_GetDesignGlyphAdvances,
1672 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1673 dwritefontface1_GetKerningPairAdjustments,
1674 dwritefontface1_HasKerningPairs,
1675 dwritefontface1_GetRecommendedRenderingMode,
1676 dwritefontface1_GetVerticalGlyphVariants,
1677 dwritefontface1_HasVerticalGlyphVariants,
1678 dwritefontface2_IsColorFont,
1679 dwritefontface2_GetColorPaletteCount,
1680 dwritefontface2_GetPaletteEntryCount,
1681 dwritefontface2_GetPaletteEntries,
1682 dwritefontface2_GetRecommendedRenderingMode,
1683 dwritefontface3_GetFontFaceReference,
1684 dwritefontface3_GetPanose,
1685 dwritefontface3_GetWeight,
1686 dwritefontface3_GetStretch,
1687 dwritefontface3_GetStyle,
1688 dwritefontface3_GetFamilyNames,
1689 dwritefontface3_GetFaceNames,
1690 dwritefontface3_GetInformationalStrings,
1691 dwritefontface3_HasCharacter,
1692 dwritefontface3_GetRecommendedRenderingMode,
1693 dwritefontface3_IsCharacterLocal,
1694 dwritefontface3_IsGlyphLocal,
1695 dwritefontface3_AreCharactersLocal,
1696 dwritefontface3_AreGlyphsLocal,
1697 dwritefontface4_GetGlyphImageFormats_,
1698 dwritefontface4_GetGlyphImageFormats,
1699 dwritefontface4_GetGlyphImageData,
1700 dwritefontface4_ReleaseGlyphImageData,
1701 dwritefontface5_GetFontAxisValueCount,
1702 dwritefontface5_GetFontAxisValues,
1703 dwritefontface5_HasVariations,
1704 dwritefontface5_GetFontResource,
1705 dwritefontface5_Equals,
1708 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1710 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1711 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1714 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1716 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1717 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1720 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1722 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1723 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1726 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1727 IDWriteFontFace3 **ret)
1729 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1731 TRACE("%p, %p.\n", iface, ret);
1733 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1734 IDWriteFontFace3_AddRef(*ret);
1736 return S_OK;
1739 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1740 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1742 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1743 DWRITE_FONT_FILE_TYPE file_type;
1744 DWRITE_FONT_FACE_TYPE face_type;
1745 IDWriteFontFace *face;
1746 BOOL is_supported;
1747 UINT32 face_num;
1748 HRESULT hr;
1750 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1752 hr = IDWriteFontFile_Analyze(fontface->file, &is_supported, &file_type, &face_type, &face_num);
1753 if (FAILED(hr))
1754 return hr;
1756 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, &fontface->file, fontface->index,
1757 simulations, &face);
1758 if (SUCCEEDED(hr))
1760 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1761 IDWriteFontFace_Release(face);
1764 return hr;
1767 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1769 FIXME("%p, %p.\n", iface, ref);
1771 return E_NOTIMPL;
1774 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1776 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1778 TRACE("%p.\n", iface);
1780 return fontface->index;
1783 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1785 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1787 TRACE("%p.\n", iface);
1789 return fontface->simulations;
1792 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1794 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1796 TRACE("%p, %p.\n", iface, file);
1798 *file = fontface->file;
1799 IDWriteFontFile_AddRef(*file);
1801 return S_OK;
1804 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1806 FIXME("%p.\n", iface);
1808 return 0;
1811 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1813 FIXME("%p.\n", iface);
1815 return 0;
1818 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1820 FIXME("%p, %p.\n", iface, writetime);
1822 return E_NOTIMPL;
1825 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1827 FIXME("%p.\n", iface);
1829 return DWRITE_LOCALITY_LOCAL;
1832 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1834 FIXME("%p.\n", iface);
1836 return E_NOTIMPL;
1839 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1840 WCHAR const *chars, UINT32 count)
1842 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1844 return E_NOTIMPL;
1847 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1848 UINT16 const *glyphs, UINT32 count)
1850 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1852 return E_NOTIMPL;
1855 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1856 UINT64 offset, UINT64 size)
1858 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1860 return E_NOTIMPL;
1863 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1865 dwritefontface_reference_QueryInterface,
1866 dwritefontface_reference_AddRef,
1867 dwritefontface_reference_Release,
1868 dwritefontface_reference_CreateFontFace,
1869 dwritefontface_reference_CreateFontFaceWithSimulations,
1870 dwritefontface_reference_Equals,
1871 dwritefontface_reference_GetFontFaceIndex,
1872 dwritefontface_reference_GetSimulations,
1873 dwritefontface_reference_GetFontFile,
1874 dwritefontface_reference_GetLocalFileSize,
1875 dwritefontface_reference_GetFileSize,
1876 dwritefontface_reference_GetFileTime,
1877 dwritefontface_reference_GetLocality,
1878 dwritefontface_reference_EnqueueFontDownloadRequest,
1879 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1880 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1881 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1884 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1886 struct dwrite_font_data *data = font->data;
1887 struct fontface_desc desc;
1888 struct list *cached_list;
1889 HRESULT hr;
1891 *fontface = NULL;
1893 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1894 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1895 if (hr == S_OK)
1896 return hr;
1898 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1899 return hr;
1901 desc.factory = font->family->collection->factory;
1902 desc.face_type = data->face_type;
1903 desc.file = data->file;
1904 desc.index = data->face_index;
1905 desc.simulations = data->simulations;
1906 desc.font_data = data;
1907 hr = create_fontface(&desc, cached_list, fontface);
1909 IDWriteFontFileStream_Release(desc.stream);
1910 return hr;
1913 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1915 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1917 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1918 IsEqualIID(riid, &IID_IDWriteFont2) ||
1919 IsEqualIID(riid, &IID_IDWriteFont1) ||
1920 IsEqualIID(riid, &IID_IDWriteFont) ||
1921 IsEqualIID(riid, &IID_IUnknown))
1923 *obj = iface;
1924 IDWriteFont3_AddRef(iface);
1925 return S_OK;
1928 WARN("%s not implemented.\n", debugstr_guid(riid));
1930 *obj = NULL;
1931 return E_NOINTERFACE;
1934 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1936 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1937 ULONG refcount = InterlockedIncrement(&font->refcount);
1939 TRACE("%p, refcount %d.\n", iface, refcount);
1941 return refcount;
1944 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1946 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1947 ULONG refcount = InterlockedDecrement(&font->refcount);
1949 TRACE("%p, refcount %d.\n", iface, refcount);
1951 if (!refcount)
1953 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
1954 release_font_data(font->data);
1955 heap_free(font);
1958 return refcount;
1961 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1963 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1965 TRACE("%p, %p.\n", iface, family);
1967 *family = (IDWriteFontFamily *)font->family;
1968 IDWriteFontFamily_AddRef(*family);
1969 return S_OK;
1972 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1974 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1976 TRACE("%p.\n", iface);
1978 return font->data->weight;
1981 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1983 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1985 TRACE("%p.\n", iface);
1987 return font->data->stretch;
1990 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1992 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1994 TRACE("%p.\n", iface);
1996 return font->style;
1999 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
2001 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2003 TRACE("%p.\n", iface);
2005 return !!(font->data->flags & FONT_IS_SYMBOL);
2008 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
2010 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2012 TRACE("%p, %p.\n", iface, names);
2014 return clone_localizedstrings(font->data->names, names);
2017 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
2018 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
2020 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2021 struct dwrite_font_data *data = font->data;
2022 struct file_stream_desc stream_desc;
2024 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
2026 /* Stream will be created if necessary. */
2027 stream_desc.stream = NULL;
2028 stream_desc.face_index = data->face_index;
2029 stream_desc.face_type = data->face_type;
2030 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
2033 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
2035 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2037 TRACE("%p.\n", iface);
2039 return font->data->simulations;
2042 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
2044 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2046 TRACE("%p, %p.\n", iface, metrics);
2048 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2051 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2053 UINT16 glyph;
2054 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2055 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2056 return glyph != 0;
2059 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2061 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2063 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2065 *exists = dwritefont_has_character(font, ch);
2067 return S_OK;
2070 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2072 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2074 TRACE("%p, %p.\n", iface, fontface);
2076 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2079 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2081 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2083 TRACE("%p, %p.\n", iface, metrics);
2085 *metrics = font->data->metrics;
2088 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2090 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2092 TRACE("%p, %p.\n", iface, panose);
2094 *panose = font->data->panose;
2097 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2098 UINT32 *count)
2100 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2102 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2104 *count = 0;
2105 if (max_count && !ranges)
2106 return E_INVALIDARG;
2108 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2109 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2112 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2114 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2116 TRACE("%p.\n", iface);
2118 return !!(font->data->flags & FONT_IS_MONOSPACED);
2121 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2123 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2125 TRACE("%p.\n", iface);
2127 return !!(font->data->flags & FONT_IS_COLORED);
2130 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2132 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2134 TRACE("%p, %p.\n", iface, fontface);
2136 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2139 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2141 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2143 TRACE("%p, %p.\n", iface, other);
2145 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2146 return FALSE;
2148 return font->data->face_index == other_font->data->face_index
2149 && font->data->simulations == other_font->data->simulations
2150 && is_same_fontfile(font->data->file, other_font->data->file);
2153 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2155 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2157 TRACE("%p, %p.\n", iface, reference);
2159 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2160 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2161 (IDWriteFontFaceReference1 **)reference);
2164 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2166 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2168 TRACE("%p, %#x.\n", iface, ch);
2170 return dwritefont_has_character(font, ch);
2173 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2175 FIXME("%p: stub.\n", iface);
2177 return DWRITE_LOCALITY_LOCAL;
2180 static const IDWriteFont3Vtbl dwritefontvtbl = {
2181 dwritefont_QueryInterface,
2182 dwritefont_AddRef,
2183 dwritefont_Release,
2184 dwritefont_GetFontFamily,
2185 dwritefont_GetWeight,
2186 dwritefont_GetStretch,
2187 dwritefont_GetStyle,
2188 dwritefont_IsSymbolFont,
2189 dwritefont_GetFaceNames,
2190 dwritefont_GetInformationalStrings,
2191 dwritefont_GetSimulations,
2192 dwritefont_GetMetrics,
2193 dwritefont_HasCharacter,
2194 dwritefont_CreateFontFace,
2195 dwritefont1_GetMetrics,
2196 dwritefont1_GetPanose,
2197 dwritefont1_GetUnicodeRanges,
2198 dwritefont1_IsMonospacedFont,
2199 dwritefont2_IsColorFont,
2200 dwritefont3_CreateFontFace,
2201 dwritefont3_Equals,
2202 dwritefont3_GetFontFaceReference,
2203 dwritefont3_HasCharacter,
2204 dwritefont3_GetLocality
2207 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2209 if (!iface)
2210 return NULL;
2211 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2212 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2215 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2217 if (!iface)
2218 return NULL;
2219 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2220 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2223 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2225 if (!iface)
2226 return NULL;
2227 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2228 return NULL;
2229 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2230 IDWriteFontFaceReference1_iface);
2233 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2235 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2236 *lf = font->data->lf;
2239 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2241 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2242 *lf = fontface->lf;
2245 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2247 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2248 *fontsig = font->data->fontsig;
2249 return S_OK;
2252 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2254 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2255 *fontsig = fontface->fontsig;
2256 return S_OK;
2259 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2261 struct dwrite_font *object;
2263 *font = NULL;
2265 if (!(object = heap_alloc(sizeof(*object))))
2266 return E_OUTOFMEMORY;
2268 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2269 object->refcount = 1;
2270 object->family = family;
2271 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2272 object->data = family->data->fonts[index];
2273 object->style = object->data->style;
2274 addref_font_data(object->data);
2276 *font = &object->IDWriteFont3_iface;
2278 return S_OK;
2281 /* IDWriteFontList2 */
2282 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2284 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2286 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2287 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2288 IsEqualIID(riid, &IID_IDWriteFontList) ||
2289 IsEqualIID(riid, &IID_IUnknown))
2291 *obj = iface;
2292 IDWriteFontList2_AddRef(iface);
2293 return S_OK;
2296 WARN("%s not implemented.\n", debugstr_guid(riid));
2298 *obj = NULL;
2299 return E_NOINTERFACE;
2302 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2304 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2305 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2307 TRACE("%p, refcount %u.\n", iface, refcount);
2309 return refcount;
2312 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2314 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2315 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2317 TRACE("%p, refcount %u.\n", iface, refcount);
2319 if (!refcount)
2321 UINT32 i;
2323 for (i = 0; i < fontlist->font_count; i++)
2324 release_font_data(fontlist->fonts[i]);
2325 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2326 heap_free(fontlist->fonts);
2327 heap_free(fontlist);
2330 return refcount;
2333 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2335 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2336 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2339 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2341 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2343 TRACE("%p.\n", iface);
2345 return fontlist->font_count;
2348 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2350 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2352 TRACE("%p, %u, %p.\n", iface, index, font);
2354 *font = NULL;
2356 if (fontlist->font_count == 0)
2357 return S_FALSE;
2359 if (index >= fontlist->font_count)
2360 return E_INVALIDARG;
2362 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2365 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2367 FIXME("%p, %u.\n", iface, index);
2369 return DWRITE_LOCALITY_LOCAL;
2372 static HRESULT fontlist_get_font(const struct dwrite_fontlist *fontlist, unsigned int index,
2373 IDWriteFont3 **font)
2375 *font = NULL;
2377 if (fontlist->font_count == 0)
2378 return S_FALSE;
2380 if (index >= fontlist->font_count)
2381 return E_FAIL;
2383 return create_font(fontlist->family, index, font);
2386 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2388 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2390 TRACE("%p, %u, %p.\n", iface, index, font);
2392 return fontlist_get_font(fontlist, index, font);
2395 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2396 IDWriteFontFaceReference **reference)
2398 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2399 IDWriteFont3 *font;
2400 HRESULT hr;
2402 TRACE("%p, %u, %p.\n", iface, index, reference);
2404 *reference = NULL;
2406 if (SUCCEEDED(hr = fontlist_get_font(fontlist, index, &font)))
2408 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2409 IDWriteFont3_Release(font);
2412 return hr;
2415 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2417 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2419 TRACE("%p, %p.\n", iface, fontset);
2421 return fontset_create_from_font_data(fontlist->family->collection->factory, fontlist->fonts,
2422 fontlist->font_count, fontset);
2425 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2427 dwritefontlist_QueryInterface,
2428 dwritefontlist_AddRef,
2429 dwritefontlist_Release,
2430 dwritefontlist_GetFontCollection,
2431 dwritefontlist_GetFontCount,
2432 dwritefontlist_GetFont,
2433 dwritefontlist1_GetFontLocality,
2434 dwritefontlist1_GetFont,
2435 dwritefontlist1_GetFontFaceReference,
2436 dwritefontlist2_GetFontSet,
2439 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2441 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2443 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2445 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2446 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2447 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2448 IsEqualIID(riid, &IID_IUnknown))
2450 *obj = iface;
2452 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2453 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2454 IsEqualIID(riid, &IID_IDWriteFontList))
2456 *obj = &family->IDWriteFontList2_iface;
2458 else
2460 WARN("%s not implemented.\n", debugstr_guid(riid));
2461 *obj = NULL;
2462 return E_NOINTERFACE;
2465 IUnknown_AddRef((IUnknown *)*obj);
2466 return S_OK;
2469 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2471 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2472 ULONG refcount = InterlockedIncrement(&family->refcount);
2474 TRACE("%p, %u.\n", iface, refcount);
2476 return refcount;
2479 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2481 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2482 ULONG refcount = InterlockedDecrement(&family->refcount);
2484 TRACE("%p, %u.\n", iface, refcount);
2486 if (!refcount)
2488 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2489 release_fontfamily_data(family->data);
2490 heap_free(family);
2493 return refcount;
2496 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2498 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2500 TRACE("%p, %p.\n", iface, collection);
2502 *collection = (IDWriteFontCollection *)family->collection;
2503 IDWriteFontCollection_AddRef(*collection);
2504 return S_OK;
2507 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2509 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2511 TRACE("%p.\n", iface);
2513 return family->data->count;
2516 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2518 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2520 TRACE("%p, %u, %p.\n", iface, index, font);
2522 *font = NULL;
2524 if (!family->data->count)
2525 return S_FALSE;
2527 if (index >= family->data->count)
2528 return E_INVALIDARG;
2530 return create_font(family, index, (IDWriteFont3 **)font);
2533 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2535 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2537 TRACE("%p, %p.\n", iface, names);
2539 return clone_localizedstrings(family->data->familyname, names);
2542 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2543 const struct dwrite_font_propvec *req)
2545 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2546 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2547 FLOAT cur_req_prod, next_req_prod;
2549 if (next_to_req < cur_to_req)
2550 return TRUE;
2552 if (next_to_req > cur_to_req)
2553 return FALSE;
2555 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2556 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2558 if (next_req_prod > cur_req_prod)
2559 return TRUE;
2561 if (next_req_prod < cur_req_prod)
2562 return FALSE;
2564 if (next->stretch > cur->stretch)
2565 return TRUE;
2566 if (next->stretch < cur->stretch)
2567 return FALSE;
2569 if (next->style > cur->style)
2570 return TRUE;
2571 if (next->style < cur->style)
2572 return FALSE;
2574 if (next->weight > cur->weight)
2575 return TRUE;
2576 if (next->weight < cur->weight)
2577 return FALSE;
2579 /* full match, no reason to prefer new variant */
2580 return FALSE;
2583 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2584 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2586 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2587 struct dwrite_font_propvec req;
2588 size_t i, match;
2590 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2592 if (!family->data->count)
2594 *font = NULL;
2595 return DWRITE_E_NOFONT;
2598 init_font_prop_vec(weight, stretch, style, &req);
2599 match = 0;
2601 for (i = 1; i < family->data->count; ++i)
2603 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2604 match = i;
2607 return create_font(family, match, (IDWriteFont3 **)font);
2610 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2612 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2614 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2617 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2619 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2622 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2624 UINT32 b = fonts->font_count - 1, j, t;
2626 while (1) {
2627 t = b;
2629 for (j = 0; j < b; j++) {
2630 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2631 struct dwrite_font_data *s = fonts->fonts[j];
2632 fonts->fonts[j] = fonts->fonts[j+1];
2633 fonts->fonts[j+1] = s;
2634 t = j;
2638 if (t == b)
2639 break;
2640 b = t;
2644 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2645 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2647 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2648 matching_filter_func func = NULL;
2649 struct dwrite_font_propvec req;
2650 struct dwrite_fontlist *fonts;
2651 size_t i;
2653 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2655 *ret = NULL;
2657 fonts = heap_alloc(sizeof(*fonts));
2658 if (!fonts)
2659 return E_OUTOFMEMORY;
2661 /* Allocate as many as family has, not all of them will be necessary used. */
2662 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2663 if (!fonts->fonts) {
2664 heap_free(fonts);
2665 return E_OUTOFMEMORY;
2668 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2669 fonts->refcount = 1;
2670 fonts->family = family;
2671 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2672 fonts->font_count = 0;
2674 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2675 if (style == DWRITE_FONT_STYLE_NORMAL) {
2676 if (family->data->has_normal_face || family->data->has_italic_face)
2677 func = is_font_acceptable_for_normal;
2679 else /* requested oblique or italic */ {
2680 if (family->data->has_oblique_face || family->data->has_italic_face)
2681 func = is_font_acceptable_for_oblique_italic;
2684 for (i = 0; i < family->data->count; ++i)
2686 if (!func || func(family->data->fonts[i]))
2688 fonts->fonts[fonts->font_count++] = addref_font_data(family->data->fonts[i]);
2692 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2693 init_font_prop_vec(weight, stretch, style, &req);
2694 matchingfonts_sort(fonts, &req);
2696 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2697 return S_OK;
2700 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2702 FIXME("%p, %u.\n", iface, index);
2704 return DWRITE_LOCALITY_LOCAL;
2707 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2709 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2711 TRACE("%p, %u, %p.\n", iface, index, font);
2713 *font = NULL;
2715 if (!family->data->count)
2716 return S_FALSE;
2718 if (index >= family->data->count)
2719 return E_FAIL;
2721 return create_font(family, index, font);
2724 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2725 IDWriteFontFaceReference **reference)
2727 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2728 const struct dwrite_font_data *font;
2730 TRACE("%p, %u, %p.\n", iface, index, reference);
2732 *reference = NULL;
2734 if (index >= family->data->count)
2735 return E_FAIL;
2737 font = family->data->fonts[index];
2738 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2739 font->file, font->face_index, font->simulations, reference);
2742 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2743 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2745 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2747 return E_NOTIMPL;
2750 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2752 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2754 TRACE("%p, %p.\n", iface, fontset);
2756 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
2757 family->data->count, fontset);
2760 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2762 dwritefontfamily_QueryInterface,
2763 dwritefontfamily_AddRef,
2764 dwritefontfamily_Release,
2765 dwritefontfamily_GetFontCollection,
2766 dwritefontfamily_GetFontCount,
2767 dwritefontfamily_GetFont,
2768 dwritefontfamily_GetFamilyNames,
2769 dwritefontfamily_GetFirstMatchingFont,
2770 dwritefontfamily_GetMatchingFonts,
2771 dwritefontfamily1_GetFontLocality,
2772 dwritefontfamily1_GetFont,
2773 dwritefontfamily1_GetFontFaceReference,
2774 dwritefontfamily2_GetMatchingFonts,
2775 dwritefontfamily2_GetFontSet,
2778 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2780 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2781 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2784 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2786 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2787 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2790 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2792 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2793 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2796 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2797 IDWriteFontCollection **collection)
2799 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2800 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2803 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2805 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2806 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2809 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2811 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2812 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2815 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2817 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2818 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2821 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2823 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2824 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2827 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2828 IDWriteFontFaceReference **reference)
2830 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2831 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2834 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2836 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2838 TRACE("%p, %p.\n", iface, fontset);
2840 return fontset_create_from_font_data(family->collection->factory, family->data->fonts,
2841 family->data->count, fontset);
2844 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2846 dwritefontfamilylist_QueryInterface,
2847 dwritefontfamilylist_AddRef,
2848 dwritefontfamilylist_Release,
2849 dwritefontfamilylist_GetFontCollection,
2850 dwritefontfamilylist_GetFontCount,
2851 dwritefontfamilylist_GetFont,
2852 dwritefontfamilylist1_GetFontLocality,
2853 dwritefontfamilylist1_GetFont,
2854 dwritefontfamilylist1_GetFontFaceReference,
2855 dwritefontfamilylist2_GetFontSet,
2858 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2859 struct dwrite_fontfamily **family)
2861 struct dwrite_fontfamily *object;
2863 *family = NULL;
2865 object = heap_alloc(sizeof(*object));
2866 if (!object)
2867 return E_OUTOFMEMORY;
2869 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2870 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2871 object->refcount = 1;
2872 object->collection = collection;
2873 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2874 object->data = collection->family_data[index];
2875 InterlockedIncrement(&object->data->refcount);
2877 *family = object;
2879 return S_OK;
2882 BOOL is_system_collection(IDWriteFontCollection *collection)
2884 void *obj;
2885 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2888 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2890 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2892 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2894 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2895 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2896 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2897 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2898 IsEqualIID(riid, &IID_IUnknown))
2900 *obj = iface;
2901 IDWriteFontCollection3_AddRef(iface);
2902 return S_OK;
2905 *obj = NULL;
2907 if (IsEqualIID(riid, &IID_issystemcollection))
2908 return S_OK;
2910 WARN("%s not implemented.\n", debugstr_guid(riid));
2912 return E_NOINTERFACE;
2915 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2917 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2919 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2920 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2921 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2922 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2923 IsEqualIID(riid, &IID_IUnknown))
2925 *obj = iface;
2926 IDWriteFontCollection3_AddRef(iface);
2927 return S_OK;
2930 WARN("%s not implemented.\n", debugstr_guid(riid));
2932 *obj = NULL;
2934 return E_NOINTERFACE;
2937 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2939 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2940 ULONG refcount = InterlockedIncrement(&collection->refcount);
2942 TRACE("%p, refcount %d.\n", collection, refcount);
2944 return refcount;
2947 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2949 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2950 ULONG refcount = InterlockedDecrement(&collection->refcount);
2951 size_t i;
2953 TRACE("%p, refcount %d.\n", iface, refcount);
2955 if (!refcount)
2957 factory_detach_fontcollection(collection->factory, iface);
2958 for (i = 0; i < collection->count; ++i)
2959 release_fontfamily_data(collection->family_data[i]);
2960 heap_free(collection->family_data);
2961 heap_free(collection);
2964 return refcount;
2967 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2969 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2971 TRACE("%p.\n", iface);
2973 return collection->count;
2976 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2977 IDWriteFontFamily **ret)
2979 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2980 struct dwrite_fontfamily *family;
2981 HRESULT hr;
2983 TRACE("%p, %u, %p.\n", iface, index, ret);
2985 *ret = NULL;
2987 if (index >= collection->count)
2988 return E_FAIL;
2990 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2991 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2993 return hr;
2996 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2998 size_t i;
3000 for (i = 0; i < collection->count; ++i)
3002 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
3003 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
3004 HRESULT hr;
3006 for (j = 0; j < count; j++) {
3007 WCHAR buffer[255];
3008 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
3009 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
3010 return i;
3014 return ~0u;
3017 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
3018 UINT32 *index, BOOL *exists)
3020 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3022 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
3024 *index = collection_find_family(collection, name);
3025 *exists = *index != ~0u;
3026 return S_OK;
3029 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
3030 IDWriteFont **font)
3032 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3033 struct dwrite_fontfamily *family;
3034 BOOL found_font = FALSE;
3035 IDWriteFontFile *file;
3036 UINT32 face_index, count;
3037 size_t i, j;
3038 HRESULT hr;
3040 TRACE("%p, %p, %p.\n", iface, face, font);
3042 *font = NULL;
3044 if (!face)
3045 return E_INVALIDARG;
3047 count = 1;
3048 hr = IDWriteFontFace_GetFiles(face, &count, &file);
3049 if (FAILED(hr))
3050 return hr;
3051 face_index = IDWriteFontFace_GetIndex(face);
3053 found_font = FALSE;
3054 for (i = 0; i < collection->count; ++i)
3056 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
3058 for (j = 0; j < family_data->count; ++j)
3060 struct dwrite_font_data *font_data = family_data->fonts[j];
3062 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3063 found_font = TRUE;
3064 break;
3068 if (found_font)
3069 break;
3071 IDWriteFontFile_Release(file);
3073 if (!found_font)
3074 return DWRITE_E_NOFONT;
3076 hr = create_fontfamily(collection, i, &family);
3077 if (FAILED(hr))
3078 return hr;
3080 hr = create_font(family, j, (IDWriteFont3 **)font);
3081 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3082 return hr;
3085 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3087 FIXME("%p, %p.\n", iface, fontset);
3089 return E_NOTIMPL;
3092 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3093 IDWriteFontFamily1 **ret)
3095 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3096 struct dwrite_fontfamily *family;
3097 HRESULT hr;
3099 TRACE("%p, %u, %p.\n", iface, index, ret);
3101 *ret = NULL;
3103 if (index >= collection->count)
3104 return E_FAIL;
3106 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3107 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3109 return hr;
3112 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3113 UINT32 index, IDWriteFontFamily2 **ret)
3115 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3116 struct dwrite_fontfamily *family;
3117 HRESULT hr;
3119 TRACE("%p, %u, %p.\n", iface, index, ret);
3121 *ret = NULL;
3123 if (index >= collection->count)
3124 return E_FAIL;
3126 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3127 *ret = &family->IDWriteFontFamily2_iface;
3129 return hr;
3132 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3133 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3134 IDWriteFontList2 **fontlist)
3136 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3138 return E_NOTIMPL;
3141 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3143 FIXME("%p.\n", iface);
3145 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3148 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3150 FIXME("%p, %p.\n", iface, fontset);
3152 return E_NOTIMPL;
3155 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3157 FIXME("%p.\n", iface);
3159 return NULL;
3162 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3164 dwritefontcollection_QueryInterface,
3165 dwritefontcollection_AddRef,
3166 dwritefontcollection_Release,
3167 dwritefontcollection_GetFontFamilyCount,
3168 dwritefontcollection_GetFontFamily,
3169 dwritefontcollection_FindFamilyName,
3170 dwritefontcollection_GetFontFromFontFace,
3171 dwritefontcollection1_GetFontSet,
3172 dwritefontcollection1_GetFontFamily,
3173 dwritefontcollection2_GetFontFamily,
3174 dwritefontcollection2_GetMatchingFonts,
3175 dwritefontcollection2_GetFontFamilyModel,
3176 dwritefontcollection2_GetFontSet,
3177 dwritefontcollection3_GetExpirationEvent,
3180 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3182 dwritesystemfontcollection_QueryInterface,
3183 dwritefontcollection_AddRef,
3184 dwritefontcollection_Release,
3185 dwritefontcollection_GetFontFamilyCount,
3186 dwritefontcollection_GetFontFamily,
3187 dwritefontcollection_FindFamilyName,
3188 dwritefontcollection_GetFontFromFontFace,
3189 dwritefontcollection1_GetFontSet,
3190 dwritefontcollection1_GetFontFamily,
3191 dwritefontcollection2_GetFontFamily,
3192 dwritefontcollection2_GetMatchingFonts,
3193 dwritefontcollection2_GetFontFamilyModel,
3194 dwritefontcollection2_GetFontSet,
3195 dwritefontcollection3_GetExpirationEvent,
3198 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3200 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3201 sizeof(*family_data->fonts)))
3203 return E_OUTOFMEMORY;
3206 family_data->fonts[family_data->count++] = font_data;
3207 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3208 family_data->has_normal_face = 1;
3209 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3210 family_data->has_oblique_face = 1;
3211 else
3212 family_data->has_italic_face = 1;
3213 return S_OK;
3216 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3217 struct dwrite_fontfamily_data *family)
3219 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3220 sizeof(*collection->family_data)))
3222 return E_OUTOFMEMORY;
3225 collection->family_data[collection->count++] = family;
3226 return S_OK;
3229 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3231 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3232 collection->refcount = 1;
3233 collection->count = 0;
3234 collection->size = 0;
3235 collection->family_data = NULL;
3237 return S_OK;
3240 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3242 IDWriteFontFileLoader *loader;
3243 const void *key;
3244 UINT32 key_size;
3245 HRESULT hr;
3247 *stream = NULL;
3249 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3250 if (FAILED(hr))
3251 return hr;
3253 hr = IDWriteFontFile_GetLoader(file, &loader);
3254 if (FAILED(hr))
3255 return hr;
3257 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3258 IDWriteFontFileLoader_Release(loader);
3259 if (FAILED(hr))
3260 return hr;
3262 return hr;
3265 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3267 BOOL exists = FALSE;
3268 UINT32 index;
3269 HRESULT hr;
3271 buffer[0] = 0;
3272 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3273 if (FAILED(hr) || !exists)
3274 return;
3276 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3279 static int trim_spaces(WCHAR *in, WCHAR *ret)
3281 int len;
3283 while (isspaceW(*in))
3284 in++;
3286 ret[0] = 0;
3287 if (!(len = strlenW(in)))
3288 return 0;
3290 while (isspaceW(in[len-1]))
3291 len--;
3293 memcpy(ret, in, len*sizeof(WCHAR));
3294 ret[len] = 0;
3296 return len;
3299 struct name_token {
3300 struct list entry;
3301 const WCHAR *ptr;
3302 INT len; /* token length */
3303 INT fulllen; /* full length including following separators */
3306 static inline BOOL is_name_separator_char(WCHAR ch)
3308 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3311 struct name_pattern {
3312 const WCHAR *part1; /* NULL indicates end of list */
3313 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3316 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3318 const struct name_pattern *pattern;
3319 struct name_token *token;
3320 int i = 0;
3322 while ((pattern = &patterns[i++])->part1) {
3323 int len_part1 = strlenW(pattern->part1);
3324 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3326 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3327 if (len_part2 == 0) {
3328 /* simple case with single part pattern */
3329 if (token->len != len_part1)
3330 continue;
3332 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3333 if (match) *match = *token;
3334 list_remove(&token->entry);
3335 heap_free(token);
3336 return TRUE;
3339 else {
3340 struct name_token *next_token;
3341 struct list *next_entry;
3343 /* pattern parts are stored in reading order, tokens list is reversed */
3344 if (token->len < len_part2)
3345 continue;
3347 /* it's possible to have combined string as a token, like ExtraCondensed */
3348 if (token->len == len_part1 + len_part2) {
3349 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3350 continue;
3352 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3353 continue;
3355 /* combined string match */
3356 if (match) *match = *token;
3357 list_remove(&token->entry);
3358 heap_free(token);
3359 return TRUE;
3362 /* now it's only possible to have two tokens matched to respective pattern parts */
3363 if (token->len != len_part2)
3364 continue;
3366 next_entry = list_next(tokens, &token->entry);
3367 if (next_entry) {
3368 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3369 if (next_token->len != len_part1)
3370 continue;
3372 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3373 continue;
3375 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3376 continue;
3378 /* both parts matched, remove tokens */
3379 if (match) {
3380 match->ptr = next_token->ptr;
3381 match->len = (token->ptr - next_token->ptr) + token->len;
3383 list_remove(&token->entry);
3384 list_remove(&next_token->entry);
3385 heap_free(next_token);
3386 heap_free(token);
3387 return TRUE;
3393 if (match) {
3394 match->ptr = NULL;
3395 match->len = 0;
3397 return FALSE;
3400 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3402 static const WCHAR itaW[] = {'i','t','a',0};
3403 static const WCHAR italW[] = {'i','t','a','l',0};
3404 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3405 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3407 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3408 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3409 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3410 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3412 static const struct name_pattern italic_patterns[] = {
3413 { itaW },
3414 { italW },
3415 { italicW },
3416 { cursiveW },
3417 { kursivW },
3418 { NULL }
3421 static const struct name_pattern oblique_patterns[] = {
3422 { inclinedW },
3423 { obliqueW },
3424 { backslantedW },
3425 { backslantW },
3426 { slantedW },
3427 { NULL }
3430 /* italic patterns first */
3431 if (match_pattern_list(tokens, italic_patterns, match))
3432 return DWRITE_FONT_STYLE_ITALIC;
3434 /* oblique patterns */
3435 if (match_pattern_list(tokens, oblique_patterns, match))
3436 return DWRITE_FONT_STYLE_OBLIQUE;
3438 return style;
3441 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3442 struct name_token *match)
3444 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3445 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3446 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3447 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3448 static const WCHAR wideW[] = {'w','i','d','e',0};
3449 static const WCHAR condW[] = {'c','o','n','d',0};
3451 static const struct name_pattern ultracondensed_patterns[] = {
3452 { extraW, compressedW },
3453 { extW, compressedW },
3454 { ultraW, compressedW },
3455 { ultraW, condensedW },
3456 { ultraW, condW },
3457 { NULL }
3460 static const struct name_pattern extracondensed_patterns[] = {
3461 { compressedW },
3462 { extraW, condensedW },
3463 { extW, condensedW },
3464 { extraW, condW },
3465 { extW, condW },
3466 { NULL }
3469 static const struct name_pattern semicondensed_patterns[] = {
3470 { narrowW },
3471 { compactW },
3472 { semiW, condensedW },
3473 { semiW, condW },
3474 { NULL }
3477 static const struct name_pattern semiexpanded_patterns[] = {
3478 { wideW },
3479 { semiW, expandedW },
3480 { semiW, extendedW },
3481 { NULL }
3484 static const struct name_pattern extraexpanded_patterns[] = {
3485 { extraW, expandedW },
3486 { extW, expandedW },
3487 { extraW, extendedW },
3488 { extW, extendedW },
3489 { NULL }
3492 static const struct name_pattern ultraexpanded_patterns[] = {
3493 { ultraW, expandedW },
3494 { ultraW, extendedW },
3495 { NULL }
3498 static const struct name_pattern condensed_patterns[] = {
3499 { condensedW },
3500 { condW },
3501 { NULL }
3504 static const struct name_pattern expanded_patterns[] = {
3505 { expandedW },
3506 { extendedW },
3507 { NULL }
3510 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3511 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3513 if (match_pattern_list(tokens, extracondensed_patterns, match))
3514 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3516 if (match_pattern_list(tokens, semicondensed_patterns, match))
3517 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3519 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3520 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3522 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3523 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3525 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3526 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3528 if (match_pattern_list(tokens, condensed_patterns, match))
3529 return DWRITE_FONT_STRETCH_CONDENSED;
3531 if (match_pattern_list(tokens, expanded_patterns, match))
3532 return DWRITE_FONT_STRETCH_EXPANDED;
3534 return stretch;
3537 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3538 struct name_token *match)
3540 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3541 static const WCHAR nordW[] = {'n','o','r','d',0};
3543 static const struct name_pattern thin_patterns[] = {
3544 { extraW, thinW },
3545 { extW, thinW },
3546 { ultraW, thinW },
3547 { NULL }
3550 static const struct name_pattern extralight_patterns[] = {
3551 { extraW, lightW },
3552 { extW, lightW },
3553 { ultraW, lightW },
3554 { NULL }
3557 static const struct name_pattern semilight_patterns[] = {
3558 { semiW, lightW },
3559 { NULL }
3562 static const struct name_pattern demibold_patterns[] = {
3563 { semiW, boldW },
3564 { demiW, boldW },
3565 { NULL }
3568 static const struct name_pattern extrabold_patterns[] = {
3569 { extraW, boldW },
3570 { extW, boldW },
3571 { ultraW, boldW },
3572 { NULL }
3575 static const struct name_pattern extrablack_patterns[] = {
3576 { extraW, blackW },
3577 { extW, blackW },
3578 { ultraW, blackW },
3579 { NULL }
3582 static const struct name_pattern bold_patterns[] = {
3583 { boldW },
3584 { NULL }
3587 static const struct name_pattern thin2_patterns[] = {
3588 { thinW },
3589 { NULL }
3592 static const struct name_pattern light_patterns[] = {
3593 { lightW },
3594 { NULL }
3597 static const struct name_pattern medium_patterns[] = {
3598 { mediumW },
3599 { NULL }
3602 static const struct name_pattern black_patterns[] = {
3603 { blackW },
3604 { heavyW },
3605 { nordW },
3606 { NULL }
3609 static const struct name_pattern demibold2_patterns[] = {
3610 { demiW },
3611 { NULL }
3614 static const struct name_pattern extrabold2_patterns[] = {
3615 { ultraW },
3616 { NULL }
3619 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3620 matching pattern. */
3622 if (match_pattern_list(tokens, thin_patterns, match))
3623 return DWRITE_FONT_WEIGHT_THIN;
3625 if (match_pattern_list(tokens, extralight_patterns, match))
3626 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3628 if (match_pattern_list(tokens, semilight_patterns, match))
3629 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3631 if (match_pattern_list(tokens, demibold_patterns, match))
3632 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3634 if (match_pattern_list(tokens, extrabold_patterns, match))
3635 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3637 if (match_pattern_list(tokens, extrablack_patterns, match))
3638 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3640 if (match_pattern_list(tokens, bold_patterns, match))
3641 return DWRITE_FONT_WEIGHT_BOLD;
3643 if (match_pattern_list(tokens, thin2_patterns, match))
3644 return DWRITE_FONT_WEIGHT_THIN;
3646 if (match_pattern_list(tokens, light_patterns, match))
3647 return DWRITE_FONT_WEIGHT_LIGHT;
3649 if (match_pattern_list(tokens, medium_patterns, match))
3650 return DWRITE_FONT_WEIGHT_MEDIUM;
3652 if (match_pattern_list(tokens, black_patterns, match))
3653 return DWRITE_FONT_WEIGHT_BLACK;
3655 if (match_pattern_list(tokens, black_patterns, match))
3656 return DWRITE_FONT_WEIGHT_BLACK;
3658 if (match_pattern_list(tokens, demibold2_patterns, match))
3659 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3661 if (match_pattern_list(tokens, extrabold2_patterns, match))
3662 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3664 /* FIXME: use abbreviated names to extract weight */
3666 return weight;
3669 struct knownweight_entry {
3670 const WCHAR *nameW;
3671 DWRITE_FONT_WEIGHT weight;
3674 static int compare_knownweights(const void *a, const void* b)
3676 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3677 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3678 int ret = 0;
3680 if (target > entry->weight)
3681 ret = 1;
3682 else if (target < entry->weight)
3683 ret = -1;
3685 return ret;
3688 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3690 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3691 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3692 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3693 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3694 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3695 static const WCHAR thinW[] = {'T','h','i','n',0};
3696 static const WCHAR lightW[] = {'L','i','g','h','t',0};
3697 static const WCHAR mediumW[] = {'M','e','d','i','u','m',0};
3698 static const WCHAR blackW[] = {'B','l','a','c','k',0};
3699 const struct knownweight_entry *ptr;
3701 static const struct knownweight_entry knownweights[] = {
3702 { thinW, DWRITE_FONT_WEIGHT_THIN },
3703 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3704 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3705 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3706 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3707 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3708 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3709 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3710 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3711 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3714 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3715 compare_knownweights);
3716 if (!ptr) {
3717 nameW[0] = 0;
3718 return FALSE;
3721 strcpyW(nameW, ptr->nameW);
3722 return TRUE;
3725 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3727 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3728 strW[name->len] = 0;
3731 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3732 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3734 static const WCHAR bookW[] = {'B','o','o','k',0};
3735 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3736 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3737 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3738 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3740 static const WCHAR *regular_patterns[] = {
3741 bookW,
3742 normalW,
3743 regularW,
3744 romanW,
3745 uprightW,
3746 NULL
3749 const WCHAR *regular_ptr = NULL, *ptr;
3750 int i = 0;
3752 if (len == -1)
3753 len = strlenW(facenameW);
3755 /* remove rightmost regular variant from face name */
3756 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3757 int pattern_len = strlenW(ptr);
3758 WCHAR *src;
3760 if (pattern_len > len)
3761 continue;
3763 src = facenameW + len - pattern_len;
3764 while (src >= facenameW) {
3765 if (!strncmpiW(src, ptr, pattern_len)) {
3766 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3767 len = strlenW(facenameW);
3768 regular_ptr = ptr;
3769 break;
3771 else
3772 src--;
3776 return regular_ptr;
3779 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3781 const WCHAR *ptr;
3783 list_init(tokens);
3784 ptr = nameW;
3786 while (*ptr) {
3787 struct name_token *token = heap_alloc(sizeof(*token));
3788 token->ptr = ptr;
3789 token->len = 0;
3790 token->fulllen = 0;
3792 while (*ptr && !is_name_separator_char(*ptr)) {
3793 token->len++;
3794 token->fulllen++;
3795 ptr++;
3798 /* skip separators */
3799 while (is_name_separator_char(*ptr)) {
3800 token->fulllen++;
3801 ptr++;
3804 list_add_head(tokens, &token->entry);
3808 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3810 struct name_token *token, *token2;
3811 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3812 int len;
3814 list_remove(&token->entry);
3816 /* don't include last separator */
3817 len = list_empty(tokens) ? token->len : token->fulllen;
3818 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3819 nameW += len;
3821 heap_free(token);
3823 *nameW = 0;
3826 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3828 struct name_token stretch_name, weight_name, style_name;
3829 WCHAR familynameW[255], facenameW[255], finalW[255];
3830 WCHAR weightW[32], stretchW[32], styleW[32];
3831 const WCHAR *regular_ptr = NULL;
3832 DWRITE_FONT_STRETCH stretch;
3833 DWRITE_FONT_WEIGHT weight;
3834 struct list tokens;
3835 int len;
3837 /* remove leading and trailing spaces from family and face name */
3838 trim_spaces(familyW, familynameW);
3839 len = trim_spaces(faceW, facenameW);
3841 /* remove rightmost regular variant from face name */
3842 regular_ptr = facename_remove_regular_term(facenameW, len);
3844 /* append face name to family name, FIXME check if face name is a substring of family name */
3845 if (*facenameW) {
3846 strcatW(familynameW, spaceW);
3847 strcatW(familynameW, facenameW);
3850 /* tokenize with " .-_" */
3851 fontname_tokenize(&tokens, familynameW);
3853 /* extract and resolve style */
3854 font->style = font_extract_style(&tokens, font->style, &style_name);
3856 /* extract stretch */
3857 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3859 /* extract weight */
3860 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3862 /* resolve weight */
3863 if (weight != font->weight) {
3864 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3865 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3866 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3867 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3868 !(abs(weight - font->weight) <= 150 &&
3869 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3870 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3871 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3873 font->weight = weight;
3877 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3878 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3879 stretch itself is normal (extracted stretch is never normal). */
3880 if (stretch != font->stretch) {
3881 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3882 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3883 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3885 font->stretch = stretch;
3889 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3891 /* get final combined string from what's left in token list, list is released */
3892 fontname_tokens_to_str(&tokens, finalW);
3894 if (!strcmpW(familyW, finalW))
3895 return FALSE;
3897 /* construct face name */
3898 strcpyW(familyW, finalW);
3900 /* resolved weight name */
3901 if (weight_name.ptr)
3902 font_name_token_to_str(&weight_name, weightW);
3903 /* ignore normal weight */
3904 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3905 weightW[0] = 0;
3906 /* for known weight values use appropriate names */
3907 else if (is_known_weight_value(font->weight, weightW)) {
3909 /* use Wnnn format as a fallback in case weight is not one of known values */
3910 else {
3911 static const WCHAR fmtW[] = {'W','%','d',0};
3912 sprintfW(weightW, fmtW, font->weight);
3915 /* resolved stretch name */
3916 if (stretch_name.ptr)
3917 font_name_token_to_str(&stretch_name, stretchW);
3918 /* ignore normal stretch */
3919 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3920 stretchW[0] = 0;
3921 /* use predefined stretch names */
3922 else {
3923 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3924 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3925 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3926 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3927 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3928 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3930 static const WCHAR *stretchnamesW[] = {
3931 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3932 ultracondensedW,
3933 extracondensedW,
3934 condensedW,
3935 semicondensedW,
3936 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3937 semiexpandedW,
3938 expandedW,
3939 extraexpandedW,
3940 ultraexpandedW
3942 strcpyW(stretchW, stretchnamesW[font->stretch]);
3945 /* resolved style name */
3946 if (style_name.ptr)
3947 font_name_token_to_str(&style_name, styleW);
3948 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3949 styleW[0] = 0;
3950 /* use predefined names */
3951 else {
3952 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3953 strcpyW(styleW, italicW);
3954 else
3955 strcpyW(styleW, obliqueW);
3958 /* use Regular match if it was found initially */
3959 if (!*weightW && !*stretchW && !*styleW)
3960 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3961 else {
3962 faceW[0] = 0;
3963 if (*stretchW)
3964 strcpyW(faceW, stretchW);
3965 if (*weightW) {
3966 if (*faceW)
3967 strcatW(faceW, spaceW);
3968 strcatW(faceW, weightW);
3970 if (*styleW) {
3971 if (*faceW)
3972 strcatW(faceW, spaceW);
3973 strcatW(faceW, styleW);
3977 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3978 return TRUE;
3981 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3983 static const float width_axis_values[] =
3985 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3986 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3987 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3988 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3989 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3990 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3991 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3992 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3993 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3994 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3997 struct file_stream_desc stream_desc;
3998 struct dwrite_font_props props;
3999 struct dwrite_font_data *data;
4000 WCHAR familyW[255], faceW[255];
4001 HRESULT hr;
4003 *ret = NULL;
4005 data = heap_alloc_zero(sizeof(*data));
4006 if (!data)
4007 return E_OUTOFMEMORY;
4009 data->refcount = 1;
4010 data->file = desc->file;
4011 data->face_index = desc->index;
4012 data->face_type = desc->face_type;
4013 IDWriteFontFile_AddRef(data->file);
4015 stream_desc.stream = desc->stream;
4016 stream_desc.face_type = desc->face_type;
4017 stream_desc.face_index = desc->index;
4018 opentype_get_font_properties(&stream_desc, &props);
4019 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
4020 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
4022 /* get family name from font file */
4023 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
4024 if (FAILED(hr)) {
4025 WARN("unable to get family name from font\n");
4026 release_font_data(data);
4027 return hr;
4030 data->style = props.style;
4031 data->stretch = props.stretch;
4032 data->weight = props.weight;
4033 data->panose = props.panose;
4034 data->fontsig = props.fontsig;
4035 data->lf = props.lf;
4036 data->flags = props.flags;
4038 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
4039 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
4040 if (font_apply_differentiation_rules(data, familyW, faceW)) {
4041 set_en_localizedstring(data->family_names, familyW);
4042 set_en_localizedstring(data->names, faceW);
4045 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4047 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
4048 data->axis[0].value = props.weight;
4049 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
4050 data->axis[1].value = width_axis_values[props.stretch];
4051 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
4052 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
4054 *ret = data;
4055 return S_OK;
4058 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS simulations,
4059 const WCHAR *facenameW, struct dwrite_font_data **ret)
4061 struct dwrite_font_data *data;
4063 *ret = NULL;
4065 data = heap_alloc_zero(sizeof(*data));
4066 if (!data)
4067 return E_OUTOFMEMORY;
4069 *data = *src;
4070 data->refcount = 1;
4071 data->simulations |= simulations;
4072 if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
4073 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4074 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
4075 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4076 memset(data->info_strings, 0, sizeof(data->info_strings));
4077 data->names = NULL;
4078 IDWriteFontFile_AddRef(data->file);
4079 IDWriteLocalizedStrings_AddRef(data->family_names);
4081 create_localizedstrings(&data->names);
4082 add_localizedstring(data->names, enusW, facenameW);
4084 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4086 *ret = data;
4087 return S_OK;
4090 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4092 struct dwrite_fontfamily_data *data;
4094 data = heap_alloc_zero(sizeof(*data));
4095 if (!data)
4096 return E_OUTOFMEMORY;
4098 data->refcount = 1;
4099 data->familyname = familyname;
4100 IDWriteLocalizedStrings_AddRef(familyname);
4102 *ret = data;
4104 return S_OK;
4107 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4109 size_t i, j, heaviest;
4111 for (i = 0; i < family->count; ++i)
4113 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4114 heaviest = i;
4116 if (family->fonts[i]->bold_sim_tested)
4117 continue;
4119 family->fonts[i]->bold_sim_tested = 1;
4120 for (j = i; j < family->count; ++j)
4122 if (family->fonts[j]->bold_sim_tested)
4123 continue;
4125 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4126 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4127 if (family->fonts[j]->weight > weight) {
4128 weight = family->fonts[j]->weight;
4129 heaviest = j;
4131 family->fonts[j]->bold_sim_tested = 1;
4135 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4136 static const struct name_pattern weightsim_patterns[] = {
4137 { extraW, lightW },
4138 { extW, lightW },
4139 { ultraW, lightW },
4140 { semiW, lightW },
4141 { semiW, boldW },
4142 { demiW, boldW },
4143 { boldW },
4144 { thinW },
4145 { lightW },
4146 { mediumW },
4147 { demiW },
4148 { NULL }
4151 WCHAR facenameW[255], initialW[255];
4152 struct dwrite_font_data *boldface;
4153 struct list tokens;
4155 /* add Bold simulation based on heaviest face data */
4157 /* Simulated face name should only contain Bold as weight term,
4158 so remove existing regular and weight terms. */
4159 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4160 facename_remove_regular_term(initialW, -1);
4162 /* remove current weight pattern */
4163 fontname_tokenize(&tokens, initialW);
4164 match_pattern_list(&tokens, weightsim_patterns, NULL);
4165 fontname_tokens_to_str(&tokens, facenameW);
4167 /* Bold suffix for new name */
4168 if (*facenameW)
4169 strcatW(facenameW, spaceW);
4170 strcatW(facenameW, boldW);
4172 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4173 boldface->bold_sim_tested = 1;
4174 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4175 fontfamily_add_font(family, boldface);
4181 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4183 size_t i, j;
4185 for (i = 0; i < family->count; ++i)
4187 UINT32 regular = ~0u, oblique = ~0u;
4188 struct dwrite_font_data *obliqueface;
4189 WCHAR facenameW[255];
4191 if (family->fonts[i]->oblique_sim_tested)
4192 continue;
4194 family->fonts[i]->oblique_sim_tested = 1;
4195 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4196 regular = i;
4197 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4198 oblique = i;
4200 /* find regular style with same weight/stretch values */
4201 for (j = i; j < family->count; ++j)
4203 if (family->fonts[j]->oblique_sim_tested)
4204 continue;
4206 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4207 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4209 family->fonts[j]->oblique_sim_tested = 1;
4210 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4211 regular = j;
4213 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4214 oblique = j;
4217 if (regular != ~0u && oblique != ~0u)
4218 break;
4221 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4222 if (regular == ~0u)
4223 continue;
4225 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4226 if (oblique != ~0u)
4227 continue;
4229 /* add oblique simulation based on this regular face */
4231 /* remove regular term if any, append 'Oblique' */
4232 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4233 facename_remove_regular_term(facenameW, -1);
4235 if (*facenameW)
4236 strcatW(facenameW, spaceW);
4237 strcatW(facenameW, obliqueW);
4239 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4240 obliqueface->oblique_sim_tested = 1;
4241 obliqueface->lf.lfItalic = 1;
4242 fontfamily_add_font(family, obliqueface);
4247 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4248 const WCHAR *replacement_name)
4250 UINT32 i = collection_find_family(collection, replacement_name);
4251 struct dwrite_fontfamily_data *target;
4252 IDWriteLocalizedStrings *strings;
4253 HRESULT hr;
4255 /* replacement does not exist */
4256 if (i == ~0u)
4257 return FALSE;
4259 hr = create_localizedstrings(&strings);
4260 if (FAILED(hr))
4261 return FALSE;
4263 /* add a new family with target name, reuse font data from replacement */
4264 add_localizedstring(strings, enusW, target_name);
4265 hr = init_fontfamily_data(strings, &target);
4266 if (hr == S_OK) {
4267 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4268 WCHAR nameW[255];
4270 for (i = 0; i < replacement->count; ++i)
4272 fontfamily_add_font(target, replacement->fonts[i]);
4273 addref_font_data(replacement->fonts[i]);
4276 fontcollection_add_family(collection, target);
4277 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4278 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4280 IDWriteLocalizedStrings_Release(strings);
4281 return TRUE;
4284 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4285 system font collections. */
4286 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4288 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4289 WCHAR *name;
4290 void *data;
4291 HKEY hkey;
4293 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4294 return;
4296 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4297 RegCloseKey(hkey);
4298 return;
4301 max_namelen++; /* returned value doesn't include room for '\0' */
4302 name = heap_alloc(max_namelen * sizeof(WCHAR));
4303 data = heap_alloc(max_datalen);
4305 datalen = max_datalen;
4306 namelen = max_namelen;
4307 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4308 if (collection_find_family(collection, name) == ~0u) {
4309 if (type == REG_MULTI_SZ) {
4310 WCHAR *replacement = data;
4311 while (*replacement) {
4312 if (fontcollection_add_replacement(collection, name, replacement))
4313 break;
4314 replacement += strlenW(replacement) + 1;
4317 else if (type == REG_SZ)
4318 fontcollection_add_replacement(collection, name, data);
4320 else
4321 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4323 datalen = max_datalen;
4324 namelen = max_namelen;
4327 heap_free(data);
4328 heap_free(name);
4329 RegCloseKey(hkey);
4332 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4333 IDWriteFontCollection3 **ret)
4335 struct fontfile_enum {
4336 struct list entry;
4337 IDWriteFontFile *file;
4339 struct fontfile_enum *fileenum, *fileenum2;
4340 struct dwrite_fontcollection *collection;
4341 struct list scannedfiles;
4342 BOOL current = FALSE;
4343 HRESULT hr = S_OK;
4344 size_t i;
4346 *ret = NULL;
4348 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4349 if (!collection) return E_OUTOFMEMORY;
4351 hr = init_font_collection(collection, is_system);
4352 if (FAILED(hr)) {
4353 heap_free(collection);
4354 return hr;
4357 *ret = &collection->IDWriteFontCollection3_iface;
4359 TRACE("building font collection:\n");
4361 list_init(&scannedfiles);
4362 while (hr == S_OK) {
4363 DWRITE_FONT_FACE_TYPE face_type;
4364 DWRITE_FONT_FILE_TYPE file_type;
4365 BOOL supported, same = FALSE;
4366 IDWriteFontFileStream *stream;
4367 IDWriteFontFile *file;
4368 UINT32 face_count;
4370 current = FALSE;
4371 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4372 if (FAILED(hr) || !current)
4373 break;
4375 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4376 if (FAILED(hr))
4377 break;
4379 /* check if we've scanned this file already */
4380 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4381 if ((same = is_same_fontfile(fileenum->file, file)))
4382 break;
4385 if (same) {
4386 IDWriteFontFile_Release(file);
4387 continue;
4390 if (FAILED(get_filestream_from_file(file, &stream))) {
4391 IDWriteFontFile_Release(file);
4392 continue;
4395 /* Unsupported formats are skipped. */
4396 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4397 if (FAILED(hr) || !supported || face_count == 0) {
4398 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4399 IDWriteFontFileStream_Release(stream);
4400 IDWriteFontFile_Release(file);
4401 hr = S_OK;
4402 continue;
4405 /* add to scanned list */
4406 fileenum = heap_alloc(sizeof(*fileenum));
4407 fileenum->file = file;
4408 list_add_tail(&scannedfiles, &fileenum->entry);
4410 for (i = 0; i < face_count; ++i)
4412 struct dwrite_font_data *font_data;
4413 struct fontface_desc desc;
4414 WCHAR familyW[255];
4415 UINT32 index;
4417 desc.factory = factory;
4418 desc.face_type = face_type;
4419 desc.file = file;
4420 desc.stream = stream;
4421 desc.index = i;
4422 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4423 desc.font_data = NULL;
4425 /* Allocate an initialize new font data structure. */
4426 hr = init_font_data(&desc, &font_data);
4427 if (FAILED(hr))
4429 /* move to next one */
4430 hr = S_OK;
4431 continue;
4434 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4436 /* ignore dot named faces */
4437 if (familyW[0] == '.')
4439 WARN("Ignoring face %s\n", debugstr_w(familyW));
4440 release_font_data(font_data);
4441 continue;
4444 index = collection_find_family(collection, familyW);
4445 if (index != ~0u)
4446 hr = fontfamily_add_font(collection->family_data[index], font_data);
4447 else {
4448 struct dwrite_fontfamily_data *family_data;
4450 /* create and init new family */
4451 hr = init_fontfamily_data(font_data->family_names, &family_data);
4452 if (hr == S_OK) {
4453 /* add font to family, family - to collection */
4454 hr = fontfamily_add_font(family_data, font_data);
4455 if (hr == S_OK)
4456 hr = fontcollection_add_family(collection, family_data);
4458 if (FAILED(hr))
4459 release_fontfamily_data(family_data);
4463 if (FAILED(hr))
4464 break;
4467 IDWriteFontFileStream_Release(stream);
4470 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4471 IDWriteFontFile_Release(fileenum->file);
4472 list_remove(&fileenum->entry);
4473 heap_free(fileenum);
4476 for (i = 0; i < collection->count; ++i)
4478 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4479 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4482 if (is_system)
4483 fontcollection_add_replacements(collection);
4485 collection->factory = factory;
4486 IDWriteFactory7_AddRef(factory);
4488 return hr;
4491 struct system_fontfile_enumerator
4493 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4494 LONG refcount;
4496 IDWriteFactory7 *factory;
4497 HKEY hkey;
4498 int index;
4500 WCHAR *filename;
4501 DWORD filename_size;
4504 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4506 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4509 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4511 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4512 IDWriteFontFileEnumerator_AddRef(iface);
4513 *obj = iface;
4514 return S_OK;
4517 WARN("%s not implemented.\n", debugstr_guid(riid));
4519 *obj = NULL;
4521 return E_NOINTERFACE;
4524 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4526 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4527 return InterlockedIncrement(&enumerator->refcount);
4530 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4532 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4533 ULONG refcount = InterlockedDecrement(&enumerator->refcount);
4535 if (!refcount)
4537 IDWriteFactory7_Release(enumerator->factory);
4538 RegCloseKey(enumerator->hkey);
4539 heap_free(enumerator->filename);
4540 heap_free(enumerator);
4543 return refcount;
4546 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4548 HRESULT hr;
4550 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4551 if (!strchrW(filename, '\\')) {
4552 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4553 WCHAR fullpathW[MAX_PATH];
4555 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4556 strcatW(fullpathW, fontsW);
4557 strcatW(fullpathW, filename);
4559 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4561 else
4562 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4564 return hr;
4567 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4569 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4571 *file = NULL;
4573 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4574 return E_FAIL;
4576 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4579 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4581 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4582 WCHAR name_buf[256], *name = name_buf;
4583 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4584 HRESULT hr = S_OK;
4585 LONG r;
4587 *current = FALSE;
4588 enumerator->index++;
4590 /* iterate until we find next string value */
4591 for (;;) {
4592 do {
4593 name_count = max_name_count;
4594 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4596 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4597 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4598 if (r == ERROR_MORE_DATA) {
4599 if (name_count >= max_name_count) {
4600 if (name != name_buf) heap_free(name);
4601 max_name_count *= 2;
4602 name = heap_alloc(max_name_count * sizeof(*name));
4603 if (!name) return E_OUTOFMEMORY;
4605 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4606 heap_free(enumerator->filename);
4607 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4608 enumerator->filename = heap_alloc(enumerator->filename_size);
4609 if (!enumerator->filename) {
4610 hr = E_OUTOFMEMORY;
4611 goto err;
4615 } while (r == ERROR_MORE_DATA);
4617 if (r != ERROR_SUCCESS) {
4618 enumerator->filename[0] = 0;
4619 break;
4621 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4622 if (type == REG_SZ && *name != '@') {
4623 *current = TRUE;
4624 break;
4626 enumerator->index++;
4628 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4630 err:
4631 if (name != name_buf) heap_free(name);
4632 return hr;
4635 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4637 systemfontfileenumerator_QueryInterface,
4638 systemfontfileenumerator_AddRef,
4639 systemfontfileenumerator_Release,
4640 systemfontfileenumerator_MoveNext,
4641 systemfontfileenumerator_GetCurrentFontFile
4644 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4646 struct system_fontfile_enumerator *enumerator;
4647 static const WCHAR fontslistW[] = {
4648 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4649 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4650 'F','o','n','t','s',0
4653 *ret = NULL;
4655 enumerator = heap_alloc(sizeof(*enumerator));
4656 if (!enumerator)
4657 return E_OUTOFMEMORY;
4659 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4660 enumerator->refcount = 1;
4661 enumerator->factory = factory;
4662 enumerator->index = -1;
4663 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4664 enumerator->filename = heap_alloc(enumerator->filename_size);
4665 if (!enumerator->filename) {
4666 heap_free(enumerator);
4667 return E_OUTOFMEMORY;
4670 IDWriteFactory7_AddRef(factory);
4672 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4674 ERR("failed to open fonts list key\n");
4675 IDWriteFactory7_Release(factory);
4676 heap_free(enumerator->filename);
4677 heap_free(enumerator);
4678 return E_FAIL;
4681 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4683 return S_OK;
4686 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4688 IDWriteFontFileEnumerator *enumerator;
4689 HRESULT hr;
4691 *collection = NULL;
4693 hr = create_system_fontfile_enumerator(factory, &enumerator);
4694 if (FAILED(hr))
4695 return hr;
4697 TRACE("building system font collection for factory %p\n", factory);
4698 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4699 IDWriteFontFileEnumerator_Release(enumerator);
4700 return hr;
4703 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4704 const WCHAR *keynameW, const WCHAR *pathW)
4706 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};
4707 static const WCHAR emptyW[] = {0};
4708 struct dwrite_fontfamily_data *family_data;
4709 IDWriteLocalizedStrings *names;
4710 DWRITE_FONT_FACE_TYPE face_type;
4711 DWRITE_FONT_FILE_TYPE file_type;
4712 IDWriteFontFileStream *stream;
4713 IDWriteFontFile *file;
4714 UINT32 face_count, i;
4715 BOOL supported;
4716 HRESULT hr;
4718 /* create font file from this path */
4719 hr = create_local_file_reference(factory, pathW, &file);
4720 if (FAILED(hr))
4721 return S_FALSE;
4723 if (FAILED(get_filestream_from_file(file, &stream))) {
4724 IDWriteFontFile_Release(file);
4725 return S_FALSE;
4728 /* Unsupported formats are skipped. */
4729 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4730 if (FAILED(hr) || !supported || face_count == 0) {
4731 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4732 IDWriteFontFileStream_Release(stream);
4733 IDWriteFontFile_Release(file);
4734 return S_FALSE;
4737 /* create and init new family */
4739 /* Family names are added for non-specific locale, represented with empty string.
4740 Default family appears with empty family name. */
4741 create_localizedstrings(&names);
4742 if (!strcmpiW(keynameW, defaultfontW))
4743 add_localizedstring(names, emptyW, emptyW);
4744 else
4745 add_localizedstring(names, emptyW, keynameW);
4747 hr = init_fontfamily_data(names, &family_data);
4748 IDWriteLocalizedStrings_Release(names);
4749 if (hr != S_OK) {
4750 IDWriteFontFile_Release(file);
4751 return hr;
4754 /* fill with faces */
4755 for (i = 0; i < face_count; i++) {
4756 struct dwrite_font_data *font_data;
4757 struct fontface_desc desc;
4759 /* Allocate new font data structure. */
4760 desc.factory = factory;
4761 desc.face_type = face_type;
4762 desc.index = i;
4763 desc.file = file;
4764 desc.stream = stream;
4765 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4766 desc.font_data = NULL;
4768 hr = init_font_data(&desc, &font_data);
4769 if (FAILED(hr))
4770 continue;
4772 /* add font to family */
4773 hr = fontfamily_add_font(family_data, font_data);
4774 if (hr != S_OK)
4775 release_font_data(font_data);
4778 /* add family to collection */
4779 hr = fontcollection_add_family(collection, family_data);
4780 if (FAILED(hr))
4781 release_fontfamily_data(family_data);
4782 IDWriteFontFileStream_Release(stream);
4783 IDWriteFontFile_Release(file);
4785 return hr;
4788 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4790 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4791 struct dwrite_fontcollection *collection;
4792 static const WCHAR emptyW[] = {0};
4793 WCHAR eudckeypathW[16];
4794 HKEY eudckey;
4795 DWORD index;
4796 BOOL exists;
4797 LONG retval;
4798 HRESULT hr;
4799 size_t i;
4801 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4803 *ret = NULL;
4805 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4806 if (!collection) return E_OUTOFMEMORY;
4808 hr = init_font_collection(collection, FALSE);
4809 if (FAILED(hr)) {
4810 heap_free(collection);
4811 return hr;
4814 *ret = &collection->IDWriteFontCollection3_iface;
4815 collection->factory = factory;
4816 IDWriteFactory7_AddRef(factory);
4818 /* return empty collection if EUDC fonts are not configured */
4819 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4820 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4821 return S_OK;
4823 retval = ERROR_SUCCESS;
4824 index = 0;
4825 while (retval != ERROR_NO_MORE_ITEMS) {
4826 WCHAR keynameW[64], pathW[MAX_PATH];
4827 DWORD type, path_len, name_len;
4829 path_len = ARRAY_SIZE(pathW);
4830 name_len = ARRAY_SIZE(keynameW);
4831 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4832 if (retval || type != REG_SZ)
4833 continue;
4835 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4836 if (hr != S_OK)
4837 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4839 RegCloseKey(eudckey);
4841 /* try to add global default if not defined for specific codepage */
4842 exists = FALSE;
4843 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4844 &index, &exists);
4845 if (FAILED(hr) || !exists) {
4846 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4847 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4848 if (hr != S_OK)
4849 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4852 /* EUDC collection offers simulated faces too */
4853 for (i = 0; i < collection->count; ++i)
4855 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4856 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4859 return S_OK;
4862 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4864 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4866 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4868 *obj = iface;
4869 IDWriteFontFile_AddRef(iface);
4870 return S_OK;
4873 WARN("%s not implemented.\n", debugstr_guid(riid));
4875 *obj = NULL;
4876 return E_NOINTERFACE;
4879 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4881 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4882 ULONG refcount = InterlockedIncrement(&file->refcount);
4884 TRACE("%p, refcount %d.\n", iface, refcount);
4886 return refcount;
4889 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4891 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4892 ULONG refcount = InterlockedDecrement(&file->refcount);
4894 TRACE("%p, refcount %d.\n", iface, refcount);
4896 if (!refcount)
4898 IDWriteFontFileLoader_Release(file->loader);
4899 if (file->stream)
4900 IDWriteFontFileStream_Release(file->stream);
4901 heap_free(file->reference_key);
4902 heap_free(file);
4905 return refcount;
4908 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
4910 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4912 TRACE("%p, %p, %p.\n", iface, key, key_size);
4914 *key = file->reference_key;
4915 *key_size = file->key_size;
4917 return S_OK;
4920 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
4922 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4924 TRACE("%p, %p.\n", iface, loader);
4926 *loader = file->loader;
4927 IDWriteFontFileLoader_AddRef(*loader);
4929 return S_OK;
4932 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4933 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4935 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4936 IDWriteFontFileStream *stream;
4937 HRESULT hr;
4939 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
4941 *is_supported = FALSE;
4942 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4943 if (face_type)
4944 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4945 *face_count = 0;
4947 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
4948 if (FAILED(hr))
4949 return hr;
4951 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4953 /* TODO: Further Analysis */
4954 IDWriteFontFileStream_Release(stream);
4955 return S_OK;
4958 static const IDWriteFontFileVtbl dwritefontfilevtbl =
4960 dwritefontfile_QueryInterface,
4961 dwritefontfile_AddRef,
4962 dwritefontfile_Release,
4963 dwritefontfile_GetReferenceKey,
4964 dwritefontfile_GetLoader,
4965 dwritefontfile_Analyze,
4968 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4969 IDWriteFontFile **ret)
4971 struct dwrite_fontfile *file;
4972 void *key;
4974 *ret = NULL;
4976 file = heap_alloc(sizeof(*file));
4977 key = heap_alloc(key_size);
4978 if (!file || !key) {
4979 heap_free(file);
4980 heap_free(key);
4981 return E_OUTOFMEMORY;
4984 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4985 file->refcount = 1;
4986 IDWriteFontFileLoader_AddRef(loader);
4987 file->loader = loader;
4988 file->stream = NULL;
4989 file->reference_key = key;
4990 memcpy(file->reference_key, reference_key, key_size);
4991 file->key_size = key_size;
4993 *ret = &file->IDWriteFontFile_iface;
4995 return S_OK;
4998 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
5000 struct file_stream_desc stream_desc;
5001 struct dwrite_font_data *font_data;
5002 struct dwrite_fontface *fontface;
5003 HRESULT hr;
5004 int i;
5006 *ret = NULL;
5008 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
5009 if (!fontface)
5010 return E_OUTOFMEMORY;
5012 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
5013 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
5014 fontface->refcount = 1;
5015 fontface->type = desc->face_type;
5016 fontface->vdmx.exists = TRUE;
5017 fontface->gasp.exists = TRUE;
5018 fontface->cpal.exists = TRUE;
5019 fontface->colr.exists = TRUE;
5020 fontface->kern.exists = TRUE;
5021 fontface->index = desc->index;
5022 fontface->simulations = desc->simulations;
5023 fontface->factory = desc->factory;
5024 IDWriteFactory7_AddRef(fontface->factory);
5025 fontface->file = desc->file;
5026 IDWriteFontFile_AddRef(fontface->file);
5027 fontface->stream = desc->stream;
5028 IDWriteFontFileStream_AddRef(fontface->stream);
5030 stream_desc.stream = fontface->stream;
5031 stream_desc.face_type = desc->face_type;
5032 stream_desc.face_index = desc->index;
5033 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
5034 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
5035 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
5036 /* TODO: test what happens if caret is already slanted */
5037 if (fontface->caret.slopeRise == 1) {
5038 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
5039 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
5042 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
5044 /* Font properties are reused from font object when 'normal' face creation path is used:
5045 collection -> family -> matching font -> fontface.
5047 If face is created directly from factory we have to go through properties resolution.
5049 if (desc->font_data)
5051 font_data = addref_font_data(desc->font_data);
5053 else
5055 hr = init_font_data(desc, &font_data);
5056 if (FAILED(hr))
5058 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5059 return hr;
5063 fontface->weight = font_data->weight;
5064 fontface->style = font_data->style;
5065 fontface->stretch = font_data->stretch;
5066 fontface->panose = font_data->panose;
5067 fontface->fontsig = font_data->fontsig;
5068 fontface->lf = font_data->lf;
5069 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5070 fontface->names = font_data->names;
5071 if (fontface->names)
5072 IDWriteLocalizedStrings_AddRef(fontface->names);
5073 fontface->family_names = font_data->family_names;
5074 if (fontface->family_names)
5075 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5076 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5077 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5079 if (fontface->info_strings[i])
5080 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5082 fontface->cmap.stream = fontface->stream;
5083 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5084 release_font_data(font_data);
5086 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5088 *ret = &fontface->IDWriteFontFace5_iface;
5090 return S_OK;
5093 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5094 struct local_refkey
5096 FILETIME writetime;
5097 WCHAR name[1];
5100 struct local_cached_stream
5102 struct list entry;
5103 IDWriteFontFileStream *stream;
5104 struct local_refkey *key;
5105 UINT32 key_size;
5108 struct dwrite_localfontfilestream
5110 IDWriteFontFileStream IDWriteFontFileStream_iface;
5111 LONG refcount;
5113 struct local_cached_stream *entry;
5114 const void *file_ptr;
5115 UINT64 size;
5118 struct dwrite_localfontfileloader
5120 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5121 LONG refcount;
5123 struct list streams;
5124 CRITICAL_SECTION cs;
5127 static struct dwrite_localfontfileloader local_fontfile_loader;
5129 struct dwrite_inmemory_stream_data
5131 LONG refcount;
5132 IUnknown *owner;
5133 void *data;
5134 UINT32 size;
5137 struct dwrite_inmemory_filestream
5139 IDWriteFontFileStream IDWriteFontFileStream_iface;
5140 LONG refcount;
5142 struct dwrite_inmemory_stream_data *data;
5145 struct dwrite_inmemory_fileloader
5147 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5148 LONG refcount;
5150 struct dwrite_inmemory_stream_data **streams;
5151 size_t size;
5152 size_t count;
5155 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5157 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5160 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5162 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5165 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5167 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5170 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5172 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5175 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5177 if (InterlockedDecrement(&stream->refcount) == 0)
5179 if (stream->owner)
5180 IUnknown_Release(stream->owner);
5181 else
5182 heap_free(stream->data);
5183 heap_free(stream);
5187 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5189 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5191 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5193 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5194 IsEqualIID(riid, &IID_IUnknown))
5196 *obj = iface;
5197 if (InterlockedIncrement(&stream->refcount) == 1)
5199 InterlockedDecrement(&stream->refcount);
5200 *obj = NULL;
5201 return E_FAIL;
5203 return S_OK;
5206 WARN("%s not implemented.\n", debugstr_guid(riid));
5208 *obj = NULL;
5209 return E_NOINTERFACE;
5212 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5214 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5215 ULONG refcount = InterlockedIncrement(&stream->refcount);
5217 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5219 return refcount;
5222 static inline void release_cached_stream(struct local_cached_stream *stream)
5224 list_remove(&stream->entry);
5225 heap_free(stream->key);
5226 heap_free(stream);
5229 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5231 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5232 ULONG refcount = InterlockedDecrement(&stream->refcount);
5234 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5236 if (!refcount)
5238 UnmapViewOfFile(stream->file_ptr);
5240 EnterCriticalSection(&local_fontfile_loader.cs);
5241 release_cached_stream(stream->entry);
5242 LeaveCriticalSection(&local_fontfile_loader.cs);
5244 heap_free(stream);
5247 return refcount;
5250 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5251 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5253 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5255 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5256 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5258 *fragment_context = NULL;
5260 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5262 *fragment_start = NULL;
5263 return E_FAIL;
5266 *fragment_start = (char *)stream->file_ptr + offset;
5267 return S_OK;
5270 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5272 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5275 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5277 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5279 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5281 *size = stream->size;
5282 return S_OK;
5285 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5287 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5288 ULARGE_INTEGER li;
5290 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5292 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5293 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5294 *last_writetime = li.QuadPart;
5296 return S_OK;
5299 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5301 localfontfilestream_QueryInterface,
5302 localfontfilestream_AddRef,
5303 localfontfilestream_Release,
5304 localfontfilestream_ReadFileFragment,
5305 localfontfilestream_ReleaseFileFragment,
5306 localfontfilestream_GetFileSize,
5307 localfontfilestream_GetLastWriteTime
5310 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5311 IDWriteFontFileStream **ret)
5313 struct dwrite_localfontfilestream *object;
5315 *ret = NULL;
5317 if (!(object = heap_alloc(sizeof(*object))))
5318 return E_OUTOFMEMORY;
5320 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5321 object->refcount = 1;
5323 object->file_ptr = file_ptr;
5324 object->size = size;
5325 object->entry = entry;
5327 *ret = &object->IDWriteFontFileStream_iface;
5329 return S_OK;
5332 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5334 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5336 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5337 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5338 IsEqualIID(riid, &IID_IUnknown))
5340 *obj = iface;
5341 IDWriteLocalFontFileLoader_AddRef(iface);
5342 return S_OK;
5345 WARN("%s not implemented.\n", debugstr_guid(riid));
5347 *obj = NULL;
5348 return E_NOINTERFACE;
5351 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5353 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5354 ULONG refcount = InterlockedIncrement(&loader->refcount);
5356 TRACE("%p, refcount %d.\n", iface, refcount);
5358 return refcount;
5361 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5363 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5364 ULONG refcount = InterlockedDecrement(&loader->refcount);
5366 TRACE("%p, refcount %d.\n", iface, refcount);
5368 return refcount;
5371 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5373 const struct local_refkey *refkey = key;
5374 struct local_cached_stream *stream;
5375 IDWriteFontFileStream *filestream;
5376 HANDLE file, mapping;
5377 LARGE_INTEGER size;
5378 void *file_ptr;
5379 HRESULT hr = S_OK;
5381 *ret = NULL;
5383 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5384 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5385 if (file == INVALID_HANDLE_VALUE) {
5386 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5387 return E_FAIL;
5390 GetFileSizeEx(file, &size);
5391 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5392 CloseHandle(file);
5393 if (!mapping)
5394 return E_FAIL;
5396 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5397 CloseHandle(mapping);
5398 if (!file_ptr) {
5399 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5400 return E_FAIL;
5403 stream = heap_alloc(sizeof(*stream));
5404 if (!stream) {
5405 UnmapViewOfFile(file_ptr);
5406 return E_OUTOFMEMORY;
5409 stream->key = heap_alloc(key_size);
5410 if (!stream->key) {
5411 UnmapViewOfFile(file_ptr);
5412 heap_free(stream);
5413 return E_OUTOFMEMORY;
5416 stream->key_size = key_size;
5417 memcpy(stream->key, key, key_size);
5419 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5420 if (FAILED(hr)) {
5421 UnmapViewOfFile(file_ptr);
5422 heap_free(stream->key);
5423 heap_free(stream);
5424 return hr;
5427 stream->stream = filestream;
5429 *ret = stream;
5431 return S_OK;
5434 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5435 UINT32 key_size, IDWriteFontFileStream **ret)
5437 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5438 struct local_cached_stream *stream;
5439 HRESULT hr = S_OK;
5441 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5443 EnterCriticalSection(&loader->cs);
5445 *ret = NULL;
5447 /* search cache first */
5448 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5450 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5451 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5452 break;
5456 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5458 list_add_head(&loader->streams, &stream->entry);
5459 *ret = stream->stream;
5462 LeaveCriticalSection(&loader->cs);
5464 return hr;
5467 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5468 UINT32 key_size, UINT32 *length)
5470 const struct local_refkey *refkey = key;
5472 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5474 *length = strlenW(refkey->name);
5475 return S_OK;
5478 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5479 UINT32 key_size, WCHAR *path, UINT32 length)
5481 const struct local_refkey *refkey = key;
5483 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5485 if (length < strlenW(refkey->name))
5486 return E_INVALIDARG;
5488 strcpyW(path, refkey->name);
5489 return S_OK;
5492 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5493 UINT32 key_size, FILETIME *writetime)
5495 const struct local_refkey *refkey = key;
5497 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5499 *writetime = refkey->writetime;
5500 return S_OK;
5503 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5505 localfontfileloader_QueryInterface,
5506 localfontfileloader_AddRef,
5507 localfontfileloader_Release,
5508 localfontfileloader_CreateStreamFromKey,
5509 localfontfileloader_GetFilePathLengthFromKey,
5510 localfontfileloader_GetFilePathFromKey,
5511 localfontfileloader_GetLastWriteTimeFromKey
5514 void init_local_fontfile_loader(void)
5516 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5517 local_fontfile_loader.refcount = 1;
5518 list_init(&local_fontfile_loader.streams);
5519 InitializeCriticalSection(&local_fontfile_loader.cs);
5520 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5523 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5525 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5528 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5530 struct local_refkey *refkey;
5532 if (!path)
5533 return E_INVALIDARG;
5535 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5536 *key = NULL;
5538 refkey = heap_alloc(*size);
5539 if (!refkey)
5540 return E_OUTOFMEMORY;
5542 if (writetime)
5543 refkey->writetime = *writetime;
5544 else {
5545 WIN32_FILE_ATTRIBUTE_DATA info;
5547 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5548 refkey->writetime = info.ftLastWriteTime;
5549 else
5550 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5552 strcpyW(refkey->name, path);
5554 *key = refkey;
5556 return S_OK;
5559 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5561 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5563 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5564 IsEqualIID(riid, &IID_IUnknown))
5566 *ppv = iface;
5567 IDWriteGlyphRunAnalysis_AddRef(iface);
5568 return S_OK;
5571 WARN("%s not implemented.\n", debugstr_guid(riid));
5573 *ppv = NULL;
5574 return E_NOINTERFACE;
5577 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5579 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5580 ULONG refcount = InterlockedIncrement(&analysis->refcount);
5582 TRACE("%p, refcount %d.\n", iface, refcount);
5584 return refcount;
5587 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5589 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5590 ULONG refcount = InterlockedDecrement(&analysis->refcount);
5592 TRACE("%p, refcount %d.\n", iface, refcount);
5594 if (!refcount)
5596 if (analysis->run.fontFace)
5597 IDWriteFontFace_Release(analysis->run.fontFace);
5598 heap_free(analysis->glyphs);
5599 heap_free(analysis->origins);
5600 heap_free(analysis->bitmap);
5601 heap_free(analysis);
5604 return refcount;
5607 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5609 switch (mode)
5611 case DWRITE_RENDERING_MODE1_NATURAL:
5612 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5613 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5614 return TRUE;
5615 default:
5616 return FALSE;
5620 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5622 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5625 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5627 struct dwrite_glyphbitmap glyph_bitmap;
5628 IDWriteFontFace4 *fontface;
5629 HRESULT hr;
5630 UINT32 i;
5632 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5633 *bounds = analysis->bounds;
5634 return;
5637 if (analysis->run.isSideways)
5638 FIXME("sideways runs are not supported.\n");
5640 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5641 if (FAILED(hr))
5642 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5644 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5645 glyph_bitmap.fontface = fontface;
5646 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5647 glyph_bitmap.emsize = analysis->run.fontEmSize;
5648 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5649 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5650 glyph_bitmap.m = &analysis->m;
5652 for (i = 0; i < analysis->run.glyphCount; i++) {
5653 RECT *bbox = &glyph_bitmap.bbox;
5654 UINT32 bitmap_size;
5656 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5657 freetype_get_glyph_bbox(&glyph_bitmap);
5659 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5660 (bbox->bottom - bbox->top);
5661 if (bitmap_size > analysis->max_glyph_bitmap_size)
5662 analysis->max_glyph_bitmap_size = bitmap_size;
5664 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5665 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5668 IDWriteFontFace4_Release(fontface);
5670 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5671 *bounds = analysis->bounds;
5674 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
5675 DWRITE_TEXTURE_TYPE type, RECT *bounds)
5677 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5679 TRACE("%p, %d, %p.\n", iface, type, bounds);
5681 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5682 SetRectEmpty(bounds);
5683 return E_INVALIDARG;
5686 if (type != analysis->texture_type)
5688 SetRectEmpty(bounds);
5689 return S_OK;
5692 glyphrunanalysis_get_texturebounds(analysis, bounds);
5693 return S_OK;
5696 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5698 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5699 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5700 (runbounds->left - bounds->left) * 3;
5701 else
5702 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5703 runbounds->left - bounds->left;
5706 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5708 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5709 struct dwrite_glyphbitmap glyph_bitmap;
5710 IDWriteFontFace4 *fontface;
5711 D2D_POINT_2F origin;
5712 UINT32 i, size;
5713 HRESULT hr;
5714 RECT *bbox;
5716 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5717 if (FAILED(hr)) {
5718 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5719 return hr;
5722 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5723 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5724 size *= 3;
5725 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5726 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5727 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5728 IDWriteFontFace4_Release(fontface);
5729 return E_OUTOFMEMORY;
5732 origin.x = origin.y = 0.0f;
5734 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5735 glyph_bitmap.fontface = fontface;
5736 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5737 glyph_bitmap.emsize = analysis->run.fontEmSize;
5738 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5739 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5740 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5741 glyph_bitmap.m = &analysis->m;
5742 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5743 IDWriteFontFace4_Release(fontface);
5744 return E_OUTOFMEMORY;
5747 bbox = &glyph_bitmap.bbox;
5749 for (i = 0; i < analysis->run.glyphCount; i++) {
5750 BYTE *src = glyph_bitmap.buf, *dst;
5751 int x, y, width, height;
5752 BOOL is_1bpp;
5754 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5755 freetype_get_glyph_bbox(&glyph_bitmap);
5757 if (IsRectEmpty(bbox))
5758 continue;
5760 width = bbox->right - bbox->left;
5761 height = bbox->bottom - bbox->top;
5763 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5764 memset(src, 0, height * glyph_bitmap.pitch);
5765 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5767 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5769 /* blit to analysis bitmap */
5770 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5772 if (is_1bpp) {
5773 /* convert 1bpp to 8bpp/24bpp */
5774 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5775 for (y = 0; y < height; y++) {
5776 for (x = 0; x < width; x++)
5777 if (src[x / 8] & masks[x % 8])
5778 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5779 src += glyph_bitmap.pitch;
5780 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5783 else {
5784 for (y = 0; y < height; y++) {
5785 for (x = 0; x < width; x++)
5786 if (src[x / 8] & masks[x % 8])
5787 dst[x] = DWRITE_ALPHA_MAX;
5788 src += glyph_bitmap.pitch;
5789 dst += analysis->bounds.right - analysis->bounds.left;
5793 else {
5794 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5795 for (y = 0; y < height; y++) {
5796 for (x = 0; x < width; x++)
5797 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5798 src += glyph_bitmap.pitch;
5799 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5802 else {
5803 for (y = 0; y < height; y++) {
5804 for (x = 0; x < width; x++)
5805 dst[x] |= src[x];
5806 src += glyph_bitmap.pitch;
5807 dst += analysis->bounds.right - analysis->bounds.left;
5812 heap_free(glyph_bitmap.buf);
5814 IDWriteFontFace4_Release(fontface);
5816 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5818 /* we don't need this anymore */
5819 heap_free(analysis->glyphs);
5820 heap_free(analysis->origins);
5821 IDWriteFontFace_Release(analysis->run.fontFace);
5823 analysis->glyphs = NULL;
5824 analysis->origins = NULL;
5825 analysis->run.glyphIndices = NULL;
5826 analysis->run.fontFace = NULL;
5828 return S_OK;
5831 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5832 RECT const *bounds, BYTE *bitmap, UINT32 size)
5834 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5835 UINT32 required;
5836 RECT runbounds;
5838 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
5840 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5841 return E_INVALIDARG;
5843 /* make sure buffer is large enough for requested texture type */
5844 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5845 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5846 required *= 3;
5848 if (size < required)
5849 return E_NOT_SUFFICIENT_BUFFER;
5851 /* validate requested texture type */
5852 if (analysis->texture_type != type)
5853 return DWRITE_E_UNSUPPORTEDOPERATION;
5855 memset(bitmap, 0, size);
5856 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
5857 if (IntersectRect(&runbounds, &runbounds, bounds))
5859 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5860 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
5861 int dst_width = (bounds->right - bounds->left) * pixel_size;
5862 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5863 BYTE *src, *dst;
5864 int y;
5866 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
5868 HRESULT hr;
5870 if (FAILED(hr = glyphrunanalysis_render(analysis)))
5871 return hr;
5874 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
5875 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5877 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5878 memcpy(dst, src, draw_width);
5879 src += src_width;
5880 dst += dst_width;
5884 return S_OK;
5887 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5888 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5890 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5892 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
5894 if (!params)
5895 return E_INVALIDARG;
5897 switch (analysis->rendering_mode)
5899 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5900 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5902 UINT value = 0;
5903 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5904 *gamma = (FLOAT)value / 1000.0f;
5905 *contrast = 0.0f;
5906 *cleartypelevel = 1.0f;
5907 break;
5909 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5910 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5911 /* fallthrough */
5912 case DWRITE_RENDERING_MODE1_ALIASED:
5913 case DWRITE_RENDERING_MODE1_NATURAL:
5914 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5915 *gamma = IDWriteRenderingParams_GetGamma(params);
5916 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5917 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5918 break;
5919 default:
5923 return S_OK;
5926 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
5928 glyphrunanalysis_QueryInterface,
5929 glyphrunanalysis_AddRef,
5930 glyphrunanalysis_Release,
5931 glyphrunanalysis_GetAlphaTextureBounds,
5932 glyphrunanalysis_CreateAlphaTexture,
5933 glyphrunanalysis_GetAlphaBlendParams
5936 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5938 D2D_POINT_2F ret;
5939 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5940 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5941 *point = ret;
5944 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5945 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5947 unsigned int upem = fontface->metrics.designUnitsPerEm;
5948 int advance;
5950 if (is_sideways)
5951 FIXME("Sideways mode is not supported.\n");
5953 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5955 switch (measuring_mode)
5957 case DWRITE_MEASURING_MODE_NATURAL:
5958 return (float)advance * emsize / (float)upem;
5959 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5960 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5961 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5962 default:
5963 WARN("Unknown measuring mode %u.\n", measuring_mode);
5964 return 0.0f;
5968 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5970 struct dwrite_glyphrunanalysis *analysis;
5971 unsigned int i;
5973 *ret = NULL;
5975 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5976 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5977 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5978 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5979 return E_INVALIDARG;
5981 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5982 return E_INVALIDARG;
5984 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5985 return E_INVALIDARG;
5987 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5988 return E_INVALIDARG;
5990 analysis = heap_alloc_zero(sizeof(*analysis));
5991 if (!analysis)
5992 return E_OUTOFMEMORY;
5994 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5995 analysis->refcount = 1;
5996 analysis->rendering_mode = desc->rendering_mode;
5998 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5999 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
6000 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
6001 else
6002 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
6004 analysis->run = *desc->run;
6005 IDWriteFontFace_AddRef(analysis->run.fontFace);
6006 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
6007 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
6009 if (!analysis->glyphs || !analysis->origins) {
6010 heap_free(analysis->glyphs);
6011 heap_free(analysis->origins);
6013 analysis->glyphs = NULL;
6014 analysis->origins = NULL;
6016 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
6017 return E_OUTOFMEMORY;
6020 /* check if transform is usable */
6021 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
6022 analysis->m = *desc->transform;
6023 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
6026 analysis->run.glyphIndices = analysis->glyphs;
6027 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
6029 compute_glyph_origins(desc->run, desc->measuring_mode, desc->origin, desc->transform, analysis->origins);
6030 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6032 for (i = 0; i < desc->run->glyphCount; ++i)
6033 transform_point(&analysis->origins[i], &analysis->m);
6036 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6037 return S_OK;
6040 /* IDWriteColorGlyphRunEnumerator1 */
6041 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6043 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6045 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6046 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6047 IsEqualIID(riid, &IID_IUnknown))
6049 *ppv = iface;
6050 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6051 return S_OK;
6054 WARN("%s not implemented.\n", debugstr_guid(riid));
6056 *ppv = NULL;
6057 return E_NOINTERFACE;
6060 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6062 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6063 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6065 TRACE("%p, refcount %u.\n", iface, refcount);
6067 return refcount;
6070 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6072 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6073 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6075 TRACE("%p, refcount %u.\n", iface, refcount);
6077 if (!refcount)
6079 heap_free(glyphenum->advances);
6080 heap_free(glyphenum->color_advances);
6081 heap_free(glyphenum->offsets);
6082 heap_free(glyphenum->color_offsets);
6083 heap_free(glyphenum->glyphindices);
6084 heap_free(glyphenum->glyphs);
6085 if (glyphenum->colr.context)
6086 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6087 IDWriteFontFace5_Release(glyphenum->fontface);
6088 heap_free(glyphenum);
6091 return refcount;
6094 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6096 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6097 FLOAT origin = 0.0f;
6099 if (g == 0)
6100 return 0.0f;
6102 while (g--)
6103 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6104 return origin;
6107 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6109 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6110 FLOAT advance_adj = 0.0f;
6111 BOOL got_palette_index;
6112 UINT32 g;
6114 /* start with regular glyphs */
6115 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6116 UINT32 first_glyph = 0;
6118 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6119 if (glyphenum->glyphs[g].num_layers == 0) {
6120 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6121 first_glyph = min(first_glyph, g);
6123 else
6124 glyphenum->glyphindices[g] = 1;
6125 glyphenum->color_advances[g] = glyphenum->advances[g];
6126 if (glyphenum->color_offsets)
6127 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6130 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6131 colorrun->baselineOriginY = glyphenum->origin_y;
6132 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6133 colorrun->paletteIndex = 0xffff;
6134 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6135 glyphenum->has_regular_glyphs = FALSE;
6136 return TRUE;
6138 else {
6139 colorrun->glyphRun.glyphCount = 0;
6140 got_palette_index = FALSE;
6143 advance_adj = 0.0f;
6144 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6146 glyphenum->glyphindices[g] = 1;
6148 /* all glyph layers were returned */
6149 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6150 advance_adj += glyphenum->advances[g];
6151 continue;
6154 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6155 UINT32 index = colorrun->glyphRun.glyphCount;
6156 if (!got_palette_index) {
6157 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6158 /* use foreground color or request one from the font */
6159 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6160 if (colorrun->paletteIndex != 0xffff)
6162 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6163 colorrun->paletteIndex, 1, &colorrun->runColor);
6164 if (FAILED(hr))
6165 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6166 glyphenum->palette, colorrun->paletteIndex, hr);
6168 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6169 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6170 colorrun->baselineOriginY = glyphenum->origin_y;
6171 glyphenum->color_advances[index] = glyphenum->advances[g];
6172 got_palette_index = TRUE;
6175 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6176 /* offsets are relative to glyph origin, nothing to fix up */
6177 if (glyphenum->color_offsets)
6178 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6179 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6180 if (index)
6181 glyphenum->color_advances[index-1] += advance_adj;
6182 colorrun->glyphRun.glyphCount++;
6183 advance_adj = 0.0f;
6185 else
6186 advance_adj += glyphenum->advances[g];
6189 /* reset last advance */
6190 if (colorrun->glyphRun.glyphCount)
6191 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6193 return colorrun->glyphRun.glyphCount > 0;
6196 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6198 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6200 TRACE("%p, %p.\n", iface, has_run);
6202 *has_run = FALSE;
6204 glyphenum->colorrun.glyphRun.glyphCount = 0;
6205 while (glyphenum->current_layer < glyphenum->max_layer_num)
6207 if (colorglyphenum_build_color_run(glyphenum))
6208 break;
6209 else
6210 glyphenum->current_layer++;
6213 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6215 return S_OK;
6218 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6219 DWRITE_COLOR_GLYPH_RUN1 const **run)
6221 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6223 *run = NULL;
6224 return E_NOT_VALID_STATE;
6227 *run = &glyphenum->colorrun;
6228 return S_OK;
6231 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6232 DWRITE_COLOR_GLYPH_RUN const **run)
6234 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6236 TRACE("%p, %p.\n", iface, run);
6238 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6241 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6242 DWRITE_COLOR_GLYPH_RUN1 const **run)
6244 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6246 TRACE("%p, %p.\n", iface, run);
6248 return colorglyphenum_get_current_run(glyphenum, run);
6251 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6253 colorglyphenum_QueryInterface,
6254 colorglyphenum_AddRef,
6255 colorglyphenum_Release,
6256 colorglyphenum_MoveNext,
6257 colorglyphenum_GetCurrentRun,
6258 colorglyphenum1_GetCurrentRun,
6261 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6262 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6263 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6265 struct dwrite_colorglyphenum *colorglyphenum;
6266 BOOL colorfont, has_colored_glyph;
6267 struct dwrite_fontface *fontface;
6268 unsigned int i;
6270 *ret = NULL;
6272 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6274 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6275 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6276 if (!colorfont)
6277 return DWRITE_E_NOCOLOR;
6279 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6280 if (!colorglyphenum)
6281 return E_OUTOFMEMORY;
6283 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6284 colorglyphenum->refcount = 1;
6285 colorglyphenum->origin_x = originX;
6286 colorglyphenum->origin_y = originY;
6287 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6288 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6289 colorglyphenum->glyphs = NULL;
6290 colorglyphenum->run = *run;
6291 colorglyphenum->run.glyphIndices = NULL;
6292 colorglyphenum->run.glyphAdvances = NULL;
6293 colorglyphenum->run.glyphOffsets = NULL;
6294 colorglyphenum->palette = palette;
6295 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6296 colorglyphenum->colr.exists = TRUE;
6297 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6298 colorglyphenum->current_layer = 0;
6299 colorglyphenum->max_layer_num = 0;
6301 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6303 has_colored_glyph = FALSE;
6304 colorglyphenum->has_regular_glyphs = FALSE;
6305 for (i = 0; i < run->glyphCount; i++) {
6306 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6307 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6308 has_colored_glyph = TRUE;
6310 if (colorglyphenum->glyphs[i].num_layers == 0)
6311 colorglyphenum->has_regular_glyphs = TRUE;
6314 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6315 is supposed to proceed normally, like if font had no color info at all. */
6316 if (!has_colored_glyph) {
6317 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6318 return DWRITE_E_NOCOLOR;
6321 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6322 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6323 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6324 if (run->glyphOffsets) {
6325 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6326 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6327 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6330 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6331 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6332 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6333 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6334 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6335 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6336 colorglyphenum->colorrun.measuringMode = measuring_mode;
6337 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6339 if (run->glyphAdvances)
6340 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6341 else
6343 for (i = 0; i < run->glyphCount; ++i)
6344 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6345 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6348 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6350 return S_OK;
6353 /* IDWriteFontFaceReference */
6354 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6356 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6358 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6359 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6360 IsEqualIID(riid, &IID_IUnknown))
6362 *obj = iface;
6363 IDWriteFontFaceReference1_AddRef(iface);
6364 return S_OK;
6367 WARN("%s not implemented.\n", debugstr_guid(riid));
6369 *obj = NULL;
6371 return E_NOINTERFACE;
6374 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6376 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6377 ULONG refcount = InterlockedIncrement(&reference->refcount);
6379 TRACE("%p, refcount %u.\n", iface, refcount);
6381 return refcount;
6384 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6386 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6387 ULONG refcount = InterlockedDecrement(&reference->refcount);
6389 TRACE("%p, refcount %u.\n", iface, refcount);
6391 if (!refcount)
6393 IDWriteFontFile_Release(reference->file);
6394 IDWriteFactory7_Release(reference->factory);
6395 heap_free(reference->axis_values);
6396 heap_free(reference);
6399 return refcount;
6402 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6404 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6406 TRACE("%p, %p.\n", iface, fontface);
6408 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6411 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6412 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6414 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6415 DWRITE_FONT_FILE_TYPE file_type;
6416 DWRITE_FONT_FACE_TYPE face_type;
6417 IDWriteFontFace *fontface;
6418 BOOL is_supported;
6419 UINT32 face_num;
6420 HRESULT hr;
6422 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6424 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6425 if (FAILED(hr))
6426 return hr;
6428 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6429 simulations, &fontface);
6430 if (SUCCEEDED(hr))
6432 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6433 IDWriteFontFace_Release(fontface);
6436 return hr;
6439 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6441 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6442 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6443 BOOL ret;
6445 TRACE("%p, %p.\n", iface, ref);
6447 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6448 reference->simulations == other->simulations;
6449 if (reference->axis_values_count)
6451 ret &= reference->axis_values_count == other->axis_values_count &&
6452 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6455 return ret;
6458 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6460 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6462 TRACE("%p.\n", iface);
6464 return reference->index;
6467 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6469 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6471 TRACE("%p.\n", iface);
6473 return reference->simulations;
6476 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6478 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6479 IDWriteFontFileLoader *loader;
6480 const void *key;
6481 UINT32 key_size;
6482 HRESULT hr;
6484 TRACE("%p, %p.\n", iface, file);
6486 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6487 if (FAILED(hr))
6488 return hr;
6490 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6491 if (FAILED(hr))
6492 return hr;
6494 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6495 IDWriteFontFileLoader_Release(loader);
6497 return hr;
6500 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6502 FIXME("%p.\n", iface);
6504 return 0;
6507 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6509 FIXME("%p.\n", iface);
6511 return 0;
6514 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6516 FIXME("%p, %p.\n", iface, writetime);
6518 return E_NOTIMPL;
6521 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6523 FIXME("%p.\n", iface);
6525 return DWRITE_LOCALITY_LOCAL;
6528 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6530 FIXME("%p.\n", iface);
6532 return E_NOTIMPL;
6535 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6536 WCHAR const *chars, UINT32 count)
6538 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6540 return E_NOTIMPL;
6543 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6544 UINT16 const *glyphs, UINT32 count)
6546 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6548 return E_NOTIMPL;
6551 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6552 UINT64 offset, UINT64 size)
6554 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6556 return E_NOTIMPL;
6559 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6561 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6562 IDWriteFontFace3 *fontface3;
6563 HRESULT hr;
6565 TRACE("%p, %p.\n", iface, fontface);
6567 /* FIXME: created instance should likely respect given axis. */
6568 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6569 &fontface3)))
6571 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6572 IDWriteFontFace3_Release(fontface3);
6575 return hr;
6578 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6580 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6582 TRACE("%p.\n", iface);
6584 return reference->axis_values_count;
6587 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6588 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6590 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6592 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6594 if (value_count < reference->axis_values_count)
6595 return E_NOT_SUFFICIENT_BUFFER;
6597 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6599 return S_OK;
6602 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6604 fontfacereference_QueryInterface,
6605 fontfacereference_AddRef,
6606 fontfacereference_Release,
6607 fontfacereference_CreateFontFace,
6608 fontfacereference_CreateFontFaceWithSimulations,
6609 fontfacereference_Equals,
6610 fontfacereference_GetFontFaceIndex,
6611 fontfacereference_GetSimulations,
6612 fontfacereference_GetFontFile,
6613 fontfacereference_GetLocalFileSize,
6614 fontfacereference_GetFileSize,
6615 fontfacereference_GetFileTime,
6616 fontfacereference_GetLocality,
6617 fontfacereference_EnqueueFontDownloadRequest,
6618 fontfacereference_EnqueueCharacterDownloadRequest,
6619 fontfacereference_EnqueueGlyphDownloadRequest,
6620 fontfacereference_EnqueueFileFragmentDownloadRequest,
6621 fontfacereference1_CreateFontFace,
6622 fontfacereference1_GetFontAxisValueCount,
6623 fontfacereference1_GetFontAxisValues,
6626 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6627 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6628 IDWriteFontFaceReference1 **ret)
6630 struct dwrite_fontfacereference *object;
6632 *ret = NULL;
6634 if (!is_simulation_valid(simulations))
6635 return E_INVALIDARG;
6637 object = heap_alloc_zero(sizeof(*object));
6638 if (!object)
6639 return E_OUTOFMEMORY;
6641 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6642 object->refcount = 1;
6644 object->factory = factory;
6645 IDWriteFactory7_AddRef(object->factory);
6646 object->file = file;
6647 IDWriteFontFile_AddRef(object->file);
6648 object->index = index;
6649 object->simulations = simulations;
6650 if (axis_values_count)
6652 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6654 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6655 return E_OUTOFMEMORY;
6657 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6658 object->axis_values_count = axis_values_count;
6661 *ret = &object->IDWriteFontFaceReference1_iface;
6663 return S_OK;
6666 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6668 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6670 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6671 *obj = iface;
6672 IDWriteFontFileStream_AddRef(iface);
6673 return S_OK;
6676 *obj = NULL;
6678 WARN("%s not implemented.\n", debugstr_guid(riid));
6679 return E_NOINTERFACE;
6682 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6684 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6685 ULONG refcount = InterlockedIncrement(&stream->refcount);
6687 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6689 return refcount;
6692 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6694 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6695 ULONG refcount = InterlockedDecrement(&stream->refcount);
6697 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6699 if (!refcount)
6701 release_inmemory_stream(stream->data);
6702 heap_free(stream);
6705 return refcount;
6708 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6709 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6711 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6713 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
6714 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6716 *fragment_context = NULL;
6718 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6719 *fragment_start = NULL;
6720 return E_FAIL;
6723 *fragment_start = (char *)stream->data->data + offset;
6724 return S_OK;
6727 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6729 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
6732 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6734 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6736 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
6738 *size = stream->data->size;
6740 return S_OK;
6743 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6745 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
6747 *last_writetime = 0;
6749 return E_NOTIMPL;
6752 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6753 inmemoryfilestream_QueryInterface,
6754 inmemoryfilestream_AddRef,
6755 inmemoryfilestream_Release,
6756 inmemoryfilestream_ReadFileFragment,
6757 inmemoryfilestream_ReleaseFileFragment,
6758 inmemoryfilestream_GetFileSize,
6759 inmemoryfilestream_GetLastWriteTime,
6762 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6763 REFIID riid, void **obj)
6765 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6767 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6768 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6769 IsEqualIID(riid, &IID_IUnknown))
6771 *obj = iface;
6772 IDWriteInMemoryFontFileLoader_AddRef(iface);
6773 return S_OK;
6776 WARN("%s not implemented.\n", debugstr_guid(riid));
6778 *obj = NULL;
6780 return E_NOINTERFACE;
6783 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6785 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6786 ULONG refcount = InterlockedIncrement(&loader->refcount);
6788 TRACE("%p, refcount %u.\n", iface, refcount);
6790 return refcount;
6793 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6795 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6796 ULONG refcount = InterlockedDecrement(&loader->refcount);
6797 size_t i;
6799 TRACE("%p, refcount %u.\n", iface, refcount);
6801 if (!refcount)
6803 for (i = 0; i < loader->count; ++i)
6804 release_inmemory_stream(loader->streams[i]);
6805 heap_free(loader->streams);
6806 heap_free(loader);
6809 return refcount;
6812 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6813 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6815 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6816 struct dwrite_inmemory_filestream *stream;
6817 DWORD index;
6819 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
6821 *ret = NULL;
6823 if (key_size != sizeof(DWORD))
6824 return E_INVALIDARG;
6826 index = *(DWORD *)key;
6828 if (index >= loader->count)
6829 return E_INVALIDARG;
6831 if (!(stream = heap_alloc(sizeof(*stream))))
6832 return E_OUTOFMEMORY;
6834 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6835 stream->refcount = 1;
6836 stream->data = loader->streams[index];
6837 InterlockedIncrement(&stream->data->refcount);
6839 *ret = &stream->IDWriteFontFileStream_iface;
6841 return S_OK;
6844 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6845 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6847 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6848 struct dwrite_inmemory_stream_data *stream;
6849 DWORD key;
6851 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
6853 *fontfile = NULL;
6855 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6856 return E_OUTOFMEMORY;
6858 if (!(stream = heap_alloc(sizeof(*stream))))
6859 return E_OUTOFMEMORY;
6861 stream->refcount = 1;
6862 stream->size = data_size;
6863 stream->owner = owner;
6864 if (stream->owner) {
6865 IUnknown_AddRef(stream->owner);
6866 stream->data = (void *)data;
6868 else {
6869 if (!(stream->data = heap_alloc(data_size))) {
6870 heap_free(stream);
6871 return E_OUTOFMEMORY;
6873 memcpy(stream->data, data, data_size);
6876 key = loader->count;
6877 loader->streams[loader->count++] = stream;
6879 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6880 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6883 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6885 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6887 TRACE("%p.\n", iface);
6889 return loader->count;
6892 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6894 inmemoryfontfileloader_QueryInterface,
6895 inmemoryfontfileloader_AddRef,
6896 inmemoryfontfileloader_Release,
6897 inmemoryfontfileloader_CreateStreamFromKey,
6898 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6899 inmemoryfontfileloader_GetFileCount,
6902 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6904 struct dwrite_inmemory_fileloader *loader;
6906 *ret = NULL;
6908 loader = heap_alloc_zero(sizeof(*loader));
6909 if (!loader)
6910 return E_OUTOFMEMORY;
6912 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6913 loader->refcount = 1;
6915 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6917 return S_OK;
6920 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6922 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6924 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6925 IsEqualIID(riid, &IID_IUnknown))
6927 *obj = iface;
6928 IDWriteFontResource_AddRef(iface);
6929 return S_OK;
6932 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6934 return E_NOINTERFACE;
6937 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6939 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6940 ULONG refcount = InterlockedIncrement(&resource->refcount);
6942 TRACE("%p, refcount %u.\n", iface, refcount);
6944 return refcount;
6947 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6949 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6950 ULONG refcount = InterlockedDecrement(&resource->refcount);
6952 TRACE("%p, refcount %u.\n", iface, refcount);
6954 if (!refcount)
6956 IDWriteFactory7_Release(resource->factory);
6957 IDWriteFontFile_Release(resource->file);
6958 heap_free(resource);
6961 return refcount;
6964 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6966 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6968 TRACE("%p, %p.\n", iface, fontfile);
6970 *fontfile = resource->file;
6971 IDWriteFontFile_AddRef(*fontfile);
6973 return S_OK;
6976 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6978 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6980 TRACE("%p.\n", iface);
6982 return resource->face_index;
6985 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6987 FIXME("%p.\n", iface);
6989 return 0;
6992 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6993 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6995 FIXME("%p, %p, %u.\n", iface, values, num_values);
6997 return E_NOTIMPL;
7000 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
7001 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
7003 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
7005 return E_NOTIMPL;
7008 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7009 UINT32 axis)
7011 FIXME("%p, %u.\n", iface, axis);
7013 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
7016 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7017 IDWriteLocalizedStrings **names)
7019 FIXME("%p, %u, %p.\n", iface, axis, names);
7021 return E_NOTIMPL;
7024 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7026 FIXME("%p, %u.\n", iface, axis);
7028 return 0;
7031 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7032 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7034 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7036 return E_NOTIMPL;
7039 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7041 FIXME("%p.\n", iface);
7043 return FALSE;
7046 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7047 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7048 IDWriteFontFace5 **fontface)
7050 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7051 IDWriteFontFaceReference1 *reference;
7052 HRESULT hr;
7054 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7056 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7057 simulations, axis_values, num_values, &reference);
7058 if (SUCCEEDED(hr))
7060 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7061 IDWriteFontFaceReference1_Release(reference);
7064 return hr;
7067 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7068 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7069 IDWriteFontFaceReference1 **reference)
7071 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7073 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7075 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7076 simulations, axis_values, num_values, reference);
7079 static const IDWriteFontResourceVtbl fontresourcevtbl =
7081 dwritefontresource_QueryInterface,
7082 dwritefontresource_AddRef,
7083 dwritefontresource_Release,
7084 dwritefontresource_GetFontFile,
7085 dwritefontresource_GetFontFaceIndex,
7086 dwritefontresource_GetFontAxisCount,
7087 dwritefontresource_GetDefaultFontAxisValues,
7088 dwritefontresource_GetFontAxisRanges,
7089 dwritefontresource_GetFontAxisAttributes,
7090 dwritefontresource_GetAxisNames,
7091 dwritefontresource_GetAxisValueNameCount,
7092 dwritefontresource_GetAxisValueNames,
7093 dwritefontresource_HasVariations,
7094 dwritefontresource_CreateFontFace,
7095 dwritefontresource_CreateFontFaceReference,
7098 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7099 IDWriteFontResource **ret)
7101 struct dwrite_fontresource *resource;
7103 *ret = NULL;
7105 resource = heap_alloc_zero(sizeof(*resource));
7106 if (!resource)
7107 return E_OUTOFMEMORY;
7109 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7110 resource->refcount = 1;
7111 resource->face_index = face_index;
7112 resource->file = file;
7113 IDWriteFontFile_AddRef(resource->file);
7114 resource->factory = factory;
7115 IDWriteFactory7_AddRef(resource->factory);
7117 *ret = &resource->IDWriteFontResource_iface;
7119 return S_OK;
7122 static HRESULT WINAPI dwritefontset_QueryInterface(IDWriteFontSet3 *iface, REFIID riid, void **obj)
7124 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7126 if (IsEqualIID(riid, &IID_IDWriteFontSet3) ||
7127 IsEqualIID(riid, &IID_IDWriteFontSet2) ||
7128 IsEqualIID(riid, &IID_IDWriteFontSet1) ||
7129 IsEqualIID(riid, &IID_IDWriteFontSet))
7131 *obj = iface;
7132 IDWriteFontSet3_AddRef(iface);
7133 return S_OK;
7136 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7137 *obj = NULL;
7138 return E_NOINTERFACE;
7141 static ULONG WINAPI dwritefontset_AddRef(IDWriteFontSet3 *iface)
7143 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7144 ULONG refcount = InterlockedIncrement(&set->refcount);
7146 TRACE("%p, refcount %u.\n", iface, refcount);
7148 return refcount;
7151 #define MISSING_SET_PROP ((void *)0x1)
7153 static void release_fontset_entry(struct dwrite_fontset_entry *entry)
7155 unsigned int i;
7157 if (InterlockedDecrement(&entry->refcount) > 0)
7158 return;
7159 IDWriteFontFile_Release(entry->file);
7160 for (i = 0; i < ARRAY_SIZE(entry->props); ++i)
7162 if (entry->props[i] && entry->props[i] != MISSING_SET_PROP)
7163 IDWriteLocalizedStrings_Release(entry->props[i]);
7165 heap_free(entry);
7168 static struct dwrite_fontset_entry * addref_fontset_entry(struct dwrite_fontset_entry *entry)
7170 InterlockedIncrement(&entry->refcount);
7171 return entry;
7174 static IDWriteLocalizedStrings * fontset_entry_get_property(struct dwrite_fontset_entry *entry,
7175 DWRITE_FONT_PROPERTY_ID property)
7177 struct file_stream_desc stream_desc = { 0 };
7178 IDWriteLocalizedStrings *value;
7180 assert(property > DWRITE_FONT_PROPERTY_ID_NONE && property <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME);
7182 if (entry->props[property] == MISSING_SET_PROP)
7183 return NULL;
7185 if ((value = entry->props[property]))
7187 IDWriteLocalizedStrings_AddRef(value);
7188 return value;
7191 get_filestream_from_file(entry->file, &stream_desc.stream);
7192 stream_desc.face_type = entry->face_type;
7193 stream_desc.face_index = entry->face_index;
7195 if (property == DWRITE_FONT_PROPERTY_ID_FULL_NAME)
7196 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_FULL_NAME, &value);
7197 else if (property == DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME)
7198 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &value);
7199 else if (property == DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG)
7200 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, &value);
7201 else if (property == DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG)
7202 opentype_get_font_info_strings(&stream_desc, DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, &value);
7203 else
7204 WARN("Unsupported property %u.\n", property);
7206 if (stream_desc.stream)
7207 IDWriteFontFileStream_Release(stream_desc.stream);
7209 if (value)
7211 entry->props[property] = value;
7212 IDWriteLocalizedStrings_AddRef(value);
7214 else
7215 entry->props[property] = MISSING_SET_PROP;
7217 return value;
7220 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7221 struct dwrite_fontset_entry **entries, unsigned int count);
7223 static ULONG WINAPI dwritefontset_Release(IDWriteFontSet3 *iface)
7225 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7226 ULONG refcount = InterlockedDecrement(&set->refcount);
7227 unsigned int i;
7229 TRACE("%p, refcount %u.\n", iface, refcount);
7231 if (!refcount)
7233 IDWriteFactory7_Release(set->factory);
7234 for (i = 0; i < set->count; ++i)
7235 release_fontset_entry(set->entries[i]);
7236 heap_free(set->entries);
7237 heap_free(set);
7240 return refcount;
7243 static UINT32 WINAPI dwritefontset_GetFontCount(IDWriteFontSet3 *iface)
7245 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7247 TRACE("%p.\n", iface);
7249 return set->count;
7252 static HRESULT WINAPI dwritefontset_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7253 IDWriteFontFaceReference **reference)
7255 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7257 TRACE("%p, %u, %p.\n", iface, index, reference);
7259 *reference = NULL;
7261 if (index >= set->count)
7262 return E_INVALIDARG;
7264 return IDWriteFactory7_CreateFontFaceReference_(set->factory, set->entries[index]->file,
7265 set->entries[index]->face_index, set->entries[index]->simulations, reference);
7268 static HRESULT WINAPI dwritefontset_FindFontFaceReference(IDWriteFontSet3 *iface,
7269 IDWriteFontFaceReference *reference, UINT32 *index, BOOL *exists)
7271 FIXME("%p, %p, %p, %p.\n", iface, reference, index, exists);
7273 return E_NOTIMPL;
7276 static HRESULT WINAPI dwritefontset_FindFontFace(IDWriteFontSet3 *iface, IDWriteFontFace *fontface,
7277 UINT32 *index, BOOL *exists)
7279 FIXME("%p, %p, %p, %p.\n", iface, fontface, index, exists);
7281 return E_NOTIMPL;
7284 static HRESULT WINAPI dwritefontset_GetPropertyValues__(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7285 IDWriteStringList **values)
7287 FIXME("%p, %d, %p.\n", iface, id, values);
7289 return E_NOTIMPL;
7292 static HRESULT WINAPI dwritefontset_GetPropertyValues_(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY_ID id,
7293 WCHAR const *preferred_locales, IDWriteStringList **values)
7295 FIXME("%p, %d, %s, %p.\n", iface, id, debugstr_w(preferred_locales), values);
7297 return E_NOTIMPL;
7300 static HRESULT WINAPI dwritefontset_GetPropertyValues(IDWriteFontSet3 *iface, UINT32 index, DWRITE_FONT_PROPERTY_ID id,
7301 BOOL *exists, IDWriteLocalizedStrings **values)
7303 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7305 TRACE("%p, %u, %d, %p, %p.\n", iface, index, id, exists, values);
7307 if (!(id > DWRITE_FONT_PROPERTY_ID_NONE && id <= DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME) ||
7308 index >= set->count)
7310 *values = NULL;
7311 *exists = FALSE;
7312 return E_INVALIDARG;
7315 *values = fontset_entry_get_property(set->entries[index], id);
7316 *exists = !!*values;
7318 return S_OK;
7321 static HRESULT WINAPI dwritefontset_GetPropertyOccurrenceCount(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7322 UINT32 *count)
7324 FIXME("%p, %p, %p.\n", iface, property, count);
7326 return E_NOTIMPL;
7329 static BOOL fontset_entry_is_matching(struct dwrite_fontset_entry *entry, DWRITE_FONT_PROPERTY const *props,
7330 unsigned int count)
7332 IDWriteLocalizedStrings *value;
7333 unsigned int i;
7334 BOOL ret;
7336 for (i = 0; i < count; ++i)
7338 switch (props[i].propertyId)
7340 case DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME:
7341 case DWRITE_FONT_PROPERTY_ID_FULL_NAME:
7342 case DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG:
7343 case DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG:
7344 if (!(value = fontset_entry_get_property(entry, props[i].propertyId)))
7345 return FALSE;
7347 ret = localizedstrings_contains(value, props[i].propertyValue);
7348 IDWriteLocalizedStrings_Release(value);
7349 if (!ret) return FALSE;
7350 break;
7351 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME:
7352 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME:
7353 case DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME:
7354 case DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME:
7355 case DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG:
7356 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
7357 case DWRITE_FONT_PROPERTY_ID_STRETCH:
7358 case DWRITE_FONT_PROPERTY_ID_STYLE:
7359 case DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME:
7360 FIXME("Unsupported property %d.\n", props[i].propertyId);
7361 /* fallthrough */
7362 default:
7363 return FALSE;
7367 return TRUE;
7370 static HRESULT WINAPI dwritefontset_GetMatchingFonts_(IDWriteFontSet3 *iface, WCHAR const *family, DWRITE_FONT_WEIGHT weight,
7371 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet **fontset)
7373 FIXME("%p, %s, %d, %d, %d, %p.\n", iface, debugstr_w(family), weight, stretch, style, fontset);
7375 return E_NOTIMPL;
7378 static HRESULT WINAPI dwritefontset_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props, UINT32 count,
7379 IDWriteFontSet **filtered_set)
7381 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7382 struct dwrite_fontset_entry **entries;
7383 unsigned int i, matched_count = 0;
7384 struct dwrite_fontset *object;
7386 TRACE("%p, %p, %u, %p.\n", iface, props, count, filtered_set);
7388 if (!props && count)
7389 return E_INVALIDARG;
7391 if (!(object = heap_alloc_zero(sizeof(*object))))
7392 return E_OUTOFMEMORY;
7394 if (!(entries = heap_calloc(set->count, sizeof(*entries))))
7396 heap_free(object);
7397 return E_OUTOFMEMORY;
7400 for (i = 0; i < set->count; ++i)
7402 if (fontset_entry_is_matching(set->entries[i], props, count))
7404 entries[matched_count++] = addref_fontset_entry(set->entries[i]);
7408 if (!matched_count)
7410 heap_free(entries);
7411 entries = NULL;
7414 init_fontset(object, set->factory, entries, matched_count);
7416 *filtered_set = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7418 return S_OK;
7421 static HRESULT WINAPI dwritefontset1_GetMatchingFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *property,
7422 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontSet1 **fontset)
7424 FIXME("%p, %p, %p, %u, %p.\n", iface, property, axis_values, num_values, fontset);
7426 return E_NOTIMPL;
7429 static HRESULT WINAPI dwritefontset1_GetFirstFontResources(IDWriteFontSet3 *iface, IDWriteFontSet1 **fontset)
7431 FIXME("%p, %p.\n", iface, fontset);
7433 return E_NOTIMPL;
7436 static HRESULT WINAPI dwritefontset1_GetFilteredFonts__(IDWriteFontSet3 *iface, UINT32 const *indices,
7437 UINT32 num_indices, IDWriteFontSet1 **fontset)
7439 FIXME("%p, %p, %u, %p.\n", iface, indices, num_indices, fontset);
7441 return E_NOTIMPL;
7444 static HRESULT WINAPI dwritefontset1_GetFilteredFonts_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *axis_ranges,
7445 UINT32 num_ranges, BOOL select_any_range, IDWriteFontSet1 **fontset)
7447 FIXME("%p, %p, %u, %d, %p.\n", iface, axis_ranges, num_ranges, select_any_range, fontset);
7449 return E_NOTIMPL;
7452 static HRESULT WINAPI dwritefontset1_GetFilteredFonts(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7453 UINT32 num_properties, BOOL select_any_property, IDWriteFontSet1 **fontset)
7455 FIXME("%p, %p, %u, %d, %p.\n", iface, props, num_properties, select_any_property, fontset);
7457 return E_NOTIMPL;
7460 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices_(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE const *ranges,
7461 UINT32 num_ranges, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7463 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, ranges, num_ranges, select_any_range, indices, num_indices, actual_num_indices);
7465 return E_NOTIMPL;
7468 static HRESULT WINAPI dwritefontset1_GetFilteredFontIndices(IDWriteFontSet3 *iface, DWRITE_FONT_PROPERTY const *props,
7469 UINT32 num_properties, BOOL select_any_range, UINT32 *indices, UINT32 num_indices, UINT32 *actual_num_indices)
7471 FIXME("%p, %p, %u, %d, %p, %u, %p.\n", iface, props, num_properties, select_any_range, indices,
7472 num_indices, actual_num_indices);
7474 return E_NOTIMPL;
7477 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges_(IDWriteFontSet3 *iface, UINT32 font_index,
7478 DWRITE_FONT_AXIS_RANGE *axis_ranges, UINT32 num_ranges, UINT32 *actual_num_ranges)
7480 FIXME("%p, %u, %p, %u, %p.\n", iface, font_index, axis_ranges, num_ranges, actual_num_ranges);
7482 return E_NOTIMPL;
7485 static HRESULT WINAPI dwritefontset1_GetFontAxisRanges(IDWriteFontSet3 *iface, DWRITE_FONT_AXIS_RANGE *axis_ranges,
7486 UINT32 num_ranges, UINT32 *actual_num_ranges)
7488 FIXME("%p, %p, %u, %p.\n", iface, axis_ranges, num_ranges, actual_num_ranges);
7490 return E_NOTIMPL;
7493 static HRESULT WINAPI dwritefontset1_GetFontFaceReference(IDWriteFontSet3 *iface, UINT32 index,
7494 IDWriteFontFaceReference1 **reference)
7496 FIXME("%p, %u, %p.\n", iface, index, reference);
7498 return E_NOTIMPL;
7501 static HRESULT WINAPI dwritefontset1_CreateFontResource(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontResource **resource)
7503 struct dwrite_fontset *set = impl_from_IDWriteFontSet3(iface);
7505 TRACE("%p, %u, %p.\n", iface, index, resource);
7507 *resource = NULL;
7509 if (index >= set->count)
7510 return E_INVALIDARG;
7512 return IDWriteFactory7_CreateFontResource(set->factory, set->entries[index]->file,
7513 set->entries[index]->face_index, resource);
7516 static HRESULT WINAPI dwritefontset1_CreateFontFace(IDWriteFontSet3 *iface, UINT32 index, IDWriteFontFace5 **fontface)
7518 FIXME("%p, %u, %p.\n", iface, index, fontface);
7520 return E_NOTIMPL;
7523 static DWRITE_LOCALITY WINAPI dwritefontset1_GetFontLocality(IDWriteFontSet3 *iface, UINT32 index)
7525 FIXME("%p, %u.\n", iface, index);
7527 return DWRITE_LOCALITY_LOCAL;
7530 static HANDLE WINAPI dwritefontset2_GetExpirationEvent(IDWriteFontSet3 *iface)
7532 FIXME("%p.\n", iface);
7534 return NULL;
7537 static DWRITE_FONT_SOURCE_TYPE WINAPI dwritefontset3_GetFontSourceType(IDWriteFontSet3 *iface, UINT32 index)
7539 FIXME("%p, %u.\n", iface, index);
7541 return DWRITE_FONT_SOURCE_TYPE_UNKNOWN;
7544 static UINT32 WINAPI dwritefontset3_GetFontSourceNameLength(IDWriteFontSet3 *iface, UINT32 index)
7546 FIXME("%p, %u.\n", iface, index);
7548 return 0;
7551 static HRESULT WINAPI dwritefontset3_GetFontSourceName(IDWriteFontSet3 *iface, UINT32 index, WCHAR *buffer, UINT32 buffer_size)
7553 FIXME("%p, %u, %p, %u.\n", iface, index, buffer, buffer_size);
7555 return E_NOTIMPL;
7558 static const IDWriteFontSet3Vtbl fontsetvtbl =
7560 dwritefontset_QueryInterface,
7561 dwritefontset_AddRef,
7562 dwritefontset_Release,
7563 dwritefontset_GetFontCount,
7564 dwritefontset_GetFontFaceReference,
7565 dwritefontset_FindFontFaceReference,
7566 dwritefontset_FindFontFace,
7567 dwritefontset_GetPropertyValues__,
7568 dwritefontset_GetPropertyValues_,
7569 dwritefontset_GetPropertyValues,
7570 dwritefontset_GetPropertyOccurrenceCount,
7571 dwritefontset_GetMatchingFonts_,
7572 dwritefontset_GetMatchingFonts,
7573 dwritefontset1_GetMatchingFonts,
7574 dwritefontset1_GetFirstFontResources,
7575 dwritefontset1_GetFilteredFonts__,
7576 dwritefontset1_GetFilteredFonts_,
7577 dwritefontset1_GetFilteredFonts,
7578 dwritefontset1_GetFilteredFontIndices_,
7579 dwritefontset1_GetFilteredFontIndices,
7580 dwritefontset1_GetFontAxisRanges_,
7581 dwritefontset1_GetFontAxisRanges,
7582 dwritefontset1_GetFontFaceReference,
7583 dwritefontset1_CreateFontResource,
7584 dwritefontset1_CreateFontFace,
7585 dwritefontset1_GetFontLocality,
7586 dwritefontset2_GetExpirationEvent,
7587 dwritefontset3_GetFontSourceType,
7588 dwritefontset3_GetFontSourceNameLength,
7589 dwritefontset3_GetFontSourceName,
7592 static HRESULT fontset_create_entry(IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type,
7593 unsigned int face_index, unsigned int simulations, struct dwrite_fontset_entry **ret)
7595 struct dwrite_fontset_entry *entry;
7597 if (!(entry = heap_alloc_zero(sizeof(*entry))))
7598 return E_OUTOFMEMORY;
7600 entry->refcount = 1;
7601 entry->file = file;
7602 IDWriteFontFile_AddRef(entry->file);
7603 entry->face_type = face_type;
7604 entry->face_index = face_index;
7605 entry->simulations = simulations;
7607 *ret = entry;
7609 return S_OK;
7612 static void init_fontset(struct dwrite_fontset *object, IDWriteFactory7 *factory,
7613 struct dwrite_fontset_entry **entries, unsigned int count)
7615 object->IDWriteFontSet3_iface.lpVtbl = &fontsetvtbl;
7616 object->refcount = 1;
7617 object->factory = factory;
7618 IDWriteFactory7_AddRef(object->factory);
7619 object->entries = entries;
7620 object->count = count;
7623 static HRESULT fontset_create_from_font_data(IDWriteFactory7 *factory, struct dwrite_font_data **fonts,
7624 unsigned int count, IDWriteFontSet1 **ret)
7626 struct dwrite_fontset_entry **entries = NULL;
7627 struct dwrite_fontset *object;
7628 unsigned int i;
7630 if (!(object = heap_alloc_zero(sizeof(*object))))
7631 return E_OUTOFMEMORY;
7633 if (count)
7635 entries = heap_calloc(count, sizeof(*entries));
7637 /* FIXME: set available properties too */
7639 for (i = 0; i < count; ++i)
7641 fontset_create_entry(fonts[i]->file, fonts[i]->face_type, fonts[i]->face_index,
7642 fonts[i]->simulations, &entries[i]);
7645 init_fontset(object, factory, entries, count);
7647 *ret = (IDWriteFontSet1 *)&object->IDWriteFontSet3_iface;
7649 return S_OK;
7652 static HRESULT fontset_builder_create_fontset(IDWriteFactory7 *factory, struct dwrite_fontset_entry **src_entries,
7653 unsigned int count, IDWriteFontSet **ret)
7655 struct dwrite_fontset_entry **entries = NULL;
7656 struct dwrite_fontset *object;
7657 unsigned int i;
7659 if (!(object = heap_alloc_zero(sizeof(*object))))
7660 return E_OUTOFMEMORY;
7662 if (count)
7664 entries = heap_calloc(count, sizeof(*entries));
7666 for (i = 0; i < count; ++i)
7667 entries[i] = addref_fontset_entry(src_entries[i]);
7669 init_fontset(object, factory, entries, count);
7671 *ret = (IDWriteFontSet *)&object->IDWriteFontSet3_iface;
7673 return S_OK;
7676 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
7677 REFIID riid, void **obj)
7679 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7681 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
7682 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
7683 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
7684 IsEqualIID(riid, &IID_IUnknown))
7686 *obj = iface;
7687 IDWriteFontSetBuilder2_AddRef(iface);
7688 return S_OK;
7691 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7692 *obj = NULL;
7693 return E_NOINTERFACE;
7696 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
7698 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7699 ULONG refcount = InterlockedIncrement(&builder->refcount);
7701 TRACE("%p, refcount %u.\n", iface, refcount);
7703 return refcount;
7706 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
7708 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7709 ULONG refcount = InterlockedDecrement(&builder->refcount);
7710 unsigned int i;
7712 TRACE("%p, refcount %u.\n", iface, refcount);
7714 if (!refcount)
7716 IDWriteFactory7_Release(builder->factory);
7717 for (i = 0; i < builder->count; ++i)
7718 release_fontset_entry(builder->entries[i]);
7719 heap_free(builder->entries);
7720 heap_free(builder);
7723 return refcount;
7726 static HRESULT fontset_builder_add_entry(struct dwrite_fontset_builder *builder, IDWriteFontFile *file,
7727 DWRITE_FONT_FACE_TYPE face_type, unsigned int face_index, unsigned int simulations)
7729 struct dwrite_fontset_entry *entry;
7730 HRESULT hr;
7732 if (!dwrite_array_reserve((void **)&builder->entries, &builder->capacity, builder->count + 1,
7733 sizeof(*builder->entries)))
7735 return E_OUTOFMEMORY;
7738 if (FAILED(hr = fontset_create_entry(file, face_type, face_index, simulations, &entry)))
7739 return hr;
7741 builder->entries[builder->count++] = entry;
7743 return S_OK;
7746 static HRESULT fontset_builder_add_file(struct dwrite_fontset_builder *builder, IDWriteFontFile *file)
7748 DWRITE_FONT_FILE_TYPE filetype;
7749 DWRITE_FONT_FACE_TYPE facetype;
7750 unsigned int i, face_count;
7751 BOOL supported = FALSE;
7752 HRESULT hr;
7754 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &filetype, &facetype, &face_count)))
7755 return hr;
7757 if (!supported)
7758 return DWRITE_E_FILEFORMAT;
7760 for (i = 0; i < face_count; ++i)
7762 if (FAILED(hr = fontset_builder_add_entry(builder, file, facetype, i, DWRITE_FONT_SIMULATIONS_NONE)))
7763 break;
7766 return hr;
7769 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
7770 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
7772 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
7774 return E_NOTIMPL;
7777 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
7778 IDWriteFontFaceReference *ref)
7780 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7781 unsigned int face_count, face_index, simulations;
7782 DWRITE_FONT_FILE_TYPE file_type;
7783 DWRITE_FONT_FACE_TYPE face_type;
7784 IDWriteFontFile *file;
7785 BOOL supported;
7786 HRESULT hr;
7788 TRACE("%p, %p.\n", iface, ref);
7790 if (FAILED(hr = IDWriteFontFaceReference_GetFontFile(ref, &file))) return hr;
7791 if (FAILED(hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count)))
7792 goto done;
7794 if (!supported)
7796 hr = DWRITE_E_FILEFORMAT;
7797 goto done;
7800 face_index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
7801 simulations = IDWriteFontFaceReference_GetSimulations(ref);
7802 hr = fontset_builder_add_entry(builder, file, face_type, face_index, simulations);
7804 done:
7805 IDWriteFontFile_Release(file);
7807 return hr;
7810 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
7812 FIXME("%p, %p.\n", iface, fontset);
7814 return E_NOTIMPL;
7817 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
7819 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7821 TRACE("%p, %p.\n", iface, fontset);
7823 return fontset_builder_create_fontset(builder->factory, builder->entries, builder->count, fontset);
7826 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
7828 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7830 TRACE("%p, %p.\n", iface, file);
7832 return fontset_builder_add_file(builder, file);
7835 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
7836 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
7837 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
7838 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
7840 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
7841 axis_ranges, num_ranges, props, num_properties);
7843 return E_NOTIMPL;
7846 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
7848 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7849 IDWriteFontFile *file;
7850 HRESULT hr;
7852 TRACE("%p, %s.\n", iface, debugstr_w(filepath));
7854 if (FAILED(hr = IDWriteFactory7_CreateFontFileReference(builder->factory, filepath, NULL, &file)))
7855 return hr;
7857 hr = fontset_builder_add_file(builder, file);
7858 IDWriteFontFile_Release(file);
7859 return hr;
7862 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
7864 dwritefontsetbuilder_QueryInterface,
7865 dwritefontsetbuilder_AddRef,
7866 dwritefontsetbuilder_Release,
7867 dwritefontsetbuilder_AddFontFaceReference_,
7868 dwritefontsetbuilder_AddFontFaceReference,
7869 dwritefontsetbuilder_AddFontSet,
7870 dwritefontsetbuilder_CreateFontSet,
7871 dwritefontsetbuilder1_AddFontFile,
7872 dwritefontsetbuilder2_AddFont,
7873 dwritefontsetbuilder2_AddFontFile,
7876 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
7878 struct dwrite_fontset_builder *builder;
7880 *ret = NULL;
7882 if (!(builder = heap_alloc_zero(sizeof(*builder))))
7883 return E_OUTOFMEMORY;
7885 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
7886 builder->refcount = 1;
7887 builder->factory = factory;
7888 IDWriteFactory7_AddRef(builder->factory);
7890 *ret = &builder->IDWriteFontSetBuilder2_iface;
7892 return S_OK;