dwrite/font: Use consistent traces for the font object.
[wine.git] / dlls / dwrite / font.c
blob9889add8899f9d02beb29cabeb0e547ca118113a
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 ref;
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 {
171 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
172 LONG ref;
174 DWRITE_RENDERING_MODE1 rendering_mode;
175 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
176 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
177 DWRITE_MATRIX m;
178 UINT16 *glyphs;
179 D2D_POINT_2F *origins;
181 UINT8 flags;
182 RECT bounds;
183 BYTE *bitmap;
184 UINT32 max_glyph_bitmap_size;
187 struct dwrite_colorglyphenum
189 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
190 LONG refcount;
192 FLOAT origin_x; /* original run origin */
193 FLOAT origin_y;
195 IDWriteFontFace5 *fontface; /* for convenience */
196 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
197 DWRITE_GLYPH_RUN run; /* base run */
198 UINT32 palette; /* palette index to get layer color from */
199 FLOAT *advances; /* original or measured advances for base glyphs */
200 FLOAT *color_advances; /* returned color run points to this */
201 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
202 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
203 UINT16 *glyphindices; /* returned color run points to this */
204 struct dwrite_colorglyph *glyphs; /* current glyph color info */
205 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
206 UINT16 current_layer; /* enumerator position, updated with MoveNext */
207 UINT16 max_layer_num; /* max number of layers for this run */
208 struct dwrite_fonttable colr; /* used to access layers */
211 #define GLYPH_BLOCK_SHIFT 8
212 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
213 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
214 #define GLYPH_MAX 65536
216 struct dwrite_fontfile {
217 IDWriteFontFile IDWriteFontFile_iface;
218 LONG ref;
220 IDWriteFontFileLoader *loader;
221 void *reference_key;
222 UINT32 key_size;
223 IDWriteFontFileStream *stream;
226 struct dwrite_fontfacereference
228 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
229 LONG refcount;
231 IDWriteFontFile *file;
232 UINT32 index;
233 USHORT simulations;
234 DWRITE_FONT_AXIS_VALUE *axis_values;
235 UINT32 axis_values_count;
236 IDWriteFactory7 *factory;
239 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
241 struct dwrite_fontresource
243 IDWriteFontResource IDWriteFontResource_iface;
244 LONG refcount;
246 IDWriteFontFile *file;
247 UINT32 face_index;
248 IDWriteFactory7 *factory;
251 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
253 struct dwrite_fontface *fontface = context;
254 BOOL exists = FALSE;
256 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
257 size, data_context, &exists)) || !exists)
259 *data = NULL;
260 *size = 0;
261 *data_context = NULL;
265 static void dwrite_release_font_table(void *context, void *data_context)
267 struct dwrite_fontface *fontface = context;
268 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
271 static UINT16 dwrite_get_font_upem(void *context)
273 struct dwrite_fontface *fontface = context;
274 return fontface->metrics.designUnitsPerEm;
277 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
279 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
280 return opentype_cmap_get_glyph(&fontface->cmap, ch);
283 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
285 struct dwrite_fontface *fontface = context;
286 return !!dwritefontface_get_glyph(fontface, codepoint);
289 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
291 struct dwrite_fontface *fontface = context;
292 return dwritefontface_get_glyph(fontface, codepoint);
295 static const struct shaping_font_ops dwrite_font_ops =
297 dwrite_grab_font_table,
298 dwrite_release_font_table,
299 dwrite_get_font_upem,
300 dwrite_has_glyph,
301 dwrite_get_glyph,
304 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
306 if (fontface->shaping_cache)
307 return fontface->shaping_cache;
309 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
312 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
314 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
317 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
319 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
322 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
324 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
327 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
329 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
331 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
334 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
336 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
339 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
341 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
344 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
346 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
349 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
351 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
354 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
356 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
359 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
361 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
364 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
366 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
369 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
371 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
374 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
376 static const DWRITE_GLYPH_METRICS nil;
377 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
379 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
380 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
381 return S_OK;
384 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
386 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
388 if (!*block) {
389 /* start new block */
390 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
391 if (!*block)
392 return E_OUTOFMEMORY;
395 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
396 return S_OK;
399 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
401 HRESULT hr;
403 if (table->data || !table->exists)
404 return table->data;
406 table->exists = FALSE;
407 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
408 &table->exists);
409 if (FAILED(hr) || !table->exists) {
410 TRACE("Font does not have %s table\n", debugstr_tag(tag));
411 return NULL;
414 return table->data;
417 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
418 struct dwrite_font_propvec *vec)
420 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
421 vec->style = style * 7.0f;
422 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
425 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
427 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
430 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
432 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
435 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
437 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
438 return &fontface->vdmx;
441 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
443 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
444 return &fontface->gasp;
447 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
449 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
450 return &fontface->cpal;
453 static void addref_font_data(struct dwrite_font_data *data)
455 InterlockedIncrement(&data->ref);
458 static void release_font_data(struct dwrite_font_data *data)
460 int i;
462 if (InterlockedDecrement(&data->ref) > 0)
463 return;
465 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
467 if (data->info_strings[i])
468 IDWriteLocalizedStrings_Release(data->info_strings[i]);
470 if (data->names)
471 IDWriteLocalizedStrings_Release(data->names);
473 if (data->family_names)
474 IDWriteLocalizedStrings_Release(data->family_names);
476 dwrite_cmap_release(&data->cmap);
477 IDWriteFontFile_Release(data->file);
478 heap_free(data->facename);
479 heap_free(data);
482 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
484 size_t i;
486 if (InterlockedDecrement(&data->refcount) > 0)
487 return;
489 for (i = 0; i < data->count; ++i)
490 release_font_data(data->fonts[i]);
491 heap_free(data->fonts);
492 IDWriteLocalizedStrings_Release(data->familyname);
493 heap_free(data);
496 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
498 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
499 fontface->cached = NULL;
502 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
504 UINT32 left_key_size, right_key_size;
505 const void *left_key, *right_key;
506 HRESULT hr;
508 if (left == right)
509 return TRUE;
511 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
512 if (FAILED(hr))
513 return FALSE;
515 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
516 if (FAILED(hr))
517 return FALSE;
519 if (left_key_size != right_key_size)
520 return FALSE;
522 return !memcmp(left_key, right_key, left_key_size);
525 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
527 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
529 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
531 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
532 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
533 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
534 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
535 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
536 IsEqualIID(riid, &IID_IDWriteFontFace) ||
537 IsEqualIID(riid, &IID_IUnknown))
539 *obj = iface;
541 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
542 *obj = &fontface->IDWriteFontFaceReference_iface;
543 else
544 *obj = NULL;
546 if (*obj)
548 if (InterlockedIncrement(&fontface->refcount) == 1)
550 InterlockedDecrement(&fontface->refcount);
551 *obj = NULL;
552 return E_FAIL;
554 return S_OK;
557 WARN("%s not implemented.\n", debugstr_guid(riid));
559 return E_NOINTERFACE;
562 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
564 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
565 ULONG refcount = InterlockedIncrement(&fontface->refcount);
567 TRACE("%p, refcount %u.\n", iface, refcount);
569 return refcount;
572 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
574 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
575 ULONG refcount = InterlockedDecrement(&fontface->refcount);
577 TRACE("%p, refcount %u.\n", iface, refcount);
579 if (!refcount)
581 UINT32 i;
583 if (fontface->cached)
585 factory_lock(fontface->factory);
586 list_remove(&fontface->cached->entry);
587 factory_unlock(fontface->factory);
588 heap_free(fontface->cached);
590 release_scriptshaping_cache(fontface->shaping_cache);
591 if (fontface->vdmx.context)
592 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
593 if (fontface->gasp.context)
594 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
595 if (fontface->cpal.context)
596 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
597 if (fontface->colr.context)
598 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
599 for (i = 0; i < fontface->file_count; i++)
601 if (fontface->files[i])
602 IDWriteFontFile_Release(fontface->files[i]);
604 if (fontface->stream)
605 IDWriteFontFileStream_Release(fontface->stream);
606 heap_free(fontface->files);
607 if (fontface->names)
608 IDWriteLocalizedStrings_Release(fontface->names);
609 if (fontface->family_names)
610 IDWriteLocalizedStrings_Release(fontface->family_names);
611 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
613 if (fontface->info_strings[i])
614 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
617 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
618 heap_free(fontface->glyphs[i]);
620 freetype_notify_cacheremove(iface);
622 dwrite_cmap_release(&fontface->cmap);
623 IDWriteFactory7_Release(fontface->factory);
624 heap_free(fontface);
627 return refcount;
630 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
632 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
634 TRACE("%p.\n", iface);
636 return fontface->type;
639 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
640 IDWriteFontFile **fontfiles)
642 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
643 int i;
645 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
647 if (fontfiles == NULL)
649 *number_of_files = fontface->file_count;
650 return S_OK;
653 if (*number_of_files < fontface->file_count)
654 return E_INVALIDARG;
656 for (i = 0; i < fontface->file_count; i++)
658 IDWriteFontFile_AddRef(fontface->files[i]);
659 fontfiles[i] = fontface->files[i];
662 return S_OK;
665 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
667 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
669 TRACE("%p.\n", iface);
671 return fontface->index;
674 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
676 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
678 TRACE("%p.\n", iface);
680 return fontface->simulations;
683 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
685 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
687 TRACE("%p.\n", iface);
689 return !!(fontface->flags & FONT_IS_SYMBOL);
692 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
694 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
696 TRACE("%p, %p.\n", iface, metrics);
698 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
701 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
703 TRACE("%p.\n", iface);
705 return freetype_get_glyphcount(iface);
708 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
709 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
711 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
712 unsigned int i;
713 HRESULT hr;
715 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
717 if (!glyphs)
718 return E_INVALIDARG;
720 if (is_sideways)
721 FIXME("sideways metrics are not supported.\n");
723 for (i = 0; i < glyph_count; i++) {
724 DWRITE_GLYPH_METRICS metrics;
726 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
727 if (hr != S_OK) {
728 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
729 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
730 if (FAILED(hr))
731 return hr;
733 ret[i] = metrics;
736 return S_OK;
739 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
740 UINT32 count, UINT16 *glyphs)
742 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
743 unsigned int i;
745 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
747 if (!glyphs)
748 return E_INVALIDARG;
750 if (!codepoints)
752 memset(glyphs, 0, count * sizeof(*glyphs));
753 return E_INVALIDARG;
756 for (i = 0; i < count; ++i)
757 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
759 return S_OK;
762 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
763 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
765 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
766 struct file_stream_desc stream_desc;
768 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
770 stream_desc.stream = fontface->stream;
771 stream_desc.face_type = fontface->type;
772 stream_desc.face_index = fontface->index;
773 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
776 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
778 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
780 TRACE("%p, %p.\n", iface, table_context);
782 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
785 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
786 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
787 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
789 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
790 count, is_sideways, is_rtl, sink);
792 if (!glyphs || !sink)
793 return E_INVALIDARG;
795 if (is_sideways)
796 FIXME("sideways mode is not supported.\n");
798 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
801 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
802 float ppem, unsigned int gasp)
804 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
806 switch (measuring)
808 case DWRITE_MEASURING_MODE_NATURAL:
810 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
811 mode = DWRITE_RENDERING_MODE_NATURAL;
812 else
813 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
814 break;
816 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
817 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
818 break;
819 case DWRITE_MEASURING_MODE_GDI_NATURAL:
820 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
821 break;
822 default:
826 return mode;
829 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
830 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
832 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
833 unsigned int flags;
834 FLOAT ppem;
836 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
838 if (!params) {
839 *mode = DWRITE_RENDERING_MODE_DEFAULT;
840 return E_INVALIDARG;
843 *mode = IDWriteRenderingParams_GetRenderingMode(params);
844 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
845 return S_OK;
847 ppem = emSize * ppdip;
849 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
850 *mode = DWRITE_RENDERING_MODE_OUTLINE;
851 return S_OK;
854 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
855 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
856 return S_OK;
859 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
860 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
862 DWRITE_FONT_METRICS1 metrics1;
863 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
864 memcpy(metrics, &metrics1, sizeof(*metrics));
865 return hr;
868 static inline int round_metric(FLOAT metric)
870 return (int)floorf(metric + 0.5f);
873 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
875 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
876 return 0;
878 return (fontface->metrics.designUnitsPerEm + 49) / 50;
881 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
882 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
883 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
885 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
886 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
887 DWRITE_MEASURING_MODE mode;
888 FLOAT scale, size;
889 HRESULT hr;
890 UINT32 i;
892 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
893 glyph_count, metrics, is_sideways);
895 if (m && memcmp(m, &identity, sizeof(*m)))
896 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
898 size = emSize * ppdip;
899 scale = size / fontface->metrics.designUnitsPerEm;
900 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
902 for (i = 0; i < glyph_count; i++) {
903 DWRITE_GLYPH_METRICS *ret = metrics + i;
904 DWRITE_GLYPH_METRICS design;
905 BOOL has_contours;
907 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
908 if (FAILED(hr))
909 return hr;
911 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
912 if (has_contours)
913 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
914 else
915 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
917 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
918 SCALE_METRIC(leftSideBearing);
919 SCALE_METRIC(rightSideBearing);
920 SCALE_METRIC(topSideBearing);
921 SCALE_METRIC(advanceHeight);
922 SCALE_METRIC(bottomSideBearing);
923 SCALE_METRIC(verticalOriginY);
924 #undef SCALE_METRIC
927 return S_OK;
930 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
932 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
934 TRACE("%p, %p.\n", iface, metrics);
936 *metrics = fontface->metrics;
939 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
940 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
942 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
943 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
944 UINT16 ascent, descent;
945 FLOAT scale;
947 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
949 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
950 memset(metrics, 0, sizeof(*metrics));
951 return E_INVALIDARG;
954 em_size *= pixels_per_dip;
955 if (m && m->m22 != 0.0f)
956 em_size *= fabs(m->m22);
958 scale = em_size / design->designUnitsPerEm;
959 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
961 ascent = round_metric(design->ascent * scale);
962 descent = round_metric(design->descent * scale);
965 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
966 metrics->designUnitsPerEm = design->designUnitsPerEm;
967 metrics->ascent = round_metric(ascent / scale);
968 metrics->descent = round_metric(descent / scale);
970 SCALE_METRIC(lineGap);
971 SCALE_METRIC(capHeight);
972 SCALE_METRIC(xHeight);
973 SCALE_METRIC(underlinePosition);
974 SCALE_METRIC(underlineThickness);
975 SCALE_METRIC(strikethroughPosition);
976 SCALE_METRIC(strikethroughThickness);
977 SCALE_METRIC(glyphBoxLeft);
978 SCALE_METRIC(glyphBoxTop);
979 SCALE_METRIC(glyphBoxRight);
980 SCALE_METRIC(glyphBoxBottom);
981 SCALE_METRIC(subscriptPositionX);
982 SCALE_METRIC(subscriptPositionY);
983 SCALE_METRIC(subscriptSizeX);
984 SCALE_METRIC(subscriptSizeY);
985 SCALE_METRIC(superscriptPositionX);
986 SCALE_METRIC(superscriptPositionY);
987 SCALE_METRIC(superscriptSizeX);
988 SCALE_METRIC(superscriptSizeY);
990 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
991 #undef SCALE_METRIC
993 return S_OK;
996 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
998 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1000 TRACE("%p, %p.\n", iface, metrics);
1002 *metrics = fontface->caret;
1005 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1006 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1008 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1010 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1012 *count = 0;
1013 if (max_count && !ranges)
1014 return E_INVALIDARG;
1016 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1017 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1020 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1022 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1024 TRACE("%p.\n", iface);
1026 return !!(fontface->flags & FONT_IS_MONOSPACED);
1029 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1030 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1032 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1033 BOOL has_contours;
1034 int advance;
1036 if (is_sideways)
1037 FIXME("Sideways mode is not supported.\n");
1039 switch (measuring_mode)
1041 case DWRITE_MEASURING_MODE_NATURAL:
1042 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1043 glyph, measuring_mode, &has_contours);
1044 if (has_contours)
1045 advance += adjustment;
1047 return advance;
1048 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1049 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1050 emsize *= ppdip;
1051 if (emsize == 0.0f)
1052 return 0.0f;
1054 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1055 FIXME("Transform is not supported.\n");
1057 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1058 &has_contours);
1059 if (has_contours)
1060 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1061 else
1062 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1064 return advance;
1065 default:
1066 WARN("Unknown measuring mode %u.\n", measuring_mode);
1067 return 0;
1071 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1072 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1074 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1075 unsigned int i;
1077 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1079 if (is_sideways)
1080 FIXME("sideways mode not supported\n");
1082 for (i = 0; i < glyph_count; ++i)
1084 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1085 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1088 return S_OK;
1091 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1092 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1093 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1095 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1096 DWRITE_MEASURING_MODE measuring_mode;
1097 UINT32 i;
1099 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1100 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1102 if (em_size < 0.0f || ppdip <= 0.0f) {
1103 memset(advances, 0, sizeof(*advances) * glyph_count);
1104 return E_INVALIDARG;
1107 if (em_size == 0.0f) {
1108 memset(advances, 0, sizeof(*advances) * glyph_count);
1109 return S_OK;
1112 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1113 for (i = 0; i < glyph_count; ++i)
1115 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1116 glyphs[i], is_sideways);
1119 return S_OK;
1122 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1123 const UINT16 *indices, INT32 *adjustments)
1125 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1126 UINT32 i;
1128 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1130 if (!(indices || adjustments) || !count)
1131 return E_INVALIDARG;
1133 if (!indices || count == 1) {
1134 memset(adjustments, 0, count*sizeof(INT32));
1135 return E_INVALIDARG;
1138 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1140 memset(adjustments, 0, count*sizeof(INT32));
1141 return S_OK;
1144 for (i = 0; i < count-1; i++)
1145 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1146 adjustments[count-1] = 0;
1148 return S_OK;
1151 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1153 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1155 TRACE("%p.\n", iface);
1157 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1160 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1161 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1162 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1164 DWRITE_GRID_FIT_MODE gridfitmode;
1165 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1166 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1169 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1170 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1172 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1174 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1176 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1179 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1181 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1183 TRACE("%p.\n", iface);
1185 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1188 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1190 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1192 TRACE("%p.\n", iface);
1194 return !!(fontface->flags & FONT_IS_COLORED);
1197 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1199 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1201 TRACE("%p.\n", iface);
1203 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1206 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1208 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1210 TRACE("%p.\n", iface);
1212 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1215 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1216 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1218 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1220 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1222 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1225 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1226 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1227 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1228 DWRITE_GRID_FIT_MODE *gridfitmode)
1230 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1231 unsigned int flags;
1232 FLOAT emthreshold;
1234 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1235 measuringmode, params, renderingmode, gridfitmode);
1237 if (m)
1238 FIXME("transform not supported %s\n", debugstr_matrix(m));
1240 if (is_sideways)
1241 FIXME("sideways mode not supported\n");
1243 emSize *= max(dpiX, dpiY) / 96.0f;
1245 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1246 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1247 if (params) {
1248 IDWriteRenderingParams2 *params2;
1249 HRESULT hr;
1251 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1252 if (hr == S_OK) {
1253 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1254 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1255 IDWriteRenderingParams2_Release(params2);
1257 else
1258 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1261 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1263 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1265 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1266 if (emSize >= emthreshold)
1267 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1268 else
1269 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1272 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1273 if (emSize >= emthreshold)
1274 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1275 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1276 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1277 else
1278 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1279 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1282 return S_OK;
1285 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1286 IDWriteFontFaceReference **reference)
1288 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1290 TRACE("%p, %p.\n", iface, reference);
1292 *reference = &fontface->IDWriteFontFaceReference_iface;
1293 IDWriteFontFaceReference_AddRef(*reference);
1295 return S_OK;
1298 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1300 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1302 TRACE("%p, %p.\n", iface, panose);
1304 *panose = fontface->panose;
1307 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1309 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1311 TRACE("%p.\n", iface);
1313 return fontface->weight;
1316 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1318 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1320 TRACE("%p.\n", iface);
1322 return fontface->stretch;
1325 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1327 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1329 TRACE("%p.\n", iface);
1331 return fontface->style;
1334 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1336 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1338 TRACE("%p, %p.\n", iface, names);
1340 return clone_localizedstrings(fontface->family_names, names);
1343 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1345 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1347 TRACE("%p, %p.\n", iface, names);
1349 return clone_localizedstrings(fontface->names, names);
1352 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1353 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1354 IDWriteLocalizedStrings **ret, BOOL *exists)
1356 HRESULT hr = S_OK;
1358 *exists = FALSE;
1359 *ret = NULL;
1361 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1362 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1364 return S_OK;
1367 if (!strings_cache[stringid])
1369 struct file_stream_desc desc = *stream_desc;
1371 if (!desc.stream)
1372 hr = get_filestream_from_file(file, &desc.stream);
1373 if (SUCCEEDED(hr))
1374 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1376 if (!stream_desc->stream && desc.stream)
1377 IDWriteFontFileStream_Release(desc.stream);
1380 if (SUCCEEDED(hr) && strings_cache[stringid])
1382 hr = clone_localizedstrings(strings_cache[stringid], ret);
1383 if (SUCCEEDED(hr))
1384 *exists = TRUE;
1387 return hr;
1390 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1391 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1393 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1394 struct file_stream_desc stream_desc;
1396 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1398 stream_desc.stream = fontface->stream;
1399 stream_desc.face_index = fontface->index;
1400 stream_desc.face_type = fontface->type;
1401 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1404 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1406 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1408 TRACE("%p, %#x.\n", iface, ch);
1410 return !!dwritefontface_get_glyph(fontface, ch);
1413 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1414 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1415 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1417 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1418 unsigned int flags;
1419 FLOAT emthreshold;
1421 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1422 measuring_mode, params, rendering_mode, gridfit_mode);
1424 if (m)
1425 FIXME("transform not supported %s\n", debugstr_matrix(m));
1427 if (is_sideways)
1428 FIXME("sideways mode not supported\n");
1430 emSize *= max(dpiX, dpiY) / 96.0f;
1432 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1433 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1434 if (params) {
1435 IDWriteRenderingParams3 *params3;
1436 HRESULT hr;
1438 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1439 if (hr == S_OK) {
1440 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1441 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1442 IDWriteRenderingParams3_Release(params3);
1444 else
1445 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1448 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1450 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1452 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1453 if (emSize >= emthreshold)
1454 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1455 else
1456 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1459 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1460 if (emSize >= emthreshold)
1461 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1462 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1463 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1464 else
1465 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1466 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1469 return S_OK;
1472 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1474 FIXME("%p, %#x: stub\n", iface, ch);
1476 return FALSE;
1479 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1481 FIXME("%p, %u: stub\n", iface, glyph);
1483 return FALSE;
1486 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1487 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1489 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1491 return E_NOTIMPL;
1494 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1495 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1497 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1499 return E_NOTIMPL;
1502 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1503 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1505 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1507 return E_NOTIMPL;
1510 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1512 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1514 TRACE("%p.\n", iface);
1516 return fontface->glyph_image_formats;
1519 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1520 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1522 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1524 return E_NOTIMPL;
1527 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1529 FIXME("%p, %p: stub\n", iface, context);
1532 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1534 FIXME("%p: stub\n", iface);
1536 return 0;
1539 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1540 UINT32 value_count)
1542 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1544 return E_NOTIMPL;
1547 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1549 static int once;
1551 if (!once++)
1552 FIXME("%p: stub\n", iface);
1554 return FALSE;
1557 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1559 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1561 TRACE("%p, %p.\n", iface, resource);
1563 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1566 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1568 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1570 TRACE("%p, %p.\n", iface, other);
1572 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1573 return FALSE;
1575 /* TODO: add variations support */
1577 return fontface->index == other_face->index &&
1578 fontface->simulations == other_face->simulations &&
1579 is_same_fontfile(fontface->files[0], other_face->files[0]);
1582 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1584 dwritefontface_QueryInterface,
1585 dwritefontface_AddRef,
1586 dwritefontface_Release,
1587 dwritefontface_GetType,
1588 dwritefontface_GetFiles,
1589 dwritefontface_GetIndex,
1590 dwritefontface_GetSimulations,
1591 dwritefontface_IsSymbolFont,
1592 dwritefontface_GetMetrics,
1593 dwritefontface_GetGlyphCount,
1594 dwritefontface_GetDesignGlyphMetrics,
1595 dwritefontface_GetGlyphIndices,
1596 dwritefontface_TryGetFontTable,
1597 dwritefontface_ReleaseFontTable,
1598 dwritefontface_GetGlyphRunOutline,
1599 dwritefontface_GetRecommendedRenderingMode,
1600 dwritefontface_GetGdiCompatibleMetrics,
1601 dwritefontface_GetGdiCompatibleGlyphMetrics,
1602 dwritefontface1_GetMetrics,
1603 dwritefontface1_GetGdiCompatibleMetrics,
1604 dwritefontface1_GetCaretMetrics,
1605 dwritefontface1_GetUnicodeRanges,
1606 dwritefontface1_IsMonospacedFont,
1607 dwritefontface1_GetDesignGlyphAdvances,
1608 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1609 dwritefontface1_GetKerningPairAdjustments,
1610 dwritefontface1_HasKerningPairs,
1611 dwritefontface1_GetRecommendedRenderingMode,
1612 dwritefontface1_GetVerticalGlyphVariants,
1613 dwritefontface1_HasVerticalGlyphVariants,
1614 dwritefontface2_IsColorFont,
1615 dwritefontface2_GetColorPaletteCount,
1616 dwritefontface2_GetPaletteEntryCount,
1617 dwritefontface2_GetPaletteEntries,
1618 dwritefontface2_GetRecommendedRenderingMode,
1619 dwritefontface3_GetFontFaceReference,
1620 dwritefontface3_GetPanose,
1621 dwritefontface3_GetWeight,
1622 dwritefontface3_GetStretch,
1623 dwritefontface3_GetStyle,
1624 dwritefontface3_GetFamilyNames,
1625 dwritefontface3_GetFaceNames,
1626 dwritefontface3_GetInformationalStrings,
1627 dwritefontface3_HasCharacter,
1628 dwritefontface3_GetRecommendedRenderingMode,
1629 dwritefontface3_IsCharacterLocal,
1630 dwritefontface3_IsGlyphLocal,
1631 dwritefontface3_AreCharactersLocal,
1632 dwritefontface3_AreGlyphsLocal,
1633 dwritefontface4_GetGlyphImageFormats_,
1634 dwritefontface4_GetGlyphImageFormats,
1635 dwritefontface4_GetGlyphImageData,
1636 dwritefontface4_ReleaseGlyphImageData,
1637 dwritefontface5_GetFontAxisValueCount,
1638 dwritefontface5_GetFontAxisValues,
1639 dwritefontface5_HasVariations,
1640 dwritefontface5_GetFontResource,
1641 dwritefontface5_Equals,
1644 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1646 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1647 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1650 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1652 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1653 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1656 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1658 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1659 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1662 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1663 IDWriteFontFace3 **ret)
1665 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1667 TRACE("%p, %p.\n", iface, ret);
1669 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1670 IDWriteFontFace3_AddRef(*ret);
1672 return S_OK;
1675 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1676 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1678 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1679 DWRITE_FONT_FILE_TYPE file_type;
1680 DWRITE_FONT_FACE_TYPE face_type;
1681 IDWriteFontFace *face;
1682 BOOL is_supported;
1683 UINT32 face_num;
1684 HRESULT hr;
1686 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1688 hr = IDWriteFontFile_Analyze(fontface->files[0], &is_supported, &file_type, &face_type, &face_num);
1689 if (FAILED(hr))
1690 return hr;
1692 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, fontface->files, fontface->index,
1693 simulations, &face);
1694 if (SUCCEEDED(hr))
1696 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1697 IDWriteFontFace_Release(face);
1700 return hr;
1703 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1705 FIXME("%p, %p.\n", iface, ref);
1707 return E_NOTIMPL;
1710 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1712 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1714 TRACE("%p.\n", iface);
1716 return fontface->index;
1719 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1721 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1723 TRACE("%p.\n", iface);
1725 return fontface->simulations;
1728 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1730 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1732 TRACE("%p, %p.\n", iface, file);
1734 *file = fontface->files[0];
1735 IDWriteFontFile_AddRef(*file);
1737 return S_OK;
1740 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1742 FIXME("%p.\n", iface);
1744 return 0;
1747 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1749 FIXME("%p.\n", iface);
1751 return 0;
1754 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1756 FIXME("%p, %p.\n", iface, writetime);
1758 return E_NOTIMPL;
1761 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1763 FIXME("%p.\n", iface);
1765 return DWRITE_LOCALITY_LOCAL;
1768 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1770 FIXME("%p.\n", iface);
1772 return E_NOTIMPL;
1775 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1776 WCHAR const *chars, UINT32 count)
1778 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1780 return E_NOTIMPL;
1783 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1784 UINT16 const *glyphs, UINT32 count)
1786 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1788 return E_NOTIMPL;
1791 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1792 UINT64 offset, UINT64 size)
1794 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1796 return E_NOTIMPL;
1799 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1801 dwritefontface_reference_QueryInterface,
1802 dwritefontface_reference_AddRef,
1803 dwritefontface_reference_Release,
1804 dwritefontface_reference_CreateFontFace,
1805 dwritefontface_reference_CreateFontFaceWithSimulations,
1806 dwritefontface_reference_Equals,
1807 dwritefontface_reference_GetFontFaceIndex,
1808 dwritefontface_reference_GetSimulations,
1809 dwritefontface_reference_GetFontFile,
1810 dwritefontface_reference_GetLocalFileSize,
1811 dwritefontface_reference_GetFileSize,
1812 dwritefontface_reference_GetFileTime,
1813 dwritefontface_reference_GetLocality,
1814 dwritefontface_reference_EnqueueFontDownloadRequest,
1815 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1816 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1817 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1820 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1822 struct dwrite_font_data *data = font->data;
1823 struct fontface_desc desc;
1824 struct list *cached_list;
1825 HRESULT hr;
1827 *fontface = NULL;
1829 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1830 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1831 if (hr == S_OK)
1832 return hr;
1834 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1835 return hr;
1837 desc.factory = font->family->collection->factory;
1838 desc.face_type = data->face_type;
1839 desc.files = &data->file;
1840 desc.files_number = 1;
1841 desc.index = data->face_index;
1842 desc.simulations = data->simulations;
1843 desc.font_data = data;
1844 hr = create_fontface(&desc, cached_list, fontface);
1846 IDWriteFontFileStream_Release(desc.stream);
1847 return hr;
1850 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1852 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1854 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1855 IsEqualIID(riid, &IID_IDWriteFont2) ||
1856 IsEqualIID(riid, &IID_IDWriteFont1) ||
1857 IsEqualIID(riid, &IID_IDWriteFont) ||
1858 IsEqualIID(riid, &IID_IUnknown))
1860 *obj = iface;
1861 IDWriteFont3_AddRef(iface);
1862 return S_OK;
1865 WARN("%s not implemented.\n", debugstr_guid(riid));
1867 *obj = NULL;
1868 return E_NOINTERFACE;
1871 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1873 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1874 ULONG refcount = InterlockedIncrement(&font->refcount);
1876 TRACE("%p, refcount %d.\n", iface, refcount);
1878 return refcount;
1881 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1883 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1884 ULONG refcount = InterlockedDecrement(&font->refcount);
1886 TRACE("%p, refcount %d.\n", iface, refcount);
1888 if (!refcount)
1890 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
1891 release_font_data(font->data);
1892 heap_free(font);
1895 return refcount;
1898 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1900 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1902 TRACE("%p, %p.\n", iface, family);
1904 *family = (IDWriteFontFamily *)font->family;
1905 IDWriteFontFamily_AddRef(*family);
1906 return S_OK;
1909 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1911 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1913 TRACE("%p.\n", iface);
1915 return font->data->weight;
1918 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1920 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1922 TRACE("%p.\n", iface);
1924 return font->data->stretch;
1927 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1929 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1931 TRACE("%p.\n", iface);
1933 return font->style;
1936 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1938 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1940 TRACE("%p.\n", iface);
1942 return !!(font->data->flags & FONT_IS_SYMBOL);
1945 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1947 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1949 TRACE("%p, %p.\n", iface, names);
1951 return clone_localizedstrings(font->data->names, names);
1954 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1955 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1957 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1958 struct dwrite_font_data *data = font->data;
1959 struct file_stream_desc stream_desc;
1961 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1963 /* Stream will be created if necessary. */
1964 stream_desc.stream = NULL;
1965 stream_desc.face_index = data->face_index;
1966 stream_desc.face_type = data->face_type;
1967 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1970 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1972 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1974 TRACE("%p.\n", iface);
1976 return font->data->simulations;
1979 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1981 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1983 TRACE("%p, %p.\n", iface, metrics);
1985 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
1988 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
1990 UINT16 glyph;
1991 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
1992 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
1993 return glyph != 0;
1996 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1998 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2000 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2002 *exists = dwritefont_has_character(font, ch);
2004 return S_OK;
2007 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2009 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2011 TRACE("%p, %p.\n", iface, fontface);
2013 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2016 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2018 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2020 TRACE("%p, %p.\n", iface, metrics);
2022 *metrics = font->data->metrics;
2025 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2027 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2029 TRACE("%p, %p.\n", iface, panose);
2031 *panose = font->data->panose;
2034 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2035 UINT32 *count)
2037 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2039 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2041 *count = 0;
2042 if (max_count && !ranges)
2043 return E_INVALIDARG;
2045 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2046 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2049 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2051 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2053 TRACE("%p.\n", iface);
2055 return !!(font->data->flags & FONT_IS_MONOSPACED);
2058 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2060 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2062 TRACE("%p.\n", iface);
2064 return !!(font->data->flags & FONT_IS_COLORED);
2067 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2069 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2071 TRACE("%p, %p.\n", iface, fontface);
2073 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2076 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2078 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2080 TRACE("%p, %p.\n", iface, other);
2082 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2083 return FALSE;
2085 return font->data->face_index == other_font->data->face_index
2086 && font->data->simulations == other_font->data->simulations
2087 && is_same_fontfile(font->data->file, other_font->data->file);
2090 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2092 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2094 TRACE("%p, %p.\n", iface, reference);
2096 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2097 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2098 (IDWriteFontFaceReference1 **)reference);
2101 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2103 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2105 TRACE("%p, %#x.\n", iface, ch);
2107 return dwritefont_has_character(font, ch);
2110 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2112 FIXME("%p: stub.\n", iface);
2114 return DWRITE_LOCALITY_LOCAL;
2117 static const IDWriteFont3Vtbl dwritefontvtbl = {
2118 dwritefont_QueryInterface,
2119 dwritefont_AddRef,
2120 dwritefont_Release,
2121 dwritefont_GetFontFamily,
2122 dwritefont_GetWeight,
2123 dwritefont_GetStretch,
2124 dwritefont_GetStyle,
2125 dwritefont_IsSymbolFont,
2126 dwritefont_GetFaceNames,
2127 dwritefont_GetInformationalStrings,
2128 dwritefont_GetSimulations,
2129 dwritefont_GetMetrics,
2130 dwritefont_HasCharacter,
2131 dwritefont_CreateFontFace,
2132 dwritefont1_GetMetrics,
2133 dwritefont1_GetPanose,
2134 dwritefont1_GetUnicodeRanges,
2135 dwritefont1_IsMonospacedFont,
2136 dwritefont2_IsColorFont,
2137 dwritefont3_CreateFontFace,
2138 dwritefont3_Equals,
2139 dwritefont3_GetFontFaceReference,
2140 dwritefont3_HasCharacter,
2141 dwritefont3_GetLocality
2144 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2146 if (!iface)
2147 return NULL;
2148 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2149 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2152 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2154 if (!iface)
2155 return NULL;
2156 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2157 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2160 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2162 if (!iface)
2163 return NULL;
2164 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2165 return NULL;
2166 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2167 IDWriteFontFaceReference1_iface);
2170 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2172 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2173 *lf = font->data->lf;
2176 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2178 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2179 *lf = fontface->lf;
2182 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2184 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2185 *fontsig = font->data->fontsig;
2186 return S_OK;
2189 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2191 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2192 *fontsig = fontface->fontsig;
2193 return S_OK;
2196 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2198 struct dwrite_font *object;
2200 *font = NULL;
2202 if (!(object = heap_alloc(sizeof(*object))))
2203 return E_OUTOFMEMORY;
2205 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2206 object->refcount = 1;
2207 object->family = family;
2208 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2209 object->data = family->data->fonts[index];
2210 object->style = object->data->style;
2211 addref_font_data(object->data);
2213 *font = &object->IDWriteFont3_iface;
2215 return S_OK;
2218 /* IDWriteFontList2 */
2219 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2221 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2223 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2224 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2225 IsEqualIID(riid, &IID_IDWriteFontList) ||
2226 IsEqualIID(riid, &IID_IUnknown))
2228 *obj = iface;
2229 IDWriteFontList2_AddRef(iface);
2230 return S_OK;
2233 WARN("%s not implemented.\n", debugstr_guid(riid));
2235 *obj = NULL;
2236 return E_NOINTERFACE;
2239 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2241 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2242 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2244 TRACE("%p, refcount %u.\n", iface, refcount);
2246 return refcount;
2249 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2251 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2252 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2254 TRACE("%p, refcount %u.\n", iface, refcount);
2256 if (!refcount)
2258 UINT32 i;
2260 for (i = 0; i < fontlist->font_count; i++)
2261 release_font_data(fontlist->fonts[i]);
2262 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2263 heap_free(fontlist->fonts);
2264 heap_free(fontlist);
2267 return refcount;
2270 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2272 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2273 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2276 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2278 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2280 TRACE("%p.\n", iface);
2282 return fontlist->font_count;
2285 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2287 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2289 TRACE("%p, %u, %p.\n", iface, index, font);
2291 *font = NULL;
2293 if (fontlist->font_count == 0)
2294 return S_FALSE;
2296 if (index >= fontlist->font_count)
2297 return E_INVALIDARG;
2299 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2302 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2304 FIXME("%p, %u.\n", iface, index);
2306 return DWRITE_LOCALITY_LOCAL;
2309 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2311 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2313 TRACE("%p, %u, %p.\n", iface, index, font);
2315 *font = NULL;
2317 if (fontlist->font_count == 0)
2318 return S_FALSE;
2320 if (index >= fontlist->font_count)
2321 return E_FAIL;
2323 return create_font(fontlist->family, index, font);
2326 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2327 IDWriteFontFaceReference **reference)
2329 IDWriteFont3 *font;
2330 HRESULT hr;
2332 TRACE("%p, %u, %p.\n", iface, index, reference);
2334 *reference = NULL;
2336 hr = IDWriteFontList2_GetFont(iface, index, &font);
2337 if (FAILED(hr))
2338 return hr;
2340 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2341 IDWriteFont3_Release(font);
2343 return hr;
2346 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2348 FIXME("%p, %p.\n", iface, fontset);
2350 return E_NOTIMPL;
2353 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2355 dwritefontlist_QueryInterface,
2356 dwritefontlist_AddRef,
2357 dwritefontlist_Release,
2358 dwritefontlist_GetFontCollection,
2359 dwritefontlist_GetFontCount,
2360 dwritefontlist_GetFont,
2361 dwritefontlist1_GetFontLocality,
2362 dwritefontlist1_GetFont,
2363 dwritefontlist1_GetFontFaceReference,
2364 dwritefontlist2_GetFontSet,
2367 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2369 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2371 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2373 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2374 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2375 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2376 IsEqualIID(riid, &IID_IUnknown))
2378 *obj = iface;
2380 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2381 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2382 IsEqualIID(riid, &IID_IDWriteFontList))
2384 *obj = &family->IDWriteFontList2_iface;
2386 else
2388 WARN("%s not implemented.\n", debugstr_guid(riid));
2389 *obj = NULL;
2390 return E_NOINTERFACE;
2393 IUnknown_AddRef((IUnknown *)*obj);
2394 return S_OK;
2397 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2399 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2400 ULONG refcount = InterlockedIncrement(&family->refcount);
2402 TRACE("%p, %u.\n", iface, refcount);
2404 return refcount;
2407 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2409 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2410 ULONG refcount = InterlockedDecrement(&family->refcount);
2412 TRACE("%p, %u.\n", iface, refcount);
2414 if (!refcount)
2416 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2417 release_fontfamily_data(family->data);
2418 heap_free(family);
2421 return refcount;
2424 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2426 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2428 TRACE("%p, %p.\n", iface, collection);
2430 *collection = (IDWriteFontCollection *)family->collection;
2431 IDWriteFontCollection_AddRef(*collection);
2432 return S_OK;
2435 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2437 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2439 TRACE("%p.\n", iface);
2441 return family->data->count;
2444 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2446 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2448 TRACE("%p, %u, %p.\n", iface, index, font);
2450 *font = NULL;
2452 if (!family->data->count)
2453 return S_FALSE;
2455 if (index >= family->data->count)
2456 return E_INVALIDARG;
2458 return create_font(family, index, (IDWriteFont3 **)font);
2461 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2463 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2465 TRACE("%p, %p.\n", iface, names);
2467 return clone_localizedstrings(family->data->familyname, names);
2470 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2471 const struct dwrite_font_propvec *req)
2473 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2474 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2475 FLOAT cur_req_prod, next_req_prod;
2477 if (next_to_req < cur_to_req)
2478 return TRUE;
2480 if (next_to_req > cur_to_req)
2481 return FALSE;
2483 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2484 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2486 if (next_req_prod > cur_req_prod)
2487 return TRUE;
2489 if (next_req_prod < cur_req_prod)
2490 return FALSE;
2492 if (next->stretch > cur->stretch)
2493 return TRUE;
2494 if (next->stretch < cur->stretch)
2495 return FALSE;
2497 if (next->style > cur->style)
2498 return TRUE;
2499 if (next->style < cur->style)
2500 return FALSE;
2502 if (next->weight > cur->weight)
2503 return TRUE;
2504 if (next->weight < cur->weight)
2505 return FALSE;
2507 /* full match, no reason to prefer new variant */
2508 return FALSE;
2511 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2512 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2514 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2515 struct dwrite_font_propvec req;
2516 size_t i, match;
2518 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2520 if (!family->data->count)
2522 *font = NULL;
2523 return DWRITE_E_NOFONT;
2526 init_font_prop_vec(weight, stretch, style, &req);
2527 match = 0;
2529 for (i = 1; i < family->data->count; ++i)
2531 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2532 match = i;
2535 return create_font(family, match, (IDWriteFont3 **)font);
2538 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2540 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2542 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2545 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2547 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2550 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2552 UINT32 b = fonts->font_count - 1, j, t;
2554 while (1) {
2555 t = b;
2557 for (j = 0; j < b; j++) {
2558 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2559 struct dwrite_font_data *s = fonts->fonts[j];
2560 fonts->fonts[j] = fonts->fonts[j+1];
2561 fonts->fonts[j+1] = s;
2562 t = j;
2566 if (t == b)
2567 break;
2568 b = t;
2572 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2573 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2575 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2576 matching_filter_func func = NULL;
2577 struct dwrite_font_propvec req;
2578 struct dwrite_fontlist *fonts;
2579 size_t i;
2581 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2583 *ret = NULL;
2585 fonts = heap_alloc(sizeof(*fonts));
2586 if (!fonts)
2587 return E_OUTOFMEMORY;
2589 /* Allocate as many as family has, not all of them will be necessary used. */
2590 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2591 if (!fonts->fonts) {
2592 heap_free(fonts);
2593 return E_OUTOFMEMORY;
2596 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2597 fonts->refcount = 1;
2598 fonts->family = family;
2599 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2600 fonts->font_count = 0;
2602 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2603 if (style == DWRITE_FONT_STYLE_NORMAL) {
2604 if (family->data->has_normal_face || family->data->has_italic_face)
2605 func = is_font_acceptable_for_normal;
2607 else /* requested oblique or italic */ {
2608 if (family->data->has_oblique_face || family->data->has_italic_face)
2609 func = is_font_acceptable_for_oblique_italic;
2612 for (i = 0; i < family->data->count; ++i)
2614 if (!func || func(family->data->fonts[i]))
2616 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2617 addref_font_data(family->data->fonts[i]);
2618 fonts->font_count++;
2622 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2623 init_font_prop_vec(weight, stretch, style, &req);
2624 matchingfonts_sort(fonts, &req);
2626 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2627 return S_OK;
2630 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2632 FIXME("%p, %u.\n", iface, index);
2634 return DWRITE_LOCALITY_LOCAL;
2637 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2639 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2641 TRACE("%p, %u, %p.\n", iface, index, font);
2643 *font = NULL;
2645 if (!family->data->count)
2646 return S_FALSE;
2648 if (index >= family->data->count)
2649 return E_FAIL;
2651 return create_font(family, index, font);
2654 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2655 IDWriteFontFaceReference **reference)
2657 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2658 const struct dwrite_font_data *font;
2660 TRACE("%p, %u, %p.\n", iface, index, reference);
2662 *reference = NULL;
2664 if (index >= family->data->count)
2665 return E_FAIL;
2667 font = family->data->fonts[index];
2668 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2669 font->file, font->face_index, font->simulations, reference);
2672 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2673 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2675 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2677 return E_NOTIMPL;
2680 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2682 FIXME("%p, %p.\n", iface, fontset);
2684 return E_NOTIMPL;
2687 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2689 dwritefontfamily_QueryInterface,
2690 dwritefontfamily_AddRef,
2691 dwritefontfamily_Release,
2692 dwritefontfamily_GetFontCollection,
2693 dwritefontfamily_GetFontCount,
2694 dwritefontfamily_GetFont,
2695 dwritefontfamily_GetFamilyNames,
2696 dwritefontfamily_GetFirstMatchingFont,
2697 dwritefontfamily_GetMatchingFonts,
2698 dwritefontfamily1_GetFontLocality,
2699 dwritefontfamily1_GetFont,
2700 dwritefontfamily1_GetFontFaceReference,
2701 dwritefontfamily2_GetMatchingFonts,
2702 dwritefontfamily2_GetFontSet,
2705 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2707 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2708 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2711 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2713 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2714 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2717 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2719 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2720 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2723 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2724 IDWriteFontCollection **collection)
2726 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2727 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2730 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2732 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2733 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2736 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2738 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2739 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2742 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2744 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2745 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2748 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2750 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2751 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2754 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2755 IDWriteFontFaceReference **reference)
2757 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2758 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2761 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2763 FIXME("%p, %p.\n", iface, fontset);
2765 return E_NOTIMPL;
2768 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2770 dwritefontfamilylist_QueryInterface,
2771 dwritefontfamilylist_AddRef,
2772 dwritefontfamilylist_Release,
2773 dwritefontfamilylist_GetFontCollection,
2774 dwritefontfamilylist_GetFontCount,
2775 dwritefontfamilylist_GetFont,
2776 dwritefontfamilylist1_GetFontLocality,
2777 dwritefontfamilylist1_GetFont,
2778 dwritefontfamilylist1_GetFontFaceReference,
2779 dwritefontfamilylist2_GetFontSet,
2782 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2783 struct dwrite_fontfamily **family)
2785 struct dwrite_fontfamily *object;
2787 *family = NULL;
2789 object = heap_alloc(sizeof(*object));
2790 if (!object)
2791 return E_OUTOFMEMORY;
2793 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2794 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2795 object->refcount = 1;
2796 object->collection = collection;
2797 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2798 object->data = collection->family_data[index];
2799 InterlockedIncrement(&object->data->refcount);
2801 *family = object;
2803 return S_OK;
2806 BOOL is_system_collection(IDWriteFontCollection *collection)
2808 void *obj;
2809 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2812 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2814 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2816 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2818 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2819 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2820 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2821 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2822 IsEqualIID(riid, &IID_IUnknown))
2824 *obj = iface;
2825 IDWriteFontCollection3_AddRef(iface);
2826 return S_OK;
2829 *obj = NULL;
2831 if (IsEqualIID(riid, &IID_issystemcollection))
2832 return S_OK;
2834 WARN("%s not implemented.\n", debugstr_guid(riid));
2836 return E_NOINTERFACE;
2839 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2841 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2843 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2844 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2845 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2846 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2847 IsEqualIID(riid, &IID_IUnknown))
2849 *obj = iface;
2850 IDWriteFontCollection3_AddRef(iface);
2851 return S_OK;
2854 WARN("%s not implemented.\n", debugstr_guid(riid));
2856 *obj = NULL;
2858 return E_NOINTERFACE;
2861 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2863 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2864 ULONG refcount = InterlockedIncrement(&collection->refcount);
2866 TRACE("%p, refcount %d.\n", collection, refcount);
2868 return refcount;
2871 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2873 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2874 ULONG refcount = InterlockedDecrement(&collection->refcount);
2875 size_t i;
2877 TRACE("%p, refcount %d.\n", iface, refcount);
2879 if (!refcount)
2881 factory_detach_fontcollection(collection->factory, iface);
2882 for (i = 0; i < collection->count; ++i)
2883 release_fontfamily_data(collection->family_data[i]);
2884 heap_free(collection->family_data);
2885 heap_free(collection);
2888 return refcount;
2891 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2893 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2895 TRACE("%p.\n", iface);
2897 return collection->count;
2900 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2901 IDWriteFontFamily **ret)
2903 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2904 struct dwrite_fontfamily *family;
2905 HRESULT hr;
2907 TRACE("%p, %u, %p.\n", iface, index, ret);
2909 *ret = NULL;
2911 if (index >= collection->count)
2912 return E_FAIL;
2914 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2915 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2917 return hr;
2920 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2922 size_t i;
2924 for (i = 0; i < collection->count; ++i)
2926 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2927 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2928 HRESULT hr;
2930 for (j = 0; j < count; j++) {
2931 WCHAR buffer[255];
2932 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2933 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2934 return i;
2938 return ~0u;
2941 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2942 UINT32 *index, BOOL *exists)
2944 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2946 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2948 *index = collection_find_family(collection, name);
2949 *exists = *index != ~0u;
2950 return S_OK;
2953 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2954 IDWriteFont **font)
2956 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2957 struct dwrite_fontfamily *family;
2958 BOOL found_font = FALSE;
2959 IDWriteFontFile *file;
2960 UINT32 face_index, count;
2961 size_t i, j;
2962 HRESULT hr;
2964 TRACE("%p, %p, %p.\n", iface, face, font);
2966 *font = NULL;
2968 if (!face)
2969 return E_INVALIDARG;
2971 count = 1;
2972 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2973 if (FAILED(hr))
2974 return hr;
2975 face_index = IDWriteFontFace_GetIndex(face);
2977 found_font = FALSE;
2978 for (i = 0; i < collection->count; ++i)
2980 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2982 for (j = 0; j < family_data->count; ++j)
2984 struct dwrite_font_data *font_data = family_data->fonts[j];
2986 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2987 found_font = TRUE;
2988 break;
2992 if (found_font)
2993 break;
2995 IDWriteFontFile_Release(file);
2997 if (!found_font)
2998 return DWRITE_E_NOFONT;
3000 hr = create_fontfamily(collection, i, &family);
3001 if (FAILED(hr))
3002 return hr;
3004 hr = create_font(family, j, (IDWriteFont3 **)font);
3005 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3006 return hr;
3009 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3011 FIXME("%p, %p.\n", iface, fontset);
3013 return E_NOTIMPL;
3016 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3017 IDWriteFontFamily1 **ret)
3019 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3020 struct dwrite_fontfamily *family;
3021 HRESULT hr;
3023 TRACE("%p, %u, %p.\n", iface, index, ret);
3025 *ret = NULL;
3027 if (index >= collection->count)
3028 return E_FAIL;
3030 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3031 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3033 return hr;
3036 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3037 UINT32 index, IDWriteFontFamily2 **ret)
3039 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3040 struct dwrite_fontfamily *family;
3041 HRESULT hr;
3043 TRACE("%p, %u, %p.\n", iface, index, ret);
3045 *ret = NULL;
3047 if (index >= collection->count)
3048 return E_FAIL;
3050 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3051 *ret = &family->IDWriteFontFamily2_iface;
3053 return hr;
3056 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3057 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3058 IDWriteFontList2 **fontlist)
3060 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3062 return E_NOTIMPL;
3065 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3067 FIXME("%p.\n", iface);
3069 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3072 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3074 FIXME("%p, %p.\n", iface, fontset);
3076 return E_NOTIMPL;
3079 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3081 FIXME("%p.\n", iface);
3083 return NULL;
3086 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3088 dwritefontcollection_QueryInterface,
3089 dwritefontcollection_AddRef,
3090 dwritefontcollection_Release,
3091 dwritefontcollection_GetFontFamilyCount,
3092 dwritefontcollection_GetFontFamily,
3093 dwritefontcollection_FindFamilyName,
3094 dwritefontcollection_GetFontFromFontFace,
3095 dwritefontcollection1_GetFontSet,
3096 dwritefontcollection1_GetFontFamily,
3097 dwritefontcollection2_GetFontFamily,
3098 dwritefontcollection2_GetMatchingFonts,
3099 dwritefontcollection2_GetFontFamilyModel,
3100 dwritefontcollection2_GetFontSet,
3101 dwritefontcollection3_GetExpirationEvent,
3104 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3106 dwritesystemfontcollection_QueryInterface,
3107 dwritefontcollection_AddRef,
3108 dwritefontcollection_Release,
3109 dwritefontcollection_GetFontFamilyCount,
3110 dwritefontcollection_GetFontFamily,
3111 dwritefontcollection_FindFamilyName,
3112 dwritefontcollection_GetFontFromFontFace,
3113 dwritefontcollection1_GetFontSet,
3114 dwritefontcollection1_GetFontFamily,
3115 dwritefontcollection2_GetFontFamily,
3116 dwritefontcollection2_GetMatchingFonts,
3117 dwritefontcollection2_GetFontFamilyModel,
3118 dwritefontcollection2_GetFontSet,
3119 dwritefontcollection3_GetExpirationEvent,
3122 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3124 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3125 sizeof(*family_data->fonts)))
3127 return E_OUTOFMEMORY;
3130 family_data->fonts[family_data->count++] = font_data;
3131 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3132 family_data->has_normal_face = 1;
3133 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3134 family_data->has_oblique_face = 1;
3135 else
3136 family_data->has_italic_face = 1;
3137 return S_OK;
3140 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3141 struct dwrite_fontfamily_data *family)
3143 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3144 sizeof(*collection->family_data)))
3146 return E_OUTOFMEMORY;
3149 collection->family_data[collection->count++] = family;
3150 return S_OK;
3153 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3155 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3156 collection->refcount = 1;
3157 collection->count = 0;
3158 collection->size = 0;
3159 collection->family_data = NULL;
3161 return S_OK;
3164 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3166 IDWriteFontFileLoader *loader;
3167 const void *key;
3168 UINT32 key_size;
3169 HRESULT hr;
3171 *stream = NULL;
3173 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3174 if (FAILED(hr))
3175 return hr;
3177 hr = IDWriteFontFile_GetLoader(file, &loader);
3178 if (FAILED(hr))
3179 return hr;
3181 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3182 IDWriteFontFileLoader_Release(loader);
3183 if (FAILED(hr))
3184 return hr;
3186 return hr;
3189 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3191 BOOL exists = FALSE;
3192 UINT32 index;
3193 HRESULT hr;
3195 buffer[0] = 0;
3196 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3197 if (FAILED(hr) || !exists)
3198 return;
3200 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3203 static int trim_spaces(WCHAR *in, WCHAR *ret)
3205 int len;
3207 while (isspaceW(*in))
3208 in++;
3210 ret[0] = 0;
3211 if (!(len = strlenW(in)))
3212 return 0;
3214 while (isspaceW(in[len-1]))
3215 len--;
3217 memcpy(ret, in, len*sizeof(WCHAR));
3218 ret[len] = 0;
3220 return len;
3223 struct name_token {
3224 struct list entry;
3225 const WCHAR *ptr;
3226 INT len; /* token length */
3227 INT fulllen; /* full length including following separators */
3230 static inline BOOL is_name_separator_char(WCHAR ch)
3232 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3235 struct name_pattern {
3236 const WCHAR *part1; /* NULL indicates end of list */
3237 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3240 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3242 const struct name_pattern *pattern;
3243 struct name_token *token;
3244 int i = 0;
3246 while ((pattern = &patterns[i++])->part1) {
3247 int len_part1 = strlenW(pattern->part1);
3248 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3250 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3251 if (len_part2 == 0) {
3252 /* simple case with single part pattern */
3253 if (token->len != len_part1)
3254 continue;
3256 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3257 if (match) *match = *token;
3258 list_remove(&token->entry);
3259 heap_free(token);
3260 return TRUE;
3263 else {
3264 struct name_token *next_token;
3265 struct list *next_entry;
3267 /* pattern parts are stored in reading order, tokens list is reversed */
3268 if (token->len < len_part2)
3269 continue;
3271 /* it's possible to have combined string as a token, like ExtraCondensed */
3272 if (token->len == len_part1 + len_part2) {
3273 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3274 continue;
3276 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3277 continue;
3279 /* combined string match */
3280 if (match) *match = *token;
3281 list_remove(&token->entry);
3282 heap_free(token);
3283 return TRUE;
3286 /* now it's only possible to have two tokens matched to respective pattern parts */
3287 if (token->len != len_part2)
3288 continue;
3290 next_entry = list_next(tokens, &token->entry);
3291 if (next_entry) {
3292 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3293 if (next_token->len != len_part1)
3294 continue;
3296 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3297 continue;
3299 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3300 continue;
3302 /* both parts matched, remove tokens */
3303 if (match) {
3304 match->ptr = next_token->ptr;
3305 match->len = (token->ptr - next_token->ptr) + token->len;
3307 list_remove(&token->entry);
3308 list_remove(&next_token->entry);
3309 heap_free(next_token);
3310 heap_free(token);
3311 return TRUE;
3317 if (match) {
3318 match->ptr = NULL;
3319 match->len = 0;
3321 return FALSE;
3324 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3326 static const WCHAR itaW[] = {'i','t','a',0};
3327 static const WCHAR italW[] = {'i','t','a','l',0};
3328 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3329 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3331 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3332 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3333 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3334 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3336 static const struct name_pattern italic_patterns[] = {
3337 { itaW },
3338 { italW },
3339 { italicW },
3340 { cursiveW },
3341 { kursivW },
3342 { NULL }
3345 static const struct name_pattern oblique_patterns[] = {
3346 { inclinedW },
3347 { obliqueW },
3348 { backslantedW },
3349 { backslantW },
3350 { slantedW },
3351 { NULL }
3354 /* italic patterns first */
3355 if (match_pattern_list(tokens, italic_patterns, match))
3356 return DWRITE_FONT_STYLE_ITALIC;
3358 /* oblique patterns */
3359 if (match_pattern_list(tokens, oblique_patterns, match))
3360 return DWRITE_FONT_STYLE_OBLIQUE;
3362 return style;
3365 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3366 struct name_token *match)
3368 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3369 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3370 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3371 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3372 static const WCHAR wideW[] = {'w','i','d','e',0};
3373 static const WCHAR condW[] = {'c','o','n','d',0};
3375 static const struct name_pattern ultracondensed_patterns[] = {
3376 { extraW, compressedW },
3377 { extW, compressedW },
3378 { ultraW, compressedW },
3379 { ultraW, condensedW },
3380 { ultraW, condW },
3381 { NULL }
3384 static const struct name_pattern extracondensed_patterns[] = {
3385 { compressedW },
3386 { extraW, condensedW },
3387 { extW, condensedW },
3388 { extraW, condW },
3389 { extW, condW },
3390 { NULL }
3393 static const struct name_pattern semicondensed_patterns[] = {
3394 { narrowW },
3395 { compactW },
3396 { semiW, condensedW },
3397 { semiW, condW },
3398 { NULL }
3401 static const struct name_pattern semiexpanded_patterns[] = {
3402 { wideW },
3403 { semiW, expandedW },
3404 { semiW, extendedW },
3405 { NULL }
3408 static const struct name_pattern extraexpanded_patterns[] = {
3409 { extraW, expandedW },
3410 { extW, expandedW },
3411 { extraW, extendedW },
3412 { extW, extendedW },
3413 { NULL }
3416 static const struct name_pattern ultraexpanded_patterns[] = {
3417 { ultraW, expandedW },
3418 { ultraW, extendedW },
3419 { NULL }
3422 static const struct name_pattern condensed_patterns[] = {
3423 { condensedW },
3424 { condW },
3425 { NULL }
3428 static const struct name_pattern expanded_patterns[] = {
3429 { expandedW },
3430 { extendedW },
3431 { NULL }
3434 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3435 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3437 if (match_pattern_list(tokens, extracondensed_patterns, match))
3438 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3440 if (match_pattern_list(tokens, semicondensed_patterns, match))
3441 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3443 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3444 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3446 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3447 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3449 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3450 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3452 if (match_pattern_list(tokens, condensed_patterns, match))
3453 return DWRITE_FONT_STRETCH_CONDENSED;
3455 if (match_pattern_list(tokens, expanded_patterns, match))
3456 return DWRITE_FONT_STRETCH_EXPANDED;
3458 return stretch;
3461 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3462 struct name_token *match)
3464 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3465 static const WCHAR nordW[] = {'n','o','r','d',0};
3467 static const struct name_pattern thin_patterns[] = {
3468 { extraW, thinW },
3469 { extW, thinW },
3470 { ultraW, thinW },
3471 { NULL }
3474 static const struct name_pattern extralight_patterns[] = {
3475 { extraW, lightW },
3476 { extW, lightW },
3477 { ultraW, lightW },
3478 { NULL }
3481 static const struct name_pattern semilight_patterns[] = {
3482 { semiW, lightW },
3483 { NULL }
3486 static const struct name_pattern demibold_patterns[] = {
3487 { semiW, boldW },
3488 { demiW, boldW },
3489 { NULL }
3492 static const struct name_pattern extrabold_patterns[] = {
3493 { extraW, boldW },
3494 { extW, boldW },
3495 { ultraW, boldW },
3496 { NULL }
3499 static const struct name_pattern extrablack_patterns[] = {
3500 { extraW, blackW },
3501 { extW, blackW },
3502 { ultraW, blackW },
3503 { NULL }
3506 static const struct name_pattern bold_patterns[] = {
3507 { boldW },
3508 { NULL }
3511 static const struct name_pattern thin2_patterns[] = {
3512 { thinW },
3513 { NULL }
3516 static const struct name_pattern light_patterns[] = {
3517 { lightW },
3518 { NULL }
3521 static const struct name_pattern medium_patterns[] = {
3522 { mediumW },
3523 { NULL }
3526 static const struct name_pattern black_patterns[] = {
3527 { blackW },
3528 { heavyW },
3529 { nordW },
3530 { NULL }
3533 static const struct name_pattern demibold2_patterns[] = {
3534 { demiW },
3535 { NULL }
3538 static const struct name_pattern extrabold2_patterns[] = {
3539 { ultraW },
3540 { NULL }
3543 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3544 matching pattern. */
3546 if (match_pattern_list(tokens, thin_patterns, match))
3547 return DWRITE_FONT_WEIGHT_THIN;
3549 if (match_pattern_list(tokens, extralight_patterns, match))
3550 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3552 if (match_pattern_list(tokens, semilight_patterns, match))
3553 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3555 if (match_pattern_list(tokens, demibold_patterns, match))
3556 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3558 if (match_pattern_list(tokens, extrabold_patterns, match))
3559 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3561 if (match_pattern_list(tokens, extrablack_patterns, match))
3562 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3564 if (match_pattern_list(tokens, bold_patterns, match))
3565 return DWRITE_FONT_WEIGHT_BOLD;
3567 if (match_pattern_list(tokens, thin2_patterns, match))
3568 return DWRITE_FONT_WEIGHT_THIN;
3570 if (match_pattern_list(tokens, light_patterns, match))
3571 return DWRITE_FONT_WEIGHT_LIGHT;
3573 if (match_pattern_list(tokens, medium_patterns, match))
3574 return DWRITE_FONT_WEIGHT_MEDIUM;
3576 if (match_pattern_list(tokens, black_patterns, match))
3577 return DWRITE_FONT_WEIGHT_BLACK;
3579 if (match_pattern_list(tokens, black_patterns, match))
3580 return DWRITE_FONT_WEIGHT_BLACK;
3582 if (match_pattern_list(tokens, demibold2_patterns, match))
3583 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3585 if (match_pattern_list(tokens, extrabold2_patterns, match))
3586 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3588 /* FIXME: use abbreviated names to extract weight */
3590 return weight;
3593 struct knownweight_entry {
3594 const WCHAR *nameW;
3595 DWRITE_FONT_WEIGHT weight;
3598 static int compare_knownweights(const void *a, const void* b)
3600 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3601 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3602 int ret = 0;
3604 if (target > entry->weight)
3605 ret = 1;
3606 else if (target < entry->weight)
3607 ret = -1;
3609 return ret;
3612 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3614 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3615 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3616 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3617 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3618 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3619 const struct knownweight_entry *ptr;
3621 static const struct knownweight_entry knownweights[] = {
3622 { thinW, DWRITE_FONT_WEIGHT_THIN },
3623 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3624 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3625 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3626 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3627 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3628 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3629 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3630 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3631 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3634 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3635 compare_knownweights);
3636 if (!ptr) {
3637 nameW[0] = 0;
3638 return FALSE;
3641 strcpyW(nameW, ptr->nameW);
3642 return TRUE;
3645 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3647 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3648 strW[name->len] = 0;
3651 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3652 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3654 static const WCHAR bookW[] = {'B','o','o','k',0};
3655 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3656 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3657 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3658 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3660 static const WCHAR *regular_patterns[] = {
3661 bookW,
3662 normalW,
3663 regularW,
3664 romanW,
3665 uprightW,
3666 NULL
3669 const WCHAR *regular_ptr = NULL, *ptr;
3670 int i = 0;
3672 if (len == -1)
3673 len = strlenW(facenameW);
3675 /* remove rightmost regular variant from face name */
3676 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3677 int pattern_len = strlenW(ptr);
3678 WCHAR *src;
3680 if (pattern_len > len)
3681 continue;
3683 src = facenameW + len - pattern_len;
3684 while (src >= facenameW) {
3685 if (!strncmpiW(src, ptr, pattern_len)) {
3686 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3687 len = strlenW(facenameW);
3688 regular_ptr = ptr;
3689 break;
3691 else
3692 src--;
3696 return regular_ptr;
3699 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3701 const WCHAR *ptr;
3703 list_init(tokens);
3704 ptr = nameW;
3706 while (*ptr) {
3707 struct name_token *token = heap_alloc(sizeof(*token));
3708 token->ptr = ptr;
3709 token->len = 0;
3710 token->fulllen = 0;
3712 while (*ptr && !is_name_separator_char(*ptr)) {
3713 token->len++;
3714 token->fulllen++;
3715 ptr++;
3718 /* skip separators */
3719 while (is_name_separator_char(*ptr)) {
3720 token->fulllen++;
3721 ptr++;
3724 list_add_head(tokens, &token->entry);
3728 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3730 struct name_token *token, *token2;
3731 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3732 int len;
3734 list_remove(&token->entry);
3736 /* don't include last separator */
3737 len = list_empty(tokens) ? token->len : token->fulllen;
3738 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3739 nameW += len;
3741 heap_free(token);
3743 *nameW = 0;
3746 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3748 struct name_token stretch_name, weight_name, style_name;
3749 WCHAR familynameW[255], facenameW[255], finalW[255];
3750 WCHAR weightW[32], stretchW[32], styleW[32];
3751 const WCHAR *regular_ptr = NULL;
3752 DWRITE_FONT_STRETCH stretch;
3753 DWRITE_FONT_WEIGHT weight;
3754 struct list tokens;
3755 int len;
3757 /* remove leading and trailing spaces from family and face name */
3758 trim_spaces(familyW, familynameW);
3759 len = trim_spaces(faceW, facenameW);
3761 /* remove rightmost regular variant from face name */
3762 regular_ptr = facename_remove_regular_term(facenameW, len);
3764 /* append face name to family name, FIXME check if face name is a substring of family name */
3765 if (*facenameW) {
3766 strcatW(familynameW, spaceW);
3767 strcatW(familynameW, facenameW);
3770 /* tokenize with " .-_" */
3771 fontname_tokenize(&tokens, familynameW);
3773 /* extract and resolve style */
3774 font->style = font_extract_style(&tokens, font->style, &style_name);
3776 /* extract stretch */
3777 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3779 /* extract weight */
3780 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3782 /* resolve weight */
3783 if (weight != font->weight) {
3784 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3785 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3786 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3787 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3788 !(abs(weight - font->weight) <= 150 &&
3789 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3790 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3791 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3793 font->weight = weight;
3797 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3798 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3799 stretch itself is normal (extracted stretch is never normal). */
3800 if (stretch != font->stretch) {
3801 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3802 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3803 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3805 font->stretch = stretch;
3809 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3811 /* get final combined string from what's left in token list, list is released */
3812 fontname_tokens_to_str(&tokens, finalW);
3814 if (!strcmpW(familyW, finalW))
3815 return FALSE;
3817 /* construct face name */
3818 strcpyW(familyW, finalW);
3820 /* resolved weight name */
3821 if (weight_name.ptr)
3822 font_name_token_to_str(&weight_name, weightW);
3823 /* ignore normal weight */
3824 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3825 weightW[0] = 0;
3826 /* for known weight values use appropriate names */
3827 else if (is_known_weight_value(font->weight, weightW)) {
3829 /* use Wnnn format as a fallback in case weight is not one of known values */
3830 else {
3831 static const WCHAR fmtW[] = {'W','%','d',0};
3832 sprintfW(weightW, fmtW, font->weight);
3835 /* resolved stretch name */
3836 if (stretch_name.ptr)
3837 font_name_token_to_str(&stretch_name, stretchW);
3838 /* ignore normal stretch */
3839 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3840 stretchW[0] = 0;
3841 /* use predefined stretch names */
3842 else {
3843 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3844 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3845 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3846 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3847 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3848 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3850 static const WCHAR *stretchnamesW[] = {
3851 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3852 ultracondensedW,
3853 extracondensedW,
3854 condensedW,
3855 semicondensedW,
3856 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3857 semiexpandedW,
3858 expandedW,
3859 extraexpandedW,
3860 ultraexpandedW
3862 strcpyW(stretchW, stretchnamesW[font->stretch]);
3865 /* resolved style name */
3866 if (style_name.ptr)
3867 font_name_token_to_str(&style_name, styleW);
3868 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3869 styleW[0] = 0;
3870 /* use predefined names */
3871 else {
3872 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3873 strcpyW(styleW, italicW);
3874 else
3875 strcpyW(styleW, obliqueW);
3878 /* use Regular match if it was found initially */
3879 if (!*weightW && !*stretchW && !*styleW)
3880 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3881 else {
3882 faceW[0] = 0;
3883 if (*stretchW)
3884 strcpyW(faceW, stretchW);
3885 if (*weightW) {
3886 if (*faceW)
3887 strcatW(faceW, spaceW);
3888 strcatW(faceW, weightW);
3890 if (*styleW) {
3891 if (*faceW)
3892 strcatW(faceW, spaceW);
3893 strcatW(faceW, styleW);
3897 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3898 return TRUE;
3901 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3903 static const float width_axis_values[] =
3905 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3906 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3907 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3908 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3909 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3910 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3911 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3912 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3913 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3914 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3917 struct file_stream_desc stream_desc;
3918 struct dwrite_font_props props;
3919 struct dwrite_font_data *data;
3920 WCHAR familyW[255], faceW[255];
3921 HRESULT hr;
3923 *ret = NULL;
3925 data = heap_alloc_zero(sizeof(*data));
3926 if (!data)
3927 return E_OUTOFMEMORY;
3929 data->ref = 1;
3930 data->file = desc->files[0];
3931 data->face_index = desc->index;
3932 data->face_type = desc->face_type;
3933 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3934 data->bold_sim_tested = 0;
3935 data->oblique_sim_tested = 0;
3936 IDWriteFontFile_AddRef(data->file);
3938 stream_desc.stream = desc->stream;
3939 stream_desc.face_type = desc->face_type;
3940 stream_desc.face_index = desc->index;
3941 opentype_get_font_properties(&stream_desc, &props);
3942 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3943 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3945 /* get family name from font file */
3946 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3947 if (FAILED(hr)) {
3948 WARN("unable to get family name from font\n");
3949 release_font_data(data);
3950 return hr;
3953 data->style = props.style;
3954 data->stretch = props.stretch;
3955 data->weight = props.weight;
3956 data->panose = props.panose;
3957 data->fontsig = props.fontsig;
3958 data->lf = props.lf;
3959 data->flags = props.flags;
3961 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3962 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3963 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3964 set_en_localizedstring(data->family_names, familyW);
3965 set_en_localizedstring(data->names, faceW);
3968 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3970 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
3971 data->axis[0].value = props.weight;
3972 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
3973 data->axis[1].value = width_axis_values[props.stretch];
3974 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
3975 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
3977 *ret = data;
3978 return S_OK;
3981 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3982 const WCHAR *facenameW, struct dwrite_font_data **ret)
3984 struct dwrite_font_data *data;
3986 *ret = NULL;
3988 data = heap_alloc_zero(sizeof(*data));
3989 if (!data)
3990 return E_OUTOFMEMORY;
3992 *data = *src;
3993 data->ref = 1;
3994 data->simulations |= sim;
3995 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3996 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3997 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3998 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3999 memset(data->info_strings, 0, sizeof(data->info_strings));
4000 data->names = NULL;
4001 IDWriteFontFile_AddRef(data->file);
4002 IDWriteLocalizedStrings_AddRef(data->family_names);
4004 create_localizedstrings(&data->names);
4005 add_localizedstring(data->names, enusW, facenameW);
4007 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4009 *ret = data;
4010 return S_OK;
4013 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4015 struct dwrite_fontfamily_data *data;
4017 data = heap_alloc_zero(sizeof(*data));
4018 if (!data)
4019 return E_OUTOFMEMORY;
4021 data->refcount = 1;
4022 data->familyname = familyname;
4023 IDWriteLocalizedStrings_AddRef(familyname);
4025 *ret = data;
4027 return S_OK;
4030 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4032 size_t i, j, heaviest;
4034 for (i = 0; i < family->count; ++i)
4036 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4037 heaviest = i;
4039 if (family->fonts[i]->bold_sim_tested)
4040 continue;
4042 family->fonts[i]->bold_sim_tested = 1;
4043 for (j = i; j < family->count; ++j)
4045 if (family->fonts[j]->bold_sim_tested)
4046 continue;
4048 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4049 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4050 if (family->fonts[j]->weight > weight) {
4051 weight = family->fonts[j]->weight;
4052 heaviest = j;
4054 family->fonts[j]->bold_sim_tested = 1;
4058 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4059 static const struct name_pattern weightsim_patterns[] = {
4060 { extraW, lightW },
4061 { extW, lightW },
4062 { ultraW, lightW },
4063 { semiW, lightW },
4064 { semiW, boldW },
4065 { demiW, boldW },
4066 { boldW },
4067 { thinW },
4068 { lightW },
4069 { mediumW },
4070 { demiW },
4071 { NULL }
4074 WCHAR facenameW[255], initialW[255];
4075 struct dwrite_font_data *boldface;
4076 struct list tokens;
4078 /* add Bold simulation based on heaviest face data */
4080 /* Simulated face name should only contain Bold as weight term,
4081 so remove existing regular and weight terms. */
4082 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4083 facename_remove_regular_term(initialW, -1);
4085 /* remove current weight pattern */
4086 fontname_tokenize(&tokens, initialW);
4087 match_pattern_list(&tokens, weightsim_patterns, NULL);
4088 fontname_tokens_to_str(&tokens, facenameW);
4090 /* Bold suffix for new name */
4091 if (*facenameW)
4092 strcatW(facenameW, spaceW);
4093 strcatW(facenameW, boldW);
4095 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4096 boldface->bold_sim_tested = 1;
4097 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4098 fontfamily_add_font(family, boldface);
4104 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4106 size_t i, j;
4108 for (i = 0; i < family->count; ++i)
4110 UINT32 regular = ~0u, oblique = ~0u;
4111 struct dwrite_font_data *obliqueface;
4112 WCHAR facenameW[255];
4114 if (family->fonts[i]->oblique_sim_tested)
4115 continue;
4117 family->fonts[i]->oblique_sim_tested = 1;
4118 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4119 regular = i;
4120 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4121 oblique = i;
4123 /* find regular style with same weight/stretch values */
4124 for (j = i; j < family->count; ++j)
4126 if (family->fonts[j]->oblique_sim_tested)
4127 continue;
4129 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4130 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4132 family->fonts[j]->oblique_sim_tested = 1;
4133 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4134 regular = j;
4136 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4137 oblique = j;
4140 if (regular != ~0u && oblique != ~0u)
4141 break;
4144 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4145 if (regular == ~0u)
4146 continue;
4148 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4149 if (oblique != ~0u)
4150 continue;
4152 /* add oblique simulation based on this regular face */
4154 /* remove regular term if any, append 'Oblique' */
4155 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4156 facename_remove_regular_term(facenameW, -1);
4158 if (*facenameW)
4159 strcatW(facenameW, spaceW);
4160 strcatW(facenameW, obliqueW);
4162 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4163 obliqueface->oblique_sim_tested = 1;
4164 obliqueface->lf.lfItalic = 1;
4165 fontfamily_add_font(family, obliqueface);
4170 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4171 const WCHAR *replacement_name)
4173 UINT32 i = collection_find_family(collection, replacement_name);
4174 struct dwrite_fontfamily_data *target;
4175 IDWriteLocalizedStrings *strings;
4176 HRESULT hr;
4178 /* replacement does not exist */
4179 if (i == ~0u)
4180 return FALSE;
4182 hr = create_localizedstrings(&strings);
4183 if (FAILED(hr))
4184 return FALSE;
4186 /* add a new family with target name, reuse font data from replacement */
4187 add_localizedstring(strings, enusW, target_name);
4188 hr = init_fontfamily_data(strings, &target);
4189 if (hr == S_OK) {
4190 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4191 WCHAR nameW[255];
4193 for (i = 0; i < replacement->count; ++i)
4195 fontfamily_add_font(target, replacement->fonts[i]);
4196 addref_font_data(replacement->fonts[i]);
4199 fontcollection_add_family(collection, target);
4200 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4201 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4203 IDWriteLocalizedStrings_Release(strings);
4204 return TRUE;
4207 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4208 system font collections. */
4209 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4211 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4212 WCHAR *name;
4213 void *data;
4214 HKEY hkey;
4216 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4217 return;
4219 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4220 RegCloseKey(hkey);
4221 return;
4224 max_namelen++; /* returned value doesn't include room for '\0' */
4225 name = heap_alloc(max_namelen * sizeof(WCHAR));
4226 data = heap_alloc(max_datalen);
4228 datalen = max_datalen;
4229 namelen = max_namelen;
4230 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4231 if (collection_find_family(collection, name) == ~0u) {
4232 if (type == REG_MULTI_SZ) {
4233 WCHAR *replacement = data;
4234 while (*replacement) {
4235 if (fontcollection_add_replacement(collection, name, replacement))
4236 break;
4237 replacement += strlenW(replacement) + 1;
4240 else if (type == REG_SZ)
4241 fontcollection_add_replacement(collection, name, data);
4243 else
4244 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4246 datalen = max_datalen;
4247 namelen = max_namelen;
4250 heap_free(data);
4251 heap_free(name);
4252 RegCloseKey(hkey);
4255 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4256 IDWriteFontCollection3 **ret)
4258 struct fontfile_enum {
4259 struct list entry;
4260 IDWriteFontFile *file;
4262 struct fontfile_enum *fileenum, *fileenum2;
4263 struct dwrite_fontcollection *collection;
4264 struct list scannedfiles;
4265 BOOL current = FALSE;
4266 HRESULT hr = S_OK;
4267 size_t i;
4269 *ret = NULL;
4271 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4272 if (!collection) return E_OUTOFMEMORY;
4274 hr = init_font_collection(collection, is_system);
4275 if (FAILED(hr)) {
4276 heap_free(collection);
4277 return hr;
4280 *ret = &collection->IDWriteFontCollection3_iface;
4282 TRACE("building font collection:\n");
4284 list_init(&scannedfiles);
4285 while (hr == S_OK) {
4286 DWRITE_FONT_FACE_TYPE face_type;
4287 DWRITE_FONT_FILE_TYPE file_type;
4288 BOOL supported, same = FALSE;
4289 IDWriteFontFileStream *stream;
4290 IDWriteFontFile *file;
4291 UINT32 face_count;
4293 current = FALSE;
4294 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4295 if (FAILED(hr) || !current)
4296 break;
4298 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4299 if (FAILED(hr))
4300 break;
4302 /* check if we've scanned this file already */
4303 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4304 if ((same = is_same_fontfile(fileenum->file, file)))
4305 break;
4308 if (same) {
4309 IDWriteFontFile_Release(file);
4310 continue;
4313 if (FAILED(get_filestream_from_file(file, &stream))) {
4314 IDWriteFontFile_Release(file);
4315 continue;
4318 /* Unsupported formats are skipped. */
4319 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4320 if (FAILED(hr) || !supported || face_count == 0) {
4321 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4322 IDWriteFontFileStream_Release(stream);
4323 IDWriteFontFile_Release(file);
4324 hr = S_OK;
4325 continue;
4328 /* add to scanned list */
4329 fileenum = heap_alloc(sizeof(*fileenum));
4330 fileenum->file = file;
4331 list_add_tail(&scannedfiles, &fileenum->entry);
4333 for (i = 0; i < face_count; ++i)
4335 struct dwrite_font_data *font_data;
4336 struct fontface_desc desc;
4337 WCHAR familyW[255];
4338 UINT32 index;
4340 desc.factory = factory;
4341 desc.face_type = face_type;
4342 desc.files = &file;
4343 desc.stream = stream;
4344 desc.files_number = 1;
4345 desc.index = i;
4346 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4347 desc.font_data = NULL;
4349 /* Allocate an initialize new font data structure. */
4350 hr = init_font_data(&desc, &font_data);
4351 if (FAILED(hr))
4353 /* move to next one */
4354 hr = S_OK;
4355 continue;
4358 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4360 /* ignore dot named faces */
4361 if (familyW[0] == '.')
4363 WARN("Ignoring face %s\n", debugstr_w(familyW));
4364 release_font_data(font_data);
4365 continue;
4368 index = collection_find_family(collection, familyW);
4369 if (index != ~0u)
4370 hr = fontfamily_add_font(collection->family_data[index], font_data);
4371 else {
4372 struct dwrite_fontfamily_data *family_data;
4374 /* create and init new family */
4375 hr = init_fontfamily_data(font_data->family_names, &family_data);
4376 if (hr == S_OK) {
4377 /* add font to family, family - to collection */
4378 hr = fontfamily_add_font(family_data, font_data);
4379 if (hr == S_OK)
4380 hr = fontcollection_add_family(collection, family_data);
4382 if (FAILED(hr))
4383 release_fontfamily_data(family_data);
4387 if (FAILED(hr))
4388 break;
4391 IDWriteFontFileStream_Release(stream);
4394 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4395 IDWriteFontFile_Release(fileenum->file);
4396 list_remove(&fileenum->entry);
4397 heap_free(fileenum);
4400 for (i = 0; i < collection->count; ++i)
4402 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4403 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4406 if (is_system)
4407 fontcollection_add_replacements(collection);
4409 collection->factory = factory;
4410 IDWriteFactory7_AddRef(factory);
4412 return hr;
4415 struct system_fontfile_enumerator
4417 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4418 LONG ref;
4420 IDWriteFactory7 *factory;
4421 HKEY hkey;
4422 int index;
4424 WCHAR *filename;
4425 DWORD filename_size;
4428 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4430 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4433 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4435 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4436 IDWriteFontFileEnumerator_AddRef(iface);
4437 *obj = iface;
4438 return S_OK;
4441 WARN("%s not implemented.\n", debugstr_guid(riid));
4443 *obj = NULL;
4445 return E_NOINTERFACE;
4448 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4450 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4451 return InterlockedIncrement(&enumerator->ref);
4454 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4456 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4457 ULONG ref = InterlockedDecrement(&enumerator->ref);
4459 if (!ref)
4461 IDWriteFactory7_Release(enumerator->factory);
4462 RegCloseKey(enumerator->hkey);
4463 heap_free(enumerator->filename);
4464 heap_free(enumerator);
4467 return ref;
4470 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4472 HRESULT hr;
4474 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4475 if (!strchrW(filename, '\\')) {
4476 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4477 WCHAR fullpathW[MAX_PATH];
4479 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4480 strcatW(fullpathW, fontsW);
4481 strcatW(fullpathW, filename);
4483 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4485 else
4486 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4488 return hr;
4491 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4493 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4495 *file = NULL;
4497 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4498 return E_FAIL;
4500 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4503 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4505 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4506 WCHAR name_buf[256], *name = name_buf;
4507 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4508 HRESULT hr = S_OK;
4509 LONG r;
4511 *current = FALSE;
4512 enumerator->index++;
4514 /* iterate until we find next string value */
4515 for (;;) {
4516 do {
4517 name_count = max_name_count;
4518 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4520 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4521 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4522 if (r == ERROR_MORE_DATA) {
4523 if (name_count >= max_name_count) {
4524 if (name != name_buf) heap_free(name);
4525 max_name_count *= 2;
4526 name = heap_alloc(max_name_count * sizeof(*name));
4527 if (!name) return E_OUTOFMEMORY;
4529 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4530 heap_free(enumerator->filename);
4531 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4532 enumerator->filename = heap_alloc(enumerator->filename_size);
4533 if (!enumerator->filename) {
4534 hr = E_OUTOFMEMORY;
4535 goto err;
4539 } while (r == ERROR_MORE_DATA);
4541 if (r != ERROR_SUCCESS) {
4542 enumerator->filename[0] = 0;
4543 break;
4545 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4546 if (type == REG_SZ && *name != '@') {
4547 *current = TRUE;
4548 break;
4550 enumerator->index++;
4552 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4554 err:
4555 if (name != name_buf) heap_free(name);
4556 return hr;
4559 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4561 systemfontfileenumerator_QueryInterface,
4562 systemfontfileenumerator_AddRef,
4563 systemfontfileenumerator_Release,
4564 systemfontfileenumerator_MoveNext,
4565 systemfontfileenumerator_GetCurrentFontFile
4568 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4570 struct system_fontfile_enumerator *enumerator;
4571 static const WCHAR fontslistW[] = {
4572 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4573 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4574 'F','o','n','t','s',0
4577 *ret = NULL;
4579 enumerator = heap_alloc(sizeof(*enumerator));
4580 if (!enumerator)
4581 return E_OUTOFMEMORY;
4583 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4584 enumerator->ref = 1;
4585 enumerator->factory = factory;
4586 enumerator->index = -1;
4587 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4588 enumerator->filename = heap_alloc(enumerator->filename_size);
4589 if (!enumerator->filename) {
4590 heap_free(enumerator);
4591 return E_OUTOFMEMORY;
4594 IDWriteFactory7_AddRef(factory);
4596 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4598 ERR("failed to open fonts list key\n");
4599 IDWriteFactory7_Release(factory);
4600 heap_free(enumerator->filename);
4601 heap_free(enumerator);
4602 return E_FAIL;
4605 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4607 return S_OK;
4610 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4612 IDWriteFontFileEnumerator *enumerator;
4613 HRESULT hr;
4615 *collection = NULL;
4617 hr = create_system_fontfile_enumerator(factory, &enumerator);
4618 if (FAILED(hr))
4619 return hr;
4621 TRACE("building system font collection for factory %p\n", factory);
4622 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4623 IDWriteFontFileEnumerator_Release(enumerator);
4624 return hr;
4627 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4628 const WCHAR *keynameW, const WCHAR *pathW)
4630 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};
4631 static const WCHAR emptyW[] = {0};
4632 struct dwrite_fontfamily_data *family_data;
4633 IDWriteLocalizedStrings *names;
4634 DWRITE_FONT_FACE_TYPE face_type;
4635 DWRITE_FONT_FILE_TYPE file_type;
4636 IDWriteFontFileStream *stream;
4637 IDWriteFontFile *file;
4638 UINT32 face_count, i;
4639 BOOL supported;
4640 HRESULT hr;
4642 /* create font file from this path */
4643 hr = create_local_file_reference(factory, pathW, &file);
4644 if (FAILED(hr))
4645 return S_FALSE;
4647 if (FAILED(get_filestream_from_file(file, &stream))) {
4648 IDWriteFontFile_Release(file);
4649 return S_FALSE;
4652 /* Unsupported formats are skipped. */
4653 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4654 if (FAILED(hr) || !supported || face_count == 0) {
4655 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4656 IDWriteFontFileStream_Release(stream);
4657 IDWriteFontFile_Release(file);
4658 return S_FALSE;
4661 /* create and init new family */
4663 /* Family names are added for non-specific locale, represented with empty string.
4664 Default family appears with empty family name. */
4665 create_localizedstrings(&names);
4666 if (!strcmpiW(keynameW, defaultfontW))
4667 add_localizedstring(names, emptyW, emptyW);
4668 else
4669 add_localizedstring(names, emptyW, keynameW);
4671 hr = init_fontfamily_data(names, &family_data);
4672 IDWriteLocalizedStrings_Release(names);
4673 if (hr != S_OK) {
4674 IDWriteFontFile_Release(file);
4675 return hr;
4678 /* fill with faces */
4679 for (i = 0; i < face_count; i++) {
4680 struct dwrite_font_data *font_data;
4681 struct fontface_desc desc;
4683 /* alloc and init new font data structure */
4684 desc.factory = factory;
4685 desc.face_type = face_type;
4686 desc.index = i;
4687 desc.files = &file;
4688 desc.stream = stream;
4689 desc.files_number = 1;
4690 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4691 desc.font_data = NULL;
4693 hr = init_font_data(&desc, &font_data);
4694 if (FAILED(hr))
4695 continue;
4697 /* add font to family */
4698 hr = fontfamily_add_font(family_data, font_data);
4699 if (hr != S_OK)
4700 release_font_data(font_data);
4703 /* add family to collection */
4704 hr = fontcollection_add_family(collection, family_data);
4705 if (FAILED(hr))
4706 release_fontfamily_data(family_data);
4707 IDWriteFontFileStream_Release(stream);
4708 IDWriteFontFile_Release(file);
4710 return hr;
4713 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4715 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4716 struct dwrite_fontcollection *collection;
4717 static const WCHAR emptyW[] = {0};
4718 WCHAR eudckeypathW[16];
4719 HKEY eudckey;
4720 DWORD index;
4721 BOOL exists;
4722 LONG retval;
4723 HRESULT hr;
4724 size_t i;
4726 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4728 *ret = NULL;
4730 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4731 if (!collection) return E_OUTOFMEMORY;
4733 hr = init_font_collection(collection, FALSE);
4734 if (FAILED(hr)) {
4735 heap_free(collection);
4736 return hr;
4739 *ret = &collection->IDWriteFontCollection3_iface;
4740 collection->factory = factory;
4741 IDWriteFactory7_AddRef(factory);
4743 /* return empty collection if EUDC fonts are not configured */
4744 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4745 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4746 return S_OK;
4748 retval = ERROR_SUCCESS;
4749 index = 0;
4750 while (retval != ERROR_NO_MORE_ITEMS) {
4751 WCHAR keynameW[64], pathW[MAX_PATH];
4752 DWORD type, path_len, name_len;
4754 path_len = ARRAY_SIZE(pathW);
4755 name_len = ARRAY_SIZE(keynameW);
4756 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4757 if (retval || type != REG_SZ)
4758 continue;
4760 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4761 if (hr != S_OK)
4762 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4764 RegCloseKey(eudckey);
4766 /* try to add global default if not defined for specific codepage */
4767 exists = FALSE;
4768 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4769 &index, &exists);
4770 if (FAILED(hr) || !exists) {
4771 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4772 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4773 if (hr != S_OK)
4774 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4777 /* EUDC collection offers simulated faces too */
4778 for (i = 0; i < collection->count; ++i)
4780 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4781 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4784 return S_OK;
4787 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4789 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4791 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4793 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4795 *obj = iface;
4796 IDWriteFontFile_AddRef(iface);
4797 return S_OK;
4800 WARN("%s not implemented.\n", debugstr_guid(riid));
4802 *obj = NULL;
4803 return E_NOINTERFACE;
4806 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4808 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4809 ULONG ref = InterlockedIncrement(&This->ref);
4810 TRACE("(%p)->(%d)\n", This, ref);
4811 return ref;
4814 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4816 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4817 ULONG ref = InterlockedDecrement(&This->ref);
4819 TRACE("(%p)->(%d)\n", This, ref);
4821 if (!ref)
4823 IDWriteFontFileLoader_Release(This->loader);
4824 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4825 heap_free(This->reference_key);
4826 heap_free(This);
4829 return ref;
4832 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4834 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4835 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4836 *fontFileReferenceKey = This->reference_key;
4837 *fontFileReferenceKeySize = This->key_size;
4839 return S_OK;
4842 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4844 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4845 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4846 *fontFileLoader = This->loader;
4847 IDWriteFontFileLoader_AddRef(This->loader);
4849 return S_OK;
4852 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4853 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4855 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4856 IDWriteFontFileStream *stream;
4857 HRESULT hr;
4859 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4861 *is_supported = FALSE;
4862 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4863 if (face_type)
4864 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4865 *face_count = 0;
4867 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4868 if (FAILED(hr))
4869 return hr;
4871 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4873 /* TODO: Further Analysis */
4874 IDWriteFontFileStream_Release(stream);
4875 return S_OK;
4878 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4879 dwritefontfile_QueryInterface,
4880 dwritefontfile_AddRef,
4881 dwritefontfile_Release,
4882 dwritefontfile_GetReferenceKey,
4883 dwritefontfile_GetLoader,
4884 dwritefontfile_Analyze,
4887 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4888 IDWriteFontFile **ret)
4890 struct dwrite_fontfile *file;
4891 void *key;
4893 *ret = NULL;
4895 file = heap_alloc(sizeof(*file));
4896 key = heap_alloc(key_size);
4897 if (!file || !key) {
4898 heap_free(file);
4899 heap_free(key);
4900 return E_OUTOFMEMORY;
4903 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4904 file->ref = 1;
4905 IDWriteFontFileLoader_AddRef(loader);
4906 file->loader = loader;
4907 file->stream = NULL;
4908 file->reference_key = key;
4909 memcpy(file->reference_key, reference_key, key_size);
4910 file->key_size = key_size;
4912 *ret = &file->IDWriteFontFile_iface;
4914 return S_OK;
4917 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4919 struct file_stream_desc stream_desc;
4920 struct dwrite_font_data *font_data;
4921 struct dwrite_fontface *fontface;
4922 HRESULT hr;
4923 int i;
4925 *ret = NULL;
4927 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4928 if (!fontface)
4929 return E_OUTOFMEMORY;
4931 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4932 if (!fontface->files) {
4933 heap_free(fontface);
4934 return E_OUTOFMEMORY;
4937 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4938 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
4939 fontface->refcount = 1;
4940 fontface->type = desc->face_type;
4941 fontface->file_count = desc->files_number;
4942 fontface->vdmx.exists = TRUE;
4943 fontface->gasp.exists = TRUE;
4944 fontface->cpal.exists = TRUE;
4945 fontface->colr.exists = TRUE;
4946 fontface->index = desc->index;
4947 fontface->simulations = desc->simulations;
4948 fontface->factory = desc->factory;
4949 IDWriteFactory7_AddRef(fontface->factory);
4951 for (i = 0; i < fontface->file_count; i++) {
4952 fontface->files[i] = desc->files[i];
4953 IDWriteFontFile_AddRef(fontface->files[i]);
4955 fontface->stream = desc->stream;
4956 IDWriteFontFileStream_AddRef(fontface->stream);
4958 stream_desc.stream = fontface->stream;
4959 stream_desc.face_type = desc->face_type;
4960 stream_desc.face_index = desc->index;
4961 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4962 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4963 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4964 /* TODO: test what happens if caret is already slanted */
4965 if (fontface->caret.slopeRise == 1) {
4966 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4967 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4971 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4972 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4973 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace5_iface))
4974 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4975 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4977 /* Font properties are reused from font object when 'normal' face creation path is used:
4978 collection -> family -> matching font -> fontface.
4980 If face is created directly from factory we have to go through properties resolution.
4982 if (desc->font_data)
4984 font_data = desc->font_data;
4985 addref_font_data(font_data);
4987 else
4989 hr = init_font_data(desc, &font_data);
4990 if (FAILED(hr))
4992 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
4993 return hr;
4997 fontface->weight = font_data->weight;
4998 fontface->style = font_data->style;
4999 fontface->stretch = font_data->stretch;
5000 fontface->panose = font_data->panose;
5001 fontface->fontsig = font_data->fontsig;
5002 fontface->lf = font_data->lf;
5003 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5004 fontface->names = font_data->names;
5005 if (fontface->names)
5006 IDWriteLocalizedStrings_AddRef(fontface->names);
5007 fontface->family_names = font_data->family_names;
5008 if (fontface->family_names)
5009 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5010 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5011 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5013 if (fontface->info_strings[i])
5014 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5016 fontface->cmap.stream = fontface->stream;
5017 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5018 release_font_data(font_data);
5020 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5022 *ret = &fontface->IDWriteFontFace5_iface;
5024 return S_OK;
5027 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5028 struct local_refkey
5030 FILETIME writetime;
5031 WCHAR name[1];
5034 struct local_cached_stream
5036 struct list entry;
5037 IDWriteFontFileStream *stream;
5038 struct local_refkey *key;
5039 UINT32 key_size;
5042 struct dwrite_localfontfilestream
5044 IDWriteFontFileStream IDWriteFontFileStream_iface;
5045 LONG ref;
5047 struct local_cached_stream *entry;
5048 const void *file_ptr;
5049 UINT64 size;
5052 struct dwrite_localfontfileloader {
5053 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5054 LONG ref;
5056 struct list streams;
5057 CRITICAL_SECTION cs;
5060 static struct dwrite_localfontfileloader local_fontfile_loader;
5062 struct dwrite_inmemory_stream_data
5064 LONG ref;
5065 IUnknown *owner;
5066 void *data;
5067 UINT32 size;
5070 struct dwrite_inmemory_filestream
5072 IDWriteFontFileStream IDWriteFontFileStream_iface;
5073 LONG ref;
5075 struct dwrite_inmemory_stream_data *data;
5078 struct dwrite_inmemory_fileloader
5080 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5081 LONG ref;
5083 struct dwrite_inmemory_stream_data **streams;
5084 size_t size;
5085 size_t count;
5088 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5090 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5093 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5095 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5098 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5100 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5103 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5105 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5108 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5110 if (InterlockedDecrement(&stream->ref) == 0) {
5111 if (stream->owner)
5112 IUnknown_Release(stream->owner);
5113 else
5114 heap_free(stream->data);
5115 heap_free(stream);
5119 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5121 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5123 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5125 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5126 IsEqualIID(riid, &IID_IUnknown))
5128 *obj = iface;
5129 if (InterlockedIncrement(&This->ref) == 1) {
5130 InterlockedDecrement(&This->ref);
5131 *obj = NULL;
5132 return E_FAIL;
5134 return S_OK;
5137 WARN("%s not implemented.\n", debugstr_guid(riid));
5139 *obj = NULL;
5140 return E_NOINTERFACE;
5143 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5145 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5146 ULONG ref = InterlockedIncrement(&This->ref);
5147 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5148 return ref;
5151 static inline void release_cached_stream(struct local_cached_stream *stream)
5153 list_remove(&stream->entry);
5154 heap_free(stream->key);
5155 heap_free(stream);
5158 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5160 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5161 ULONG ref = InterlockedDecrement(&This->ref);
5163 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5165 if (!ref) {
5166 UnmapViewOfFile(This->file_ptr);
5168 EnterCriticalSection(&local_fontfile_loader.cs);
5169 release_cached_stream(This->entry);
5170 LeaveCriticalSection(&local_fontfile_loader.cs);
5172 heap_free(This);
5175 return ref;
5178 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5179 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5181 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5183 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
5184 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5186 *fragment_context = NULL;
5188 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
5189 *fragment_start = NULL;
5190 return E_FAIL;
5193 *fragment_start = (char*)This->file_ptr + offset;
5194 return S_OK;
5197 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5199 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5200 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
5203 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5205 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5206 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
5207 *size = This->size;
5208 return S_OK;
5211 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5213 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5214 ULARGE_INTEGER li;
5216 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
5218 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
5219 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
5220 *last_writetime = li.QuadPart;
5222 return S_OK;
5225 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5227 localfontfilestream_QueryInterface,
5228 localfontfilestream_AddRef,
5229 localfontfilestream_Release,
5230 localfontfilestream_ReadFileFragment,
5231 localfontfilestream_ReleaseFileFragment,
5232 localfontfilestream_GetFileSize,
5233 localfontfilestream_GetLastWriteTime
5236 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
5238 struct dwrite_localfontfilestream *This;
5240 *ret = NULL;
5242 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
5243 if (!This)
5244 return E_OUTOFMEMORY;
5246 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5247 This->ref = 1;
5249 This->file_ptr = file_ptr;
5250 This->size = size;
5251 This->entry = entry;
5253 *ret = &This->IDWriteFontFileStream_iface;
5254 return S_OK;
5257 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5259 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5261 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5263 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5264 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5265 IsEqualIID(riid, &IID_IUnknown))
5267 *obj = iface;
5268 IDWriteLocalFontFileLoader_AddRef(iface);
5269 return S_OK;
5272 WARN("%s not implemented.\n", debugstr_guid(riid));
5274 *obj = NULL;
5275 return E_NOINTERFACE;
5278 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5280 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5281 ULONG ref = InterlockedIncrement(&This->ref);
5282 TRACE("(%p)->(%d)\n", This, ref);
5283 return ref;
5286 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5288 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5289 ULONG ref = InterlockedDecrement(&This->ref);
5291 TRACE("(%p)->(%d)\n", This, ref);
5293 return ref;
5296 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5298 const struct local_refkey *refkey = key;
5299 struct local_cached_stream *stream;
5300 IDWriteFontFileStream *filestream;
5301 HANDLE file, mapping;
5302 LARGE_INTEGER size;
5303 void *file_ptr;
5304 HRESULT hr = S_OK;
5306 *ret = NULL;
5308 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5309 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5310 if (file == INVALID_HANDLE_VALUE) {
5311 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5312 return E_FAIL;
5315 GetFileSizeEx(file, &size);
5316 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5317 CloseHandle(file);
5318 if (!mapping)
5319 return E_FAIL;
5321 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5322 CloseHandle(mapping);
5323 if (!file_ptr) {
5324 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5325 return E_FAIL;
5328 stream = heap_alloc(sizeof(*stream));
5329 if (!stream) {
5330 UnmapViewOfFile(file_ptr);
5331 return E_OUTOFMEMORY;
5334 stream->key = heap_alloc(key_size);
5335 if (!stream->key) {
5336 UnmapViewOfFile(file_ptr);
5337 heap_free(stream);
5338 return E_OUTOFMEMORY;
5341 stream->key_size = key_size;
5342 memcpy(stream->key, key, key_size);
5344 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5345 if (FAILED(hr)) {
5346 UnmapViewOfFile(file_ptr);
5347 heap_free(stream->key);
5348 heap_free(stream);
5349 return hr;
5352 stream->stream = filestream;
5354 *ret = stream;
5356 return S_OK;
5359 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5360 UINT32 key_size, IDWriteFontFileStream **ret)
5362 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5363 const struct local_refkey *refkey = key;
5364 struct local_cached_stream *stream;
5365 HRESULT hr = S_OK;
5367 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
5368 TRACE("name: %s\n", debugstr_w(refkey->name));
5370 EnterCriticalSection(&This->cs);
5372 *ret = NULL;
5374 /* search cache first */
5375 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
5376 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5377 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5378 break;
5382 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
5383 list_add_head(&This->streams, &stream->entry);
5384 *ret = stream->stream;
5387 LeaveCriticalSection(&This->cs);
5389 return hr;
5392 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
5394 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5395 const struct local_refkey *refkey = key;
5397 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
5399 *length = strlenW(refkey->name);
5400 return S_OK;
5403 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
5405 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5406 const struct local_refkey *refkey = key;
5408 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
5410 if (length < strlenW(refkey->name))
5411 return E_INVALIDARG;
5413 strcpyW(path, refkey->name);
5414 return S_OK;
5417 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5418 UINT32 key_size, FILETIME *writetime)
5420 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5421 const struct local_refkey *refkey = key;
5423 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
5425 *writetime = refkey->writetime;
5426 return S_OK;
5429 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
5430 localfontfileloader_QueryInterface,
5431 localfontfileloader_AddRef,
5432 localfontfileloader_Release,
5433 localfontfileloader_CreateStreamFromKey,
5434 localfontfileloader_GetFilePathLengthFromKey,
5435 localfontfileloader_GetFilePathFromKey,
5436 localfontfileloader_GetLastWriteTimeFromKey
5439 void init_local_fontfile_loader(void)
5441 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5442 local_fontfile_loader.ref = 1;
5443 list_init(&local_fontfile_loader.streams);
5444 InitializeCriticalSection(&local_fontfile_loader.cs);
5445 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5448 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5450 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5453 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5455 struct local_refkey *refkey;
5457 if (!path)
5458 return E_INVALIDARG;
5460 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5461 *key = NULL;
5463 refkey = heap_alloc(*size);
5464 if (!refkey)
5465 return E_OUTOFMEMORY;
5467 if (writetime)
5468 refkey->writetime = *writetime;
5469 else {
5470 WIN32_FILE_ATTRIBUTE_DATA info;
5472 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5473 refkey->writetime = info.ftLastWriteTime;
5474 else
5475 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5477 strcpyW(refkey->name, path);
5479 *key = refkey;
5481 return S_OK;
5484 /* IDWriteGlyphRunAnalysis */
5485 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5487 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5489 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5491 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5492 IsEqualIID(riid, &IID_IUnknown))
5494 *ppv = iface;
5495 IDWriteGlyphRunAnalysis_AddRef(iface);
5496 return S_OK;
5499 WARN("%s not implemented.\n", debugstr_guid(riid));
5501 *ppv = NULL;
5502 return E_NOINTERFACE;
5505 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5507 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5508 ULONG ref = InterlockedIncrement(&This->ref);
5509 TRACE("(%p)->(%u)\n", This, ref);
5510 return ref;
5513 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5515 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5516 ULONG ref = InterlockedDecrement(&This->ref);
5518 TRACE("(%p)->(%u)\n", This, ref);
5520 if (!ref) {
5521 if (This->run.fontFace)
5522 IDWriteFontFace_Release(This->run.fontFace);
5523 heap_free(This->glyphs);
5524 heap_free(This->origins);
5525 heap_free(This->bitmap);
5526 heap_free(This);
5529 return ref;
5532 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5534 switch (mode)
5536 case DWRITE_RENDERING_MODE1_NATURAL:
5537 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5538 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5539 return TRUE;
5540 default:
5541 return FALSE;
5545 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5547 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5550 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5552 struct dwrite_glyphbitmap glyph_bitmap;
5553 IDWriteFontFace4 *fontface;
5554 HRESULT hr;
5555 UINT32 i;
5557 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5558 *bounds = analysis->bounds;
5559 return;
5562 if (analysis->run.isSideways)
5563 FIXME("sideways runs are not supported.\n");
5565 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5566 if (FAILED(hr))
5567 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5569 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5570 glyph_bitmap.fontface = fontface;
5571 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5572 glyph_bitmap.emsize = analysis->run.fontEmSize;
5573 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5574 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5575 glyph_bitmap.m = &analysis->m;
5577 for (i = 0; i < analysis->run.glyphCount; i++) {
5578 RECT *bbox = &glyph_bitmap.bbox;
5579 UINT32 bitmap_size;
5581 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5582 freetype_get_glyph_bbox(&glyph_bitmap);
5584 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5585 (bbox->bottom - bbox->top);
5586 if (bitmap_size > analysis->max_glyph_bitmap_size)
5587 analysis->max_glyph_bitmap_size = bitmap_size;
5589 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5590 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5593 IDWriteFontFace4_Release(fontface);
5595 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5596 *bounds = analysis->bounds;
5599 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5601 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5603 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5605 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5606 SetRectEmpty(bounds);
5607 return E_INVALIDARG;
5610 if (type != This->texture_type) {
5611 SetRectEmpty(bounds);
5612 return S_OK;
5615 glyphrunanalysis_get_texturebounds(This, bounds);
5616 return S_OK;
5619 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5621 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5622 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5623 (runbounds->left - bounds->left) * 3;
5624 else
5625 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5626 runbounds->left - bounds->left;
5629 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5631 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5632 struct dwrite_glyphbitmap glyph_bitmap;
5633 IDWriteFontFace4 *fontface;
5634 D2D_POINT_2F origin;
5635 UINT32 i, size;
5636 HRESULT hr;
5637 RECT *bbox;
5639 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5640 if (FAILED(hr)) {
5641 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5642 return hr;
5645 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5646 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5647 size *= 3;
5648 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5649 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5650 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5651 IDWriteFontFace4_Release(fontface);
5652 return E_OUTOFMEMORY;
5655 origin.x = origin.y = 0.0f;
5657 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5658 glyph_bitmap.fontface = fontface;
5659 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5660 glyph_bitmap.emsize = analysis->run.fontEmSize;
5661 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5662 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5663 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5664 glyph_bitmap.m = &analysis->m;
5665 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5666 IDWriteFontFace4_Release(fontface);
5667 return E_OUTOFMEMORY;
5670 bbox = &glyph_bitmap.bbox;
5672 for (i = 0; i < analysis->run.glyphCount; i++) {
5673 BYTE *src = glyph_bitmap.buf, *dst;
5674 int x, y, width, height;
5675 BOOL is_1bpp;
5677 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5678 freetype_get_glyph_bbox(&glyph_bitmap);
5680 if (IsRectEmpty(bbox))
5681 continue;
5683 width = bbox->right - bbox->left;
5684 height = bbox->bottom - bbox->top;
5686 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5687 memset(src, 0, height * glyph_bitmap.pitch);
5688 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5690 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5692 /* blit to analysis bitmap */
5693 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5695 if (is_1bpp) {
5696 /* convert 1bpp to 8bpp/24bpp */
5697 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5698 for (y = 0; y < height; y++) {
5699 for (x = 0; x < width; x++)
5700 if (src[x / 8] & masks[x % 8])
5701 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5702 src += glyph_bitmap.pitch;
5703 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5706 else {
5707 for (y = 0; y < height; y++) {
5708 for (x = 0; x < width; x++)
5709 if (src[x / 8] & masks[x % 8])
5710 dst[x] = DWRITE_ALPHA_MAX;
5711 src += glyph_bitmap.pitch;
5712 dst += analysis->bounds.right - analysis->bounds.left;
5716 else {
5717 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5718 for (y = 0; y < height; y++) {
5719 for (x = 0; x < width; x++)
5720 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5721 src += glyph_bitmap.pitch;
5722 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5725 else {
5726 for (y = 0; y < height; y++) {
5727 for (x = 0; x < width; x++)
5728 dst[x] |= src[x];
5729 src += glyph_bitmap.pitch;
5730 dst += analysis->bounds.right - analysis->bounds.left;
5735 heap_free(glyph_bitmap.buf);
5737 IDWriteFontFace4_Release(fontface);
5739 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5741 /* we don't need this anymore */
5742 heap_free(analysis->glyphs);
5743 heap_free(analysis->origins);
5744 IDWriteFontFace_Release(analysis->run.fontFace);
5746 analysis->glyphs = NULL;
5747 analysis->origins = NULL;
5748 analysis->run.glyphIndices = NULL;
5749 analysis->run.fontFace = NULL;
5751 return S_OK;
5754 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5755 RECT const *bounds, BYTE *bitmap, UINT32 size)
5757 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5758 UINT32 required;
5759 RECT runbounds;
5761 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5763 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5764 return E_INVALIDARG;
5766 /* make sure buffer is large enough for requested texture type */
5767 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5768 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5769 required *= 3;
5771 if (size < required)
5772 return E_NOT_SUFFICIENT_BUFFER;
5774 /* validate requested texture type */
5775 if (This->texture_type != type)
5776 return DWRITE_E_UNSUPPORTEDOPERATION;
5778 memset(bitmap, 0, size);
5779 glyphrunanalysis_get_texturebounds(This, &runbounds);
5780 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5781 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5782 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5783 int dst_width = (bounds->right - bounds->left) * pixel_size;
5784 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5785 BYTE *src, *dst;
5786 int y;
5788 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5789 HRESULT hr;
5791 if (FAILED(hr = glyphrunanalysis_render(This)))
5792 return hr;
5795 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5796 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5798 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5799 memcpy(dst, src, draw_width);
5800 src += src_width;
5801 dst += dst_width;
5805 return S_OK;
5808 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5809 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5811 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5813 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5815 if (!params)
5816 return E_INVALIDARG;
5818 switch (This->rendering_mode)
5820 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5821 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5823 UINT value = 0;
5824 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5825 *gamma = (FLOAT)value / 1000.0f;
5826 *contrast = 0.0f;
5827 *cleartypelevel = 1.0f;
5828 break;
5830 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5831 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5832 /* fallthrough */
5833 case DWRITE_RENDERING_MODE1_ALIASED:
5834 case DWRITE_RENDERING_MODE1_NATURAL:
5835 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5836 *gamma = IDWriteRenderingParams_GetGamma(params);
5837 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5838 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5839 break;
5840 default:
5844 return S_OK;
5847 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5848 glyphrunanalysis_QueryInterface,
5849 glyphrunanalysis_AddRef,
5850 glyphrunanalysis_Release,
5851 glyphrunanalysis_GetAlphaTextureBounds,
5852 glyphrunanalysis_CreateAlphaTexture,
5853 glyphrunanalysis_GetAlphaBlendParams
5856 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5858 D2D_POINT_2F ret;
5859 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5860 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5861 *point = ret;
5864 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5865 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5867 unsigned int upem = fontface->metrics.designUnitsPerEm;
5868 int advance;
5870 if (is_sideways)
5871 FIXME("Sideways mode is not supported.\n");
5873 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5875 switch (measuring_mode)
5877 case DWRITE_MEASURING_MODE_NATURAL:
5878 return (float)advance * emsize / (float)upem;
5879 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5880 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5881 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5882 default:
5883 WARN("Unknown measuring mode %u.\n", measuring_mode);
5884 return 0.0f;
5888 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5890 struct dwrite_glyphrunanalysis *analysis;
5891 struct dwrite_fontface *fontface;
5892 D2D_POINT_2F origin;
5893 FLOAT rtl_factor;
5894 UINT32 i;
5896 *ret = NULL;
5898 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5899 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5900 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5901 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5902 return E_INVALIDARG;
5904 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5905 return E_INVALIDARG;
5907 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5908 return E_INVALIDARG;
5910 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5911 return E_INVALIDARG;
5913 analysis = heap_alloc(sizeof(*analysis));
5914 if (!analysis)
5915 return E_OUTOFMEMORY;
5917 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5918 analysis->ref = 1;
5919 analysis->rendering_mode = desc->rendering_mode;
5921 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5922 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5923 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5924 else
5925 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5927 analysis->flags = 0;
5928 analysis->bitmap = NULL;
5929 analysis->max_glyph_bitmap_size = 0;
5930 SetRectEmpty(&analysis->bounds);
5931 analysis->run = *desc->run;
5932 IDWriteFontFace_AddRef(analysis->run.fontFace);
5933 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5934 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5936 if (!analysis->glyphs || !analysis->origins) {
5937 heap_free(analysis->glyphs);
5938 heap_free(analysis->origins);
5940 analysis->glyphs = NULL;
5941 analysis->origins = NULL;
5943 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5944 return E_OUTOFMEMORY;
5947 /* check if transform is usable */
5948 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5949 analysis->m = *desc->transform;
5950 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5952 else
5953 memset(&analysis->m, 0, sizeof(analysis->m));
5955 analysis->run.glyphIndices = analysis->glyphs;
5956 analysis->run.glyphAdvances = NULL;
5957 analysis->run.glyphOffsets = NULL;
5959 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5961 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5963 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5965 origin.x = desc->origin.x;
5966 origin.y = desc->origin.y;
5967 for (i = 0; i < desc->run->glyphCount; ++i)
5969 float advance;
5971 /* Use nominal advances if not provided by caller. */
5972 if (desc->run->glyphAdvances)
5973 advance = rtl_factor * desc->run->glyphAdvances[i];
5974 else
5975 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5976 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5978 analysis->origins[i] = origin;
5979 if (desc->run->bidiLevel & 1)
5981 if (desc->run->isSideways)
5982 analysis->origins[i].y += advance;
5983 else
5984 analysis->origins[i].x += advance;
5987 /* Offsets are optional, appled to pre-transformed origin. */
5988 if (desc->run->glyphOffsets) {
5989 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5990 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5992 if (desc->run->isSideways) {
5993 analysis->origins[i].x += ascenderoffset;
5994 analysis->origins[i].y += advanceoffset;
5996 else {
5997 analysis->origins[i].x += advanceoffset;
5998 analysis->origins[i].y += ascenderoffset;
6002 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6003 transform_point(analysis->origins + i, &analysis->m);
6005 if (desc->run->isSideways)
6006 origin.y += advance;
6007 else
6008 origin.x += advance;
6011 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6012 return S_OK;
6015 /* IDWriteColorGlyphRunEnumerator1 */
6016 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6018 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6020 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6021 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6022 IsEqualIID(riid, &IID_IUnknown))
6024 *ppv = iface;
6025 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6026 return S_OK;
6029 WARN("%s not implemented.\n", debugstr_guid(riid));
6031 *ppv = NULL;
6032 return E_NOINTERFACE;
6035 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6037 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6038 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6040 TRACE("%p, refcount %u.\n", iface, refcount);
6042 return refcount;
6045 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6047 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6048 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6050 TRACE("%p, refcount %u.\n", iface, refcount);
6052 if (!refcount)
6054 heap_free(glyphenum->advances);
6055 heap_free(glyphenum->color_advances);
6056 heap_free(glyphenum->offsets);
6057 heap_free(glyphenum->color_offsets);
6058 heap_free(glyphenum->glyphindices);
6059 heap_free(glyphenum->glyphs);
6060 if (glyphenum->colr.context)
6061 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6062 IDWriteFontFace5_Release(glyphenum->fontface);
6063 heap_free(glyphenum);
6066 return refcount;
6069 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6071 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6072 FLOAT origin = 0.0f;
6074 if (g == 0)
6075 return 0.0f;
6077 while (g--)
6078 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6079 return origin;
6082 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6084 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6085 FLOAT advance_adj = 0.0f;
6086 BOOL got_palette_index;
6087 UINT32 g;
6089 /* start with regular glyphs */
6090 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6091 UINT32 first_glyph = 0;
6093 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6094 if (glyphenum->glyphs[g].num_layers == 0) {
6095 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6096 first_glyph = min(first_glyph, g);
6098 else
6099 glyphenum->glyphindices[g] = 1;
6100 glyphenum->color_advances[g] = glyphenum->advances[g];
6101 if (glyphenum->color_offsets)
6102 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6105 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6106 colorrun->baselineOriginY = glyphenum->origin_y;
6107 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6108 colorrun->paletteIndex = 0xffff;
6109 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6110 glyphenum->has_regular_glyphs = FALSE;
6111 return TRUE;
6113 else {
6114 colorrun->glyphRun.glyphCount = 0;
6115 got_palette_index = FALSE;
6118 advance_adj = 0.0f;
6119 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6121 glyphenum->glyphindices[g] = 1;
6123 /* all glyph layers were returned */
6124 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6125 advance_adj += glyphenum->advances[g];
6126 continue;
6129 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6130 UINT32 index = colorrun->glyphRun.glyphCount;
6131 if (!got_palette_index) {
6132 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6133 /* use foreground color or request one from the font */
6134 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6135 if (colorrun->paletteIndex != 0xffff)
6137 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6138 colorrun->paletteIndex, 1, &colorrun->runColor);
6139 if (FAILED(hr))
6140 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6141 glyphenum->palette, colorrun->paletteIndex, hr);
6143 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6144 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6145 colorrun->baselineOriginY = glyphenum->origin_y;
6146 glyphenum->color_advances[index] = glyphenum->advances[g];
6147 got_palette_index = TRUE;
6150 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6151 /* offsets are relative to glyph origin, nothing to fix up */
6152 if (glyphenum->color_offsets)
6153 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6154 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6155 if (index)
6156 glyphenum->color_advances[index-1] += advance_adj;
6157 colorrun->glyphRun.glyphCount++;
6158 advance_adj = 0.0f;
6160 else
6161 advance_adj += glyphenum->advances[g];
6164 /* reset last advance */
6165 if (colorrun->glyphRun.glyphCount)
6166 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6168 return colorrun->glyphRun.glyphCount > 0;
6171 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6173 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6175 TRACE("%p, %p.\n", iface, has_run);
6177 *has_run = FALSE;
6179 glyphenum->colorrun.glyphRun.glyphCount = 0;
6180 while (glyphenum->current_layer < glyphenum->max_layer_num)
6182 if (colorglyphenum_build_color_run(glyphenum))
6183 break;
6184 else
6185 glyphenum->current_layer++;
6188 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6190 return S_OK;
6193 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6194 DWRITE_COLOR_GLYPH_RUN1 const **run)
6196 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6198 *run = NULL;
6199 return E_NOT_VALID_STATE;
6202 *run = &glyphenum->colorrun;
6203 return S_OK;
6206 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6207 DWRITE_COLOR_GLYPH_RUN const **run)
6209 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6211 TRACE("%p, %p.\n", iface, run);
6213 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6216 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6217 DWRITE_COLOR_GLYPH_RUN1 const **run)
6219 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6221 TRACE("%p, %p.\n", iface, run);
6223 return colorglyphenum_get_current_run(glyphenum, run);
6226 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6228 colorglyphenum_QueryInterface,
6229 colorglyphenum_AddRef,
6230 colorglyphenum_Release,
6231 colorglyphenum_MoveNext,
6232 colorglyphenum_GetCurrentRun,
6233 colorglyphenum1_GetCurrentRun,
6236 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6237 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6238 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6240 struct dwrite_colorglyphenum *colorglyphenum;
6241 BOOL colorfont, has_colored_glyph;
6242 struct dwrite_fontface *fontface;
6243 unsigned int i;
6245 *ret = NULL;
6247 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6249 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6250 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6251 if (!colorfont)
6252 return DWRITE_E_NOCOLOR;
6254 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6255 if (!colorglyphenum)
6256 return E_OUTOFMEMORY;
6258 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6259 colorglyphenum->refcount = 1;
6260 colorglyphenum->origin_x = originX;
6261 colorglyphenum->origin_y = originY;
6262 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6263 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6264 colorglyphenum->glyphs = NULL;
6265 colorglyphenum->run = *run;
6266 colorglyphenum->run.glyphIndices = NULL;
6267 colorglyphenum->run.glyphAdvances = NULL;
6268 colorglyphenum->run.glyphOffsets = NULL;
6269 colorglyphenum->palette = palette;
6270 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6271 colorglyphenum->colr.exists = TRUE;
6272 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6273 colorglyphenum->current_layer = 0;
6274 colorglyphenum->max_layer_num = 0;
6276 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6278 has_colored_glyph = FALSE;
6279 colorglyphenum->has_regular_glyphs = FALSE;
6280 for (i = 0; i < run->glyphCount; i++) {
6281 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6282 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6283 has_colored_glyph = TRUE;
6285 if (colorglyphenum->glyphs[i].num_layers == 0)
6286 colorglyphenum->has_regular_glyphs = TRUE;
6289 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6290 is supposed to proceed normally, like if font had no color info at all. */
6291 if (!has_colored_glyph) {
6292 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6293 return DWRITE_E_NOCOLOR;
6296 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6297 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6298 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6299 if (run->glyphOffsets) {
6300 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6301 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6302 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6305 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6306 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6307 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6308 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6309 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6310 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6311 colorglyphenum->colorrun.measuringMode = measuring_mode;
6312 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6314 if (run->glyphAdvances)
6315 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6316 else
6318 for (i = 0; i < run->glyphCount; ++i)
6319 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6320 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6323 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6325 return S_OK;
6328 /* IDWriteFontFaceReference */
6329 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6331 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6333 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6334 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6335 IsEqualIID(riid, &IID_IUnknown))
6337 *obj = iface;
6338 IDWriteFontFaceReference1_AddRef(iface);
6339 return S_OK;
6342 WARN("%s not implemented.\n", debugstr_guid(riid));
6344 *obj = NULL;
6346 return E_NOINTERFACE;
6349 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6351 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6352 ULONG refcount = InterlockedIncrement(&reference->refcount);
6354 TRACE("%p, refcount %u.\n", iface, refcount);
6356 return refcount;
6359 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6361 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6362 ULONG refcount = InterlockedDecrement(&reference->refcount);
6364 TRACE("%p, refcount %u.\n", iface, refcount);
6366 if (!refcount)
6368 IDWriteFontFile_Release(reference->file);
6369 IDWriteFactory7_Release(reference->factory);
6370 heap_free(reference->axis_values);
6371 heap_free(reference);
6374 return refcount;
6377 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6379 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6381 TRACE("%p, %p.\n", iface, fontface);
6383 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6386 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6387 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6389 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6390 DWRITE_FONT_FILE_TYPE file_type;
6391 DWRITE_FONT_FACE_TYPE face_type;
6392 IDWriteFontFace *fontface;
6393 BOOL is_supported;
6394 UINT32 face_num;
6395 HRESULT hr;
6397 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6399 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6400 if (FAILED(hr))
6401 return hr;
6403 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6404 simulations, &fontface);
6405 if (SUCCEEDED(hr))
6407 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6408 IDWriteFontFace_Release(fontface);
6411 return hr;
6414 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6416 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6417 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6418 BOOL ret;
6420 TRACE("%p, %p.\n", iface, ref);
6422 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6423 reference->simulations == other->simulations;
6424 if (reference->axis_values_count)
6426 ret &= reference->axis_values_count == other->axis_values_count &&
6427 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6430 return ret;
6433 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6435 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6437 TRACE("%p.\n", iface);
6439 return reference->index;
6442 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6444 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6446 TRACE("%p.\n", iface);
6448 return reference->simulations;
6451 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6453 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6454 IDWriteFontFileLoader *loader;
6455 const void *key;
6456 UINT32 key_size;
6457 HRESULT hr;
6459 TRACE("%p, %p.\n", iface, file);
6461 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6462 if (FAILED(hr))
6463 return hr;
6465 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6466 if (FAILED(hr))
6467 return hr;
6469 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6470 IDWriteFontFileLoader_Release(loader);
6472 return hr;
6475 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6477 FIXME("%p.\n", iface);
6479 return 0;
6482 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6484 FIXME("%p.\n", iface);
6486 return 0;
6489 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6491 FIXME("%p, %p.\n", iface, writetime);
6493 return E_NOTIMPL;
6496 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6498 FIXME("%p.\n", iface);
6500 return DWRITE_LOCALITY_LOCAL;
6503 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6505 FIXME("%p.\n", iface);
6507 return E_NOTIMPL;
6510 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6511 WCHAR const *chars, UINT32 count)
6513 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6515 return E_NOTIMPL;
6518 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6519 UINT16 const *glyphs, UINT32 count)
6521 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6523 return E_NOTIMPL;
6526 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6527 UINT64 offset, UINT64 size)
6529 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6531 return E_NOTIMPL;
6534 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6536 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6537 IDWriteFontFace3 *fontface3;
6538 HRESULT hr;
6540 TRACE("%p, %p.\n", iface, fontface);
6542 /* FIXME: created instance should likely respect given axis. */
6543 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6544 &fontface3)))
6546 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6547 IDWriteFontFace3_Release(fontface3);
6550 return hr;
6553 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6555 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6557 TRACE("%p.\n", iface);
6559 return reference->axis_values_count;
6562 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6563 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6565 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6567 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6569 if (value_count < reference->axis_values_count)
6570 return E_NOT_SUFFICIENT_BUFFER;
6572 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6574 return S_OK;
6577 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6579 fontfacereference_QueryInterface,
6580 fontfacereference_AddRef,
6581 fontfacereference_Release,
6582 fontfacereference_CreateFontFace,
6583 fontfacereference_CreateFontFaceWithSimulations,
6584 fontfacereference_Equals,
6585 fontfacereference_GetFontFaceIndex,
6586 fontfacereference_GetSimulations,
6587 fontfacereference_GetFontFile,
6588 fontfacereference_GetLocalFileSize,
6589 fontfacereference_GetFileSize,
6590 fontfacereference_GetFileTime,
6591 fontfacereference_GetLocality,
6592 fontfacereference_EnqueueFontDownloadRequest,
6593 fontfacereference_EnqueueCharacterDownloadRequest,
6594 fontfacereference_EnqueueGlyphDownloadRequest,
6595 fontfacereference_EnqueueFileFragmentDownloadRequest,
6596 fontfacereference1_CreateFontFace,
6597 fontfacereference1_GetFontAxisValueCount,
6598 fontfacereference1_GetFontAxisValues,
6601 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6602 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6603 IDWriteFontFaceReference1 **ret)
6605 struct dwrite_fontfacereference *object;
6607 *ret = NULL;
6609 if (!is_simulation_valid(simulations))
6610 return E_INVALIDARG;
6612 object = heap_alloc_zero(sizeof(*object));
6613 if (!object)
6614 return E_OUTOFMEMORY;
6616 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6617 object->refcount = 1;
6619 object->factory = factory;
6620 IDWriteFactory7_AddRef(object->factory);
6621 object->file = file;
6622 IDWriteFontFile_AddRef(object->file);
6623 object->index = index;
6624 object->simulations = simulations;
6625 if (axis_values_count)
6627 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6629 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6630 return E_OUTOFMEMORY;
6632 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6633 object->axis_values_count = axis_values_count;
6636 *ret = &object->IDWriteFontFaceReference1_iface;
6638 return S_OK;
6641 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6643 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6645 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6647 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6648 *obj = iface;
6649 IDWriteFontFileStream_AddRef(iface);
6650 return S_OK;
6653 *obj = NULL;
6655 WARN("%s not implemented.\n", debugstr_guid(riid));
6656 return E_NOINTERFACE;
6659 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6661 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6662 ULONG ref = InterlockedIncrement(&stream->ref);
6663 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6664 return ref;
6667 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6669 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6670 ULONG ref = InterlockedDecrement(&stream->ref);
6672 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6674 if (!ref) {
6675 release_inmemory_stream(stream->data);
6676 heap_free(stream);
6679 return ref;
6682 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6683 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6685 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6687 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6688 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6690 *fragment_context = NULL;
6692 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6693 *fragment_start = NULL;
6694 return E_FAIL;
6697 *fragment_start = (char *)stream->data->data + offset;
6698 return S_OK;
6701 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6703 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6705 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6708 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6710 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6712 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6714 *size = stream->data->size;
6716 return S_OK;
6719 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6721 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6723 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6725 *last_writetime = 0;
6727 return E_NOTIMPL;
6730 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6731 inmemoryfilestream_QueryInterface,
6732 inmemoryfilestream_AddRef,
6733 inmemoryfilestream_Release,
6734 inmemoryfilestream_ReadFileFragment,
6735 inmemoryfilestream_ReleaseFileFragment,
6736 inmemoryfilestream_GetFileSize,
6737 inmemoryfilestream_GetLastWriteTime,
6740 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6741 REFIID riid, void **obj)
6743 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6745 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6747 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6748 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6749 IsEqualIID(riid, &IID_IUnknown))
6751 *obj = iface;
6752 IDWriteInMemoryFontFileLoader_AddRef(iface);
6753 return S_OK;
6756 WARN("%s not implemented.\n", debugstr_guid(riid));
6758 *obj = NULL;
6760 return E_NOINTERFACE;
6763 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6765 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6766 ULONG ref = InterlockedIncrement(&loader->ref);
6767 TRACE("(%p)->(%u)\n", loader, ref);
6768 return ref;
6771 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6773 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6774 ULONG ref = InterlockedDecrement(&loader->ref);
6775 size_t i;
6777 TRACE("(%p)->(%u)\n", loader, ref);
6779 if (!ref) {
6780 for (i = 0; i < loader->count; ++i)
6781 release_inmemory_stream(loader->streams[i]);
6782 heap_free(loader->streams);
6783 heap_free(loader);
6786 return ref;
6789 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6790 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6792 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6793 struct dwrite_inmemory_filestream *stream;
6794 DWORD index;
6796 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6798 *ret = NULL;
6800 if (key_size != sizeof(DWORD))
6801 return E_INVALIDARG;
6803 index = *(DWORD *)key;
6805 if (index >= loader->count)
6806 return E_INVALIDARG;
6808 if (!(stream = heap_alloc(sizeof(*stream))))
6809 return E_OUTOFMEMORY;
6811 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6812 stream->ref = 1;
6813 stream->data = loader->streams[index];
6814 InterlockedIncrement(&stream->data->ref);
6816 *ret = &stream->IDWriteFontFileStream_iface;
6818 return S_OK;
6821 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6822 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6824 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6825 struct dwrite_inmemory_stream_data *stream;
6826 DWORD key;
6828 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6830 *fontfile = NULL;
6832 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6833 return E_OUTOFMEMORY;
6835 if (!(stream = heap_alloc(sizeof(*stream))))
6836 return E_OUTOFMEMORY;
6838 stream->ref = 1;
6839 stream->size = data_size;
6840 stream->owner = owner;
6841 if (stream->owner) {
6842 IUnknown_AddRef(stream->owner);
6843 stream->data = (void *)data;
6845 else {
6846 if (!(stream->data = heap_alloc(data_size))) {
6847 heap_free(stream);
6848 return E_OUTOFMEMORY;
6850 memcpy(stream->data, data, data_size);
6853 key = loader->count;
6854 loader->streams[loader->count++] = stream;
6856 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6857 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6860 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6862 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6864 TRACE("%p.\n", iface);
6866 return loader->count;
6869 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6871 inmemoryfontfileloader_QueryInterface,
6872 inmemoryfontfileloader_AddRef,
6873 inmemoryfontfileloader_Release,
6874 inmemoryfontfileloader_CreateStreamFromKey,
6875 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6876 inmemoryfontfileloader_GetFileCount,
6879 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6881 struct dwrite_inmemory_fileloader *loader;
6883 *ret = NULL;
6885 loader = heap_alloc_zero(sizeof(*loader));
6886 if (!loader)
6887 return E_OUTOFMEMORY;
6889 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6890 loader->ref = 1;
6892 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6894 return S_OK;
6897 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6899 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6901 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6902 IsEqualIID(riid, &IID_IUnknown))
6904 *obj = iface;
6905 IDWriteFontResource_AddRef(iface);
6906 return S_OK;
6909 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6911 return E_NOINTERFACE;
6914 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6916 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6917 ULONG refcount = InterlockedIncrement(&resource->refcount);
6919 TRACE("%p, refcount %u.\n", iface, refcount);
6921 return refcount;
6924 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6926 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6927 ULONG refcount = InterlockedDecrement(&resource->refcount);
6929 TRACE("%p, refcount %u.\n", iface, refcount);
6931 if (!refcount)
6933 IDWriteFactory7_Release(resource->factory);
6934 IDWriteFontFile_Release(resource->file);
6935 heap_free(resource);
6938 return refcount;
6941 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6943 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6945 TRACE("%p, %p.\n", iface, fontfile);
6947 *fontfile = resource->file;
6948 IDWriteFontFile_AddRef(*fontfile);
6950 return S_OK;
6953 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6955 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6957 TRACE("%p.\n", iface);
6959 return resource->face_index;
6962 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6964 FIXME("%p.\n", iface);
6966 return 0;
6969 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6970 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6972 FIXME("%p, %p, %u.\n", iface, values, num_values);
6974 return E_NOTIMPL;
6977 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6978 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
6980 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
6982 return E_NOTIMPL;
6985 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
6986 UINT32 axis)
6988 FIXME("%p, %u.\n", iface, axis);
6990 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
6993 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
6994 IDWriteLocalizedStrings **names)
6996 FIXME("%p, %u, %p.\n", iface, axis, names);
6998 return E_NOTIMPL;
7001 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7003 FIXME("%p, %u.\n", iface, axis);
7005 return 0;
7008 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7009 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7011 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7013 return E_NOTIMPL;
7016 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7018 FIXME("%p.\n", iface);
7020 return FALSE;
7023 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7024 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7025 IDWriteFontFace5 **fontface)
7027 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7028 IDWriteFontFaceReference1 *reference;
7029 HRESULT hr;
7031 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7033 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7034 simulations, axis_values, num_values, &reference);
7035 if (SUCCEEDED(hr))
7037 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7038 IDWriteFontFaceReference1_Release(reference);
7041 return hr;
7044 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7045 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7046 IDWriteFontFaceReference1 **reference)
7048 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7050 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7052 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7053 simulations, axis_values, num_values, reference);
7056 static const IDWriteFontResourceVtbl fontresourcevtbl =
7058 dwritefontresource_QueryInterface,
7059 dwritefontresource_AddRef,
7060 dwritefontresource_Release,
7061 dwritefontresource_GetFontFile,
7062 dwritefontresource_GetFontFaceIndex,
7063 dwritefontresource_GetFontAxisCount,
7064 dwritefontresource_GetDefaultFontAxisValues,
7065 dwritefontresource_GetFontAxisRanges,
7066 dwritefontresource_GetFontAxisAttributes,
7067 dwritefontresource_GetAxisNames,
7068 dwritefontresource_GetAxisValueNameCount,
7069 dwritefontresource_GetAxisValueNames,
7070 dwritefontresource_HasVariations,
7071 dwritefontresource_CreateFontFace,
7072 dwritefontresource_CreateFontFaceReference,
7075 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7076 IDWriteFontResource **ret)
7078 struct dwrite_fontresource *resource;
7080 *ret = NULL;
7082 resource = heap_alloc_zero(sizeof(*resource));
7083 if (!resource)
7084 return E_OUTOFMEMORY;
7086 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7087 resource->refcount = 1;
7088 resource->face_index = face_index;
7089 resource->file = file;
7090 IDWriteFontFile_AddRef(resource->file);
7091 resource->factory = factory;
7092 IDWriteFactory7_AddRef(resource->factory);
7094 *ret = &resource->IDWriteFontResource_iface;
7096 return S_OK;