d2d1: Partially implement d2d_device_context_DrawImage().
[wine.git] / dlls / dwrite / font.c
blobc10234e09fcf0b28935f56e73756e84b280f00f0
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
172 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
173 LONG refcount;
175 DWRITE_RENDERING_MODE1 rendering_mode;
176 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
177 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
178 DWRITE_MATRIX m;
179 UINT16 *glyphs;
180 D2D_POINT_2F *origins;
182 UINT8 flags;
183 RECT bounds;
184 BYTE *bitmap;
185 UINT32 max_glyph_bitmap_size;
188 struct dwrite_colorglyphenum
190 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
191 LONG refcount;
193 FLOAT origin_x; /* original run origin */
194 FLOAT origin_y;
196 IDWriteFontFace5 *fontface; /* for convenience */
197 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
198 DWRITE_GLYPH_RUN run; /* base run */
199 UINT32 palette; /* palette index to get layer color from */
200 FLOAT *advances; /* original or measured advances for base glyphs */
201 FLOAT *color_advances; /* returned color run points to this */
202 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
203 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
204 UINT16 *glyphindices; /* returned color run points to this */
205 struct dwrite_colorglyph *glyphs; /* current glyph color info */
206 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
207 UINT16 current_layer; /* enumerator position, updated with MoveNext */
208 UINT16 max_layer_num; /* max number of layers for this run */
209 struct dwrite_fonttable colr; /* used to access layers */
212 #define GLYPH_BLOCK_SHIFT 8
213 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
214 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
215 #define GLYPH_MAX 65536
217 struct dwrite_fontfile
219 IDWriteFontFile IDWriteFontFile_iface;
220 LONG refcount;
222 IDWriteFontFileLoader *loader;
223 void *reference_key;
224 UINT32 key_size;
225 IDWriteFontFileStream *stream;
228 struct dwrite_fontfacereference
230 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
231 LONG refcount;
233 IDWriteFontFile *file;
234 UINT32 index;
235 USHORT simulations;
236 DWRITE_FONT_AXIS_VALUE *axis_values;
237 UINT32 axis_values_count;
238 IDWriteFactory7 *factory;
241 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
243 struct dwrite_fontresource
245 IDWriteFontResource IDWriteFontResource_iface;
246 LONG refcount;
248 IDWriteFontFile *file;
249 UINT32 face_index;
250 IDWriteFactory7 *factory;
253 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
255 struct dwrite_fontface *fontface = context;
256 BOOL exists = FALSE;
258 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
259 size, data_context, &exists)) || !exists)
261 *data = NULL;
262 *size = 0;
263 *data_context = NULL;
267 static void dwrite_release_font_table(void *context, void *data_context)
269 struct dwrite_fontface *fontface = context;
270 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
273 static UINT16 dwrite_get_font_upem(void *context)
275 struct dwrite_fontface *fontface = context;
276 return fontface->metrics.designUnitsPerEm;
279 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
281 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
282 return opentype_cmap_get_glyph(&fontface->cmap, ch);
285 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
287 struct dwrite_fontface *fontface = context;
288 return !!dwritefontface_get_glyph(fontface, codepoint);
291 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
293 struct dwrite_fontface *fontface = context;
294 return dwritefontface_get_glyph(fontface, codepoint);
297 static const struct shaping_font_ops dwrite_font_ops =
299 dwrite_grab_font_table,
300 dwrite_release_font_table,
301 dwrite_get_font_upem,
302 dwrite_has_glyph,
303 dwrite_get_glyph,
306 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
308 if (fontface->shaping_cache)
309 return fontface->shaping_cache;
311 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
314 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
316 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
319 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
321 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
324 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
326 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
329 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
331 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
333 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
336 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
338 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
341 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
343 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
346 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
348 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
351 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
353 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
356 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
358 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
361 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
363 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
366 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
368 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
371 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
373 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
376 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
378 static const DWRITE_GLYPH_METRICS nil;
379 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
381 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
382 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
383 return S_OK;
386 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
388 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
390 if (!*block) {
391 /* start new block */
392 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
393 if (!*block)
394 return E_OUTOFMEMORY;
397 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
398 return S_OK;
401 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
403 HRESULT hr;
405 if (table->data || !table->exists)
406 return table->data;
408 table->exists = FALSE;
409 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
410 &table->exists);
411 if (FAILED(hr) || !table->exists) {
412 TRACE("Font does not have %s table\n", debugstr_tag(tag));
413 return NULL;
416 return table->data;
419 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
420 struct dwrite_font_propvec *vec)
422 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
423 vec->style = style * 7.0f;
424 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
427 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
429 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
432 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
434 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
437 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
439 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
440 return &fontface->vdmx;
443 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
445 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
446 return &fontface->gasp;
449 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
451 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
452 return &fontface->cpal;
455 static void addref_font_data(struct dwrite_font_data *data)
457 InterlockedIncrement(&data->ref);
460 static void release_font_data(struct dwrite_font_data *data)
462 int i;
464 if (InterlockedDecrement(&data->ref) > 0)
465 return;
467 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
469 if (data->info_strings[i])
470 IDWriteLocalizedStrings_Release(data->info_strings[i]);
472 if (data->names)
473 IDWriteLocalizedStrings_Release(data->names);
475 if (data->family_names)
476 IDWriteLocalizedStrings_Release(data->family_names);
478 dwrite_cmap_release(&data->cmap);
479 IDWriteFontFile_Release(data->file);
480 heap_free(data->facename);
481 heap_free(data);
484 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
486 size_t i;
488 if (InterlockedDecrement(&data->refcount) > 0)
489 return;
491 for (i = 0; i < data->count; ++i)
492 release_font_data(data->fonts[i]);
493 heap_free(data->fonts);
494 IDWriteLocalizedStrings_Release(data->familyname);
495 heap_free(data);
498 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
500 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
501 fontface->cached = NULL;
504 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
506 UINT32 left_key_size, right_key_size;
507 const void *left_key, *right_key;
508 HRESULT hr;
510 if (left == right)
511 return TRUE;
513 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
514 if (FAILED(hr))
515 return FALSE;
517 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
518 if (FAILED(hr))
519 return FALSE;
521 if (left_key_size != right_key_size)
522 return FALSE;
524 return !memcmp(left_key, right_key, left_key_size);
527 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
529 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
531 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
533 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
534 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
535 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
536 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
537 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
538 IsEqualIID(riid, &IID_IDWriteFontFace) ||
539 IsEqualIID(riid, &IID_IUnknown))
541 *obj = iface;
543 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
544 *obj = &fontface->IDWriteFontFaceReference_iface;
545 else
546 *obj = NULL;
548 if (*obj)
550 if (InterlockedIncrement(&fontface->refcount) == 1)
552 InterlockedDecrement(&fontface->refcount);
553 *obj = NULL;
554 return E_FAIL;
556 return S_OK;
559 WARN("%s not implemented.\n", debugstr_guid(riid));
561 return E_NOINTERFACE;
564 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
566 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
567 ULONG refcount = InterlockedIncrement(&fontface->refcount);
569 TRACE("%p, refcount %u.\n", iface, refcount);
571 return refcount;
574 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
576 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
577 ULONG refcount = InterlockedDecrement(&fontface->refcount);
579 TRACE("%p, refcount %u.\n", iface, refcount);
581 if (!refcount)
583 UINT32 i;
585 if (fontface->cached)
587 factory_lock(fontface->factory);
588 list_remove(&fontface->cached->entry);
589 factory_unlock(fontface->factory);
590 heap_free(fontface->cached);
592 release_scriptshaping_cache(fontface->shaping_cache);
593 if (fontface->vdmx.context)
594 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
595 if (fontface->gasp.context)
596 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
597 if (fontface->cpal.context)
598 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
599 if (fontface->colr.context)
600 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
601 for (i = 0; i < fontface->file_count; i++)
603 if (fontface->files[i])
604 IDWriteFontFile_Release(fontface->files[i]);
606 if (fontface->stream)
607 IDWriteFontFileStream_Release(fontface->stream);
608 heap_free(fontface->files);
609 if (fontface->names)
610 IDWriteLocalizedStrings_Release(fontface->names);
611 if (fontface->family_names)
612 IDWriteLocalizedStrings_Release(fontface->family_names);
613 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
615 if (fontface->info_strings[i])
616 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
619 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
620 heap_free(fontface->glyphs[i]);
622 freetype_notify_cacheremove(iface);
624 dwrite_cmap_release(&fontface->cmap);
625 IDWriteFactory7_Release(fontface->factory);
626 heap_free(fontface);
629 return refcount;
632 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
634 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
636 TRACE("%p.\n", iface);
638 return fontface->type;
641 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
642 IDWriteFontFile **fontfiles)
644 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
645 int i;
647 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
649 if (fontfiles == NULL)
651 *number_of_files = fontface->file_count;
652 return S_OK;
655 if (*number_of_files < fontface->file_count)
656 return E_INVALIDARG;
658 for (i = 0; i < fontface->file_count; i++)
660 IDWriteFontFile_AddRef(fontface->files[i]);
661 fontfiles[i] = fontface->files[i];
664 return S_OK;
667 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
669 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
671 TRACE("%p.\n", iface);
673 return fontface->index;
676 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
678 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
680 TRACE("%p.\n", iface);
682 return fontface->simulations;
685 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
687 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
689 TRACE("%p.\n", iface);
691 return !!(fontface->flags & FONT_IS_SYMBOL);
694 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
696 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
698 TRACE("%p, %p.\n", iface, metrics);
700 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
703 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
705 TRACE("%p.\n", iface);
707 return freetype_get_glyphcount(iface);
710 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
711 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
713 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
714 unsigned int i;
715 HRESULT hr;
717 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
719 if (!glyphs)
720 return E_INVALIDARG;
722 if (is_sideways)
723 FIXME("sideways metrics are not supported.\n");
725 for (i = 0; i < glyph_count; i++) {
726 DWRITE_GLYPH_METRICS metrics;
728 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
729 if (hr != S_OK) {
730 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
731 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
732 if (FAILED(hr))
733 return hr;
735 ret[i] = metrics;
738 return S_OK;
741 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
742 UINT32 count, UINT16 *glyphs)
744 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
745 unsigned int i;
747 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
749 if (!glyphs)
750 return E_INVALIDARG;
752 if (!codepoints)
754 memset(glyphs, 0, count * sizeof(*glyphs));
755 return E_INVALIDARG;
758 for (i = 0; i < count; ++i)
759 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
761 return S_OK;
764 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
765 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
767 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
768 struct file_stream_desc stream_desc;
770 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
772 stream_desc.stream = fontface->stream;
773 stream_desc.face_type = fontface->type;
774 stream_desc.face_index = fontface->index;
775 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
778 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
780 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
782 TRACE("%p, %p.\n", iface, table_context);
784 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
787 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
788 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
789 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
791 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
792 count, is_sideways, is_rtl, sink);
794 if (!glyphs || !sink)
795 return E_INVALIDARG;
797 if (is_sideways)
798 FIXME("sideways mode is not supported.\n");
800 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
803 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
804 float ppem, unsigned int gasp)
806 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
808 switch (measuring)
810 case DWRITE_MEASURING_MODE_NATURAL:
812 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
813 mode = DWRITE_RENDERING_MODE_NATURAL;
814 else
815 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
816 break;
818 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
819 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
820 break;
821 case DWRITE_MEASURING_MODE_GDI_NATURAL:
822 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
823 break;
824 default:
828 return mode;
831 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
832 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
834 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
835 unsigned int flags;
836 FLOAT ppem;
838 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
840 if (!params) {
841 *mode = DWRITE_RENDERING_MODE_DEFAULT;
842 return E_INVALIDARG;
845 *mode = IDWriteRenderingParams_GetRenderingMode(params);
846 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
847 return S_OK;
849 ppem = emSize * ppdip;
851 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
852 *mode = DWRITE_RENDERING_MODE_OUTLINE;
853 return S_OK;
856 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
857 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
858 return S_OK;
861 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
862 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
864 DWRITE_FONT_METRICS1 metrics1;
865 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
866 memcpy(metrics, &metrics1, sizeof(*metrics));
867 return hr;
870 static inline int round_metric(FLOAT metric)
872 return (int)floorf(metric + 0.5f);
875 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
877 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
878 return 0;
880 return (fontface->metrics.designUnitsPerEm + 49) / 50;
883 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
884 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
885 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
887 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
888 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
889 DWRITE_MEASURING_MODE mode;
890 FLOAT scale, size;
891 HRESULT hr;
892 UINT32 i;
894 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
895 glyph_count, metrics, is_sideways);
897 if (m && memcmp(m, &identity, sizeof(*m)))
898 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
900 size = emSize * ppdip;
901 scale = size / fontface->metrics.designUnitsPerEm;
902 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
904 for (i = 0; i < glyph_count; i++) {
905 DWRITE_GLYPH_METRICS *ret = metrics + i;
906 DWRITE_GLYPH_METRICS design;
907 BOOL has_contours;
909 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
910 if (FAILED(hr))
911 return hr;
913 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
914 if (has_contours)
915 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
916 else
917 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
919 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
920 SCALE_METRIC(leftSideBearing);
921 SCALE_METRIC(rightSideBearing);
922 SCALE_METRIC(topSideBearing);
923 SCALE_METRIC(advanceHeight);
924 SCALE_METRIC(bottomSideBearing);
925 SCALE_METRIC(verticalOriginY);
926 #undef SCALE_METRIC
929 return S_OK;
932 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
934 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
936 TRACE("%p, %p.\n", iface, metrics);
938 *metrics = fontface->metrics;
941 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
942 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
944 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
945 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
946 UINT16 ascent, descent;
947 FLOAT scale;
949 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
951 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
952 memset(metrics, 0, sizeof(*metrics));
953 return E_INVALIDARG;
956 em_size *= pixels_per_dip;
957 if (m && m->m22 != 0.0f)
958 em_size *= fabs(m->m22);
960 scale = em_size / design->designUnitsPerEm;
961 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
963 ascent = round_metric(design->ascent * scale);
964 descent = round_metric(design->descent * scale);
967 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
968 metrics->designUnitsPerEm = design->designUnitsPerEm;
969 metrics->ascent = round_metric(ascent / scale);
970 metrics->descent = round_metric(descent / scale);
972 SCALE_METRIC(lineGap);
973 SCALE_METRIC(capHeight);
974 SCALE_METRIC(xHeight);
975 SCALE_METRIC(underlinePosition);
976 SCALE_METRIC(underlineThickness);
977 SCALE_METRIC(strikethroughPosition);
978 SCALE_METRIC(strikethroughThickness);
979 SCALE_METRIC(glyphBoxLeft);
980 SCALE_METRIC(glyphBoxTop);
981 SCALE_METRIC(glyphBoxRight);
982 SCALE_METRIC(glyphBoxBottom);
983 SCALE_METRIC(subscriptPositionX);
984 SCALE_METRIC(subscriptPositionY);
985 SCALE_METRIC(subscriptSizeX);
986 SCALE_METRIC(subscriptSizeY);
987 SCALE_METRIC(superscriptPositionX);
988 SCALE_METRIC(superscriptPositionY);
989 SCALE_METRIC(superscriptSizeX);
990 SCALE_METRIC(superscriptSizeY);
992 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
993 #undef SCALE_METRIC
995 return S_OK;
998 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1000 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1002 TRACE("%p, %p.\n", iface, metrics);
1004 *metrics = fontface->caret;
1007 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1008 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1010 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1012 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1014 *count = 0;
1015 if (max_count && !ranges)
1016 return E_INVALIDARG;
1018 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1019 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1022 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1024 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1026 TRACE("%p.\n", iface);
1028 return !!(fontface->flags & FONT_IS_MONOSPACED);
1031 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1032 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1034 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1035 BOOL has_contours;
1036 int advance;
1038 if (is_sideways)
1039 FIXME("Sideways mode is not supported.\n");
1041 switch (measuring_mode)
1043 case DWRITE_MEASURING_MODE_NATURAL:
1044 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1045 glyph, measuring_mode, &has_contours);
1046 if (has_contours)
1047 advance += adjustment;
1049 return advance;
1050 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1051 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1052 emsize *= ppdip;
1053 if (emsize == 0.0f)
1054 return 0.0f;
1056 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1057 FIXME("Transform is not supported.\n");
1059 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1060 &has_contours);
1061 if (has_contours)
1062 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1063 else
1064 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1066 return advance;
1067 default:
1068 WARN("Unknown measuring mode %u.\n", measuring_mode);
1069 return 0;
1073 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1074 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1076 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1077 unsigned int i;
1079 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1081 if (is_sideways)
1082 FIXME("sideways mode not supported\n");
1084 for (i = 0; i < glyph_count; ++i)
1086 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1087 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1090 return S_OK;
1093 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1094 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1095 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1097 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1098 DWRITE_MEASURING_MODE measuring_mode;
1099 UINT32 i;
1101 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1102 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1104 if (em_size < 0.0f || ppdip <= 0.0f) {
1105 memset(advances, 0, sizeof(*advances) * glyph_count);
1106 return E_INVALIDARG;
1109 if (em_size == 0.0f) {
1110 memset(advances, 0, sizeof(*advances) * glyph_count);
1111 return S_OK;
1114 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1115 for (i = 0; i < glyph_count; ++i)
1117 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1118 glyphs[i], is_sideways);
1121 return S_OK;
1124 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1125 const UINT16 *indices, INT32 *adjustments)
1127 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1128 UINT32 i;
1130 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1132 if (!(indices || adjustments) || !count)
1133 return E_INVALIDARG;
1135 if (!indices || count == 1) {
1136 memset(adjustments, 0, count*sizeof(INT32));
1137 return E_INVALIDARG;
1140 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1142 memset(adjustments, 0, count*sizeof(INT32));
1143 return S_OK;
1146 for (i = 0; i < count-1; i++)
1147 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1148 adjustments[count-1] = 0;
1150 return S_OK;
1153 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1155 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1157 TRACE("%p.\n", iface);
1159 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1162 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1163 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1164 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1166 DWRITE_GRID_FIT_MODE gridfitmode;
1167 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1168 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1171 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1172 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1174 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1176 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1178 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1181 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1183 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1185 TRACE("%p.\n", iface);
1187 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1190 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1192 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1194 TRACE("%p.\n", iface);
1196 return !!(fontface->flags & FONT_IS_COLORED);
1199 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1201 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1203 TRACE("%p.\n", iface);
1205 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1208 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1210 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1212 TRACE("%p.\n", iface);
1214 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1217 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1218 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1220 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1222 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1224 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1227 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1228 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1229 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1230 DWRITE_GRID_FIT_MODE *gridfitmode)
1232 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1233 unsigned int flags;
1234 FLOAT emthreshold;
1236 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1237 measuringmode, params, renderingmode, gridfitmode);
1239 if (m)
1240 FIXME("transform not supported %s\n", debugstr_matrix(m));
1242 if (is_sideways)
1243 FIXME("sideways mode not supported\n");
1245 emSize *= max(dpiX, dpiY) / 96.0f;
1247 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1248 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1249 if (params) {
1250 IDWriteRenderingParams2 *params2;
1251 HRESULT hr;
1253 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1254 if (hr == S_OK) {
1255 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1256 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1257 IDWriteRenderingParams2_Release(params2);
1259 else
1260 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1263 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1265 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1267 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1268 if (emSize >= emthreshold)
1269 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1270 else
1271 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1274 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1275 if (emSize >= emthreshold)
1276 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1277 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1278 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1279 else
1280 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1281 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1284 return S_OK;
1287 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1288 IDWriteFontFaceReference **reference)
1290 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1292 TRACE("%p, %p.\n", iface, reference);
1294 *reference = &fontface->IDWriteFontFaceReference_iface;
1295 IDWriteFontFaceReference_AddRef(*reference);
1297 return S_OK;
1300 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1302 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1304 TRACE("%p, %p.\n", iface, panose);
1306 *panose = fontface->panose;
1309 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1311 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1313 TRACE("%p.\n", iface);
1315 return fontface->weight;
1318 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1320 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1322 TRACE("%p.\n", iface);
1324 return fontface->stretch;
1327 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1329 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1331 TRACE("%p.\n", iface);
1333 return fontface->style;
1336 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1338 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1340 TRACE("%p, %p.\n", iface, names);
1342 return clone_localizedstrings(fontface->family_names, names);
1345 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1347 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1349 TRACE("%p, %p.\n", iface, names);
1351 return clone_localizedstrings(fontface->names, names);
1354 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1355 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1356 IDWriteLocalizedStrings **ret, BOOL *exists)
1358 HRESULT hr = S_OK;
1360 *exists = FALSE;
1361 *ret = NULL;
1363 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1364 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1366 return S_OK;
1369 if (!strings_cache[stringid])
1371 struct file_stream_desc desc = *stream_desc;
1373 if (!desc.stream)
1374 hr = get_filestream_from_file(file, &desc.stream);
1375 if (SUCCEEDED(hr))
1376 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1378 if (!stream_desc->stream && desc.stream)
1379 IDWriteFontFileStream_Release(desc.stream);
1382 if (SUCCEEDED(hr) && strings_cache[stringid])
1384 hr = clone_localizedstrings(strings_cache[stringid], ret);
1385 if (SUCCEEDED(hr))
1386 *exists = TRUE;
1389 return hr;
1392 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1393 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1395 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1396 struct file_stream_desc stream_desc;
1398 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1400 stream_desc.stream = fontface->stream;
1401 stream_desc.face_index = fontface->index;
1402 stream_desc.face_type = fontface->type;
1403 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1406 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1408 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1410 TRACE("%p, %#x.\n", iface, ch);
1412 return !!dwritefontface_get_glyph(fontface, ch);
1415 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1416 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1417 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1419 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1420 unsigned int flags;
1421 FLOAT emthreshold;
1423 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1424 measuring_mode, params, rendering_mode, gridfit_mode);
1426 if (m)
1427 FIXME("transform not supported %s\n", debugstr_matrix(m));
1429 if (is_sideways)
1430 FIXME("sideways mode not supported\n");
1432 emSize *= max(dpiX, dpiY) / 96.0f;
1434 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1435 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1436 if (params) {
1437 IDWriteRenderingParams3 *params3;
1438 HRESULT hr;
1440 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1441 if (hr == S_OK) {
1442 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1443 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1444 IDWriteRenderingParams3_Release(params3);
1446 else
1447 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1450 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1452 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1454 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1455 if (emSize >= emthreshold)
1456 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1457 else
1458 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1461 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1462 if (emSize >= emthreshold)
1463 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1464 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1465 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1466 else
1467 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1468 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1471 return S_OK;
1474 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1476 FIXME("%p, %#x: stub\n", iface, ch);
1478 return FALSE;
1481 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1483 FIXME("%p, %u: stub\n", iface, glyph);
1485 return FALSE;
1488 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1489 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1491 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1493 return E_NOTIMPL;
1496 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1497 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1499 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1501 return E_NOTIMPL;
1504 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1505 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1507 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1509 return E_NOTIMPL;
1512 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1514 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1516 TRACE("%p.\n", iface);
1518 return fontface->glyph_image_formats;
1521 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1522 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1524 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1526 return E_NOTIMPL;
1529 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1531 FIXME("%p, %p: stub\n", iface, context);
1534 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1536 FIXME("%p: stub\n", iface);
1538 return 0;
1541 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1542 UINT32 value_count)
1544 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1546 return E_NOTIMPL;
1549 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1551 static int once;
1553 if (!once++)
1554 FIXME("%p: stub\n", iface);
1556 return FALSE;
1559 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1561 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1563 TRACE("%p, %p.\n", iface, resource);
1565 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1568 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1570 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1572 TRACE("%p, %p.\n", iface, other);
1574 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1575 return FALSE;
1577 /* TODO: add variations support */
1579 return fontface->index == other_face->index &&
1580 fontface->simulations == other_face->simulations &&
1581 is_same_fontfile(fontface->files[0], other_face->files[0]);
1584 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1586 dwritefontface_QueryInterface,
1587 dwritefontface_AddRef,
1588 dwritefontface_Release,
1589 dwritefontface_GetType,
1590 dwritefontface_GetFiles,
1591 dwritefontface_GetIndex,
1592 dwritefontface_GetSimulations,
1593 dwritefontface_IsSymbolFont,
1594 dwritefontface_GetMetrics,
1595 dwritefontface_GetGlyphCount,
1596 dwritefontface_GetDesignGlyphMetrics,
1597 dwritefontface_GetGlyphIndices,
1598 dwritefontface_TryGetFontTable,
1599 dwritefontface_ReleaseFontTable,
1600 dwritefontface_GetGlyphRunOutline,
1601 dwritefontface_GetRecommendedRenderingMode,
1602 dwritefontface_GetGdiCompatibleMetrics,
1603 dwritefontface_GetGdiCompatibleGlyphMetrics,
1604 dwritefontface1_GetMetrics,
1605 dwritefontface1_GetGdiCompatibleMetrics,
1606 dwritefontface1_GetCaretMetrics,
1607 dwritefontface1_GetUnicodeRanges,
1608 dwritefontface1_IsMonospacedFont,
1609 dwritefontface1_GetDesignGlyphAdvances,
1610 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1611 dwritefontface1_GetKerningPairAdjustments,
1612 dwritefontface1_HasKerningPairs,
1613 dwritefontface1_GetRecommendedRenderingMode,
1614 dwritefontface1_GetVerticalGlyphVariants,
1615 dwritefontface1_HasVerticalGlyphVariants,
1616 dwritefontface2_IsColorFont,
1617 dwritefontface2_GetColorPaletteCount,
1618 dwritefontface2_GetPaletteEntryCount,
1619 dwritefontface2_GetPaletteEntries,
1620 dwritefontface2_GetRecommendedRenderingMode,
1621 dwritefontface3_GetFontFaceReference,
1622 dwritefontface3_GetPanose,
1623 dwritefontface3_GetWeight,
1624 dwritefontface3_GetStretch,
1625 dwritefontface3_GetStyle,
1626 dwritefontface3_GetFamilyNames,
1627 dwritefontface3_GetFaceNames,
1628 dwritefontface3_GetInformationalStrings,
1629 dwritefontface3_HasCharacter,
1630 dwritefontface3_GetRecommendedRenderingMode,
1631 dwritefontface3_IsCharacterLocal,
1632 dwritefontface3_IsGlyphLocal,
1633 dwritefontface3_AreCharactersLocal,
1634 dwritefontface3_AreGlyphsLocal,
1635 dwritefontface4_GetGlyphImageFormats_,
1636 dwritefontface4_GetGlyphImageFormats,
1637 dwritefontface4_GetGlyphImageData,
1638 dwritefontface4_ReleaseGlyphImageData,
1639 dwritefontface5_GetFontAxisValueCount,
1640 dwritefontface5_GetFontAxisValues,
1641 dwritefontface5_HasVariations,
1642 dwritefontface5_GetFontResource,
1643 dwritefontface5_Equals,
1646 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1648 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1649 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1652 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1654 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1655 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1658 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1660 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1661 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1664 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1665 IDWriteFontFace3 **ret)
1667 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1669 TRACE("%p, %p.\n", iface, ret);
1671 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1672 IDWriteFontFace3_AddRef(*ret);
1674 return S_OK;
1677 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1678 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1680 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1681 DWRITE_FONT_FILE_TYPE file_type;
1682 DWRITE_FONT_FACE_TYPE face_type;
1683 IDWriteFontFace *face;
1684 BOOL is_supported;
1685 UINT32 face_num;
1686 HRESULT hr;
1688 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1690 hr = IDWriteFontFile_Analyze(fontface->files[0], &is_supported, &file_type, &face_type, &face_num);
1691 if (FAILED(hr))
1692 return hr;
1694 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, fontface->files, fontface->index,
1695 simulations, &face);
1696 if (SUCCEEDED(hr))
1698 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1699 IDWriteFontFace_Release(face);
1702 return hr;
1705 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1707 FIXME("%p, %p.\n", iface, ref);
1709 return E_NOTIMPL;
1712 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1714 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1716 TRACE("%p.\n", iface);
1718 return fontface->index;
1721 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1723 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1725 TRACE("%p.\n", iface);
1727 return fontface->simulations;
1730 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1732 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1734 TRACE("%p, %p.\n", iface, file);
1736 *file = fontface->files[0];
1737 IDWriteFontFile_AddRef(*file);
1739 return S_OK;
1742 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1744 FIXME("%p.\n", iface);
1746 return 0;
1749 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1751 FIXME("%p.\n", iface);
1753 return 0;
1756 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1758 FIXME("%p, %p.\n", iface, writetime);
1760 return E_NOTIMPL;
1763 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1765 FIXME("%p.\n", iface);
1767 return DWRITE_LOCALITY_LOCAL;
1770 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1772 FIXME("%p.\n", iface);
1774 return E_NOTIMPL;
1777 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1778 WCHAR const *chars, UINT32 count)
1780 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1782 return E_NOTIMPL;
1785 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1786 UINT16 const *glyphs, UINT32 count)
1788 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1790 return E_NOTIMPL;
1793 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1794 UINT64 offset, UINT64 size)
1796 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1798 return E_NOTIMPL;
1801 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1803 dwritefontface_reference_QueryInterface,
1804 dwritefontface_reference_AddRef,
1805 dwritefontface_reference_Release,
1806 dwritefontface_reference_CreateFontFace,
1807 dwritefontface_reference_CreateFontFaceWithSimulations,
1808 dwritefontface_reference_Equals,
1809 dwritefontface_reference_GetFontFaceIndex,
1810 dwritefontface_reference_GetSimulations,
1811 dwritefontface_reference_GetFontFile,
1812 dwritefontface_reference_GetLocalFileSize,
1813 dwritefontface_reference_GetFileSize,
1814 dwritefontface_reference_GetFileTime,
1815 dwritefontface_reference_GetLocality,
1816 dwritefontface_reference_EnqueueFontDownloadRequest,
1817 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1818 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1819 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1822 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1824 struct dwrite_font_data *data = font->data;
1825 struct fontface_desc desc;
1826 struct list *cached_list;
1827 HRESULT hr;
1829 *fontface = NULL;
1831 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1832 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1833 if (hr == S_OK)
1834 return hr;
1836 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1837 return hr;
1839 desc.factory = font->family->collection->factory;
1840 desc.face_type = data->face_type;
1841 desc.files = &data->file;
1842 desc.files_number = 1;
1843 desc.index = data->face_index;
1844 desc.simulations = data->simulations;
1845 desc.font_data = data;
1846 hr = create_fontface(&desc, cached_list, fontface);
1848 IDWriteFontFileStream_Release(desc.stream);
1849 return hr;
1852 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1854 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1856 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1857 IsEqualIID(riid, &IID_IDWriteFont2) ||
1858 IsEqualIID(riid, &IID_IDWriteFont1) ||
1859 IsEqualIID(riid, &IID_IDWriteFont) ||
1860 IsEqualIID(riid, &IID_IUnknown))
1862 *obj = iface;
1863 IDWriteFont3_AddRef(iface);
1864 return S_OK;
1867 WARN("%s not implemented.\n", debugstr_guid(riid));
1869 *obj = NULL;
1870 return E_NOINTERFACE;
1873 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1875 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1876 ULONG refcount = InterlockedIncrement(&font->refcount);
1878 TRACE("%p, refcount %d.\n", iface, refcount);
1880 return refcount;
1883 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1885 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1886 ULONG refcount = InterlockedDecrement(&font->refcount);
1888 TRACE("%p, refcount %d.\n", iface, refcount);
1890 if (!refcount)
1892 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
1893 release_font_data(font->data);
1894 heap_free(font);
1897 return refcount;
1900 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1902 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1904 TRACE("%p, %p.\n", iface, family);
1906 *family = (IDWriteFontFamily *)font->family;
1907 IDWriteFontFamily_AddRef(*family);
1908 return S_OK;
1911 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1913 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1915 TRACE("%p.\n", iface);
1917 return font->data->weight;
1920 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1922 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1924 TRACE("%p.\n", iface);
1926 return font->data->stretch;
1929 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1931 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1933 TRACE("%p.\n", iface);
1935 return font->style;
1938 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1940 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1942 TRACE("%p.\n", iface);
1944 return !!(font->data->flags & FONT_IS_SYMBOL);
1947 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1949 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1951 TRACE("%p, %p.\n", iface, names);
1953 return clone_localizedstrings(font->data->names, names);
1956 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1957 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1959 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1960 struct dwrite_font_data *data = font->data;
1961 struct file_stream_desc stream_desc;
1963 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1965 /* Stream will be created if necessary. */
1966 stream_desc.stream = NULL;
1967 stream_desc.face_index = data->face_index;
1968 stream_desc.face_type = data->face_type;
1969 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1972 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1974 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1976 TRACE("%p.\n", iface);
1978 return font->data->simulations;
1981 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1983 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1985 TRACE("%p, %p.\n", iface, metrics);
1987 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
1990 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
1992 UINT16 glyph;
1993 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
1994 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
1995 return glyph != 0;
1998 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2000 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2002 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2004 *exists = dwritefont_has_character(font, ch);
2006 return S_OK;
2009 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2011 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2013 TRACE("%p, %p.\n", iface, fontface);
2015 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2018 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2020 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2022 TRACE("%p, %p.\n", iface, metrics);
2024 *metrics = font->data->metrics;
2027 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2029 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2031 TRACE("%p, %p.\n", iface, panose);
2033 *panose = font->data->panose;
2036 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2037 UINT32 *count)
2039 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2041 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2043 *count = 0;
2044 if (max_count && !ranges)
2045 return E_INVALIDARG;
2047 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2048 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2051 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2053 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2055 TRACE("%p.\n", iface);
2057 return !!(font->data->flags & FONT_IS_MONOSPACED);
2060 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2062 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2064 TRACE("%p.\n", iface);
2066 return !!(font->data->flags & FONT_IS_COLORED);
2069 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2071 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2073 TRACE("%p, %p.\n", iface, fontface);
2075 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2078 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2080 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2082 TRACE("%p, %p.\n", iface, other);
2084 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2085 return FALSE;
2087 return font->data->face_index == other_font->data->face_index
2088 && font->data->simulations == other_font->data->simulations
2089 && is_same_fontfile(font->data->file, other_font->data->file);
2092 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2094 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2096 TRACE("%p, %p.\n", iface, reference);
2098 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2099 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2100 (IDWriteFontFaceReference1 **)reference);
2103 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2105 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2107 TRACE("%p, %#x.\n", iface, ch);
2109 return dwritefont_has_character(font, ch);
2112 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2114 FIXME("%p: stub.\n", iface);
2116 return DWRITE_LOCALITY_LOCAL;
2119 static const IDWriteFont3Vtbl dwritefontvtbl = {
2120 dwritefont_QueryInterface,
2121 dwritefont_AddRef,
2122 dwritefont_Release,
2123 dwritefont_GetFontFamily,
2124 dwritefont_GetWeight,
2125 dwritefont_GetStretch,
2126 dwritefont_GetStyle,
2127 dwritefont_IsSymbolFont,
2128 dwritefont_GetFaceNames,
2129 dwritefont_GetInformationalStrings,
2130 dwritefont_GetSimulations,
2131 dwritefont_GetMetrics,
2132 dwritefont_HasCharacter,
2133 dwritefont_CreateFontFace,
2134 dwritefont1_GetMetrics,
2135 dwritefont1_GetPanose,
2136 dwritefont1_GetUnicodeRanges,
2137 dwritefont1_IsMonospacedFont,
2138 dwritefont2_IsColorFont,
2139 dwritefont3_CreateFontFace,
2140 dwritefont3_Equals,
2141 dwritefont3_GetFontFaceReference,
2142 dwritefont3_HasCharacter,
2143 dwritefont3_GetLocality
2146 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2148 if (!iface)
2149 return NULL;
2150 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2151 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2154 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2156 if (!iface)
2157 return NULL;
2158 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2159 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2162 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2164 if (!iface)
2165 return NULL;
2166 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2167 return NULL;
2168 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2169 IDWriteFontFaceReference1_iface);
2172 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2174 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2175 *lf = font->data->lf;
2178 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2180 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2181 *lf = fontface->lf;
2184 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2186 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2187 *fontsig = font->data->fontsig;
2188 return S_OK;
2191 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2193 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2194 *fontsig = fontface->fontsig;
2195 return S_OK;
2198 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2200 struct dwrite_font *object;
2202 *font = NULL;
2204 if (!(object = heap_alloc(sizeof(*object))))
2205 return E_OUTOFMEMORY;
2207 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2208 object->refcount = 1;
2209 object->family = family;
2210 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2211 object->data = family->data->fonts[index];
2212 object->style = object->data->style;
2213 addref_font_data(object->data);
2215 *font = &object->IDWriteFont3_iface;
2217 return S_OK;
2220 /* IDWriteFontList2 */
2221 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2223 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2225 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2226 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2227 IsEqualIID(riid, &IID_IDWriteFontList) ||
2228 IsEqualIID(riid, &IID_IUnknown))
2230 *obj = iface;
2231 IDWriteFontList2_AddRef(iface);
2232 return S_OK;
2235 WARN("%s not implemented.\n", debugstr_guid(riid));
2237 *obj = NULL;
2238 return E_NOINTERFACE;
2241 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2243 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2244 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2246 TRACE("%p, refcount %u.\n", iface, refcount);
2248 return refcount;
2251 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2253 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2254 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2256 TRACE("%p, refcount %u.\n", iface, refcount);
2258 if (!refcount)
2260 UINT32 i;
2262 for (i = 0; i < fontlist->font_count; i++)
2263 release_font_data(fontlist->fonts[i]);
2264 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2265 heap_free(fontlist->fonts);
2266 heap_free(fontlist);
2269 return refcount;
2272 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2274 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2275 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2278 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2280 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2282 TRACE("%p.\n", iface);
2284 return fontlist->font_count;
2287 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2289 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2291 TRACE("%p, %u, %p.\n", iface, index, font);
2293 *font = NULL;
2295 if (fontlist->font_count == 0)
2296 return S_FALSE;
2298 if (index >= fontlist->font_count)
2299 return E_INVALIDARG;
2301 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2304 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2306 FIXME("%p, %u.\n", iface, index);
2308 return DWRITE_LOCALITY_LOCAL;
2311 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2313 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2315 TRACE("%p, %u, %p.\n", iface, index, font);
2317 *font = NULL;
2319 if (fontlist->font_count == 0)
2320 return S_FALSE;
2322 if (index >= fontlist->font_count)
2323 return E_FAIL;
2325 return create_font(fontlist->family, index, font);
2328 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2329 IDWriteFontFaceReference **reference)
2331 IDWriteFont3 *font;
2332 HRESULT hr;
2334 TRACE("%p, %u, %p.\n", iface, index, reference);
2336 *reference = NULL;
2338 hr = IDWriteFontList2_GetFont(iface, index, &font);
2339 if (FAILED(hr))
2340 return hr;
2342 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2343 IDWriteFont3_Release(font);
2345 return hr;
2348 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2350 FIXME("%p, %p.\n", iface, fontset);
2352 return E_NOTIMPL;
2355 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2357 dwritefontlist_QueryInterface,
2358 dwritefontlist_AddRef,
2359 dwritefontlist_Release,
2360 dwritefontlist_GetFontCollection,
2361 dwritefontlist_GetFontCount,
2362 dwritefontlist_GetFont,
2363 dwritefontlist1_GetFontLocality,
2364 dwritefontlist1_GetFont,
2365 dwritefontlist1_GetFontFaceReference,
2366 dwritefontlist2_GetFontSet,
2369 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2371 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2373 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2375 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2376 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2377 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2378 IsEqualIID(riid, &IID_IUnknown))
2380 *obj = iface;
2382 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2383 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2384 IsEqualIID(riid, &IID_IDWriteFontList))
2386 *obj = &family->IDWriteFontList2_iface;
2388 else
2390 WARN("%s not implemented.\n", debugstr_guid(riid));
2391 *obj = NULL;
2392 return E_NOINTERFACE;
2395 IUnknown_AddRef((IUnknown *)*obj);
2396 return S_OK;
2399 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2401 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2402 ULONG refcount = InterlockedIncrement(&family->refcount);
2404 TRACE("%p, %u.\n", iface, refcount);
2406 return refcount;
2409 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2411 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2412 ULONG refcount = InterlockedDecrement(&family->refcount);
2414 TRACE("%p, %u.\n", iface, refcount);
2416 if (!refcount)
2418 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2419 release_fontfamily_data(family->data);
2420 heap_free(family);
2423 return refcount;
2426 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2428 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2430 TRACE("%p, %p.\n", iface, collection);
2432 *collection = (IDWriteFontCollection *)family->collection;
2433 IDWriteFontCollection_AddRef(*collection);
2434 return S_OK;
2437 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2439 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2441 TRACE("%p.\n", iface);
2443 return family->data->count;
2446 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2448 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2450 TRACE("%p, %u, %p.\n", iface, index, font);
2452 *font = NULL;
2454 if (!family->data->count)
2455 return S_FALSE;
2457 if (index >= family->data->count)
2458 return E_INVALIDARG;
2460 return create_font(family, index, (IDWriteFont3 **)font);
2463 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2465 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2467 TRACE("%p, %p.\n", iface, names);
2469 return clone_localizedstrings(family->data->familyname, names);
2472 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2473 const struct dwrite_font_propvec *req)
2475 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2476 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2477 FLOAT cur_req_prod, next_req_prod;
2479 if (next_to_req < cur_to_req)
2480 return TRUE;
2482 if (next_to_req > cur_to_req)
2483 return FALSE;
2485 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2486 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2488 if (next_req_prod > cur_req_prod)
2489 return TRUE;
2491 if (next_req_prod < cur_req_prod)
2492 return FALSE;
2494 if (next->stretch > cur->stretch)
2495 return TRUE;
2496 if (next->stretch < cur->stretch)
2497 return FALSE;
2499 if (next->style > cur->style)
2500 return TRUE;
2501 if (next->style < cur->style)
2502 return FALSE;
2504 if (next->weight > cur->weight)
2505 return TRUE;
2506 if (next->weight < cur->weight)
2507 return FALSE;
2509 /* full match, no reason to prefer new variant */
2510 return FALSE;
2513 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2514 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2516 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2517 struct dwrite_font_propvec req;
2518 size_t i, match;
2520 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2522 if (!family->data->count)
2524 *font = NULL;
2525 return DWRITE_E_NOFONT;
2528 init_font_prop_vec(weight, stretch, style, &req);
2529 match = 0;
2531 for (i = 1; i < family->data->count; ++i)
2533 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2534 match = i;
2537 return create_font(family, match, (IDWriteFont3 **)font);
2540 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2542 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2544 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2547 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2549 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2552 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2554 UINT32 b = fonts->font_count - 1, j, t;
2556 while (1) {
2557 t = b;
2559 for (j = 0; j < b; j++) {
2560 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2561 struct dwrite_font_data *s = fonts->fonts[j];
2562 fonts->fonts[j] = fonts->fonts[j+1];
2563 fonts->fonts[j+1] = s;
2564 t = j;
2568 if (t == b)
2569 break;
2570 b = t;
2574 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2575 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2577 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2578 matching_filter_func func = NULL;
2579 struct dwrite_font_propvec req;
2580 struct dwrite_fontlist *fonts;
2581 size_t i;
2583 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2585 *ret = NULL;
2587 fonts = heap_alloc(sizeof(*fonts));
2588 if (!fonts)
2589 return E_OUTOFMEMORY;
2591 /* Allocate as many as family has, not all of them will be necessary used. */
2592 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2593 if (!fonts->fonts) {
2594 heap_free(fonts);
2595 return E_OUTOFMEMORY;
2598 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2599 fonts->refcount = 1;
2600 fonts->family = family;
2601 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2602 fonts->font_count = 0;
2604 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2605 if (style == DWRITE_FONT_STYLE_NORMAL) {
2606 if (family->data->has_normal_face || family->data->has_italic_face)
2607 func = is_font_acceptable_for_normal;
2609 else /* requested oblique or italic */ {
2610 if (family->data->has_oblique_face || family->data->has_italic_face)
2611 func = is_font_acceptable_for_oblique_italic;
2614 for (i = 0; i < family->data->count; ++i)
2616 if (!func || func(family->data->fonts[i]))
2618 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2619 addref_font_data(family->data->fonts[i]);
2620 fonts->font_count++;
2624 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2625 init_font_prop_vec(weight, stretch, style, &req);
2626 matchingfonts_sort(fonts, &req);
2628 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2629 return S_OK;
2632 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2634 FIXME("%p, %u.\n", iface, index);
2636 return DWRITE_LOCALITY_LOCAL;
2639 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2641 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2643 TRACE("%p, %u, %p.\n", iface, index, font);
2645 *font = NULL;
2647 if (!family->data->count)
2648 return S_FALSE;
2650 if (index >= family->data->count)
2651 return E_FAIL;
2653 return create_font(family, index, font);
2656 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2657 IDWriteFontFaceReference **reference)
2659 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2660 const struct dwrite_font_data *font;
2662 TRACE("%p, %u, %p.\n", iface, index, reference);
2664 *reference = NULL;
2666 if (index >= family->data->count)
2667 return E_FAIL;
2669 font = family->data->fonts[index];
2670 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2671 font->file, font->face_index, font->simulations, reference);
2674 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2675 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2677 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2679 return E_NOTIMPL;
2682 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2684 FIXME("%p, %p.\n", iface, fontset);
2686 return E_NOTIMPL;
2689 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2691 dwritefontfamily_QueryInterface,
2692 dwritefontfamily_AddRef,
2693 dwritefontfamily_Release,
2694 dwritefontfamily_GetFontCollection,
2695 dwritefontfamily_GetFontCount,
2696 dwritefontfamily_GetFont,
2697 dwritefontfamily_GetFamilyNames,
2698 dwritefontfamily_GetFirstMatchingFont,
2699 dwritefontfamily_GetMatchingFonts,
2700 dwritefontfamily1_GetFontLocality,
2701 dwritefontfamily1_GetFont,
2702 dwritefontfamily1_GetFontFaceReference,
2703 dwritefontfamily2_GetMatchingFonts,
2704 dwritefontfamily2_GetFontSet,
2707 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2709 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2710 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2713 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2715 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2716 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2719 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2721 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2722 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2725 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2726 IDWriteFontCollection **collection)
2728 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2729 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2732 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2734 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2735 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2738 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2740 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2741 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2744 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2746 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2747 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2750 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2752 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2753 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2756 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2757 IDWriteFontFaceReference **reference)
2759 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2760 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2763 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2765 FIXME("%p, %p.\n", iface, fontset);
2767 return E_NOTIMPL;
2770 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2772 dwritefontfamilylist_QueryInterface,
2773 dwritefontfamilylist_AddRef,
2774 dwritefontfamilylist_Release,
2775 dwritefontfamilylist_GetFontCollection,
2776 dwritefontfamilylist_GetFontCount,
2777 dwritefontfamilylist_GetFont,
2778 dwritefontfamilylist1_GetFontLocality,
2779 dwritefontfamilylist1_GetFont,
2780 dwritefontfamilylist1_GetFontFaceReference,
2781 dwritefontfamilylist2_GetFontSet,
2784 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2785 struct dwrite_fontfamily **family)
2787 struct dwrite_fontfamily *object;
2789 *family = NULL;
2791 object = heap_alloc(sizeof(*object));
2792 if (!object)
2793 return E_OUTOFMEMORY;
2795 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2796 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2797 object->refcount = 1;
2798 object->collection = collection;
2799 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2800 object->data = collection->family_data[index];
2801 InterlockedIncrement(&object->data->refcount);
2803 *family = object;
2805 return S_OK;
2808 BOOL is_system_collection(IDWriteFontCollection *collection)
2810 void *obj;
2811 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2814 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2816 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2818 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2820 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2821 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2822 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2823 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2824 IsEqualIID(riid, &IID_IUnknown))
2826 *obj = iface;
2827 IDWriteFontCollection3_AddRef(iface);
2828 return S_OK;
2831 *obj = NULL;
2833 if (IsEqualIID(riid, &IID_issystemcollection))
2834 return S_OK;
2836 WARN("%s not implemented.\n", debugstr_guid(riid));
2838 return E_NOINTERFACE;
2841 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2843 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2845 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2846 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2847 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2848 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2849 IsEqualIID(riid, &IID_IUnknown))
2851 *obj = iface;
2852 IDWriteFontCollection3_AddRef(iface);
2853 return S_OK;
2856 WARN("%s not implemented.\n", debugstr_guid(riid));
2858 *obj = NULL;
2860 return E_NOINTERFACE;
2863 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2865 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2866 ULONG refcount = InterlockedIncrement(&collection->refcount);
2868 TRACE("%p, refcount %d.\n", collection, refcount);
2870 return refcount;
2873 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2875 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2876 ULONG refcount = InterlockedDecrement(&collection->refcount);
2877 size_t i;
2879 TRACE("%p, refcount %d.\n", iface, refcount);
2881 if (!refcount)
2883 factory_detach_fontcollection(collection->factory, iface);
2884 for (i = 0; i < collection->count; ++i)
2885 release_fontfamily_data(collection->family_data[i]);
2886 heap_free(collection->family_data);
2887 heap_free(collection);
2890 return refcount;
2893 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2895 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2897 TRACE("%p.\n", iface);
2899 return collection->count;
2902 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2903 IDWriteFontFamily **ret)
2905 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2906 struct dwrite_fontfamily *family;
2907 HRESULT hr;
2909 TRACE("%p, %u, %p.\n", iface, index, ret);
2911 *ret = NULL;
2913 if (index >= collection->count)
2914 return E_FAIL;
2916 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2917 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2919 return hr;
2922 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2924 size_t i;
2926 for (i = 0; i < collection->count; ++i)
2928 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2929 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2930 HRESULT hr;
2932 for (j = 0; j < count; j++) {
2933 WCHAR buffer[255];
2934 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2935 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2936 return i;
2940 return ~0u;
2943 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2944 UINT32 *index, BOOL *exists)
2946 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2948 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2950 *index = collection_find_family(collection, name);
2951 *exists = *index != ~0u;
2952 return S_OK;
2955 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2956 IDWriteFont **font)
2958 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2959 struct dwrite_fontfamily *family;
2960 BOOL found_font = FALSE;
2961 IDWriteFontFile *file;
2962 UINT32 face_index, count;
2963 size_t i, j;
2964 HRESULT hr;
2966 TRACE("%p, %p, %p.\n", iface, face, font);
2968 *font = NULL;
2970 if (!face)
2971 return E_INVALIDARG;
2973 count = 1;
2974 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2975 if (FAILED(hr))
2976 return hr;
2977 face_index = IDWriteFontFace_GetIndex(face);
2979 found_font = FALSE;
2980 for (i = 0; i < collection->count; ++i)
2982 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2984 for (j = 0; j < family_data->count; ++j)
2986 struct dwrite_font_data *font_data = family_data->fonts[j];
2988 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2989 found_font = TRUE;
2990 break;
2994 if (found_font)
2995 break;
2997 IDWriteFontFile_Release(file);
2999 if (!found_font)
3000 return DWRITE_E_NOFONT;
3002 hr = create_fontfamily(collection, i, &family);
3003 if (FAILED(hr))
3004 return hr;
3006 hr = create_font(family, j, (IDWriteFont3 **)font);
3007 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3008 return hr;
3011 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3013 FIXME("%p, %p.\n", iface, fontset);
3015 return E_NOTIMPL;
3018 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3019 IDWriteFontFamily1 **ret)
3021 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3022 struct dwrite_fontfamily *family;
3023 HRESULT hr;
3025 TRACE("%p, %u, %p.\n", iface, index, ret);
3027 *ret = NULL;
3029 if (index >= collection->count)
3030 return E_FAIL;
3032 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3033 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3035 return hr;
3038 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3039 UINT32 index, IDWriteFontFamily2 **ret)
3041 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3042 struct dwrite_fontfamily *family;
3043 HRESULT hr;
3045 TRACE("%p, %u, %p.\n", iface, index, ret);
3047 *ret = NULL;
3049 if (index >= collection->count)
3050 return E_FAIL;
3052 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3053 *ret = &family->IDWriteFontFamily2_iface;
3055 return hr;
3058 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3059 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3060 IDWriteFontList2 **fontlist)
3062 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3064 return E_NOTIMPL;
3067 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3069 FIXME("%p.\n", iface);
3071 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3074 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3076 FIXME("%p, %p.\n", iface, fontset);
3078 return E_NOTIMPL;
3081 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3083 FIXME("%p.\n", iface);
3085 return NULL;
3088 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3090 dwritefontcollection_QueryInterface,
3091 dwritefontcollection_AddRef,
3092 dwritefontcollection_Release,
3093 dwritefontcollection_GetFontFamilyCount,
3094 dwritefontcollection_GetFontFamily,
3095 dwritefontcollection_FindFamilyName,
3096 dwritefontcollection_GetFontFromFontFace,
3097 dwritefontcollection1_GetFontSet,
3098 dwritefontcollection1_GetFontFamily,
3099 dwritefontcollection2_GetFontFamily,
3100 dwritefontcollection2_GetMatchingFonts,
3101 dwritefontcollection2_GetFontFamilyModel,
3102 dwritefontcollection2_GetFontSet,
3103 dwritefontcollection3_GetExpirationEvent,
3106 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3108 dwritesystemfontcollection_QueryInterface,
3109 dwritefontcollection_AddRef,
3110 dwritefontcollection_Release,
3111 dwritefontcollection_GetFontFamilyCount,
3112 dwritefontcollection_GetFontFamily,
3113 dwritefontcollection_FindFamilyName,
3114 dwritefontcollection_GetFontFromFontFace,
3115 dwritefontcollection1_GetFontSet,
3116 dwritefontcollection1_GetFontFamily,
3117 dwritefontcollection2_GetFontFamily,
3118 dwritefontcollection2_GetMatchingFonts,
3119 dwritefontcollection2_GetFontFamilyModel,
3120 dwritefontcollection2_GetFontSet,
3121 dwritefontcollection3_GetExpirationEvent,
3124 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3126 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3127 sizeof(*family_data->fonts)))
3129 return E_OUTOFMEMORY;
3132 family_data->fonts[family_data->count++] = font_data;
3133 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3134 family_data->has_normal_face = 1;
3135 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3136 family_data->has_oblique_face = 1;
3137 else
3138 family_data->has_italic_face = 1;
3139 return S_OK;
3142 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3143 struct dwrite_fontfamily_data *family)
3145 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3146 sizeof(*collection->family_data)))
3148 return E_OUTOFMEMORY;
3151 collection->family_data[collection->count++] = family;
3152 return S_OK;
3155 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3157 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3158 collection->refcount = 1;
3159 collection->count = 0;
3160 collection->size = 0;
3161 collection->family_data = NULL;
3163 return S_OK;
3166 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3168 IDWriteFontFileLoader *loader;
3169 const void *key;
3170 UINT32 key_size;
3171 HRESULT hr;
3173 *stream = NULL;
3175 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3176 if (FAILED(hr))
3177 return hr;
3179 hr = IDWriteFontFile_GetLoader(file, &loader);
3180 if (FAILED(hr))
3181 return hr;
3183 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3184 IDWriteFontFileLoader_Release(loader);
3185 if (FAILED(hr))
3186 return hr;
3188 return hr;
3191 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3193 BOOL exists = FALSE;
3194 UINT32 index;
3195 HRESULT hr;
3197 buffer[0] = 0;
3198 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3199 if (FAILED(hr) || !exists)
3200 return;
3202 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3205 static int trim_spaces(WCHAR *in, WCHAR *ret)
3207 int len;
3209 while (isspaceW(*in))
3210 in++;
3212 ret[0] = 0;
3213 if (!(len = strlenW(in)))
3214 return 0;
3216 while (isspaceW(in[len-1]))
3217 len--;
3219 memcpy(ret, in, len*sizeof(WCHAR));
3220 ret[len] = 0;
3222 return len;
3225 struct name_token {
3226 struct list entry;
3227 const WCHAR *ptr;
3228 INT len; /* token length */
3229 INT fulllen; /* full length including following separators */
3232 static inline BOOL is_name_separator_char(WCHAR ch)
3234 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3237 struct name_pattern {
3238 const WCHAR *part1; /* NULL indicates end of list */
3239 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3242 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3244 const struct name_pattern *pattern;
3245 struct name_token *token;
3246 int i = 0;
3248 while ((pattern = &patterns[i++])->part1) {
3249 int len_part1 = strlenW(pattern->part1);
3250 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3252 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3253 if (len_part2 == 0) {
3254 /* simple case with single part pattern */
3255 if (token->len != len_part1)
3256 continue;
3258 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3259 if (match) *match = *token;
3260 list_remove(&token->entry);
3261 heap_free(token);
3262 return TRUE;
3265 else {
3266 struct name_token *next_token;
3267 struct list *next_entry;
3269 /* pattern parts are stored in reading order, tokens list is reversed */
3270 if (token->len < len_part2)
3271 continue;
3273 /* it's possible to have combined string as a token, like ExtraCondensed */
3274 if (token->len == len_part1 + len_part2) {
3275 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3276 continue;
3278 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3279 continue;
3281 /* combined string match */
3282 if (match) *match = *token;
3283 list_remove(&token->entry);
3284 heap_free(token);
3285 return TRUE;
3288 /* now it's only possible to have two tokens matched to respective pattern parts */
3289 if (token->len != len_part2)
3290 continue;
3292 next_entry = list_next(tokens, &token->entry);
3293 if (next_entry) {
3294 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3295 if (next_token->len != len_part1)
3296 continue;
3298 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3299 continue;
3301 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3302 continue;
3304 /* both parts matched, remove tokens */
3305 if (match) {
3306 match->ptr = next_token->ptr;
3307 match->len = (token->ptr - next_token->ptr) + token->len;
3309 list_remove(&token->entry);
3310 list_remove(&next_token->entry);
3311 heap_free(next_token);
3312 heap_free(token);
3313 return TRUE;
3319 if (match) {
3320 match->ptr = NULL;
3321 match->len = 0;
3323 return FALSE;
3326 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3328 static const WCHAR itaW[] = {'i','t','a',0};
3329 static const WCHAR italW[] = {'i','t','a','l',0};
3330 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3331 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3333 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3334 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3335 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3336 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3338 static const struct name_pattern italic_patterns[] = {
3339 { itaW },
3340 { italW },
3341 { italicW },
3342 { cursiveW },
3343 { kursivW },
3344 { NULL }
3347 static const struct name_pattern oblique_patterns[] = {
3348 { inclinedW },
3349 { obliqueW },
3350 { backslantedW },
3351 { backslantW },
3352 { slantedW },
3353 { NULL }
3356 /* italic patterns first */
3357 if (match_pattern_list(tokens, italic_patterns, match))
3358 return DWRITE_FONT_STYLE_ITALIC;
3360 /* oblique patterns */
3361 if (match_pattern_list(tokens, oblique_patterns, match))
3362 return DWRITE_FONT_STYLE_OBLIQUE;
3364 return style;
3367 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3368 struct name_token *match)
3370 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3371 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3372 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3373 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3374 static const WCHAR wideW[] = {'w','i','d','e',0};
3375 static const WCHAR condW[] = {'c','o','n','d',0};
3377 static const struct name_pattern ultracondensed_patterns[] = {
3378 { extraW, compressedW },
3379 { extW, compressedW },
3380 { ultraW, compressedW },
3381 { ultraW, condensedW },
3382 { ultraW, condW },
3383 { NULL }
3386 static const struct name_pattern extracondensed_patterns[] = {
3387 { compressedW },
3388 { extraW, condensedW },
3389 { extW, condensedW },
3390 { extraW, condW },
3391 { extW, condW },
3392 { NULL }
3395 static const struct name_pattern semicondensed_patterns[] = {
3396 { narrowW },
3397 { compactW },
3398 { semiW, condensedW },
3399 { semiW, condW },
3400 { NULL }
3403 static const struct name_pattern semiexpanded_patterns[] = {
3404 { wideW },
3405 { semiW, expandedW },
3406 { semiW, extendedW },
3407 { NULL }
3410 static const struct name_pattern extraexpanded_patterns[] = {
3411 { extraW, expandedW },
3412 { extW, expandedW },
3413 { extraW, extendedW },
3414 { extW, extendedW },
3415 { NULL }
3418 static const struct name_pattern ultraexpanded_patterns[] = {
3419 { ultraW, expandedW },
3420 { ultraW, extendedW },
3421 { NULL }
3424 static const struct name_pattern condensed_patterns[] = {
3425 { condensedW },
3426 { condW },
3427 { NULL }
3430 static const struct name_pattern expanded_patterns[] = {
3431 { expandedW },
3432 { extendedW },
3433 { NULL }
3436 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3437 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3439 if (match_pattern_list(tokens, extracondensed_patterns, match))
3440 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3442 if (match_pattern_list(tokens, semicondensed_patterns, match))
3443 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3445 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3446 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3448 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3449 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3451 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3452 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3454 if (match_pattern_list(tokens, condensed_patterns, match))
3455 return DWRITE_FONT_STRETCH_CONDENSED;
3457 if (match_pattern_list(tokens, expanded_patterns, match))
3458 return DWRITE_FONT_STRETCH_EXPANDED;
3460 return stretch;
3463 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3464 struct name_token *match)
3466 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3467 static const WCHAR nordW[] = {'n','o','r','d',0};
3469 static const struct name_pattern thin_patterns[] = {
3470 { extraW, thinW },
3471 { extW, thinW },
3472 { ultraW, thinW },
3473 { NULL }
3476 static const struct name_pattern extralight_patterns[] = {
3477 { extraW, lightW },
3478 { extW, lightW },
3479 { ultraW, lightW },
3480 { NULL }
3483 static const struct name_pattern semilight_patterns[] = {
3484 { semiW, lightW },
3485 { NULL }
3488 static const struct name_pattern demibold_patterns[] = {
3489 { semiW, boldW },
3490 { demiW, boldW },
3491 { NULL }
3494 static const struct name_pattern extrabold_patterns[] = {
3495 { extraW, boldW },
3496 { extW, boldW },
3497 { ultraW, boldW },
3498 { NULL }
3501 static const struct name_pattern extrablack_patterns[] = {
3502 { extraW, blackW },
3503 { extW, blackW },
3504 { ultraW, blackW },
3505 { NULL }
3508 static const struct name_pattern bold_patterns[] = {
3509 { boldW },
3510 { NULL }
3513 static const struct name_pattern thin2_patterns[] = {
3514 { thinW },
3515 { NULL }
3518 static const struct name_pattern light_patterns[] = {
3519 { lightW },
3520 { NULL }
3523 static const struct name_pattern medium_patterns[] = {
3524 { mediumW },
3525 { NULL }
3528 static const struct name_pattern black_patterns[] = {
3529 { blackW },
3530 { heavyW },
3531 { nordW },
3532 { NULL }
3535 static const struct name_pattern demibold2_patterns[] = {
3536 { demiW },
3537 { NULL }
3540 static const struct name_pattern extrabold2_patterns[] = {
3541 { ultraW },
3542 { NULL }
3545 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3546 matching pattern. */
3548 if (match_pattern_list(tokens, thin_patterns, match))
3549 return DWRITE_FONT_WEIGHT_THIN;
3551 if (match_pattern_list(tokens, extralight_patterns, match))
3552 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3554 if (match_pattern_list(tokens, semilight_patterns, match))
3555 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3557 if (match_pattern_list(tokens, demibold_patterns, match))
3558 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3560 if (match_pattern_list(tokens, extrabold_patterns, match))
3561 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3563 if (match_pattern_list(tokens, extrablack_patterns, match))
3564 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3566 if (match_pattern_list(tokens, bold_patterns, match))
3567 return DWRITE_FONT_WEIGHT_BOLD;
3569 if (match_pattern_list(tokens, thin2_patterns, match))
3570 return DWRITE_FONT_WEIGHT_THIN;
3572 if (match_pattern_list(tokens, light_patterns, match))
3573 return DWRITE_FONT_WEIGHT_LIGHT;
3575 if (match_pattern_list(tokens, medium_patterns, match))
3576 return DWRITE_FONT_WEIGHT_MEDIUM;
3578 if (match_pattern_list(tokens, black_patterns, match))
3579 return DWRITE_FONT_WEIGHT_BLACK;
3581 if (match_pattern_list(tokens, black_patterns, match))
3582 return DWRITE_FONT_WEIGHT_BLACK;
3584 if (match_pattern_list(tokens, demibold2_patterns, match))
3585 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3587 if (match_pattern_list(tokens, extrabold2_patterns, match))
3588 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3590 /* FIXME: use abbreviated names to extract weight */
3592 return weight;
3595 struct knownweight_entry {
3596 const WCHAR *nameW;
3597 DWRITE_FONT_WEIGHT weight;
3600 static int compare_knownweights(const void *a, const void* b)
3602 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3603 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3604 int ret = 0;
3606 if (target > entry->weight)
3607 ret = 1;
3608 else if (target < entry->weight)
3609 ret = -1;
3611 return ret;
3614 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3616 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3617 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3618 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3619 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3620 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3621 const struct knownweight_entry *ptr;
3623 static const struct knownweight_entry knownweights[] = {
3624 { thinW, DWRITE_FONT_WEIGHT_THIN },
3625 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3626 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3627 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3628 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3629 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3630 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3631 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3632 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3633 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3636 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3637 compare_knownweights);
3638 if (!ptr) {
3639 nameW[0] = 0;
3640 return FALSE;
3643 strcpyW(nameW, ptr->nameW);
3644 return TRUE;
3647 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3649 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3650 strW[name->len] = 0;
3653 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3654 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3656 static const WCHAR bookW[] = {'B','o','o','k',0};
3657 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3658 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3659 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3660 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3662 static const WCHAR *regular_patterns[] = {
3663 bookW,
3664 normalW,
3665 regularW,
3666 romanW,
3667 uprightW,
3668 NULL
3671 const WCHAR *regular_ptr = NULL, *ptr;
3672 int i = 0;
3674 if (len == -1)
3675 len = strlenW(facenameW);
3677 /* remove rightmost regular variant from face name */
3678 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3679 int pattern_len = strlenW(ptr);
3680 WCHAR *src;
3682 if (pattern_len > len)
3683 continue;
3685 src = facenameW + len - pattern_len;
3686 while (src >= facenameW) {
3687 if (!strncmpiW(src, ptr, pattern_len)) {
3688 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3689 len = strlenW(facenameW);
3690 regular_ptr = ptr;
3691 break;
3693 else
3694 src--;
3698 return regular_ptr;
3701 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3703 const WCHAR *ptr;
3705 list_init(tokens);
3706 ptr = nameW;
3708 while (*ptr) {
3709 struct name_token *token = heap_alloc(sizeof(*token));
3710 token->ptr = ptr;
3711 token->len = 0;
3712 token->fulllen = 0;
3714 while (*ptr && !is_name_separator_char(*ptr)) {
3715 token->len++;
3716 token->fulllen++;
3717 ptr++;
3720 /* skip separators */
3721 while (is_name_separator_char(*ptr)) {
3722 token->fulllen++;
3723 ptr++;
3726 list_add_head(tokens, &token->entry);
3730 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3732 struct name_token *token, *token2;
3733 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3734 int len;
3736 list_remove(&token->entry);
3738 /* don't include last separator */
3739 len = list_empty(tokens) ? token->len : token->fulllen;
3740 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3741 nameW += len;
3743 heap_free(token);
3745 *nameW = 0;
3748 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3750 struct name_token stretch_name, weight_name, style_name;
3751 WCHAR familynameW[255], facenameW[255], finalW[255];
3752 WCHAR weightW[32], stretchW[32], styleW[32];
3753 const WCHAR *regular_ptr = NULL;
3754 DWRITE_FONT_STRETCH stretch;
3755 DWRITE_FONT_WEIGHT weight;
3756 struct list tokens;
3757 int len;
3759 /* remove leading and trailing spaces from family and face name */
3760 trim_spaces(familyW, familynameW);
3761 len = trim_spaces(faceW, facenameW);
3763 /* remove rightmost regular variant from face name */
3764 regular_ptr = facename_remove_regular_term(facenameW, len);
3766 /* append face name to family name, FIXME check if face name is a substring of family name */
3767 if (*facenameW) {
3768 strcatW(familynameW, spaceW);
3769 strcatW(familynameW, facenameW);
3772 /* tokenize with " .-_" */
3773 fontname_tokenize(&tokens, familynameW);
3775 /* extract and resolve style */
3776 font->style = font_extract_style(&tokens, font->style, &style_name);
3778 /* extract stretch */
3779 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3781 /* extract weight */
3782 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3784 /* resolve weight */
3785 if (weight != font->weight) {
3786 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3787 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3788 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3789 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3790 !(abs(weight - font->weight) <= 150 &&
3791 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3792 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3793 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3795 font->weight = weight;
3799 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3800 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3801 stretch itself is normal (extracted stretch is never normal). */
3802 if (stretch != font->stretch) {
3803 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3804 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3805 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3807 font->stretch = stretch;
3811 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3813 /* get final combined string from what's left in token list, list is released */
3814 fontname_tokens_to_str(&tokens, finalW);
3816 if (!strcmpW(familyW, finalW))
3817 return FALSE;
3819 /* construct face name */
3820 strcpyW(familyW, finalW);
3822 /* resolved weight name */
3823 if (weight_name.ptr)
3824 font_name_token_to_str(&weight_name, weightW);
3825 /* ignore normal weight */
3826 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3827 weightW[0] = 0;
3828 /* for known weight values use appropriate names */
3829 else if (is_known_weight_value(font->weight, weightW)) {
3831 /* use Wnnn format as a fallback in case weight is not one of known values */
3832 else {
3833 static const WCHAR fmtW[] = {'W','%','d',0};
3834 sprintfW(weightW, fmtW, font->weight);
3837 /* resolved stretch name */
3838 if (stretch_name.ptr)
3839 font_name_token_to_str(&stretch_name, stretchW);
3840 /* ignore normal stretch */
3841 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3842 stretchW[0] = 0;
3843 /* use predefined stretch names */
3844 else {
3845 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3846 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3847 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3848 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3849 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3850 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3852 static const WCHAR *stretchnamesW[] = {
3853 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3854 ultracondensedW,
3855 extracondensedW,
3856 condensedW,
3857 semicondensedW,
3858 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3859 semiexpandedW,
3860 expandedW,
3861 extraexpandedW,
3862 ultraexpandedW
3864 strcpyW(stretchW, stretchnamesW[font->stretch]);
3867 /* resolved style name */
3868 if (style_name.ptr)
3869 font_name_token_to_str(&style_name, styleW);
3870 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3871 styleW[0] = 0;
3872 /* use predefined names */
3873 else {
3874 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3875 strcpyW(styleW, italicW);
3876 else
3877 strcpyW(styleW, obliqueW);
3880 /* use Regular match if it was found initially */
3881 if (!*weightW && !*stretchW && !*styleW)
3882 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3883 else {
3884 faceW[0] = 0;
3885 if (*stretchW)
3886 strcpyW(faceW, stretchW);
3887 if (*weightW) {
3888 if (*faceW)
3889 strcatW(faceW, spaceW);
3890 strcatW(faceW, weightW);
3892 if (*styleW) {
3893 if (*faceW)
3894 strcatW(faceW, spaceW);
3895 strcatW(faceW, styleW);
3899 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3900 return TRUE;
3903 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3905 static const float width_axis_values[] =
3907 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3908 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3909 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3910 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3911 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3912 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3913 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3914 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3915 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3916 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3919 struct file_stream_desc stream_desc;
3920 struct dwrite_font_props props;
3921 struct dwrite_font_data *data;
3922 WCHAR familyW[255], faceW[255];
3923 HRESULT hr;
3925 *ret = NULL;
3927 data = heap_alloc_zero(sizeof(*data));
3928 if (!data)
3929 return E_OUTOFMEMORY;
3931 data->ref = 1;
3932 data->file = desc->files[0];
3933 data->face_index = desc->index;
3934 data->face_type = desc->face_type;
3935 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3936 data->bold_sim_tested = 0;
3937 data->oblique_sim_tested = 0;
3938 IDWriteFontFile_AddRef(data->file);
3940 stream_desc.stream = desc->stream;
3941 stream_desc.face_type = desc->face_type;
3942 stream_desc.face_index = desc->index;
3943 opentype_get_font_properties(&stream_desc, &props);
3944 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3945 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3947 /* get family name from font file */
3948 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3949 if (FAILED(hr)) {
3950 WARN("unable to get family name from font\n");
3951 release_font_data(data);
3952 return hr;
3955 data->style = props.style;
3956 data->stretch = props.stretch;
3957 data->weight = props.weight;
3958 data->panose = props.panose;
3959 data->fontsig = props.fontsig;
3960 data->lf = props.lf;
3961 data->flags = props.flags;
3963 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3964 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3965 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3966 set_en_localizedstring(data->family_names, familyW);
3967 set_en_localizedstring(data->names, faceW);
3970 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3972 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
3973 data->axis[0].value = props.weight;
3974 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
3975 data->axis[1].value = width_axis_values[props.stretch];
3976 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
3977 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
3979 *ret = data;
3980 return S_OK;
3983 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3984 const WCHAR *facenameW, struct dwrite_font_data **ret)
3986 struct dwrite_font_data *data;
3988 *ret = NULL;
3990 data = heap_alloc_zero(sizeof(*data));
3991 if (!data)
3992 return E_OUTOFMEMORY;
3994 *data = *src;
3995 data->ref = 1;
3996 data->simulations |= sim;
3997 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3998 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3999 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
4000 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4001 memset(data->info_strings, 0, sizeof(data->info_strings));
4002 data->names = NULL;
4003 IDWriteFontFile_AddRef(data->file);
4004 IDWriteLocalizedStrings_AddRef(data->family_names);
4006 create_localizedstrings(&data->names);
4007 add_localizedstring(data->names, enusW, facenameW);
4009 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4011 *ret = data;
4012 return S_OK;
4015 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4017 struct dwrite_fontfamily_data *data;
4019 data = heap_alloc_zero(sizeof(*data));
4020 if (!data)
4021 return E_OUTOFMEMORY;
4023 data->refcount = 1;
4024 data->familyname = familyname;
4025 IDWriteLocalizedStrings_AddRef(familyname);
4027 *ret = data;
4029 return S_OK;
4032 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4034 size_t i, j, heaviest;
4036 for (i = 0; i < family->count; ++i)
4038 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4039 heaviest = i;
4041 if (family->fonts[i]->bold_sim_tested)
4042 continue;
4044 family->fonts[i]->bold_sim_tested = 1;
4045 for (j = i; j < family->count; ++j)
4047 if (family->fonts[j]->bold_sim_tested)
4048 continue;
4050 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4051 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4052 if (family->fonts[j]->weight > weight) {
4053 weight = family->fonts[j]->weight;
4054 heaviest = j;
4056 family->fonts[j]->bold_sim_tested = 1;
4060 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4061 static const struct name_pattern weightsim_patterns[] = {
4062 { extraW, lightW },
4063 { extW, lightW },
4064 { ultraW, lightW },
4065 { semiW, lightW },
4066 { semiW, boldW },
4067 { demiW, boldW },
4068 { boldW },
4069 { thinW },
4070 { lightW },
4071 { mediumW },
4072 { demiW },
4073 { NULL }
4076 WCHAR facenameW[255], initialW[255];
4077 struct dwrite_font_data *boldface;
4078 struct list tokens;
4080 /* add Bold simulation based on heaviest face data */
4082 /* Simulated face name should only contain Bold as weight term,
4083 so remove existing regular and weight terms. */
4084 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4085 facename_remove_regular_term(initialW, -1);
4087 /* remove current weight pattern */
4088 fontname_tokenize(&tokens, initialW);
4089 match_pattern_list(&tokens, weightsim_patterns, NULL);
4090 fontname_tokens_to_str(&tokens, facenameW);
4092 /* Bold suffix for new name */
4093 if (*facenameW)
4094 strcatW(facenameW, spaceW);
4095 strcatW(facenameW, boldW);
4097 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4098 boldface->bold_sim_tested = 1;
4099 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4100 fontfamily_add_font(family, boldface);
4106 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4108 size_t i, j;
4110 for (i = 0; i < family->count; ++i)
4112 UINT32 regular = ~0u, oblique = ~0u;
4113 struct dwrite_font_data *obliqueface;
4114 WCHAR facenameW[255];
4116 if (family->fonts[i]->oblique_sim_tested)
4117 continue;
4119 family->fonts[i]->oblique_sim_tested = 1;
4120 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4121 regular = i;
4122 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4123 oblique = i;
4125 /* find regular style with same weight/stretch values */
4126 for (j = i; j < family->count; ++j)
4128 if (family->fonts[j]->oblique_sim_tested)
4129 continue;
4131 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4132 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4134 family->fonts[j]->oblique_sim_tested = 1;
4135 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4136 regular = j;
4138 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4139 oblique = j;
4142 if (regular != ~0u && oblique != ~0u)
4143 break;
4146 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4147 if (regular == ~0u)
4148 continue;
4150 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4151 if (oblique != ~0u)
4152 continue;
4154 /* add oblique simulation based on this regular face */
4156 /* remove regular term if any, append 'Oblique' */
4157 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4158 facename_remove_regular_term(facenameW, -1);
4160 if (*facenameW)
4161 strcatW(facenameW, spaceW);
4162 strcatW(facenameW, obliqueW);
4164 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4165 obliqueface->oblique_sim_tested = 1;
4166 obliqueface->lf.lfItalic = 1;
4167 fontfamily_add_font(family, obliqueface);
4172 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4173 const WCHAR *replacement_name)
4175 UINT32 i = collection_find_family(collection, replacement_name);
4176 struct dwrite_fontfamily_data *target;
4177 IDWriteLocalizedStrings *strings;
4178 HRESULT hr;
4180 /* replacement does not exist */
4181 if (i == ~0u)
4182 return FALSE;
4184 hr = create_localizedstrings(&strings);
4185 if (FAILED(hr))
4186 return FALSE;
4188 /* add a new family with target name, reuse font data from replacement */
4189 add_localizedstring(strings, enusW, target_name);
4190 hr = init_fontfamily_data(strings, &target);
4191 if (hr == S_OK) {
4192 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4193 WCHAR nameW[255];
4195 for (i = 0; i < replacement->count; ++i)
4197 fontfamily_add_font(target, replacement->fonts[i]);
4198 addref_font_data(replacement->fonts[i]);
4201 fontcollection_add_family(collection, target);
4202 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4203 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4205 IDWriteLocalizedStrings_Release(strings);
4206 return TRUE;
4209 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4210 system font collections. */
4211 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4213 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4214 WCHAR *name;
4215 void *data;
4216 HKEY hkey;
4218 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4219 return;
4221 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4222 RegCloseKey(hkey);
4223 return;
4226 max_namelen++; /* returned value doesn't include room for '\0' */
4227 name = heap_alloc(max_namelen * sizeof(WCHAR));
4228 data = heap_alloc(max_datalen);
4230 datalen = max_datalen;
4231 namelen = max_namelen;
4232 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4233 if (collection_find_family(collection, name) == ~0u) {
4234 if (type == REG_MULTI_SZ) {
4235 WCHAR *replacement = data;
4236 while (*replacement) {
4237 if (fontcollection_add_replacement(collection, name, replacement))
4238 break;
4239 replacement += strlenW(replacement) + 1;
4242 else if (type == REG_SZ)
4243 fontcollection_add_replacement(collection, name, data);
4245 else
4246 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4248 datalen = max_datalen;
4249 namelen = max_namelen;
4252 heap_free(data);
4253 heap_free(name);
4254 RegCloseKey(hkey);
4257 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4258 IDWriteFontCollection3 **ret)
4260 struct fontfile_enum {
4261 struct list entry;
4262 IDWriteFontFile *file;
4264 struct fontfile_enum *fileenum, *fileenum2;
4265 struct dwrite_fontcollection *collection;
4266 struct list scannedfiles;
4267 BOOL current = FALSE;
4268 HRESULT hr = S_OK;
4269 size_t i;
4271 *ret = NULL;
4273 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4274 if (!collection) return E_OUTOFMEMORY;
4276 hr = init_font_collection(collection, is_system);
4277 if (FAILED(hr)) {
4278 heap_free(collection);
4279 return hr;
4282 *ret = &collection->IDWriteFontCollection3_iface;
4284 TRACE("building font collection:\n");
4286 list_init(&scannedfiles);
4287 while (hr == S_OK) {
4288 DWRITE_FONT_FACE_TYPE face_type;
4289 DWRITE_FONT_FILE_TYPE file_type;
4290 BOOL supported, same = FALSE;
4291 IDWriteFontFileStream *stream;
4292 IDWriteFontFile *file;
4293 UINT32 face_count;
4295 current = FALSE;
4296 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4297 if (FAILED(hr) || !current)
4298 break;
4300 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4301 if (FAILED(hr))
4302 break;
4304 /* check if we've scanned this file already */
4305 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4306 if ((same = is_same_fontfile(fileenum->file, file)))
4307 break;
4310 if (same) {
4311 IDWriteFontFile_Release(file);
4312 continue;
4315 if (FAILED(get_filestream_from_file(file, &stream))) {
4316 IDWriteFontFile_Release(file);
4317 continue;
4320 /* Unsupported formats are skipped. */
4321 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4322 if (FAILED(hr) || !supported || face_count == 0) {
4323 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4324 IDWriteFontFileStream_Release(stream);
4325 IDWriteFontFile_Release(file);
4326 hr = S_OK;
4327 continue;
4330 /* add to scanned list */
4331 fileenum = heap_alloc(sizeof(*fileenum));
4332 fileenum->file = file;
4333 list_add_tail(&scannedfiles, &fileenum->entry);
4335 for (i = 0; i < face_count; ++i)
4337 struct dwrite_font_data *font_data;
4338 struct fontface_desc desc;
4339 WCHAR familyW[255];
4340 UINT32 index;
4342 desc.factory = factory;
4343 desc.face_type = face_type;
4344 desc.files = &file;
4345 desc.stream = stream;
4346 desc.files_number = 1;
4347 desc.index = i;
4348 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4349 desc.font_data = NULL;
4351 /* Allocate an initialize new font data structure. */
4352 hr = init_font_data(&desc, &font_data);
4353 if (FAILED(hr))
4355 /* move to next one */
4356 hr = S_OK;
4357 continue;
4360 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4362 /* ignore dot named faces */
4363 if (familyW[0] == '.')
4365 WARN("Ignoring face %s\n", debugstr_w(familyW));
4366 release_font_data(font_data);
4367 continue;
4370 index = collection_find_family(collection, familyW);
4371 if (index != ~0u)
4372 hr = fontfamily_add_font(collection->family_data[index], font_data);
4373 else {
4374 struct dwrite_fontfamily_data *family_data;
4376 /* create and init new family */
4377 hr = init_fontfamily_data(font_data->family_names, &family_data);
4378 if (hr == S_OK) {
4379 /* add font to family, family - to collection */
4380 hr = fontfamily_add_font(family_data, font_data);
4381 if (hr == S_OK)
4382 hr = fontcollection_add_family(collection, family_data);
4384 if (FAILED(hr))
4385 release_fontfamily_data(family_data);
4389 if (FAILED(hr))
4390 break;
4393 IDWriteFontFileStream_Release(stream);
4396 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4397 IDWriteFontFile_Release(fileenum->file);
4398 list_remove(&fileenum->entry);
4399 heap_free(fileenum);
4402 for (i = 0; i < collection->count; ++i)
4404 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4405 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4408 if (is_system)
4409 fontcollection_add_replacements(collection);
4411 collection->factory = factory;
4412 IDWriteFactory7_AddRef(factory);
4414 return hr;
4417 struct system_fontfile_enumerator
4419 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4420 LONG ref;
4422 IDWriteFactory7 *factory;
4423 HKEY hkey;
4424 int index;
4426 WCHAR *filename;
4427 DWORD filename_size;
4430 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4432 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4435 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4437 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4438 IDWriteFontFileEnumerator_AddRef(iface);
4439 *obj = iface;
4440 return S_OK;
4443 WARN("%s not implemented.\n", debugstr_guid(riid));
4445 *obj = NULL;
4447 return E_NOINTERFACE;
4450 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4452 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4453 return InterlockedIncrement(&enumerator->ref);
4456 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4458 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4459 ULONG ref = InterlockedDecrement(&enumerator->ref);
4461 if (!ref)
4463 IDWriteFactory7_Release(enumerator->factory);
4464 RegCloseKey(enumerator->hkey);
4465 heap_free(enumerator->filename);
4466 heap_free(enumerator);
4469 return ref;
4472 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4474 HRESULT hr;
4476 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4477 if (!strchrW(filename, '\\')) {
4478 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4479 WCHAR fullpathW[MAX_PATH];
4481 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4482 strcatW(fullpathW, fontsW);
4483 strcatW(fullpathW, filename);
4485 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4487 else
4488 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4490 return hr;
4493 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4495 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4497 *file = NULL;
4499 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4500 return E_FAIL;
4502 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4505 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4507 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4508 WCHAR name_buf[256], *name = name_buf;
4509 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4510 HRESULT hr = S_OK;
4511 LONG r;
4513 *current = FALSE;
4514 enumerator->index++;
4516 /* iterate until we find next string value */
4517 for (;;) {
4518 do {
4519 name_count = max_name_count;
4520 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4522 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4523 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4524 if (r == ERROR_MORE_DATA) {
4525 if (name_count >= max_name_count) {
4526 if (name != name_buf) heap_free(name);
4527 max_name_count *= 2;
4528 name = heap_alloc(max_name_count * sizeof(*name));
4529 if (!name) return E_OUTOFMEMORY;
4531 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4532 heap_free(enumerator->filename);
4533 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4534 enumerator->filename = heap_alloc(enumerator->filename_size);
4535 if (!enumerator->filename) {
4536 hr = E_OUTOFMEMORY;
4537 goto err;
4541 } while (r == ERROR_MORE_DATA);
4543 if (r != ERROR_SUCCESS) {
4544 enumerator->filename[0] = 0;
4545 break;
4547 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4548 if (type == REG_SZ && *name != '@') {
4549 *current = TRUE;
4550 break;
4552 enumerator->index++;
4554 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4556 err:
4557 if (name != name_buf) heap_free(name);
4558 return hr;
4561 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4563 systemfontfileenumerator_QueryInterface,
4564 systemfontfileenumerator_AddRef,
4565 systemfontfileenumerator_Release,
4566 systemfontfileenumerator_MoveNext,
4567 systemfontfileenumerator_GetCurrentFontFile
4570 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4572 struct system_fontfile_enumerator *enumerator;
4573 static const WCHAR fontslistW[] = {
4574 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4575 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4576 'F','o','n','t','s',0
4579 *ret = NULL;
4581 enumerator = heap_alloc(sizeof(*enumerator));
4582 if (!enumerator)
4583 return E_OUTOFMEMORY;
4585 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4586 enumerator->ref = 1;
4587 enumerator->factory = factory;
4588 enumerator->index = -1;
4589 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4590 enumerator->filename = heap_alloc(enumerator->filename_size);
4591 if (!enumerator->filename) {
4592 heap_free(enumerator);
4593 return E_OUTOFMEMORY;
4596 IDWriteFactory7_AddRef(factory);
4598 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4600 ERR("failed to open fonts list key\n");
4601 IDWriteFactory7_Release(factory);
4602 heap_free(enumerator->filename);
4603 heap_free(enumerator);
4604 return E_FAIL;
4607 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4609 return S_OK;
4612 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4614 IDWriteFontFileEnumerator *enumerator;
4615 HRESULT hr;
4617 *collection = NULL;
4619 hr = create_system_fontfile_enumerator(factory, &enumerator);
4620 if (FAILED(hr))
4621 return hr;
4623 TRACE("building system font collection for factory %p\n", factory);
4624 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4625 IDWriteFontFileEnumerator_Release(enumerator);
4626 return hr;
4629 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4630 const WCHAR *keynameW, const WCHAR *pathW)
4632 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};
4633 static const WCHAR emptyW[] = {0};
4634 struct dwrite_fontfamily_data *family_data;
4635 IDWriteLocalizedStrings *names;
4636 DWRITE_FONT_FACE_TYPE face_type;
4637 DWRITE_FONT_FILE_TYPE file_type;
4638 IDWriteFontFileStream *stream;
4639 IDWriteFontFile *file;
4640 UINT32 face_count, i;
4641 BOOL supported;
4642 HRESULT hr;
4644 /* create font file from this path */
4645 hr = create_local_file_reference(factory, pathW, &file);
4646 if (FAILED(hr))
4647 return S_FALSE;
4649 if (FAILED(get_filestream_from_file(file, &stream))) {
4650 IDWriteFontFile_Release(file);
4651 return S_FALSE;
4654 /* Unsupported formats are skipped. */
4655 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4656 if (FAILED(hr) || !supported || face_count == 0) {
4657 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4658 IDWriteFontFileStream_Release(stream);
4659 IDWriteFontFile_Release(file);
4660 return S_FALSE;
4663 /* create and init new family */
4665 /* Family names are added for non-specific locale, represented with empty string.
4666 Default family appears with empty family name. */
4667 create_localizedstrings(&names);
4668 if (!strcmpiW(keynameW, defaultfontW))
4669 add_localizedstring(names, emptyW, emptyW);
4670 else
4671 add_localizedstring(names, emptyW, keynameW);
4673 hr = init_fontfamily_data(names, &family_data);
4674 IDWriteLocalizedStrings_Release(names);
4675 if (hr != S_OK) {
4676 IDWriteFontFile_Release(file);
4677 return hr;
4680 /* fill with faces */
4681 for (i = 0; i < face_count; i++) {
4682 struct dwrite_font_data *font_data;
4683 struct fontface_desc desc;
4685 /* alloc and init new font data structure */
4686 desc.factory = factory;
4687 desc.face_type = face_type;
4688 desc.index = i;
4689 desc.files = &file;
4690 desc.stream = stream;
4691 desc.files_number = 1;
4692 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4693 desc.font_data = NULL;
4695 hr = init_font_data(&desc, &font_data);
4696 if (FAILED(hr))
4697 continue;
4699 /* add font to family */
4700 hr = fontfamily_add_font(family_data, font_data);
4701 if (hr != S_OK)
4702 release_font_data(font_data);
4705 /* add family to collection */
4706 hr = fontcollection_add_family(collection, family_data);
4707 if (FAILED(hr))
4708 release_fontfamily_data(family_data);
4709 IDWriteFontFileStream_Release(stream);
4710 IDWriteFontFile_Release(file);
4712 return hr;
4715 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4717 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4718 struct dwrite_fontcollection *collection;
4719 static const WCHAR emptyW[] = {0};
4720 WCHAR eudckeypathW[16];
4721 HKEY eudckey;
4722 DWORD index;
4723 BOOL exists;
4724 LONG retval;
4725 HRESULT hr;
4726 size_t i;
4728 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4730 *ret = NULL;
4732 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4733 if (!collection) return E_OUTOFMEMORY;
4735 hr = init_font_collection(collection, FALSE);
4736 if (FAILED(hr)) {
4737 heap_free(collection);
4738 return hr;
4741 *ret = &collection->IDWriteFontCollection3_iface;
4742 collection->factory = factory;
4743 IDWriteFactory7_AddRef(factory);
4745 /* return empty collection if EUDC fonts are not configured */
4746 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4747 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4748 return S_OK;
4750 retval = ERROR_SUCCESS;
4751 index = 0;
4752 while (retval != ERROR_NO_MORE_ITEMS) {
4753 WCHAR keynameW[64], pathW[MAX_PATH];
4754 DWORD type, path_len, name_len;
4756 path_len = ARRAY_SIZE(pathW);
4757 name_len = ARRAY_SIZE(keynameW);
4758 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4759 if (retval || type != REG_SZ)
4760 continue;
4762 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4763 if (hr != S_OK)
4764 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4766 RegCloseKey(eudckey);
4768 /* try to add global default if not defined for specific codepage */
4769 exists = FALSE;
4770 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4771 &index, &exists);
4772 if (FAILED(hr) || !exists) {
4773 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4774 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4775 if (hr != S_OK)
4776 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4779 /* EUDC collection offers simulated faces too */
4780 for (i = 0; i < collection->count; ++i)
4782 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4783 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4786 return S_OK;
4789 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4791 TRACE("%p, %s, %p.\n", iface, 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 *file = impl_from_IDWriteFontFile(iface);
4809 ULONG refcount = InterlockedIncrement(&file->refcount);
4811 TRACE("%p, refcount %d.\n", iface, refcount);
4813 return refcount;
4816 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4818 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4819 ULONG refcount = InterlockedDecrement(&file->refcount);
4821 TRACE("%p, refcount %d.\n", iface, refcount);
4823 if (!refcount)
4825 IDWriteFontFileLoader_Release(file->loader);
4826 if (file->stream)
4827 IDWriteFontFileStream_Release(file->stream);
4828 heap_free(file->reference_key);
4829 heap_free(file);
4832 return refcount;
4835 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
4837 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4839 TRACE("%p, %p, %p.\n", iface, key, key_size);
4841 *key = file->reference_key;
4842 *key_size = file->key_size;
4844 return S_OK;
4847 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
4849 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4851 TRACE("%p, %p.\n", iface, loader);
4853 *loader = file->loader;
4854 IDWriteFontFileLoader_AddRef(*loader);
4856 return S_OK;
4859 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4860 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4862 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4863 IDWriteFontFileStream *stream;
4864 HRESULT hr;
4866 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
4868 *is_supported = FALSE;
4869 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4870 if (face_type)
4871 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4872 *face_count = 0;
4874 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
4875 if (FAILED(hr))
4876 return hr;
4878 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4880 /* TODO: Further Analysis */
4881 IDWriteFontFileStream_Release(stream);
4882 return S_OK;
4885 static const IDWriteFontFileVtbl dwritefontfilevtbl =
4887 dwritefontfile_QueryInterface,
4888 dwritefontfile_AddRef,
4889 dwritefontfile_Release,
4890 dwritefontfile_GetReferenceKey,
4891 dwritefontfile_GetLoader,
4892 dwritefontfile_Analyze,
4895 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4896 IDWriteFontFile **ret)
4898 struct dwrite_fontfile *file;
4899 void *key;
4901 *ret = NULL;
4903 file = heap_alloc(sizeof(*file));
4904 key = heap_alloc(key_size);
4905 if (!file || !key) {
4906 heap_free(file);
4907 heap_free(key);
4908 return E_OUTOFMEMORY;
4911 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4912 file->refcount = 1;
4913 IDWriteFontFileLoader_AddRef(loader);
4914 file->loader = loader;
4915 file->stream = NULL;
4916 file->reference_key = key;
4917 memcpy(file->reference_key, reference_key, key_size);
4918 file->key_size = key_size;
4920 *ret = &file->IDWriteFontFile_iface;
4922 return S_OK;
4925 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4927 struct file_stream_desc stream_desc;
4928 struct dwrite_font_data *font_data;
4929 struct dwrite_fontface *fontface;
4930 HRESULT hr;
4931 int i;
4933 *ret = NULL;
4935 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4936 if (!fontface)
4937 return E_OUTOFMEMORY;
4939 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4940 if (!fontface->files) {
4941 heap_free(fontface);
4942 return E_OUTOFMEMORY;
4945 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4946 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
4947 fontface->refcount = 1;
4948 fontface->type = desc->face_type;
4949 fontface->file_count = desc->files_number;
4950 fontface->vdmx.exists = TRUE;
4951 fontface->gasp.exists = TRUE;
4952 fontface->cpal.exists = TRUE;
4953 fontface->colr.exists = TRUE;
4954 fontface->index = desc->index;
4955 fontface->simulations = desc->simulations;
4956 fontface->factory = desc->factory;
4957 IDWriteFactory7_AddRef(fontface->factory);
4959 for (i = 0; i < fontface->file_count; i++) {
4960 fontface->files[i] = desc->files[i];
4961 IDWriteFontFile_AddRef(fontface->files[i]);
4963 fontface->stream = desc->stream;
4964 IDWriteFontFileStream_AddRef(fontface->stream);
4966 stream_desc.stream = fontface->stream;
4967 stream_desc.face_type = desc->face_type;
4968 stream_desc.face_index = desc->index;
4969 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4970 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4971 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4972 /* TODO: test what happens if caret is already slanted */
4973 if (fontface->caret.slopeRise == 1) {
4974 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4975 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4979 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4980 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4981 if (opentype_has_vertical_variants(fontface))
4982 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4983 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4985 /* Font properties are reused from font object when 'normal' face creation path is used:
4986 collection -> family -> matching font -> fontface.
4988 If face is created directly from factory we have to go through properties resolution.
4990 if (desc->font_data)
4992 font_data = desc->font_data;
4993 addref_font_data(font_data);
4995 else
4997 hr = init_font_data(desc, &font_data);
4998 if (FAILED(hr))
5000 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5001 return hr;
5005 fontface->weight = font_data->weight;
5006 fontface->style = font_data->style;
5007 fontface->stretch = font_data->stretch;
5008 fontface->panose = font_data->panose;
5009 fontface->fontsig = font_data->fontsig;
5010 fontface->lf = font_data->lf;
5011 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5012 fontface->names = font_data->names;
5013 if (fontface->names)
5014 IDWriteLocalizedStrings_AddRef(fontface->names);
5015 fontface->family_names = font_data->family_names;
5016 if (fontface->family_names)
5017 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5018 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5019 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5021 if (fontface->info_strings[i])
5022 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5024 fontface->cmap.stream = fontface->stream;
5025 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5026 release_font_data(font_data);
5028 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5030 *ret = &fontface->IDWriteFontFace5_iface;
5032 return S_OK;
5035 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5036 struct local_refkey
5038 FILETIME writetime;
5039 WCHAR name[1];
5042 struct local_cached_stream
5044 struct list entry;
5045 IDWriteFontFileStream *stream;
5046 struct local_refkey *key;
5047 UINT32 key_size;
5050 struct dwrite_localfontfilestream
5052 IDWriteFontFileStream IDWriteFontFileStream_iface;
5053 LONG refcount;
5055 struct local_cached_stream *entry;
5056 const void *file_ptr;
5057 UINT64 size;
5060 struct dwrite_localfontfileloader
5062 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5063 LONG refcount;
5065 struct list streams;
5066 CRITICAL_SECTION cs;
5069 static struct dwrite_localfontfileloader local_fontfile_loader;
5071 struct dwrite_inmemory_stream_data
5073 LONG ref;
5074 IUnknown *owner;
5075 void *data;
5076 UINT32 size;
5079 struct dwrite_inmemory_filestream
5081 IDWriteFontFileStream IDWriteFontFileStream_iface;
5082 LONG ref;
5084 struct dwrite_inmemory_stream_data *data;
5087 struct dwrite_inmemory_fileloader
5089 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5090 LONG ref;
5092 struct dwrite_inmemory_stream_data **streams;
5093 size_t size;
5094 size_t count;
5097 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5099 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5102 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5104 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5107 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5109 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5112 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5114 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5117 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5119 if (InterlockedDecrement(&stream->ref) == 0) {
5120 if (stream->owner)
5121 IUnknown_Release(stream->owner);
5122 else
5123 heap_free(stream->data);
5124 heap_free(stream);
5128 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5130 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5132 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5134 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5135 IsEqualIID(riid, &IID_IUnknown))
5137 *obj = iface;
5138 if (InterlockedIncrement(&stream->refcount) == 1)
5140 InterlockedDecrement(&stream->refcount);
5141 *obj = NULL;
5142 return E_FAIL;
5144 return S_OK;
5147 WARN("%s not implemented.\n", debugstr_guid(riid));
5149 *obj = NULL;
5150 return E_NOINTERFACE;
5153 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5155 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5156 ULONG refcount = InterlockedIncrement(&stream->refcount);
5158 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5160 return refcount;
5163 static inline void release_cached_stream(struct local_cached_stream *stream)
5165 list_remove(&stream->entry);
5166 heap_free(stream->key);
5167 heap_free(stream);
5170 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5172 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5173 ULONG refcount = InterlockedDecrement(&stream->refcount);
5175 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5177 if (!refcount)
5179 UnmapViewOfFile(stream->file_ptr);
5181 EnterCriticalSection(&local_fontfile_loader.cs);
5182 release_cached_stream(stream->entry);
5183 LeaveCriticalSection(&local_fontfile_loader.cs);
5185 heap_free(stream);
5188 return refcount;
5191 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5192 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5194 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5196 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5197 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5199 *fragment_context = NULL;
5201 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5203 *fragment_start = NULL;
5204 return E_FAIL;
5207 *fragment_start = (char *)stream->file_ptr + offset;
5208 return S_OK;
5211 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5213 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5216 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5218 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5220 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5222 *size = stream->size;
5223 return S_OK;
5226 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5228 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5229 ULARGE_INTEGER li;
5231 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5233 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5234 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5235 *last_writetime = li.QuadPart;
5237 return S_OK;
5240 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5242 localfontfilestream_QueryInterface,
5243 localfontfilestream_AddRef,
5244 localfontfilestream_Release,
5245 localfontfilestream_ReadFileFragment,
5246 localfontfilestream_ReleaseFileFragment,
5247 localfontfilestream_GetFileSize,
5248 localfontfilestream_GetLastWriteTime
5251 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5252 IDWriteFontFileStream **ret)
5254 struct dwrite_localfontfilestream *object;
5256 *ret = NULL;
5258 if (!(object = heap_alloc(sizeof(*object))))
5259 return E_OUTOFMEMORY;
5261 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5262 object->refcount = 1;
5264 object->file_ptr = file_ptr;
5265 object->size = size;
5266 object->entry = entry;
5268 *ret = &object->IDWriteFontFileStream_iface;
5270 return S_OK;
5273 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5275 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5277 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5278 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5279 IsEqualIID(riid, &IID_IUnknown))
5281 *obj = iface;
5282 IDWriteLocalFontFileLoader_AddRef(iface);
5283 return S_OK;
5286 WARN("%s not implemented.\n", debugstr_guid(riid));
5288 *obj = NULL;
5289 return E_NOINTERFACE;
5292 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5294 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5295 ULONG refcount = InterlockedIncrement(&loader->refcount);
5297 TRACE("%p, refcount %d.\n", iface, refcount);
5299 return refcount;
5302 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5304 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5305 ULONG refcount = InterlockedDecrement(&loader->refcount);
5307 TRACE("%p, refcount %d.\n", iface, refcount);
5309 return refcount;
5312 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5314 const struct local_refkey *refkey = key;
5315 struct local_cached_stream *stream;
5316 IDWriteFontFileStream *filestream;
5317 HANDLE file, mapping;
5318 LARGE_INTEGER size;
5319 void *file_ptr;
5320 HRESULT hr = S_OK;
5322 *ret = NULL;
5324 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5325 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5326 if (file == INVALID_HANDLE_VALUE) {
5327 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5328 return E_FAIL;
5331 GetFileSizeEx(file, &size);
5332 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5333 CloseHandle(file);
5334 if (!mapping)
5335 return E_FAIL;
5337 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5338 CloseHandle(mapping);
5339 if (!file_ptr) {
5340 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5341 return E_FAIL;
5344 stream = heap_alloc(sizeof(*stream));
5345 if (!stream) {
5346 UnmapViewOfFile(file_ptr);
5347 return E_OUTOFMEMORY;
5350 stream->key = heap_alloc(key_size);
5351 if (!stream->key) {
5352 UnmapViewOfFile(file_ptr);
5353 heap_free(stream);
5354 return E_OUTOFMEMORY;
5357 stream->key_size = key_size;
5358 memcpy(stream->key, key, key_size);
5360 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5361 if (FAILED(hr)) {
5362 UnmapViewOfFile(file_ptr);
5363 heap_free(stream->key);
5364 heap_free(stream);
5365 return hr;
5368 stream->stream = filestream;
5370 *ret = stream;
5372 return S_OK;
5375 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5376 UINT32 key_size, IDWriteFontFileStream **ret)
5378 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5379 struct local_cached_stream *stream;
5380 HRESULT hr = S_OK;
5382 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5384 EnterCriticalSection(&loader->cs);
5386 *ret = NULL;
5388 /* search cache first */
5389 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5391 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5392 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5393 break;
5397 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5399 list_add_head(&loader->streams, &stream->entry);
5400 *ret = stream->stream;
5403 LeaveCriticalSection(&loader->cs);
5405 return hr;
5408 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5409 UINT32 key_size, UINT32 *length)
5411 const struct local_refkey *refkey = key;
5413 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5415 *length = strlenW(refkey->name);
5416 return S_OK;
5419 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5420 UINT32 key_size, WCHAR *path, UINT32 length)
5422 const struct local_refkey *refkey = key;
5424 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5426 if (length < strlenW(refkey->name))
5427 return E_INVALIDARG;
5429 strcpyW(path, refkey->name);
5430 return S_OK;
5433 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5434 UINT32 key_size, FILETIME *writetime)
5436 const struct local_refkey *refkey = key;
5438 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5440 *writetime = refkey->writetime;
5441 return S_OK;
5444 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5446 localfontfileloader_QueryInterface,
5447 localfontfileloader_AddRef,
5448 localfontfileloader_Release,
5449 localfontfileloader_CreateStreamFromKey,
5450 localfontfileloader_GetFilePathLengthFromKey,
5451 localfontfileloader_GetFilePathFromKey,
5452 localfontfileloader_GetLastWriteTimeFromKey
5455 void init_local_fontfile_loader(void)
5457 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5458 local_fontfile_loader.refcount = 1;
5459 list_init(&local_fontfile_loader.streams);
5460 InitializeCriticalSection(&local_fontfile_loader.cs);
5461 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5464 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5466 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5469 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5471 struct local_refkey *refkey;
5473 if (!path)
5474 return E_INVALIDARG;
5476 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5477 *key = NULL;
5479 refkey = heap_alloc(*size);
5480 if (!refkey)
5481 return E_OUTOFMEMORY;
5483 if (writetime)
5484 refkey->writetime = *writetime;
5485 else {
5486 WIN32_FILE_ATTRIBUTE_DATA info;
5488 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5489 refkey->writetime = info.ftLastWriteTime;
5490 else
5491 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5493 strcpyW(refkey->name, path);
5495 *key = refkey;
5497 return S_OK;
5500 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5502 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5504 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5505 IsEqualIID(riid, &IID_IUnknown))
5507 *ppv = iface;
5508 IDWriteGlyphRunAnalysis_AddRef(iface);
5509 return S_OK;
5512 WARN("%s not implemented.\n", debugstr_guid(riid));
5514 *ppv = NULL;
5515 return E_NOINTERFACE;
5518 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5520 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5521 ULONG refcount = InterlockedIncrement(&analysis->refcount);
5523 TRACE("%p, refcount %d.\n", iface, refcount);
5525 return refcount;
5528 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5530 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5531 ULONG refcount = InterlockedDecrement(&analysis->refcount);
5533 TRACE("%p, refcount %d.\n", iface, refcount);
5535 if (!refcount)
5537 if (analysis->run.fontFace)
5538 IDWriteFontFace_Release(analysis->run.fontFace);
5539 heap_free(analysis->glyphs);
5540 heap_free(analysis->origins);
5541 heap_free(analysis->bitmap);
5542 heap_free(analysis);
5545 return refcount;
5548 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5550 switch (mode)
5552 case DWRITE_RENDERING_MODE1_NATURAL:
5553 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5554 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5555 return TRUE;
5556 default:
5557 return FALSE;
5561 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5563 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5566 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5568 struct dwrite_glyphbitmap glyph_bitmap;
5569 IDWriteFontFace4 *fontface;
5570 HRESULT hr;
5571 UINT32 i;
5573 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5574 *bounds = analysis->bounds;
5575 return;
5578 if (analysis->run.isSideways)
5579 FIXME("sideways runs are not supported.\n");
5581 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5582 if (FAILED(hr))
5583 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5585 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5586 glyph_bitmap.fontface = fontface;
5587 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5588 glyph_bitmap.emsize = analysis->run.fontEmSize;
5589 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5590 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5591 glyph_bitmap.m = &analysis->m;
5593 for (i = 0; i < analysis->run.glyphCount; i++) {
5594 RECT *bbox = &glyph_bitmap.bbox;
5595 UINT32 bitmap_size;
5597 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5598 freetype_get_glyph_bbox(&glyph_bitmap);
5600 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5601 (bbox->bottom - bbox->top);
5602 if (bitmap_size > analysis->max_glyph_bitmap_size)
5603 analysis->max_glyph_bitmap_size = bitmap_size;
5605 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5606 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5609 IDWriteFontFace4_Release(fontface);
5611 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5612 *bounds = analysis->bounds;
5615 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
5616 DWRITE_TEXTURE_TYPE type, RECT *bounds)
5618 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5620 TRACE("%p, %d, %p.\n", iface, type, bounds);
5622 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5623 SetRectEmpty(bounds);
5624 return E_INVALIDARG;
5627 if (type != analysis->texture_type)
5629 SetRectEmpty(bounds);
5630 return S_OK;
5633 glyphrunanalysis_get_texturebounds(analysis, bounds);
5634 return S_OK;
5637 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5639 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5640 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5641 (runbounds->left - bounds->left) * 3;
5642 else
5643 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5644 runbounds->left - bounds->left;
5647 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5649 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5650 struct dwrite_glyphbitmap glyph_bitmap;
5651 IDWriteFontFace4 *fontface;
5652 D2D_POINT_2F origin;
5653 UINT32 i, size;
5654 HRESULT hr;
5655 RECT *bbox;
5657 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5658 if (FAILED(hr)) {
5659 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5660 return hr;
5663 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5664 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5665 size *= 3;
5666 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5667 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5668 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5669 IDWriteFontFace4_Release(fontface);
5670 return E_OUTOFMEMORY;
5673 origin.x = origin.y = 0.0f;
5675 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5676 glyph_bitmap.fontface = fontface;
5677 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5678 glyph_bitmap.emsize = analysis->run.fontEmSize;
5679 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5680 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5681 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5682 glyph_bitmap.m = &analysis->m;
5683 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5684 IDWriteFontFace4_Release(fontface);
5685 return E_OUTOFMEMORY;
5688 bbox = &glyph_bitmap.bbox;
5690 for (i = 0; i < analysis->run.glyphCount; i++) {
5691 BYTE *src = glyph_bitmap.buf, *dst;
5692 int x, y, width, height;
5693 BOOL is_1bpp;
5695 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5696 freetype_get_glyph_bbox(&glyph_bitmap);
5698 if (IsRectEmpty(bbox))
5699 continue;
5701 width = bbox->right - bbox->left;
5702 height = bbox->bottom - bbox->top;
5704 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5705 memset(src, 0, height * glyph_bitmap.pitch);
5706 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5708 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5710 /* blit to analysis bitmap */
5711 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5713 if (is_1bpp) {
5714 /* convert 1bpp to 8bpp/24bpp */
5715 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5716 for (y = 0; y < height; y++) {
5717 for (x = 0; x < width; x++)
5718 if (src[x / 8] & masks[x % 8])
5719 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5720 src += glyph_bitmap.pitch;
5721 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5724 else {
5725 for (y = 0; y < height; y++) {
5726 for (x = 0; x < width; x++)
5727 if (src[x / 8] & masks[x % 8])
5728 dst[x] = DWRITE_ALPHA_MAX;
5729 src += glyph_bitmap.pitch;
5730 dst += analysis->bounds.right - analysis->bounds.left;
5734 else {
5735 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5736 for (y = 0; y < height; y++) {
5737 for (x = 0; x < width; x++)
5738 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5739 src += glyph_bitmap.pitch;
5740 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5743 else {
5744 for (y = 0; y < height; y++) {
5745 for (x = 0; x < width; x++)
5746 dst[x] |= src[x];
5747 src += glyph_bitmap.pitch;
5748 dst += analysis->bounds.right - analysis->bounds.left;
5753 heap_free(glyph_bitmap.buf);
5755 IDWriteFontFace4_Release(fontface);
5757 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5759 /* we don't need this anymore */
5760 heap_free(analysis->glyphs);
5761 heap_free(analysis->origins);
5762 IDWriteFontFace_Release(analysis->run.fontFace);
5764 analysis->glyphs = NULL;
5765 analysis->origins = NULL;
5766 analysis->run.glyphIndices = NULL;
5767 analysis->run.fontFace = NULL;
5769 return S_OK;
5772 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5773 RECT const *bounds, BYTE *bitmap, UINT32 size)
5775 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5776 UINT32 required;
5777 RECT runbounds;
5779 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
5781 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5782 return E_INVALIDARG;
5784 /* make sure buffer is large enough for requested texture type */
5785 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5786 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5787 required *= 3;
5789 if (size < required)
5790 return E_NOT_SUFFICIENT_BUFFER;
5792 /* validate requested texture type */
5793 if (analysis->texture_type != type)
5794 return DWRITE_E_UNSUPPORTEDOPERATION;
5796 memset(bitmap, 0, size);
5797 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
5798 if (IntersectRect(&runbounds, &runbounds, bounds))
5800 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5801 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
5802 int dst_width = (bounds->right - bounds->left) * pixel_size;
5803 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5804 BYTE *src, *dst;
5805 int y;
5807 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
5809 HRESULT hr;
5811 if (FAILED(hr = glyphrunanalysis_render(analysis)))
5812 return hr;
5815 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
5816 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5818 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5819 memcpy(dst, src, draw_width);
5820 src += src_width;
5821 dst += dst_width;
5825 return S_OK;
5828 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5829 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5831 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5833 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
5835 if (!params)
5836 return E_INVALIDARG;
5838 switch (analysis->rendering_mode)
5840 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5841 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5843 UINT value = 0;
5844 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5845 *gamma = (FLOAT)value / 1000.0f;
5846 *contrast = 0.0f;
5847 *cleartypelevel = 1.0f;
5848 break;
5850 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5851 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5852 /* fallthrough */
5853 case DWRITE_RENDERING_MODE1_ALIASED:
5854 case DWRITE_RENDERING_MODE1_NATURAL:
5855 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5856 *gamma = IDWriteRenderingParams_GetGamma(params);
5857 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5858 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5859 break;
5860 default:
5864 return S_OK;
5867 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
5869 glyphrunanalysis_QueryInterface,
5870 glyphrunanalysis_AddRef,
5871 glyphrunanalysis_Release,
5872 glyphrunanalysis_GetAlphaTextureBounds,
5873 glyphrunanalysis_CreateAlphaTexture,
5874 glyphrunanalysis_GetAlphaBlendParams
5877 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5879 D2D_POINT_2F ret;
5880 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5881 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5882 *point = ret;
5885 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5886 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5888 unsigned int upem = fontface->metrics.designUnitsPerEm;
5889 int advance;
5891 if (is_sideways)
5892 FIXME("Sideways mode is not supported.\n");
5894 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5896 switch (measuring_mode)
5898 case DWRITE_MEASURING_MODE_NATURAL:
5899 return (float)advance * emsize / (float)upem;
5900 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5901 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5902 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5903 default:
5904 WARN("Unknown measuring mode %u.\n", measuring_mode);
5905 return 0.0f;
5909 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5911 struct dwrite_glyphrunanalysis *analysis;
5912 struct dwrite_fontface *fontface;
5913 D2D_POINT_2F origin;
5914 FLOAT rtl_factor;
5915 UINT32 i;
5917 *ret = NULL;
5919 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5920 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5921 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5922 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5923 return E_INVALIDARG;
5925 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5926 return E_INVALIDARG;
5928 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5929 return E_INVALIDARG;
5931 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5932 return E_INVALIDARG;
5934 analysis = heap_alloc(sizeof(*analysis));
5935 if (!analysis)
5936 return E_OUTOFMEMORY;
5938 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5939 analysis->refcount = 1;
5940 analysis->rendering_mode = desc->rendering_mode;
5942 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5943 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5944 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5945 else
5946 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5948 analysis->flags = 0;
5949 analysis->bitmap = NULL;
5950 analysis->max_glyph_bitmap_size = 0;
5951 SetRectEmpty(&analysis->bounds);
5952 analysis->run = *desc->run;
5953 IDWriteFontFace_AddRef(analysis->run.fontFace);
5954 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5955 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5957 if (!analysis->glyphs || !analysis->origins) {
5958 heap_free(analysis->glyphs);
5959 heap_free(analysis->origins);
5961 analysis->glyphs = NULL;
5962 analysis->origins = NULL;
5964 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5965 return E_OUTOFMEMORY;
5968 /* check if transform is usable */
5969 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5970 analysis->m = *desc->transform;
5971 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5973 else
5974 memset(&analysis->m, 0, sizeof(analysis->m));
5976 analysis->run.glyphIndices = analysis->glyphs;
5977 analysis->run.glyphAdvances = NULL;
5978 analysis->run.glyphOffsets = NULL;
5980 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5982 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5984 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5986 origin.x = desc->origin.x;
5987 origin.y = desc->origin.y;
5988 for (i = 0; i < desc->run->glyphCount; ++i)
5990 float advance;
5992 /* Use nominal advances if not provided by caller. */
5993 if (desc->run->glyphAdvances)
5994 advance = rtl_factor * desc->run->glyphAdvances[i];
5995 else
5996 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5997 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5999 analysis->origins[i] = origin;
6000 if (desc->run->bidiLevel & 1)
6002 if (desc->run->isSideways)
6003 analysis->origins[i].y += advance;
6004 else
6005 analysis->origins[i].x += advance;
6008 /* Offsets are optional, appled to pre-transformed origin. */
6009 if (desc->run->glyphOffsets) {
6010 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
6011 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
6013 if (desc->run->isSideways) {
6014 analysis->origins[i].x += ascenderoffset;
6015 analysis->origins[i].y += advanceoffset;
6017 else {
6018 analysis->origins[i].x += advanceoffset;
6019 analysis->origins[i].y += ascenderoffset;
6023 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6024 transform_point(analysis->origins + i, &analysis->m);
6026 if (desc->run->isSideways)
6027 origin.y += advance;
6028 else
6029 origin.x += advance;
6032 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6033 return S_OK;
6036 /* IDWriteColorGlyphRunEnumerator1 */
6037 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6039 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6041 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6042 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6043 IsEqualIID(riid, &IID_IUnknown))
6045 *ppv = iface;
6046 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6047 return S_OK;
6050 WARN("%s not implemented.\n", debugstr_guid(riid));
6052 *ppv = NULL;
6053 return E_NOINTERFACE;
6056 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6058 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6059 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6061 TRACE("%p, refcount %u.\n", iface, refcount);
6063 return refcount;
6066 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6068 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6069 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6071 TRACE("%p, refcount %u.\n", iface, refcount);
6073 if (!refcount)
6075 heap_free(glyphenum->advances);
6076 heap_free(glyphenum->color_advances);
6077 heap_free(glyphenum->offsets);
6078 heap_free(glyphenum->color_offsets);
6079 heap_free(glyphenum->glyphindices);
6080 heap_free(glyphenum->glyphs);
6081 if (glyphenum->colr.context)
6082 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6083 IDWriteFontFace5_Release(glyphenum->fontface);
6084 heap_free(glyphenum);
6087 return refcount;
6090 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6092 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6093 FLOAT origin = 0.0f;
6095 if (g == 0)
6096 return 0.0f;
6098 while (g--)
6099 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6100 return origin;
6103 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6105 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6106 FLOAT advance_adj = 0.0f;
6107 BOOL got_palette_index;
6108 UINT32 g;
6110 /* start with regular glyphs */
6111 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6112 UINT32 first_glyph = 0;
6114 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6115 if (glyphenum->glyphs[g].num_layers == 0) {
6116 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6117 first_glyph = min(first_glyph, g);
6119 else
6120 glyphenum->glyphindices[g] = 1;
6121 glyphenum->color_advances[g] = glyphenum->advances[g];
6122 if (glyphenum->color_offsets)
6123 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6126 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6127 colorrun->baselineOriginY = glyphenum->origin_y;
6128 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6129 colorrun->paletteIndex = 0xffff;
6130 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6131 glyphenum->has_regular_glyphs = FALSE;
6132 return TRUE;
6134 else {
6135 colorrun->glyphRun.glyphCount = 0;
6136 got_palette_index = FALSE;
6139 advance_adj = 0.0f;
6140 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6142 glyphenum->glyphindices[g] = 1;
6144 /* all glyph layers were returned */
6145 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6146 advance_adj += glyphenum->advances[g];
6147 continue;
6150 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6151 UINT32 index = colorrun->glyphRun.glyphCount;
6152 if (!got_palette_index) {
6153 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6154 /* use foreground color or request one from the font */
6155 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6156 if (colorrun->paletteIndex != 0xffff)
6158 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6159 colorrun->paletteIndex, 1, &colorrun->runColor);
6160 if (FAILED(hr))
6161 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6162 glyphenum->palette, colorrun->paletteIndex, hr);
6164 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6165 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6166 colorrun->baselineOriginY = glyphenum->origin_y;
6167 glyphenum->color_advances[index] = glyphenum->advances[g];
6168 got_palette_index = TRUE;
6171 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6172 /* offsets are relative to glyph origin, nothing to fix up */
6173 if (glyphenum->color_offsets)
6174 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6175 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6176 if (index)
6177 glyphenum->color_advances[index-1] += advance_adj;
6178 colorrun->glyphRun.glyphCount++;
6179 advance_adj = 0.0f;
6181 else
6182 advance_adj += glyphenum->advances[g];
6185 /* reset last advance */
6186 if (colorrun->glyphRun.glyphCount)
6187 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6189 return colorrun->glyphRun.glyphCount > 0;
6192 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6194 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6196 TRACE("%p, %p.\n", iface, has_run);
6198 *has_run = FALSE;
6200 glyphenum->colorrun.glyphRun.glyphCount = 0;
6201 while (glyphenum->current_layer < glyphenum->max_layer_num)
6203 if (colorglyphenum_build_color_run(glyphenum))
6204 break;
6205 else
6206 glyphenum->current_layer++;
6209 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6211 return S_OK;
6214 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6215 DWRITE_COLOR_GLYPH_RUN1 const **run)
6217 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6219 *run = NULL;
6220 return E_NOT_VALID_STATE;
6223 *run = &glyphenum->colorrun;
6224 return S_OK;
6227 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6228 DWRITE_COLOR_GLYPH_RUN const **run)
6230 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6232 TRACE("%p, %p.\n", iface, run);
6234 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6237 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6238 DWRITE_COLOR_GLYPH_RUN1 const **run)
6240 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6242 TRACE("%p, %p.\n", iface, run);
6244 return colorglyphenum_get_current_run(glyphenum, run);
6247 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6249 colorglyphenum_QueryInterface,
6250 colorglyphenum_AddRef,
6251 colorglyphenum_Release,
6252 colorglyphenum_MoveNext,
6253 colorglyphenum_GetCurrentRun,
6254 colorglyphenum1_GetCurrentRun,
6257 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6258 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6259 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6261 struct dwrite_colorglyphenum *colorglyphenum;
6262 BOOL colorfont, has_colored_glyph;
6263 struct dwrite_fontface *fontface;
6264 unsigned int i;
6266 *ret = NULL;
6268 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6270 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6271 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6272 if (!colorfont)
6273 return DWRITE_E_NOCOLOR;
6275 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6276 if (!colorglyphenum)
6277 return E_OUTOFMEMORY;
6279 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6280 colorglyphenum->refcount = 1;
6281 colorglyphenum->origin_x = originX;
6282 colorglyphenum->origin_y = originY;
6283 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6284 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6285 colorglyphenum->glyphs = NULL;
6286 colorglyphenum->run = *run;
6287 colorglyphenum->run.glyphIndices = NULL;
6288 colorglyphenum->run.glyphAdvances = NULL;
6289 colorglyphenum->run.glyphOffsets = NULL;
6290 colorglyphenum->palette = palette;
6291 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6292 colorglyphenum->colr.exists = TRUE;
6293 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6294 colorglyphenum->current_layer = 0;
6295 colorglyphenum->max_layer_num = 0;
6297 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6299 has_colored_glyph = FALSE;
6300 colorglyphenum->has_regular_glyphs = FALSE;
6301 for (i = 0; i < run->glyphCount; i++) {
6302 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6303 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6304 has_colored_glyph = TRUE;
6306 if (colorglyphenum->glyphs[i].num_layers == 0)
6307 colorglyphenum->has_regular_glyphs = TRUE;
6310 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6311 is supposed to proceed normally, like if font had no color info at all. */
6312 if (!has_colored_glyph) {
6313 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6314 return DWRITE_E_NOCOLOR;
6317 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6318 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6319 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6320 if (run->glyphOffsets) {
6321 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6322 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6323 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6326 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6327 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6328 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6329 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6330 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6331 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6332 colorglyphenum->colorrun.measuringMode = measuring_mode;
6333 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6335 if (run->glyphAdvances)
6336 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6337 else
6339 for (i = 0; i < run->glyphCount; ++i)
6340 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6341 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6344 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6346 return S_OK;
6349 /* IDWriteFontFaceReference */
6350 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6352 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6354 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6355 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6356 IsEqualIID(riid, &IID_IUnknown))
6358 *obj = iface;
6359 IDWriteFontFaceReference1_AddRef(iface);
6360 return S_OK;
6363 WARN("%s not implemented.\n", debugstr_guid(riid));
6365 *obj = NULL;
6367 return E_NOINTERFACE;
6370 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6372 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6373 ULONG refcount = InterlockedIncrement(&reference->refcount);
6375 TRACE("%p, refcount %u.\n", iface, refcount);
6377 return refcount;
6380 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6382 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6383 ULONG refcount = InterlockedDecrement(&reference->refcount);
6385 TRACE("%p, refcount %u.\n", iface, refcount);
6387 if (!refcount)
6389 IDWriteFontFile_Release(reference->file);
6390 IDWriteFactory7_Release(reference->factory);
6391 heap_free(reference->axis_values);
6392 heap_free(reference);
6395 return refcount;
6398 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6400 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6402 TRACE("%p, %p.\n", iface, fontface);
6404 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6407 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6408 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6410 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6411 DWRITE_FONT_FILE_TYPE file_type;
6412 DWRITE_FONT_FACE_TYPE face_type;
6413 IDWriteFontFace *fontface;
6414 BOOL is_supported;
6415 UINT32 face_num;
6416 HRESULT hr;
6418 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6420 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6421 if (FAILED(hr))
6422 return hr;
6424 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6425 simulations, &fontface);
6426 if (SUCCEEDED(hr))
6428 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6429 IDWriteFontFace_Release(fontface);
6432 return hr;
6435 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6437 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6438 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6439 BOOL ret;
6441 TRACE("%p, %p.\n", iface, ref);
6443 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6444 reference->simulations == other->simulations;
6445 if (reference->axis_values_count)
6447 ret &= reference->axis_values_count == other->axis_values_count &&
6448 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6451 return ret;
6454 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6456 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6458 TRACE("%p.\n", iface);
6460 return reference->index;
6463 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6465 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6467 TRACE("%p.\n", iface);
6469 return reference->simulations;
6472 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6474 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6475 IDWriteFontFileLoader *loader;
6476 const void *key;
6477 UINT32 key_size;
6478 HRESULT hr;
6480 TRACE("%p, %p.\n", iface, file);
6482 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6483 if (FAILED(hr))
6484 return hr;
6486 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6487 if (FAILED(hr))
6488 return hr;
6490 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6491 IDWriteFontFileLoader_Release(loader);
6493 return hr;
6496 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6498 FIXME("%p.\n", iface);
6500 return 0;
6503 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6505 FIXME("%p.\n", iface);
6507 return 0;
6510 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6512 FIXME("%p, %p.\n", iface, writetime);
6514 return E_NOTIMPL;
6517 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6519 FIXME("%p.\n", iface);
6521 return DWRITE_LOCALITY_LOCAL;
6524 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6526 FIXME("%p.\n", iface);
6528 return E_NOTIMPL;
6531 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6532 WCHAR const *chars, UINT32 count)
6534 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6536 return E_NOTIMPL;
6539 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6540 UINT16 const *glyphs, UINT32 count)
6542 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6544 return E_NOTIMPL;
6547 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6548 UINT64 offset, UINT64 size)
6550 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6552 return E_NOTIMPL;
6555 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6557 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6558 IDWriteFontFace3 *fontface3;
6559 HRESULT hr;
6561 TRACE("%p, %p.\n", iface, fontface);
6563 /* FIXME: created instance should likely respect given axis. */
6564 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6565 &fontface3)))
6567 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6568 IDWriteFontFace3_Release(fontface3);
6571 return hr;
6574 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6576 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6578 TRACE("%p.\n", iface);
6580 return reference->axis_values_count;
6583 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6584 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6586 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6588 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6590 if (value_count < reference->axis_values_count)
6591 return E_NOT_SUFFICIENT_BUFFER;
6593 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6595 return S_OK;
6598 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6600 fontfacereference_QueryInterface,
6601 fontfacereference_AddRef,
6602 fontfacereference_Release,
6603 fontfacereference_CreateFontFace,
6604 fontfacereference_CreateFontFaceWithSimulations,
6605 fontfacereference_Equals,
6606 fontfacereference_GetFontFaceIndex,
6607 fontfacereference_GetSimulations,
6608 fontfacereference_GetFontFile,
6609 fontfacereference_GetLocalFileSize,
6610 fontfacereference_GetFileSize,
6611 fontfacereference_GetFileTime,
6612 fontfacereference_GetLocality,
6613 fontfacereference_EnqueueFontDownloadRequest,
6614 fontfacereference_EnqueueCharacterDownloadRequest,
6615 fontfacereference_EnqueueGlyphDownloadRequest,
6616 fontfacereference_EnqueueFileFragmentDownloadRequest,
6617 fontfacereference1_CreateFontFace,
6618 fontfacereference1_GetFontAxisValueCount,
6619 fontfacereference1_GetFontAxisValues,
6622 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6623 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6624 IDWriteFontFaceReference1 **ret)
6626 struct dwrite_fontfacereference *object;
6628 *ret = NULL;
6630 if (!is_simulation_valid(simulations))
6631 return E_INVALIDARG;
6633 object = heap_alloc_zero(sizeof(*object));
6634 if (!object)
6635 return E_OUTOFMEMORY;
6637 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6638 object->refcount = 1;
6640 object->factory = factory;
6641 IDWriteFactory7_AddRef(object->factory);
6642 object->file = file;
6643 IDWriteFontFile_AddRef(object->file);
6644 object->index = index;
6645 object->simulations = simulations;
6646 if (axis_values_count)
6648 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6650 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6651 return E_OUTOFMEMORY;
6653 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6654 object->axis_values_count = axis_values_count;
6657 *ret = &object->IDWriteFontFaceReference1_iface;
6659 return S_OK;
6662 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6664 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6666 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6668 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6669 *obj = iface;
6670 IDWriteFontFileStream_AddRef(iface);
6671 return S_OK;
6674 *obj = NULL;
6676 WARN("%s not implemented.\n", debugstr_guid(riid));
6677 return E_NOINTERFACE;
6680 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6682 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6683 ULONG ref = InterlockedIncrement(&stream->ref);
6684 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6685 return ref;
6688 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6690 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6691 ULONG ref = InterlockedDecrement(&stream->ref);
6693 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6695 if (!ref) {
6696 release_inmemory_stream(stream->data);
6697 heap_free(stream);
6700 return ref;
6703 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6704 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6706 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6708 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6709 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6711 *fragment_context = NULL;
6713 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6714 *fragment_start = NULL;
6715 return E_FAIL;
6718 *fragment_start = (char *)stream->data->data + offset;
6719 return S_OK;
6722 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6724 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6726 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6729 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6731 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6733 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6735 *size = stream->data->size;
6737 return S_OK;
6740 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6742 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6744 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6746 *last_writetime = 0;
6748 return E_NOTIMPL;
6751 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6752 inmemoryfilestream_QueryInterface,
6753 inmemoryfilestream_AddRef,
6754 inmemoryfilestream_Release,
6755 inmemoryfilestream_ReadFileFragment,
6756 inmemoryfilestream_ReleaseFileFragment,
6757 inmemoryfilestream_GetFileSize,
6758 inmemoryfilestream_GetLastWriteTime,
6761 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6762 REFIID riid, void **obj)
6764 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6766 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6768 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6769 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6770 IsEqualIID(riid, &IID_IUnknown))
6772 *obj = iface;
6773 IDWriteInMemoryFontFileLoader_AddRef(iface);
6774 return S_OK;
6777 WARN("%s not implemented.\n", debugstr_guid(riid));
6779 *obj = NULL;
6781 return E_NOINTERFACE;
6784 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6786 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6787 ULONG ref = InterlockedIncrement(&loader->ref);
6788 TRACE("(%p)->(%u)\n", loader, ref);
6789 return ref;
6792 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6794 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6795 ULONG ref = InterlockedDecrement(&loader->ref);
6796 size_t i;
6798 TRACE("(%p)->(%u)\n", loader, ref);
6800 if (!ref) {
6801 for (i = 0; i < loader->count; ++i)
6802 release_inmemory_stream(loader->streams[i]);
6803 heap_free(loader->streams);
6804 heap_free(loader);
6807 return ref;
6810 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6811 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6813 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6814 struct dwrite_inmemory_filestream *stream;
6815 DWORD index;
6817 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6819 *ret = NULL;
6821 if (key_size != sizeof(DWORD))
6822 return E_INVALIDARG;
6824 index = *(DWORD *)key;
6826 if (index >= loader->count)
6827 return E_INVALIDARG;
6829 if (!(stream = heap_alloc(sizeof(*stream))))
6830 return E_OUTOFMEMORY;
6832 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6833 stream->ref = 1;
6834 stream->data = loader->streams[index];
6835 InterlockedIncrement(&stream->data->ref);
6837 *ret = &stream->IDWriteFontFileStream_iface;
6839 return S_OK;
6842 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6843 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6845 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6846 struct dwrite_inmemory_stream_data *stream;
6847 DWORD key;
6849 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6851 *fontfile = NULL;
6853 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6854 return E_OUTOFMEMORY;
6856 if (!(stream = heap_alloc(sizeof(*stream))))
6857 return E_OUTOFMEMORY;
6859 stream->ref = 1;
6860 stream->size = data_size;
6861 stream->owner = owner;
6862 if (stream->owner) {
6863 IUnknown_AddRef(stream->owner);
6864 stream->data = (void *)data;
6866 else {
6867 if (!(stream->data = heap_alloc(data_size))) {
6868 heap_free(stream);
6869 return E_OUTOFMEMORY;
6871 memcpy(stream->data, data, data_size);
6874 key = loader->count;
6875 loader->streams[loader->count++] = stream;
6877 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6878 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6881 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6883 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6885 TRACE("%p.\n", iface);
6887 return loader->count;
6890 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6892 inmemoryfontfileloader_QueryInterface,
6893 inmemoryfontfileloader_AddRef,
6894 inmemoryfontfileloader_Release,
6895 inmemoryfontfileloader_CreateStreamFromKey,
6896 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6897 inmemoryfontfileloader_GetFileCount,
6900 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6902 struct dwrite_inmemory_fileloader *loader;
6904 *ret = NULL;
6906 loader = heap_alloc_zero(sizeof(*loader));
6907 if (!loader)
6908 return E_OUTOFMEMORY;
6910 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6911 loader->ref = 1;
6913 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6915 return S_OK;
6918 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6920 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6922 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6923 IsEqualIID(riid, &IID_IUnknown))
6925 *obj = iface;
6926 IDWriteFontResource_AddRef(iface);
6927 return S_OK;
6930 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6932 return E_NOINTERFACE;
6935 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6937 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6938 ULONG refcount = InterlockedIncrement(&resource->refcount);
6940 TRACE("%p, refcount %u.\n", iface, refcount);
6942 return refcount;
6945 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6947 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6948 ULONG refcount = InterlockedDecrement(&resource->refcount);
6950 TRACE("%p, refcount %u.\n", iface, refcount);
6952 if (!refcount)
6954 IDWriteFactory7_Release(resource->factory);
6955 IDWriteFontFile_Release(resource->file);
6956 heap_free(resource);
6959 return refcount;
6962 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6964 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6966 TRACE("%p, %p.\n", iface, fontfile);
6968 *fontfile = resource->file;
6969 IDWriteFontFile_AddRef(*fontfile);
6971 return S_OK;
6974 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6976 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6978 TRACE("%p.\n", iface);
6980 return resource->face_index;
6983 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6985 FIXME("%p.\n", iface);
6987 return 0;
6990 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6991 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6993 FIXME("%p, %p, %u.\n", iface, values, num_values);
6995 return E_NOTIMPL;
6998 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6999 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
7001 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
7003 return E_NOTIMPL;
7006 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7007 UINT32 axis)
7009 FIXME("%p, %u.\n", iface, axis);
7011 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
7014 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7015 IDWriteLocalizedStrings **names)
7017 FIXME("%p, %u, %p.\n", iface, axis, names);
7019 return E_NOTIMPL;
7022 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7024 FIXME("%p, %u.\n", iface, axis);
7026 return 0;
7029 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7030 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7032 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7034 return E_NOTIMPL;
7037 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7039 FIXME("%p.\n", iface);
7041 return FALSE;
7044 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7045 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7046 IDWriteFontFace5 **fontface)
7048 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7049 IDWriteFontFaceReference1 *reference;
7050 HRESULT hr;
7052 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7054 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7055 simulations, axis_values, num_values, &reference);
7056 if (SUCCEEDED(hr))
7058 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7059 IDWriteFontFaceReference1_Release(reference);
7062 return hr;
7065 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7066 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7067 IDWriteFontFaceReference1 **reference)
7069 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7071 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7073 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7074 simulations, axis_values, num_values, reference);
7077 static const IDWriteFontResourceVtbl fontresourcevtbl =
7079 dwritefontresource_QueryInterface,
7080 dwritefontresource_AddRef,
7081 dwritefontresource_Release,
7082 dwritefontresource_GetFontFile,
7083 dwritefontresource_GetFontFaceIndex,
7084 dwritefontresource_GetFontAxisCount,
7085 dwritefontresource_GetDefaultFontAxisValues,
7086 dwritefontresource_GetFontAxisRanges,
7087 dwritefontresource_GetFontAxisAttributes,
7088 dwritefontresource_GetAxisNames,
7089 dwritefontresource_GetAxisValueNameCount,
7090 dwritefontresource_GetAxisValueNames,
7091 dwritefontresource_HasVariations,
7092 dwritefontresource_CreateFontFace,
7093 dwritefontresource_CreateFontFaceReference,
7096 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7097 IDWriteFontResource **ret)
7099 struct dwrite_fontresource *resource;
7101 *ret = NULL;
7103 resource = heap_alloc_zero(sizeof(*resource));
7104 if (!resource)
7105 return E_OUTOFMEMORY;
7107 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7108 resource->refcount = 1;
7109 resource->face_index = face_index;
7110 resource->file = file;
7111 IDWriteFontFile_AddRef(resource->file);
7112 resource->factory = factory;
7113 IDWriteFactory7_AddRef(resource->factory);
7115 *ret = &resource->IDWriteFontResource_iface;
7117 return S_OK;