include: Make sure __int64 is correctly defined on PPC64.
[wine.git] / dlls / dwrite / font.c
blobe22e4abf2714b750b2444c12dea091a407d772d4
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 struct dwrite_fontset_builder
255 IDWriteFontSetBuilder2 IDWriteFontSetBuilder2_iface;
256 LONG refcount;
257 IDWriteFactory7 *factory;
260 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
262 struct dwrite_fontface *fontface = context;
263 BOOL exists = FALSE;
265 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
266 size, data_context, &exists)) || !exists)
268 *data = NULL;
269 *size = 0;
270 *data_context = NULL;
274 static void dwrite_release_font_table(void *context, void *data_context)
276 struct dwrite_fontface *fontface = context;
277 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
280 static UINT16 dwrite_get_font_upem(void *context)
282 struct dwrite_fontface *fontface = context;
283 return fontface->metrics.designUnitsPerEm;
286 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
288 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
289 return opentype_cmap_get_glyph(&fontface->cmap, ch);
292 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
294 struct dwrite_fontface *fontface = context;
295 return !!dwritefontface_get_glyph(fontface, codepoint);
298 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
300 struct dwrite_fontface *fontface = context;
301 return dwritefontface_get_glyph(fontface, codepoint);
304 static const struct shaping_font_ops dwrite_font_ops =
306 dwrite_grab_font_table,
307 dwrite_release_font_table,
308 dwrite_get_font_upem,
309 dwrite_has_glyph,
310 dwrite_get_glyph,
313 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
315 if (fontface->shaping_cache)
316 return fontface->shaping_cache;
318 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
321 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
326 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
328 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
331 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
333 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
336 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
338 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
343 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
348 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
353 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
355 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
358 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
360 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
363 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
365 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
368 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
370 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
373 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
375 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
378 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
380 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
383 static struct dwrite_fontset_builder *impl_from_IDWriteFontSetBuilder2(IDWriteFontSetBuilder2 *iface)
385 return CONTAINING_RECORD(iface, struct dwrite_fontset_builder, IDWriteFontSetBuilder2_iface);
388 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
390 static const DWRITE_GLYPH_METRICS nil;
391 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
393 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
394 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
395 return S_OK;
398 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
400 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
402 if (!*block) {
403 /* start new block */
404 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
405 if (!*block)
406 return E_OUTOFMEMORY;
409 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
410 return S_OK;
413 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
415 HRESULT hr;
417 if (table->data || !table->exists)
418 return table->data;
420 table->exists = FALSE;
421 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
422 &table->exists);
423 if (FAILED(hr) || !table->exists) {
424 TRACE("Font does not have %s table\n", debugstr_tag(tag));
425 return NULL;
428 return table->data;
431 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
432 struct dwrite_font_propvec *vec)
434 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
435 vec->style = style * 7.0f;
436 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
439 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
441 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
444 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
446 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
449 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
451 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
452 return &fontface->vdmx;
455 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
457 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
458 return &fontface->gasp;
461 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
463 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
464 return &fontface->cpal;
467 static void addref_font_data(struct dwrite_font_data *data)
469 InterlockedIncrement(&data->ref);
472 static void release_font_data(struct dwrite_font_data *data)
474 int i;
476 if (InterlockedDecrement(&data->ref) > 0)
477 return;
479 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
481 if (data->info_strings[i])
482 IDWriteLocalizedStrings_Release(data->info_strings[i]);
484 if (data->names)
485 IDWriteLocalizedStrings_Release(data->names);
487 if (data->family_names)
488 IDWriteLocalizedStrings_Release(data->family_names);
490 dwrite_cmap_release(&data->cmap);
491 IDWriteFontFile_Release(data->file);
492 heap_free(data->facename);
493 heap_free(data);
496 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
498 size_t i;
500 if (InterlockedDecrement(&data->refcount) > 0)
501 return;
503 for (i = 0; i < data->count; ++i)
504 release_font_data(data->fonts[i]);
505 heap_free(data->fonts);
506 IDWriteLocalizedStrings_Release(data->familyname);
507 heap_free(data);
510 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
512 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
513 fontface->cached = NULL;
516 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
518 UINT32 left_key_size, right_key_size;
519 const void *left_key, *right_key;
520 HRESULT hr;
522 if (left == right)
523 return TRUE;
525 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
526 if (FAILED(hr))
527 return FALSE;
529 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
530 if (FAILED(hr))
531 return FALSE;
533 if (left_key_size != right_key_size)
534 return FALSE;
536 return !memcmp(left_key, right_key, left_key_size);
539 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
541 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
543 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
545 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
546 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
547 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
548 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
549 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
550 IsEqualIID(riid, &IID_IDWriteFontFace) ||
551 IsEqualIID(riid, &IID_IUnknown))
553 *obj = iface;
555 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
556 *obj = &fontface->IDWriteFontFaceReference_iface;
557 else
558 *obj = NULL;
560 if (*obj)
562 if (InterlockedIncrement(&fontface->refcount) == 1)
564 InterlockedDecrement(&fontface->refcount);
565 *obj = NULL;
566 return E_FAIL;
568 return S_OK;
571 WARN("%s not implemented.\n", debugstr_guid(riid));
573 return E_NOINTERFACE;
576 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
578 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
579 ULONG refcount = InterlockedIncrement(&fontface->refcount);
581 TRACE("%p, refcount %u.\n", iface, refcount);
583 return refcount;
586 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
588 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
589 ULONG refcount = InterlockedDecrement(&fontface->refcount);
591 TRACE("%p, refcount %u.\n", iface, refcount);
593 if (!refcount)
595 UINT32 i;
597 if (fontface->cached)
599 factory_lock(fontface->factory);
600 list_remove(&fontface->cached->entry);
601 factory_unlock(fontface->factory);
602 heap_free(fontface->cached);
604 release_scriptshaping_cache(fontface->shaping_cache);
605 if (fontface->vdmx.context)
606 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
607 if (fontface->gasp.context)
608 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
609 if (fontface->cpal.context)
610 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
611 if (fontface->colr.context)
612 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
613 for (i = 0; i < fontface->file_count; i++)
615 if (fontface->files[i])
616 IDWriteFontFile_Release(fontface->files[i]);
618 if (fontface->stream)
619 IDWriteFontFileStream_Release(fontface->stream);
620 heap_free(fontface->files);
621 if (fontface->names)
622 IDWriteLocalizedStrings_Release(fontface->names);
623 if (fontface->family_names)
624 IDWriteLocalizedStrings_Release(fontface->family_names);
625 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
627 if (fontface->info_strings[i])
628 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
631 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
632 heap_free(fontface->glyphs[i]);
634 freetype_notify_cacheremove(iface);
636 dwrite_cmap_release(&fontface->cmap);
637 IDWriteFactory7_Release(fontface->factory);
638 heap_free(fontface);
641 return refcount;
644 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
646 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
648 TRACE("%p.\n", iface);
650 return fontface->type;
653 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
654 IDWriteFontFile **fontfiles)
656 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
657 int i;
659 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
661 if (fontfiles == NULL)
663 *number_of_files = fontface->file_count;
664 return S_OK;
667 if (*number_of_files < fontface->file_count)
668 return E_INVALIDARG;
670 for (i = 0; i < fontface->file_count; i++)
672 IDWriteFontFile_AddRef(fontface->files[i]);
673 fontfiles[i] = fontface->files[i];
676 return S_OK;
679 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
681 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
683 TRACE("%p.\n", iface);
685 return fontface->index;
688 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
690 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
692 TRACE("%p.\n", iface);
694 return fontface->simulations;
697 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
699 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
701 TRACE("%p.\n", iface);
703 return !!(fontface->flags & FONT_IS_SYMBOL);
706 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
708 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
710 TRACE("%p, %p.\n", iface, metrics);
712 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
715 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
717 TRACE("%p.\n", iface);
719 return freetype_get_glyphcount(iface);
722 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
723 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
725 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
726 unsigned int i;
727 HRESULT hr;
729 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
731 if (!glyphs)
732 return E_INVALIDARG;
734 if (is_sideways)
735 FIXME("sideways metrics are not supported.\n");
737 for (i = 0; i < glyph_count; i++) {
738 DWRITE_GLYPH_METRICS metrics;
740 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
741 if (hr != S_OK) {
742 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
743 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
744 if (FAILED(hr))
745 return hr;
747 ret[i] = metrics;
750 return S_OK;
753 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
754 UINT32 count, UINT16 *glyphs)
756 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
757 unsigned int i;
759 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
761 if (!glyphs)
762 return E_INVALIDARG;
764 if (!codepoints)
766 memset(glyphs, 0, count * sizeof(*glyphs));
767 return E_INVALIDARG;
770 for (i = 0; i < count; ++i)
771 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
773 return S_OK;
776 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
777 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
779 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
780 struct file_stream_desc stream_desc;
782 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
784 stream_desc.stream = fontface->stream;
785 stream_desc.face_type = fontface->type;
786 stream_desc.face_index = fontface->index;
787 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
790 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
792 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
794 TRACE("%p, %p.\n", iface, table_context);
796 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
799 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
800 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
801 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
803 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
804 count, is_sideways, is_rtl, sink);
806 if (!glyphs || !sink)
807 return E_INVALIDARG;
809 if (is_sideways)
810 FIXME("sideways mode is not supported.\n");
812 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
815 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
816 float ppem, unsigned int gasp)
818 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
820 switch (measuring)
822 case DWRITE_MEASURING_MODE_NATURAL:
824 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
825 mode = DWRITE_RENDERING_MODE_NATURAL;
826 else
827 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
828 break;
830 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
831 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
832 break;
833 case DWRITE_MEASURING_MODE_GDI_NATURAL:
834 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
835 break;
836 default:
840 return mode;
843 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
844 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
846 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
847 unsigned int flags;
848 FLOAT ppem;
850 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
852 if (!params) {
853 *mode = DWRITE_RENDERING_MODE_DEFAULT;
854 return E_INVALIDARG;
857 *mode = IDWriteRenderingParams_GetRenderingMode(params);
858 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
859 return S_OK;
861 ppem = emSize * ppdip;
863 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
864 *mode = DWRITE_RENDERING_MODE_OUTLINE;
865 return S_OK;
868 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
869 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
870 return S_OK;
873 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
874 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
876 DWRITE_FONT_METRICS1 metrics1;
877 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
878 memcpy(metrics, &metrics1, sizeof(*metrics));
879 return hr;
882 static inline int round_metric(FLOAT metric)
884 return (int)floorf(metric + 0.5f);
887 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
889 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
890 return 0;
892 return (fontface->metrics.designUnitsPerEm + 49) / 50;
895 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
896 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
897 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
899 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
900 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
901 DWRITE_MEASURING_MODE mode;
902 FLOAT scale, size;
903 HRESULT hr;
904 UINT32 i;
906 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
907 glyph_count, metrics, is_sideways);
909 if (m && memcmp(m, &identity, sizeof(*m)))
910 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
912 size = emSize * ppdip;
913 scale = size / fontface->metrics.designUnitsPerEm;
914 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
916 for (i = 0; i < glyph_count; i++) {
917 DWRITE_GLYPH_METRICS *ret = metrics + i;
918 DWRITE_GLYPH_METRICS design;
919 BOOL has_contours;
921 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
922 if (FAILED(hr))
923 return hr;
925 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
926 if (has_contours)
927 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
928 else
929 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
931 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
932 SCALE_METRIC(leftSideBearing);
933 SCALE_METRIC(rightSideBearing);
934 SCALE_METRIC(topSideBearing);
935 SCALE_METRIC(advanceHeight);
936 SCALE_METRIC(bottomSideBearing);
937 SCALE_METRIC(verticalOriginY);
938 #undef SCALE_METRIC
941 return S_OK;
944 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
946 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
948 TRACE("%p, %p.\n", iface, metrics);
950 *metrics = fontface->metrics;
953 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
954 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
956 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
957 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
958 UINT16 ascent, descent;
959 FLOAT scale;
961 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
963 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
964 memset(metrics, 0, sizeof(*metrics));
965 return E_INVALIDARG;
968 em_size *= pixels_per_dip;
969 if (m && m->m22 != 0.0f)
970 em_size *= fabs(m->m22);
972 scale = em_size / design->designUnitsPerEm;
973 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
975 ascent = round_metric(design->ascent * scale);
976 descent = round_metric(design->descent * scale);
979 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
980 metrics->designUnitsPerEm = design->designUnitsPerEm;
981 metrics->ascent = round_metric(ascent / scale);
982 metrics->descent = round_metric(descent / scale);
984 SCALE_METRIC(lineGap);
985 SCALE_METRIC(capHeight);
986 SCALE_METRIC(xHeight);
987 SCALE_METRIC(underlinePosition);
988 SCALE_METRIC(underlineThickness);
989 SCALE_METRIC(strikethroughPosition);
990 SCALE_METRIC(strikethroughThickness);
991 SCALE_METRIC(glyphBoxLeft);
992 SCALE_METRIC(glyphBoxTop);
993 SCALE_METRIC(glyphBoxRight);
994 SCALE_METRIC(glyphBoxBottom);
995 SCALE_METRIC(subscriptPositionX);
996 SCALE_METRIC(subscriptPositionY);
997 SCALE_METRIC(subscriptSizeX);
998 SCALE_METRIC(subscriptSizeY);
999 SCALE_METRIC(superscriptPositionX);
1000 SCALE_METRIC(superscriptPositionY);
1001 SCALE_METRIC(superscriptSizeX);
1002 SCALE_METRIC(superscriptSizeY);
1004 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
1005 #undef SCALE_METRIC
1007 return S_OK;
1010 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
1012 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1014 TRACE("%p, %p.\n", iface, metrics);
1016 *metrics = fontface->caret;
1019 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1020 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1022 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1024 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1026 *count = 0;
1027 if (max_count && !ranges)
1028 return E_INVALIDARG;
1030 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1031 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1034 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1036 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1038 TRACE("%p.\n", iface);
1040 return !!(fontface->flags & FONT_IS_MONOSPACED);
1043 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1044 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1046 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1047 BOOL has_contours;
1048 int advance;
1050 if (is_sideways)
1051 FIXME("Sideways mode is not supported.\n");
1053 switch (measuring_mode)
1055 case DWRITE_MEASURING_MODE_NATURAL:
1056 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1057 glyph, measuring_mode, &has_contours);
1058 if (has_contours)
1059 advance += adjustment;
1061 return advance;
1062 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1063 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1064 emsize *= ppdip;
1065 if (emsize == 0.0f)
1066 return 0.0f;
1068 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1069 FIXME("Transform is not supported.\n");
1071 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1072 &has_contours);
1073 if (has_contours)
1074 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1075 else
1076 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1078 return advance;
1079 default:
1080 WARN("Unknown measuring mode %u.\n", measuring_mode);
1081 return 0;
1085 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1086 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1088 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1089 unsigned int i;
1091 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1093 if (is_sideways)
1094 FIXME("sideways mode not supported\n");
1096 for (i = 0; i < glyph_count; ++i)
1098 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1099 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1102 return S_OK;
1105 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1106 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1107 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1109 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1110 DWRITE_MEASURING_MODE measuring_mode;
1111 UINT32 i;
1113 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1114 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1116 if (em_size < 0.0f || ppdip <= 0.0f) {
1117 memset(advances, 0, sizeof(*advances) * glyph_count);
1118 return E_INVALIDARG;
1121 if (em_size == 0.0f) {
1122 memset(advances, 0, sizeof(*advances) * glyph_count);
1123 return S_OK;
1126 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1127 for (i = 0; i < glyph_count; ++i)
1129 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1130 glyphs[i], is_sideways);
1133 return S_OK;
1136 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1137 const UINT16 *indices, INT32 *adjustments)
1139 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1140 UINT32 i;
1142 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1144 if (!(indices || adjustments) || !count)
1145 return E_INVALIDARG;
1147 if (!indices || count == 1) {
1148 memset(adjustments, 0, count*sizeof(INT32));
1149 return E_INVALIDARG;
1152 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1154 memset(adjustments, 0, count*sizeof(INT32));
1155 return S_OK;
1158 for (i = 0; i < count-1; i++)
1159 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1160 adjustments[count-1] = 0;
1162 return S_OK;
1165 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1167 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1169 TRACE("%p.\n", iface);
1171 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1174 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1175 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1176 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1178 DWRITE_GRID_FIT_MODE gridfitmode;
1179 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1180 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1183 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1184 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1186 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1188 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1190 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1193 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1195 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1197 TRACE("%p.\n", iface);
1199 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1202 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1204 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1206 TRACE("%p.\n", iface);
1208 return !!(fontface->flags & FONT_IS_COLORED);
1211 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1213 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1215 TRACE("%p.\n", iface);
1217 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1220 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1222 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1224 TRACE("%p.\n", iface);
1226 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1229 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1230 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1232 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1234 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1236 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1239 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1240 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1241 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1242 DWRITE_GRID_FIT_MODE *gridfitmode)
1244 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1245 unsigned int flags;
1246 FLOAT emthreshold;
1248 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1249 measuringmode, params, renderingmode, gridfitmode);
1251 if (m)
1252 FIXME("transform not supported %s\n", debugstr_matrix(m));
1254 if (is_sideways)
1255 FIXME("sideways mode not supported\n");
1257 emSize *= max(dpiX, dpiY) / 96.0f;
1259 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1260 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1261 if (params) {
1262 IDWriteRenderingParams2 *params2;
1263 HRESULT hr;
1265 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1266 if (hr == S_OK) {
1267 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1268 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1269 IDWriteRenderingParams2_Release(params2);
1271 else
1272 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1275 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1277 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1279 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1280 if (emSize >= emthreshold)
1281 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1282 else
1283 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1286 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1287 if (emSize >= emthreshold)
1288 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1289 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1290 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1291 else
1292 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1293 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1296 return S_OK;
1299 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1300 IDWriteFontFaceReference **reference)
1302 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1304 TRACE("%p, %p.\n", iface, reference);
1306 *reference = &fontface->IDWriteFontFaceReference_iface;
1307 IDWriteFontFaceReference_AddRef(*reference);
1309 return S_OK;
1312 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1314 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1316 TRACE("%p, %p.\n", iface, panose);
1318 *panose = fontface->panose;
1321 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1323 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1325 TRACE("%p.\n", iface);
1327 return fontface->weight;
1330 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1332 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1334 TRACE("%p.\n", iface);
1336 return fontface->stretch;
1339 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1341 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1343 TRACE("%p.\n", iface);
1345 return fontface->style;
1348 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1350 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1352 TRACE("%p, %p.\n", iface, names);
1354 return clone_localizedstrings(fontface->family_names, names);
1357 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1359 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1361 TRACE("%p, %p.\n", iface, names);
1363 return clone_localizedstrings(fontface->names, names);
1366 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1367 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1368 IDWriteLocalizedStrings **ret, BOOL *exists)
1370 HRESULT hr = S_OK;
1372 *exists = FALSE;
1373 *ret = NULL;
1375 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1376 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1378 return S_OK;
1381 if (!strings_cache[stringid])
1383 struct file_stream_desc desc = *stream_desc;
1385 if (!desc.stream)
1386 hr = get_filestream_from_file(file, &desc.stream);
1387 if (SUCCEEDED(hr))
1388 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1390 if (!stream_desc->stream && desc.stream)
1391 IDWriteFontFileStream_Release(desc.stream);
1394 if (SUCCEEDED(hr) && strings_cache[stringid])
1396 hr = clone_localizedstrings(strings_cache[stringid], ret);
1397 if (SUCCEEDED(hr))
1398 *exists = TRUE;
1401 return hr;
1404 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1405 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1407 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1408 struct file_stream_desc stream_desc;
1410 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1412 stream_desc.stream = fontface->stream;
1413 stream_desc.face_index = fontface->index;
1414 stream_desc.face_type = fontface->type;
1415 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1418 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1420 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1422 TRACE("%p, %#x.\n", iface, ch);
1424 return !!dwritefontface_get_glyph(fontface, ch);
1427 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1428 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1429 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1431 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1432 unsigned int flags;
1433 FLOAT emthreshold;
1435 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1436 measuring_mode, params, rendering_mode, gridfit_mode);
1438 if (m)
1439 FIXME("transform not supported %s\n", debugstr_matrix(m));
1441 if (is_sideways)
1442 FIXME("sideways mode not supported\n");
1444 emSize *= max(dpiX, dpiY) / 96.0f;
1446 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1447 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1448 if (params) {
1449 IDWriteRenderingParams3 *params3;
1450 HRESULT hr;
1452 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1453 if (hr == S_OK) {
1454 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1455 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1456 IDWriteRenderingParams3_Release(params3);
1458 else
1459 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1462 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1464 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1466 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1467 if (emSize >= emthreshold)
1468 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1469 else
1470 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1473 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1474 if (emSize >= emthreshold)
1475 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1476 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1477 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1478 else
1479 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1480 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1483 return S_OK;
1486 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1488 FIXME("%p, %#x: stub\n", iface, ch);
1490 return FALSE;
1493 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1495 FIXME("%p, %u: stub\n", iface, glyph);
1497 return FALSE;
1500 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1501 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1503 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1505 return E_NOTIMPL;
1508 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1509 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1511 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1513 return E_NOTIMPL;
1516 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1517 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1519 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1521 return E_NOTIMPL;
1524 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1526 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1528 TRACE("%p.\n", iface);
1530 return fontface->glyph_image_formats;
1533 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1534 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1536 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1538 return E_NOTIMPL;
1541 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1543 FIXME("%p, %p: stub\n", iface, context);
1546 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1548 FIXME("%p: stub\n", iface);
1550 return 0;
1553 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1554 UINT32 value_count)
1556 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1558 return E_NOTIMPL;
1561 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1563 static int once;
1565 if (!once++)
1566 FIXME("%p: stub\n", iface);
1568 return FALSE;
1571 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1573 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1575 TRACE("%p, %p.\n", iface, resource);
1577 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1580 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1582 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1584 TRACE("%p, %p.\n", iface, other);
1586 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1587 return FALSE;
1589 /* TODO: add variations support */
1591 return fontface->index == other_face->index &&
1592 fontface->simulations == other_face->simulations &&
1593 is_same_fontfile(fontface->files[0], other_face->files[0]);
1596 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1598 dwritefontface_QueryInterface,
1599 dwritefontface_AddRef,
1600 dwritefontface_Release,
1601 dwritefontface_GetType,
1602 dwritefontface_GetFiles,
1603 dwritefontface_GetIndex,
1604 dwritefontface_GetSimulations,
1605 dwritefontface_IsSymbolFont,
1606 dwritefontface_GetMetrics,
1607 dwritefontface_GetGlyphCount,
1608 dwritefontface_GetDesignGlyphMetrics,
1609 dwritefontface_GetGlyphIndices,
1610 dwritefontface_TryGetFontTable,
1611 dwritefontface_ReleaseFontTable,
1612 dwritefontface_GetGlyphRunOutline,
1613 dwritefontface_GetRecommendedRenderingMode,
1614 dwritefontface_GetGdiCompatibleMetrics,
1615 dwritefontface_GetGdiCompatibleGlyphMetrics,
1616 dwritefontface1_GetMetrics,
1617 dwritefontface1_GetGdiCompatibleMetrics,
1618 dwritefontface1_GetCaretMetrics,
1619 dwritefontface1_GetUnicodeRanges,
1620 dwritefontface1_IsMonospacedFont,
1621 dwritefontface1_GetDesignGlyphAdvances,
1622 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1623 dwritefontface1_GetKerningPairAdjustments,
1624 dwritefontface1_HasKerningPairs,
1625 dwritefontface1_GetRecommendedRenderingMode,
1626 dwritefontface1_GetVerticalGlyphVariants,
1627 dwritefontface1_HasVerticalGlyphVariants,
1628 dwritefontface2_IsColorFont,
1629 dwritefontface2_GetColorPaletteCount,
1630 dwritefontface2_GetPaletteEntryCount,
1631 dwritefontface2_GetPaletteEntries,
1632 dwritefontface2_GetRecommendedRenderingMode,
1633 dwritefontface3_GetFontFaceReference,
1634 dwritefontface3_GetPanose,
1635 dwritefontface3_GetWeight,
1636 dwritefontface3_GetStretch,
1637 dwritefontface3_GetStyle,
1638 dwritefontface3_GetFamilyNames,
1639 dwritefontface3_GetFaceNames,
1640 dwritefontface3_GetInformationalStrings,
1641 dwritefontface3_HasCharacter,
1642 dwritefontface3_GetRecommendedRenderingMode,
1643 dwritefontface3_IsCharacterLocal,
1644 dwritefontface3_IsGlyphLocal,
1645 dwritefontface3_AreCharactersLocal,
1646 dwritefontface3_AreGlyphsLocal,
1647 dwritefontface4_GetGlyphImageFormats_,
1648 dwritefontface4_GetGlyphImageFormats,
1649 dwritefontface4_GetGlyphImageData,
1650 dwritefontface4_ReleaseGlyphImageData,
1651 dwritefontface5_GetFontAxisValueCount,
1652 dwritefontface5_GetFontAxisValues,
1653 dwritefontface5_HasVariations,
1654 dwritefontface5_GetFontResource,
1655 dwritefontface5_Equals,
1658 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1660 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1661 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1664 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1666 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1667 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1670 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1672 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1673 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1676 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1677 IDWriteFontFace3 **ret)
1679 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1681 TRACE("%p, %p.\n", iface, ret);
1683 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1684 IDWriteFontFace3_AddRef(*ret);
1686 return S_OK;
1689 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1690 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1692 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1693 DWRITE_FONT_FILE_TYPE file_type;
1694 DWRITE_FONT_FACE_TYPE face_type;
1695 IDWriteFontFace *face;
1696 BOOL is_supported;
1697 UINT32 face_num;
1698 HRESULT hr;
1700 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1702 hr = IDWriteFontFile_Analyze(fontface->files[0], &is_supported, &file_type, &face_type, &face_num);
1703 if (FAILED(hr))
1704 return hr;
1706 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, fontface->files, fontface->index,
1707 simulations, &face);
1708 if (SUCCEEDED(hr))
1710 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1711 IDWriteFontFace_Release(face);
1714 return hr;
1717 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1719 FIXME("%p, %p.\n", iface, ref);
1721 return E_NOTIMPL;
1724 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1726 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1728 TRACE("%p.\n", iface);
1730 return fontface->index;
1733 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1735 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1737 TRACE("%p.\n", iface);
1739 return fontface->simulations;
1742 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1744 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1746 TRACE("%p, %p.\n", iface, file);
1748 *file = fontface->files[0];
1749 IDWriteFontFile_AddRef(*file);
1751 return S_OK;
1754 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1756 FIXME("%p.\n", iface);
1758 return 0;
1761 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1763 FIXME("%p.\n", iface);
1765 return 0;
1768 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1770 FIXME("%p, %p.\n", iface, writetime);
1772 return E_NOTIMPL;
1775 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1777 FIXME("%p.\n", iface);
1779 return DWRITE_LOCALITY_LOCAL;
1782 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1784 FIXME("%p.\n", iface);
1786 return E_NOTIMPL;
1789 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1790 WCHAR const *chars, UINT32 count)
1792 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1794 return E_NOTIMPL;
1797 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1798 UINT16 const *glyphs, UINT32 count)
1800 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1802 return E_NOTIMPL;
1805 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1806 UINT64 offset, UINT64 size)
1808 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1810 return E_NOTIMPL;
1813 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1815 dwritefontface_reference_QueryInterface,
1816 dwritefontface_reference_AddRef,
1817 dwritefontface_reference_Release,
1818 dwritefontface_reference_CreateFontFace,
1819 dwritefontface_reference_CreateFontFaceWithSimulations,
1820 dwritefontface_reference_Equals,
1821 dwritefontface_reference_GetFontFaceIndex,
1822 dwritefontface_reference_GetSimulations,
1823 dwritefontface_reference_GetFontFile,
1824 dwritefontface_reference_GetLocalFileSize,
1825 dwritefontface_reference_GetFileSize,
1826 dwritefontface_reference_GetFileTime,
1827 dwritefontface_reference_GetLocality,
1828 dwritefontface_reference_EnqueueFontDownloadRequest,
1829 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1830 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1831 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1834 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1836 struct dwrite_font_data *data = font->data;
1837 struct fontface_desc desc;
1838 struct list *cached_list;
1839 HRESULT hr;
1841 *fontface = NULL;
1843 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1844 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1845 if (hr == S_OK)
1846 return hr;
1848 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1849 return hr;
1851 desc.factory = font->family->collection->factory;
1852 desc.face_type = data->face_type;
1853 desc.files = &data->file;
1854 desc.files_number = 1;
1855 desc.index = data->face_index;
1856 desc.simulations = data->simulations;
1857 desc.font_data = data;
1858 hr = create_fontface(&desc, cached_list, fontface);
1860 IDWriteFontFileStream_Release(desc.stream);
1861 return hr;
1864 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1866 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1868 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1869 IsEqualIID(riid, &IID_IDWriteFont2) ||
1870 IsEqualIID(riid, &IID_IDWriteFont1) ||
1871 IsEqualIID(riid, &IID_IDWriteFont) ||
1872 IsEqualIID(riid, &IID_IUnknown))
1874 *obj = iface;
1875 IDWriteFont3_AddRef(iface);
1876 return S_OK;
1879 WARN("%s not implemented.\n", debugstr_guid(riid));
1881 *obj = NULL;
1882 return E_NOINTERFACE;
1885 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1887 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1888 ULONG refcount = InterlockedIncrement(&font->refcount);
1890 TRACE("%p, refcount %d.\n", iface, refcount);
1892 return refcount;
1895 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1897 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1898 ULONG refcount = InterlockedDecrement(&font->refcount);
1900 TRACE("%p, refcount %d.\n", iface, refcount);
1902 if (!refcount)
1904 IDWriteFontFamily2_Release(&font->family->IDWriteFontFamily2_iface);
1905 release_font_data(font->data);
1906 heap_free(font);
1909 return refcount;
1912 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1914 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1916 TRACE("%p, %p.\n", iface, family);
1918 *family = (IDWriteFontFamily *)font->family;
1919 IDWriteFontFamily_AddRef(*family);
1920 return S_OK;
1923 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1925 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1927 TRACE("%p.\n", iface);
1929 return font->data->weight;
1932 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1934 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1936 TRACE("%p.\n", iface);
1938 return font->data->stretch;
1941 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1943 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1945 TRACE("%p.\n", iface);
1947 return font->style;
1950 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1952 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1954 TRACE("%p.\n", iface);
1956 return !!(font->data->flags & FONT_IS_SYMBOL);
1959 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1961 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1963 TRACE("%p, %p.\n", iface, names);
1965 return clone_localizedstrings(font->data->names, names);
1968 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1969 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1971 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1972 struct dwrite_font_data *data = font->data;
1973 struct file_stream_desc stream_desc;
1975 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1977 /* Stream will be created if necessary. */
1978 stream_desc.stream = NULL;
1979 stream_desc.face_index = data->face_index;
1980 stream_desc.face_type = data->face_type;
1981 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1984 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1986 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1988 TRACE("%p.\n", iface);
1990 return font->data->simulations;
1993 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1995 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1997 TRACE("%p, %p.\n", iface, metrics);
1999 memcpy(metrics, &font->data->metrics, sizeof(*metrics));
2002 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
2004 UINT16 glyph;
2005 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2006 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
2007 return glyph != 0;
2010 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
2012 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2014 TRACE("%p, %#x, %p.\n", iface, ch, exists);
2016 *exists = dwritefont_has_character(font, ch);
2018 return S_OK;
2021 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
2023 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2025 TRACE("%p, %p.\n", iface, fontface);
2027 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2030 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2032 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2034 TRACE("%p, %p.\n", iface, metrics);
2036 *metrics = font->data->metrics;
2039 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2041 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2043 TRACE("%p, %p.\n", iface, panose);
2045 *panose = font->data->panose;
2048 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2049 UINT32 *count)
2051 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2053 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2055 *count = 0;
2056 if (max_count && !ranges)
2057 return E_INVALIDARG;
2059 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2060 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2063 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2065 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2067 TRACE("%p.\n", iface);
2069 return !!(font->data->flags & FONT_IS_MONOSPACED);
2072 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2074 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2076 TRACE("%p.\n", iface);
2078 return !!(font->data->flags & FONT_IS_COLORED);
2081 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2083 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2085 TRACE("%p, %p.\n", iface, fontface);
2087 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2090 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2092 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2094 TRACE("%p, %p.\n", iface, other);
2096 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2097 return FALSE;
2099 return font->data->face_index == other_font->data->face_index
2100 && font->data->simulations == other_font->data->simulations
2101 && is_same_fontfile(font->data->file, other_font->data->file);
2104 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2106 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2108 TRACE("%p, %p.\n", iface, reference);
2110 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2111 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2112 (IDWriteFontFaceReference1 **)reference);
2115 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2117 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2119 TRACE("%p, %#x.\n", iface, ch);
2121 return dwritefont_has_character(font, ch);
2124 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2126 FIXME("%p: stub.\n", iface);
2128 return DWRITE_LOCALITY_LOCAL;
2131 static const IDWriteFont3Vtbl dwritefontvtbl = {
2132 dwritefont_QueryInterface,
2133 dwritefont_AddRef,
2134 dwritefont_Release,
2135 dwritefont_GetFontFamily,
2136 dwritefont_GetWeight,
2137 dwritefont_GetStretch,
2138 dwritefont_GetStyle,
2139 dwritefont_IsSymbolFont,
2140 dwritefont_GetFaceNames,
2141 dwritefont_GetInformationalStrings,
2142 dwritefont_GetSimulations,
2143 dwritefont_GetMetrics,
2144 dwritefont_HasCharacter,
2145 dwritefont_CreateFontFace,
2146 dwritefont1_GetMetrics,
2147 dwritefont1_GetPanose,
2148 dwritefont1_GetUnicodeRanges,
2149 dwritefont1_IsMonospacedFont,
2150 dwritefont2_IsColorFont,
2151 dwritefont3_CreateFontFace,
2152 dwritefont3_Equals,
2153 dwritefont3_GetFontFaceReference,
2154 dwritefont3_HasCharacter,
2155 dwritefont3_GetLocality
2158 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2160 if (!iface)
2161 return NULL;
2162 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2163 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2166 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2168 if (!iface)
2169 return NULL;
2170 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2171 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2174 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2176 if (!iface)
2177 return NULL;
2178 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2179 return NULL;
2180 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2181 IDWriteFontFaceReference1_iface);
2184 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2186 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2187 *lf = font->data->lf;
2190 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2192 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2193 *lf = fontface->lf;
2196 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2198 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2199 *fontsig = font->data->fontsig;
2200 return S_OK;
2203 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2205 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2206 *fontsig = fontface->fontsig;
2207 return S_OK;
2210 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2212 struct dwrite_font *object;
2214 *font = NULL;
2216 if (!(object = heap_alloc(sizeof(*object))))
2217 return E_OUTOFMEMORY;
2219 object->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2220 object->refcount = 1;
2221 object->family = family;
2222 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2223 object->data = family->data->fonts[index];
2224 object->style = object->data->style;
2225 addref_font_data(object->data);
2227 *font = &object->IDWriteFont3_iface;
2229 return S_OK;
2232 /* IDWriteFontList2 */
2233 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2235 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2237 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2238 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2239 IsEqualIID(riid, &IID_IDWriteFontList) ||
2240 IsEqualIID(riid, &IID_IUnknown))
2242 *obj = iface;
2243 IDWriteFontList2_AddRef(iface);
2244 return S_OK;
2247 WARN("%s not implemented.\n", debugstr_guid(riid));
2249 *obj = NULL;
2250 return E_NOINTERFACE;
2253 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2255 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2256 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2258 TRACE("%p, refcount %u.\n", iface, refcount);
2260 return refcount;
2263 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2265 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2266 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2268 TRACE("%p, refcount %u.\n", iface, refcount);
2270 if (!refcount)
2272 UINT32 i;
2274 for (i = 0; i < fontlist->font_count; i++)
2275 release_font_data(fontlist->fonts[i]);
2276 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2277 heap_free(fontlist->fonts);
2278 heap_free(fontlist);
2281 return refcount;
2284 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2286 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2287 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2290 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2292 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2294 TRACE("%p.\n", iface);
2296 return fontlist->font_count;
2299 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2301 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2303 TRACE("%p, %u, %p.\n", iface, index, font);
2305 *font = NULL;
2307 if (fontlist->font_count == 0)
2308 return S_FALSE;
2310 if (index >= fontlist->font_count)
2311 return E_INVALIDARG;
2313 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2316 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2318 FIXME("%p, %u.\n", iface, index);
2320 return DWRITE_LOCALITY_LOCAL;
2323 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2325 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2327 TRACE("%p, %u, %p.\n", iface, index, font);
2329 *font = NULL;
2331 if (fontlist->font_count == 0)
2332 return S_FALSE;
2334 if (index >= fontlist->font_count)
2335 return E_FAIL;
2337 return create_font(fontlist->family, index, font);
2340 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2341 IDWriteFontFaceReference **reference)
2343 IDWriteFont3 *font;
2344 HRESULT hr;
2346 TRACE("%p, %u, %p.\n", iface, index, reference);
2348 *reference = NULL;
2350 hr = IDWriteFontList2_GetFont(iface, index, &font);
2351 if (FAILED(hr))
2352 return hr;
2354 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2355 IDWriteFont3_Release(font);
2357 return hr;
2360 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2362 FIXME("%p, %p.\n", iface, fontset);
2364 return E_NOTIMPL;
2367 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2369 dwritefontlist_QueryInterface,
2370 dwritefontlist_AddRef,
2371 dwritefontlist_Release,
2372 dwritefontlist_GetFontCollection,
2373 dwritefontlist_GetFontCount,
2374 dwritefontlist_GetFont,
2375 dwritefontlist1_GetFontLocality,
2376 dwritefontlist1_GetFont,
2377 dwritefontlist1_GetFontFaceReference,
2378 dwritefontlist2_GetFontSet,
2381 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2383 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2385 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2387 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2388 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2389 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2390 IsEqualIID(riid, &IID_IUnknown))
2392 *obj = iface;
2394 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2395 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2396 IsEqualIID(riid, &IID_IDWriteFontList))
2398 *obj = &family->IDWriteFontList2_iface;
2400 else
2402 WARN("%s not implemented.\n", debugstr_guid(riid));
2403 *obj = NULL;
2404 return E_NOINTERFACE;
2407 IUnknown_AddRef((IUnknown *)*obj);
2408 return S_OK;
2411 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2413 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2414 ULONG refcount = InterlockedIncrement(&family->refcount);
2416 TRACE("%p, %u.\n", iface, refcount);
2418 return refcount;
2421 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2423 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2424 ULONG refcount = InterlockedDecrement(&family->refcount);
2426 TRACE("%p, %u.\n", iface, refcount);
2428 if (!refcount)
2430 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2431 release_fontfamily_data(family->data);
2432 heap_free(family);
2435 return refcount;
2438 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2440 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2442 TRACE("%p, %p.\n", iface, collection);
2444 *collection = (IDWriteFontCollection *)family->collection;
2445 IDWriteFontCollection_AddRef(*collection);
2446 return S_OK;
2449 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2451 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2453 TRACE("%p.\n", iface);
2455 return family->data->count;
2458 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2460 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2462 TRACE("%p, %u, %p.\n", iface, index, font);
2464 *font = NULL;
2466 if (!family->data->count)
2467 return S_FALSE;
2469 if (index >= family->data->count)
2470 return E_INVALIDARG;
2472 return create_font(family, index, (IDWriteFont3 **)font);
2475 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2477 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2479 TRACE("%p, %p.\n", iface, names);
2481 return clone_localizedstrings(family->data->familyname, names);
2484 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2485 const struct dwrite_font_propvec *req)
2487 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2488 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2489 FLOAT cur_req_prod, next_req_prod;
2491 if (next_to_req < cur_to_req)
2492 return TRUE;
2494 if (next_to_req > cur_to_req)
2495 return FALSE;
2497 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2498 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2500 if (next_req_prod > cur_req_prod)
2501 return TRUE;
2503 if (next_req_prod < cur_req_prod)
2504 return FALSE;
2506 if (next->stretch > cur->stretch)
2507 return TRUE;
2508 if (next->stretch < cur->stretch)
2509 return FALSE;
2511 if (next->style > cur->style)
2512 return TRUE;
2513 if (next->style < cur->style)
2514 return FALSE;
2516 if (next->weight > cur->weight)
2517 return TRUE;
2518 if (next->weight < cur->weight)
2519 return FALSE;
2521 /* full match, no reason to prefer new variant */
2522 return FALSE;
2525 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2526 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2528 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2529 struct dwrite_font_propvec req;
2530 size_t i, match;
2532 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2534 if (!family->data->count)
2536 *font = NULL;
2537 return DWRITE_E_NOFONT;
2540 init_font_prop_vec(weight, stretch, style, &req);
2541 match = 0;
2543 for (i = 1; i < family->data->count; ++i)
2545 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2546 match = i;
2549 return create_font(family, match, (IDWriteFont3 **)font);
2552 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2554 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2556 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2559 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2561 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2564 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2566 UINT32 b = fonts->font_count - 1, j, t;
2568 while (1) {
2569 t = b;
2571 for (j = 0; j < b; j++) {
2572 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2573 struct dwrite_font_data *s = fonts->fonts[j];
2574 fonts->fonts[j] = fonts->fonts[j+1];
2575 fonts->fonts[j+1] = s;
2576 t = j;
2580 if (t == b)
2581 break;
2582 b = t;
2586 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2587 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2589 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2590 matching_filter_func func = NULL;
2591 struct dwrite_font_propvec req;
2592 struct dwrite_fontlist *fonts;
2593 size_t i;
2595 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2597 *ret = NULL;
2599 fonts = heap_alloc(sizeof(*fonts));
2600 if (!fonts)
2601 return E_OUTOFMEMORY;
2603 /* Allocate as many as family has, not all of them will be necessary used. */
2604 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2605 if (!fonts->fonts) {
2606 heap_free(fonts);
2607 return E_OUTOFMEMORY;
2610 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2611 fonts->refcount = 1;
2612 fonts->family = family;
2613 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2614 fonts->font_count = 0;
2616 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2617 if (style == DWRITE_FONT_STYLE_NORMAL) {
2618 if (family->data->has_normal_face || family->data->has_italic_face)
2619 func = is_font_acceptable_for_normal;
2621 else /* requested oblique or italic */ {
2622 if (family->data->has_oblique_face || family->data->has_italic_face)
2623 func = is_font_acceptable_for_oblique_italic;
2626 for (i = 0; i < family->data->count; ++i)
2628 if (!func || func(family->data->fonts[i]))
2630 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2631 addref_font_data(family->data->fonts[i]);
2632 fonts->font_count++;
2636 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2637 init_font_prop_vec(weight, stretch, style, &req);
2638 matchingfonts_sort(fonts, &req);
2640 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2641 return S_OK;
2644 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2646 FIXME("%p, %u.\n", iface, index);
2648 return DWRITE_LOCALITY_LOCAL;
2651 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2653 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2655 TRACE("%p, %u, %p.\n", iface, index, font);
2657 *font = NULL;
2659 if (!family->data->count)
2660 return S_FALSE;
2662 if (index >= family->data->count)
2663 return E_FAIL;
2665 return create_font(family, index, font);
2668 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2669 IDWriteFontFaceReference **reference)
2671 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2672 const struct dwrite_font_data *font;
2674 TRACE("%p, %u, %p.\n", iface, index, reference);
2676 *reference = NULL;
2678 if (index >= family->data->count)
2679 return E_FAIL;
2681 font = family->data->fonts[index];
2682 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2683 font->file, font->face_index, font->simulations, reference);
2686 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2687 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2689 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2691 return E_NOTIMPL;
2694 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2696 FIXME("%p, %p.\n", iface, fontset);
2698 return E_NOTIMPL;
2701 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2703 dwritefontfamily_QueryInterface,
2704 dwritefontfamily_AddRef,
2705 dwritefontfamily_Release,
2706 dwritefontfamily_GetFontCollection,
2707 dwritefontfamily_GetFontCount,
2708 dwritefontfamily_GetFont,
2709 dwritefontfamily_GetFamilyNames,
2710 dwritefontfamily_GetFirstMatchingFont,
2711 dwritefontfamily_GetMatchingFonts,
2712 dwritefontfamily1_GetFontLocality,
2713 dwritefontfamily1_GetFont,
2714 dwritefontfamily1_GetFontFaceReference,
2715 dwritefontfamily2_GetMatchingFonts,
2716 dwritefontfamily2_GetFontSet,
2719 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2721 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2722 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2725 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2727 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2728 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2731 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2733 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2734 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2737 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2738 IDWriteFontCollection **collection)
2740 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2741 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2744 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2746 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2747 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2750 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2752 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2753 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2756 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2758 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2759 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2762 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2764 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2765 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2768 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2769 IDWriteFontFaceReference **reference)
2771 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2772 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2775 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2777 FIXME("%p, %p.\n", iface, fontset);
2779 return E_NOTIMPL;
2782 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2784 dwritefontfamilylist_QueryInterface,
2785 dwritefontfamilylist_AddRef,
2786 dwritefontfamilylist_Release,
2787 dwritefontfamilylist_GetFontCollection,
2788 dwritefontfamilylist_GetFontCount,
2789 dwritefontfamilylist_GetFont,
2790 dwritefontfamilylist1_GetFontLocality,
2791 dwritefontfamilylist1_GetFont,
2792 dwritefontfamilylist1_GetFontFaceReference,
2793 dwritefontfamilylist2_GetFontSet,
2796 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2797 struct dwrite_fontfamily **family)
2799 struct dwrite_fontfamily *object;
2801 *family = NULL;
2803 object = heap_alloc(sizeof(*object));
2804 if (!object)
2805 return E_OUTOFMEMORY;
2807 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2808 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2809 object->refcount = 1;
2810 object->collection = collection;
2811 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2812 object->data = collection->family_data[index];
2813 InterlockedIncrement(&object->data->refcount);
2815 *family = object;
2817 return S_OK;
2820 BOOL is_system_collection(IDWriteFontCollection *collection)
2822 void *obj;
2823 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2826 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2828 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2830 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2832 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2833 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2834 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2835 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2836 IsEqualIID(riid, &IID_IUnknown))
2838 *obj = iface;
2839 IDWriteFontCollection3_AddRef(iface);
2840 return S_OK;
2843 *obj = NULL;
2845 if (IsEqualIID(riid, &IID_issystemcollection))
2846 return S_OK;
2848 WARN("%s not implemented.\n", debugstr_guid(riid));
2850 return E_NOINTERFACE;
2853 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2855 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2857 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2858 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2859 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2860 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2861 IsEqualIID(riid, &IID_IUnknown))
2863 *obj = iface;
2864 IDWriteFontCollection3_AddRef(iface);
2865 return S_OK;
2868 WARN("%s not implemented.\n", debugstr_guid(riid));
2870 *obj = NULL;
2872 return E_NOINTERFACE;
2875 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2877 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2878 ULONG refcount = InterlockedIncrement(&collection->refcount);
2880 TRACE("%p, refcount %d.\n", collection, refcount);
2882 return refcount;
2885 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2887 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2888 ULONG refcount = InterlockedDecrement(&collection->refcount);
2889 size_t i;
2891 TRACE("%p, refcount %d.\n", iface, refcount);
2893 if (!refcount)
2895 factory_detach_fontcollection(collection->factory, iface);
2896 for (i = 0; i < collection->count; ++i)
2897 release_fontfamily_data(collection->family_data[i]);
2898 heap_free(collection->family_data);
2899 heap_free(collection);
2902 return refcount;
2905 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2907 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2909 TRACE("%p.\n", iface);
2911 return collection->count;
2914 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2915 IDWriteFontFamily **ret)
2917 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2918 struct dwrite_fontfamily *family;
2919 HRESULT hr;
2921 TRACE("%p, %u, %p.\n", iface, index, ret);
2923 *ret = NULL;
2925 if (index >= collection->count)
2926 return E_FAIL;
2928 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2929 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2931 return hr;
2934 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2936 size_t i;
2938 for (i = 0; i < collection->count; ++i)
2940 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2941 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2942 HRESULT hr;
2944 for (j = 0; j < count; j++) {
2945 WCHAR buffer[255];
2946 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2947 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2948 return i;
2952 return ~0u;
2955 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2956 UINT32 *index, BOOL *exists)
2958 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2960 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2962 *index = collection_find_family(collection, name);
2963 *exists = *index != ~0u;
2964 return S_OK;
2967 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2968 IDWriteFont **font)
2970 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2971 struct dwrite_fontfamily *family;
2972 BOOL found_font = FALSE;
2973 IDWriteFontFile *file;
2974 UINT32 face_index, count;
2975 size_t i, j;
2976 HRESULT hr;
2978 TRACE("%p, %p, %p.\n", iface, face, font);
2980 *font = NULL;
2982 if (!face)
2983 return E_INVALIDARG;
2985 count = 1;
2986 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2987 if (FAILED(hr))
2988 return hr;
2989 face_index = IDWriteFontFace_GetIndex(face);
2991 found_font = FALSE;
2992 for (i = 0; i < collection->count; ++i)
2994 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2996 for (j = 0; j < family_data->count; ++j)
2998 struct dwrite_font_data *font_data = family_data->fonts[j];
3000 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
3001 found_font = TRUE;
3002 break;
3006 if (found_font)
3007 break;
3009 IDWriteFontFile_Release(file);
3011 if (!found_font)
3012 return DWRITE_E_NOFONT;
3014 hr = create_fontfamily(collection, i, &family);
3015 if (FAILED(hr))
3016 return hr;
3018 hr = create_font(family, j, (IDWriteFont3 **)font);
3019 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
3020 return hr;
3023 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
3025 FIXME("%p, %p.\n", iface, fontset);
3027 return E_NOTIMPL;
3030 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3031 IDWriteFontFamily1 **ret)
3033 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3034 struct dwrite_fontfamily *family;
3035 HRESULT hr;
3037 TRACE("%p, %u, %p.\n", iface, index, ret);
3039 *ret = NULL;
3041 if (index >= collection->count)
3042 return E_FAIL;
3044 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3045 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3047 return hr;
3050 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3051 UINT32 index, IDWriteFontFamily2 **ret)
3053 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3054 struct dwrite_fontfamily *family;
3055 HRESULT hr;
3057 TRACE("%p, %u, %p.\n", iface, index, ret);
3059 *ret = NULL;
3061 if (index >= collection->count)
3062 return E_FAIL;
3064 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3065 *ret = &family->IDWriteFontFamily2_iface;
3067 return hr;
3070 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3071 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3072 IDWriteFontList2 **fontlist)
3074 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3076 return E_NOTIMPL;
3079 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3081 FIXME("%p.\n", iface);
3083 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3086 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3088 FIXME("%p, %p.\n", iface, fontset);
3090 return E_NOTIMPL;
3093 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3095 FIXME("%p.\n", iface);
3097 return NULL;
3100 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3102 dwritefontcollection_QueryInterface,
3103 dwritefontcollection_AddRef,
3104 dwritefontcollection_Release,
3105 dwritefontcollection_GetFontFamilyCount,
3106 dwritefontcollection_GetFontFamily,
3107 dwritefontcollection_FindFamilyName,
3108 dwritefontcollection_GetFontFromFontFace,
3109 dwritefontcollection1_GetFontSet,
3110 dwritefontcollection1_GetFontFamily,
3111 dwritefontcollection2_GetFontFamily,
3112 dwritefontcollection2_GetMatchingFonts,
3113 dwritefontcollection2_GetFontFamilyModel,
3114 dwritefontcollection2_GetFontSet,
3115 dwritefontcollection3_GetExpirationEvent,
3118 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3120 dwritesystemfontcollection_QueryInterface,
3121 dwritefontcollection_AddRef,
3122 dwritefontcollection_Release,
3123 dwritefontcollection_GetFontFamilyCount,
3124 dwritefontcollection_GetFontFamily,
3125 dwritefontcollection_FindFamilyName,
3126 dwritefontcollection_GetFontFromFontFace,
3127 dwritefontcollection1_GetFontSet,
3128 dwritefontcollection1_GetFontFamily,
3129 dwritefontcollection2_GetFontFamily,
3130 dwritefontcollection2_GetMatchingFonts,
3131 dwritefontcollection2_GetFontFamilyModel,
3132 dwritefontcollection2_GetFontSet,
3133 dwritefontcollection3_GetExpirationEvent,
3136 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3138 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3139 sizeof(*family_data->fonts)))
3141 return E_OUTOFMEMORY;
3144 family_data->fonts[family_data->count++] = font_data;
3145 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3146 family_data->has_normal_face = 1;
3147 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3148 family_data->has_oblique_face = 1;
3149 else
3150 family_data->has_italic_face = 1;
3151 return S_OK;
3154 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3155 struct dwrite_fontfamily_data *family)
3157 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3158 sizeof(*collection->family_data)))
3160 return E_OUTOFMEMORY;
3163 collection->family_data[collection->count++] = family;
3164 return S_OK;
3167 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3169 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3170 collection->refcount = 1;
3171 collection->count = 0;
3172 collection->size = 0;
3173 collection->family_data = NULL;
3175 return S_OK;
3178 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3180 IDWriteFontFileLoader *loader;
3181 const void *key;
3182 UINT32 key_size;
3183 HRESULT hr;
3185 *stream = NULL;
3187 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3188 if (FAILED(hr))
3189 return hr;
3191 hr = IDWriteFontFile_GetLoader(file, &loader);
3192 if (FAILED(hr))
3193 return hr;
3195 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3196 IDWriteFontFileLoader_Release(loader);
3197 if (FAILED(hr))
3198 return hr;
3200 return hr;
3203 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3205 BOOL exists = FALSE;
3206 UINT32 index;
3207 HRESULT hr;
3209 buffer[0] = 0;
3210 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3211 if (FAILED(hr) || !exists)
3212 return;
3214 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3217 static int trim_spaces(WCHAR *in, WCHAR *ret)
3219 int len;
3221 while (isspaceW(*in))
3222 in++;
3224 ret[0] = 0;
3225 if (!(len = strlenW(in)))
3226 return 0;
3228 while (isspaceW(in[len-1]))
3229 len--;
3231 memcpy(ret, in, len*sizeof(WCHAR));
3232 ret[len] = 0;
3234 return len;
3237 struct name_token {
3238 struct list entry;
3239 const WCHAR *ptr;
3240 INT len; /* token length */
3241 INT fulllen; /* full length including following separators */
3244 static inline BOOL is_name_separator_char(WCHAR ch)
3246 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3249 struct name_pattern {
3250 const WCHAR *part1; /* NULL indicates end of list */
3251 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3254 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3256 const struct name_pattern *pattern;
3257 struct name_token *token;
3258 int i = 0;
3260 while ((pattern = &patterns[i++])->part1) {
3261 int len_part1 = strlenW(pattern->part1);
3262 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3264 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3265 if (len_part2 == 0) {
3266 /* simple case with single part pattern */
3267 if (token->len != len_part1)
3268 continue;
3270 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3271 if (match) *match = *token;
3272 list_remove(&token->entry);
3273 heap_free(token);
3274 return TRUE;
3277 else {
3278 struct name_token *next_token;
3279 struct list *next_entry;
3281 /* pattern parts are stored in reading order, tokens list is reversed */
3282 if (token->len < len_part2)
3283 continue;
3285 /* it's possible to have combined string as a token, like ExtraCondensed */
3286 if (token->len == len_part1 + len_part2) {
3287 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3288 continue;
3290 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3291 continue;
3293 /* combined string match */
3294 if (match) *match = *token;
3295 list_remove(&token->entry);
3296 heap_free(token);
3297 return TRUE;
3300 /* now it's only possible to have two tokens matched to respective pattern parts */
3301 if (token->len != len_part2)
3302 continue;
3304 next_entry = list_next(tokens, &token->entry);
3305 if (next_entry) {
3306 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3307 if (next_token->len != len_part1)
3308 continue;
3310 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3311 continue;
3313 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3314 continue;
3316 /* both parts matched, remove tokens */
3317 if (match) {
3318 match->ptr = next_token->ptr;
3319 match->len = (token->ptr - next_token->ptr) + token->len;
3321 list_remove(&token->entry);
3322 list_remove(&next_token->entry);
3323 heap_free(next_token);
3324 heap_free(token);
3325 return TRUE;
3331 if (match) {
3332 match->ptr = NULL;
3333 match->len = 0;
3335 return FALSE;
3338 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3340 static const WCHAR itaW[] = {'i','t','a',0};
3341 static const WCHAR italW[] = {'i','t','a','l',0};
3342 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3343 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3345 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3346 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3347 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3348 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3350 static const struct name_pattern italic_patterns[] = {
3351 { itaW },
3352 { italW },
3353 { italicW },
3354 { cursiveW },
3355 { kursivW },
3356 { NULL }
3359 static const struct name_pattern oblique_patterns[] = {
3360 { inclinedW },
3361 { obliqueW },
3362 { backslantedW },
3363 { backslantW },
3364 { slantedW },
3365 { NULL }
3368 /* italic patterns first */
3369 if (match_pattern_list(tokens, italic_patterns, match))
3370 return DWRITE_FONT_STYLE_ITALIC;
3372 /* oblique patterns */
3373 if (match_pattern_list(tokens, oblique_patterns, match))
3374 return DWRITE_FONT_STYLE_OBLIQUE;
3376 return style;
3379 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3380 struct name_token *match)
3382 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3383 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3384 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3385 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3386 static const WCHAR wideW[] = {'w','i','d','e',0};
3387 static const WCHAR condW[] = {'c','o','n','d',0};
3389 static const struct name_pattern ultracondensed_patterns[] = {
3390 { extraW, compressedW },
3391 { extW, compressedW },
3392 { ultraW, compressedW },
3393 { ultraW, condensedW },
3394 { ultraW, condW },
3395 { NULL }
3398 static const struct name_pattern extracondensed_patterns[] = {
3399 { compressedW },
3400 { extraW, condensedW },
3401 { extW, condensedW },
3402 { extraW, condW },
3403 { extW, condW },
3404 { NULL }
3407 static const struct name_pattern semicondensed_patterns[] = {
3408 { narrowW },
3409 { compactW },
3410 { semiW, condensedW },
3411 { semiW, condW },
3412 { NULL }
3415 static const struct name_pattern semiexpanded_patterns[] = {
3416 { wideW },
3417 { semiW, expandedW },
3418 { semiW, extendedW },
3419 { NULL }
3422 static const struct name_pattern extraexpanded_patterns[] = {
3423 { extraW, expandedW },
3424 { extW, expandedW },
3425 { extraW, extendedW },
3426 { extW, extendedW },
3427 { NULL }
3430 static const struct name_pattern ultraexpanded_patterns[] = {
3431 { ultraW, expandedW },
3432 { ultraW, extendedW },
3433 { NULL }
3436 static const struct name_pattern condensed_patterns[] = {
3437 { condensedW },
3438 { condW },
3439 { NULL }
3442 static const struct name_pattern expanded_patterns[] = {
3443 { expandedW },
3444 { extendedW },
3445 { NULL }
3448 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3449 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3451 if (match_pattern_list(tokens, extracondensed_patterns, match))
3452 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3454 if (match_pattern_list(tokens, semicondensed_patterns, match))
3455 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3457 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3458 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3460 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3461 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3463 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3464 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3466 if (match_pattern_list(tokens, condensed_patterns, match))
3467 return DWRITE_FONT_STRETCH_CONDENSED;
3469 if (match_pattern_list(tokens, expanded_patterns, match))
3470 return DWRITE_FONT_STRETCH_EXPANDED;
3472 return stretch;
3475 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3476 struct name_token *match)
3478 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3479 static const WCHAR nordW[] = {'n','o','r','d',0};
3481 static const struct name_pattern thin_patterns[] = {
3482 { extraW, thinW },
3483 { extW, thinW },
3484 { ultraW, thinW },
3485 { NULL }
3488 static const struct name_pattern extralight_patterns[] = {
3489 { extraW, lightW },
3490 { extW, lightW },
3491 { ultraW, lightW },
3492 { NULL }
3495 static const struct name_pattern semilight_patterns[] = {
3496 { semiW, lightW },
3497 { NULL }
3500 static const struct name_pattern demibold_patterns[] = {
3501 { semiW, boldW },
3502 { demiW, boldW },
3503 { NULL }
3506 static const struct name_pattern extrabold_patterns[] = {
3507 { extraW, boldW },
3508 { extW, boldW },
3509 { ultraW, boldW },
3510 { NULL }
3513 static const struct name_pattern extrablack_patterns[] = {
3514 { extraW, blackW },
3515 { extW, blackW },
3516 { ultraW, blackW },
3517 { NULL }
3520 static const struct name_pattern bold_patterns[] = {
3521 { boldW },
3522 { NULL }
3525 static const struct name_pattern thin2_patterns[] = {
3526 { thinW },
3527 { NULL }
3530 static const struct name_pattern light_patterns[] = {
3531 { lightW },
3532 { NULL }
3535 static const struct name_pattern medium_patterns[] = {
3536 { mediumW },
3537 { NULL }
3540 static const struct name_pattern black_patterns[] = {
3541 { blackW },
3542 { heavyW },
3543 { nordW },
3544 { NULL }
3547 static const struct name_pattern demibold2_patterns[] = {
3548 { demiW },
3549 { NULL }
3552 static const struct name_pattern extrabold2_patterns[] = {
3553 { ultraW },
3554 { NULL }
3557 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3558 matching pattern. */
3560 if (match_pattern_list(tokens, thin_patterns, match))
3561 return DWRITE_FONT_WEIGHT_THIN;
3563 if (match_pattern_list(tokens, extralight_patterns, match))
3564 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3566 if (match_pattern_list(tokens, semilight_patterns, match))
3567 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3569 if (match_pattern_list(tokens, demibold_patterns, match))
3570 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3572 if (match_pattern_list(tokens, extrabold_patterns, match))
3573 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3575 if (match_pattern_list(tokens, extrablack_patterns, match))
3576 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3578 if (match_pattern_list(tokens, bold_patterns, match))
3579 return DWRITE_FONT_WEIGHT_BOLD;
3581 if (match_pattern_list(tokens, thin2_patterns, match))
3582 return DWRITE_FONT_WEIGHT_THIN;
3584 if (match_pattern_list(tokens, light_patterns, match))
3585 return DWRITE_FONT_WEIGHT_LIGHT;
3587 if (match_pattern_list(tokens, medium_patterns, match))
3588 return DWRITE_FONT_WEIGHT_MEDIUM;
3590 if (match_pattern_list(tokens, black_patterns, match))
3591 return DWRITE_FONT_WEIGHT_BLACK;
3593 if (match_pattern_list(tokens, black_patterns, match))
3594 return DWRITE_FONT_WEIGHT_BLACK;
3596 if (match_pattern_list(tokens, demibold2_patterns, match))
3597 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3599 if (match_pattern_list(tokens, extrabold2_patterns, match))
3600 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3602 /* FIXME: use abbreviated names to extract weight */
3604 return weight;
3607 struct knownweight_entry {
3608 const WCHAR *nameW;
3609 DWRITE_FONT_WEIGHT weight;
3612 static int compare_knownweights(const void *a, const void* b)
3614 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3615 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3616 int ret = 0;
3618 if (target > entry->weight)
3619 ret = 1;
3620 else if (target < entry->weight)
3621 ret = -1;
3623 return ret;
3626 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3628 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3629 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3630 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3631 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3632 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3633 const struct knownweight_entry *ptr;
3635 static const struct knownweight_entry knownweights[] = {
3636 { thinW, DWRITE_FONT_WEIGHT_THIN },
3637 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3638 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3639 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3640 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3641 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3642 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3643 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3644 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3645 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3648 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3649 compare_knownweights);
3650 if (!ptr) {
3651 nameW[0] = 0;
3652 return FALSE;
3655 strcpyW(nameW, ptr->nameW);
3656 return TRUE;
3659 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3661 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3662 strW[name->len] = 0;
3665 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3666 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3668 static const WCHAR bookW[] = {'B','o','o','k',0};
3669 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3670 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3671 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3672 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3674 static const WCHAR *regular_patterns[] = {
3675 bookW,
3676 normalW,
3677 regularW,
3678 romanW,
3679 uprightW,
3680 NULL
3683 const WCHAR *regular_ptr = NULL, *ptr;
3684 int i = 0;
3686 if (len == -1)
3687 len = strlenW(facenameW);
3689 /* remove rightmost regular variant from face name */
3690 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3691 int pattern_len = strlenW(ptr);
3692 WCHAR *src;
3694 if (pattern_len > len)
3695 continue;
3697 src = facenameW + len - pattern_len;
3698 while (src >= facenameW) {
3699 if (!strncmpiW(src, ptr, pattern_len)) {
3700 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3701 len = strlenW(facenameW);
3702 regular_ptr = ptr;
3703 break;
3705 else
3706 src--;
3710 return regular_ptr;
3713 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3715 const WCHAR *ptr;
3717 list_init(tokens);
3718 ptr = nameW;
3720 while (*ptr) {
3721 struct name_token *token = heap_alloc(sizeof(*token));
3722 token->ptr = ptr;
3723 token->len = 0;
3724 token->fulllen = 0;
3726 while (*ptr && !is_name_separator_char(*ptr)) {
3727 token->len++;
3728 token->fulllen++;
3729 ptr++;
3732 /* skip separators */
3733 while (is_name_separator_char(*ptr)) {
3734 token->fulllen++;
3735 ptr++;
3738 list_add_head(tokens, &token->entry);
3742 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3744 struct name_token *token, *token2;
3745 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3746 int len;
3748 list_remove(&token->entry);
3750 /* don't include last separator */
3751 len = list_empty(tokens) ? token->len : token->fulllen;
3752 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3753 nameW += len;
3755 heap_free(token);
3757 *nameW = 0;
3760 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3762 struct name_token stretch_name, weight_name, style_name;
3763 WCHAR familynameW[255], facenameW[255], finalW[255];
3764 WCHAR weightW[32], stretchW[32], styleW[32];
3765 const WCHAR *regular_ptr = NULL;
3766 DWRITE_FONT_STRETCH stretch;
3767 DWRITE_FONT_WEIGHT weight;
3768 struct list tokens;
3769 int len;
3771 /* remove leading and trailing spaces from family and face name */
3772 trim_spaces(familyW, familynameW);
3773 len = trim_spaces(faceW, facenameW);
3775 /* remove rightmost regular variant from face name */
3776 regular_ptr = facename_remove_regular_term(facenameW, len);
3778 /* append face name to family name, FIXME check if face name is a substring of family name */
3779 if (*facenameW) {
3780 strcatW(familynameW, spaceW);
3781 strcatW(familynameW, facenameW);
3784 /* tokenize with " .-_" */
3785 fontname_tokenize(&tokens, familynameW);
3787 /* extract and resolve style */
3788 font->style = font_extract_style(&tokens, font->style, &style_name);
3790 /* extract stretch */
3791 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3793 /* extract weight */
3794 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3796 /* resolve weight */
3797 if (weight != font->weight) {
3798 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3799 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3800 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3801 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3802 !(abs(weight - font->weight) <= 150 &&
3803 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3804 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3805 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3807 font->weight = weight;
3811 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3812 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3813 stretch itself is normal (extracted stretch is never normal). */
3814 if (stretch != font->stretch) {
3815 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3816 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3817 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3819 font->stretch = stretch;
3823 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3825 /* get final combined string from what's left in token list, list is released */
3826 fontname_tokens_to_str(&tokens, finalW);
3828 if (!strcmpW(familyW, finalW))
3829 return FALSE;
3831 /* construct face name */
3832 strcpyW(familyW, finalW);
3834 /* resolved weight name */
3835 if (weight_name.ptr)
3836 font_name_token_to_str(&weight_name, weightW);
3837 /* ignore normal weight */
3838 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3839 weightW[0] = 0;
3840 /* for known weight values use appropriate names */
3841 else if (is_known_weight_value(font->weight, weightW)) {
3843 /* use Wnnn format as a fallback in case weight is not one of known values */
3844 else {
3845 static const WCHAR fmtW[] = {'W','%','d',0};
3846 sprintfW(weightW, fmtW, font->weight);
3849 /* resolved stretch name */
3850 if (stretch_name.ptr)
3851 font_name_token_to_str(&stretch_name, stretchW);
3852 /* ignore normal stretch */
3853 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3854 stretchW[0] = 0;
3855 /* use predefined stretch names */
3856 else {
3857 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3858 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3859 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3860 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3861 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3862 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3864 static const WCHAR *stretchnamesW[] = {
3865 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3866 ultracondensedW,
3867 extracondensedW,
3868 condensedW,
3869 semicondensedW,
3870 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3871 semiexpandedW,
3872 expandedW,
3873 extraexpandedW,
3874 ultraexpandedW
3876 strcpyW(stretchW, stretchnamesW[font->stretch]);
3879 /* resolved style name */
3880 if (style_name.ptr)
3881 font_name_token_to_str(&style_name, styleW);
3882 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3883 styleW[0] = 0;
3884 /* use predefined names */
3885 else {
3886 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3887 strcpyW(styleW, italicW);
3888 else
3889 strcpyW(styleW, obliqueW);
3892 /* use Regular match if it was found initially */
3893 if (!*weightW && !*stretchW && !*styleW)
3894 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3895 else {
3896 faceW[0] = 0;
3897 if (*stretchW)
3898 strcpyW(faceW, stretchW);
3899 if (*weightW) {
3900 if (*faceW)
3901 strcatW(faceW, spaceW);
3902 strcatW(faceW, weightW);
3904 if (*styleW) {
3905 if (*faceW)
3906 strcatW(faceW, spaceW);
3907 strcatW(faceW, styleW);
3911 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3912 return TRUE;
3915 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3917 static const float width_axis_values[] =
3919 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3920 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3921 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3922 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3923 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3924 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3925 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3926 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3927 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3928 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3931 struct file_stream_desc stream_desc;
3932 struct dwrite_font_props props;
3933 struct dwrite_font_data *data;
3934 WCHAR familyW[255], faceW[255];
3935 HRESULT hr;
3937 *ret = NULL;
3939 data = heap_alloc_zero(sizeof(*data));
3940 if (!data)
3941 return E_OUTOFMEMORY;
3943 data->ref = 1;
3944 data->file = desc->files[0];
3945 data->face_index = desc->index;
3946 data->face_type = desc->face_type;
3947 IDWriteFontFile_AddRef(data->file);
3949 stream_desc.stream = desc->stream;
3950 stream_desc.face_type = desc->face_type;
3951 stream_desc.face_index = desc->index;
3952 opentype_get_font_properties(&stream_desc, &props);
3953 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3954 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3956 /* get family name from font file */
3957 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3958 if (FAILED(hr)) {
3959 WARN("unable to get family name from font\n");
3960 release_font_data(data);
3961 return hr;
3964 data->style = props.style;
3965 data->stretch = props.stretch;
3966 data->weight = props.weight;
3967 data->panose = props.panose;
3968 data->fontsig = props.fontsig;
3969 data->lf = props.lf;
3970 data->flags = props.flags;
3972 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3973 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3974 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3975 set_en_localizedstring(data->family_names, familyW);
3976 set_en_localizedstring(data->names, faceW);
3979 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3981 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
3982 data->axis[0].value = props.weight;
3983 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
3984 data->axis[1].value = width_axis_values[props.stretch];
3985 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
3986 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
3988 *ret = data;
3989 return S_OK;
3992 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3993 const WCHAR *facenameW, struct dwrite_font_data **ret)
3995 struct dwrite_font_data *data;
3997 *ret = NULL;
3999 data = heap_alloc_zero(sizeof(*data));
4000 if (!data)
4001 return E_OUTOFMEMORY;
4003 *data = *src;
4004 data->ref = 1;
4005 data->simulations |= sim;
4006 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
4007 data->weight = DWRITE_FONT_WEIGHT_BOLD;
4008 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
4009 data->style = DWRITE_FONT_STYLE_OBLIQUE;
4010 memset(data->info_strings, 0, sizeof(data->info_strings));
4011 data->names = NULL;
4012 IDWriteFontFile_AddRef(data->file);
4013 IDWriteLocalizedStrings_AddRef(data->family_names);
4015 create_localizedstrings(&data->names);
4016 add_localizedstring(data->names, enusW, facenameW);
4018 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
4020 *ret = data;
4021 return S_OK;
4024 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4026 struct dwrite_fontfamily_data *data;
4028 data = heap_alloc_zero(sizeof(*data));
4029 if (!data)
4030 return E_OUTOFMEMORY;
4032 data->refcount = 1;
4033 data->familyname = familyname;
4034 IDWriteLocalizedStrings_AddRef(familyname);
4036 *ret = data;
4038 return S_OK;
4041 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4043 size_t i, j, heaviest;
4045 for (i = 0; i < family->count; ++i)
4047 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4048 heaviest = i;
4050 if (family->fonts[i]->bold_sim_tested)
4051 continue;
4053 family->fonts[i]->bold_sim_tested = 1;
4054 for (j = i; j < family->count; ++j)
4056 if (family->fonts[j]->bold_sim_tested)
4057 continue;
4059 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4060 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4061 if (family->fonts[j]->weight > weight) {
4062 weight = family->fonts[j]->weight;
4063 heaviest = j;
4065 family->fonts[j]->bold_sim_tested = 1;
4069 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4070 static const struct name_pattern weightsim_patterns[] = {
4071 { extraW, lightW },
4072 { extW, lightW },
4073 { ultraW, lightW },
4074 { semiW, lightW },
4075 { semiW, boldW },
4076 { demiW, boldW },
4077 { boldW },
4078 { thinW },
4079 { lightW },
4080 { mediumW },
4081 { demiW },
4082 { NULL }
4085 WCHAR facenameW[255], initialW[255];
4086 struct dwrite_font_data *boldface;
4087 struct list tokens;
4089 /* add Bold simulation based on heaviest face data */
4091 /* Simulated face name should only contain Bold as weight term,
4092 so remove existing regular and weight terms. */
4093 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4094 facename_remove_regular_term(initialW, -1);
4096 /* remove current weight pattern */
4097 fontname_tokenize(&tokens, initialW);
4098 match_pattern_list(&tokens, weightsim_patterns, NULL);
4099 fontname_tokens_to_str(&tokens, facenameW);
4101 /* Bold suffix for new name */
4102 if (*facenameW)
4103 strcatW(facenameW, spaceW);
4104 strcatW(facenameW, boldW);
4106 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4107 boldface->bold_sim_tested = 1;
4108 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4109 fontfamily_add_font(family, boldface);
4115 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4117 size_t i, j;
4119 for (i = 0; i < family->count; ++i)
4121 UINT32 regular = ~0u, oblique = ~0u;
4122 struct dwrite_font_data *obliqueface;
4123 WCHAR facenameW[255];
4125 if (family->fonts[i]->oblique_sim_tested)
4126 continue;
4128 family->fonts[i]->oblique_sim_tested = 1;
4129 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4130 regular = i;
4131 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4132 oblique = i;
4134 /* find regular style with same weight/stretch values */
4135 for (j = i; j < family->count; ++j)
4137 if (family->fonts[j]->oblique_sim_tested)
4138 continue;
4140 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4141 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4143 family->fonts[j]->oblique_sim_tested = 1;
4144 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4145 regular = j;
4147 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4148 oblique = j;
4151 if (regular != ~0u && oblique != ~0u)
4152 break;
4155 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4156 if (regular == ~0u)
4157 continue;
4159 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4160 if (oblique != ~0u)
4161 continue;
4163 /* add oblique simulation based on this regular face */
4165 /* remove regular term if any, append 'Oblique' */
4166 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4167 facename_remove_regular_term(facenameW, -1);
4169 if (*facenameW)
4170 strcatW(facenameW, spaceW);
4171 strcatW(facenameW, obliqueW);
4173 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4174 obliqueface->oblique_sim_tested = 1;
4175 obliqueface->lf.lfItalic = 1;
4176 fontfamily_add_font(family, obliqueface);
4181 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4182 const WCHAR *replacement_name)
4184 UINT32 i = collection_find_family(collection, replacement_name);
4185 struct dwrite_fontfamily_data *target;
4186 IDWriteLocalizedStrings *strings;
4187 HRESULT hr;
4189 /* replacement does not exist */
4190 if (i == ~0u)
4191 return FALSE;
4193 hr = create_localizedstrings(&strings);
4194 if (FAILED(hr))
4195 return FALSE;
4197 /* add a new family with target name, reuse font data from replacement */
4198 add_localizedstring(strings, enusW, target_name);
4199 hr = init_fontfamily_data(strings, &target);
4200 if (hr == S_OK) {
4201 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4202 WCHAR nameW[255];
4204 for (i = 0; i < replacement->count; ++i)
4206 fontfamily_add_font(target, replacement->fonts[i]);
4207 addref_font_data(replacement->fonts[i]);
4210 fontcollection_add_family(collection, target);
4211 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4212 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4214 IDWriteLocalizedStrings_Release(strings);
4215 return TRUE;
4218 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4219 system font collections. */
4220 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4222 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4223 WCHAR *name;
4224 void *data;
4225 HKEY hkey;
4227 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4228 return;
4230 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4231 RegCloseKey(hkey);
4232 return;
4235 max_namelen++; /* returned value doesn't include room for '\0' */
4236 name = heap_alloc(max_namelen * sizeof(WCHAR));
4237 data = heap_alloc(max_datalen);
4239 datalen = max_datalen;
4240 namelen = max_namelen;
4241 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4242 if (collection_find_family(collection, name) == ~0u) {
4243 if (type == REG_MULTI_SZ) {
4244 WCHAR *replacement = data;
4245 while (*replacement) {
4246 if (fontcollection_add_replacement(collection, name, replacement))
4247 break;
4248 replacement += strlenW(replacement) + 1;
4251 else if (type == REG_SZ)
4252 fontcollection_add_replacement(collection, name, data);
4254 else
4255 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4257 datalen = max_datalen;
4258 namelen = max_namelen;
4261 heap_free(data);
4262 heap_free(name);
4263 RegCloseKey(hkey);
4266 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4267 IDWriteFontCollection3 **ret)
4269 struct fontfile_enum {
4270 struct list entry;
4271 IDWriteFontFile *file;
4273 struct fontfile_enum *fileenum, *fileenum2;
4274 struct dwrite_fontcollection *collection;
4275 struct list scannedfiles;
4276 BOOL current = FALSE;
4277 HRESULT hr = S_OK;
4278 size_t i;
4280 *ret = NULL;
4282 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4283 if (!collection) return E_OUTOFMEMORY;
4285 hr = init_font_collection(collection, is_system);
4286 if (FAILED(hr)) {
4287 heap_free(collection);
4288 return hr;
4291 *ret = &collection->IDWriteFontCollection3_iface;
4293 TRACE("building font collection:\n");
4295 list_init(&scannedfiles);
4296 while (hr == S_OK) {
4297 DWRITE_FONT_FACE_TYPE face_type;
4298 DWRITE_FONT_FILE_TYPE file_type;
4299 BOOL supported, same = FALSE;
4300 IDWriteFontFileStream *stream;
4301 IDWriteFontFile *file;
4302 UINT32 face_count;
4304 current = FALSE;
4305 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4306 if (FAILED(hr) || !current)
4307 break;
4309 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4310 if (FAILED(hr))
4311 break;
4313 /* check if we've scanned this file already */
4314 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4315 if ((same = is_same_fontfile(fileenum->file, file)))
4316 break;
4319 if (same) {
4320 IDWriteFontFile_Release(file);
4321 continue;
4324 if (FAILED(get_filestream_from_file(file, &stream))) {
4325 IDWriteFontFile_Release(file);
4326 continue;
4329 /* Unsupported formats are skipped. */
4330 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4331 if (FAILED(hr) || !supported || face_count == 0) {
4332 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4333 IDWriteFontFileStream_Release(stream);
4334 IDWriteFontFile_Release(file);
4335 hr = S_OK;
4336 continue;
4339 /* add to scanned list */
4340 fileenum = heap_alloc(sizeof(*fileenum));
4341 fileenum->file = file;
4342 list_add_tail(&scannedfiles, &fileenum->entry);
4344 for (i = 0; i < face_count; ++i)
4346 struct dwrite_font_data *font_data;
4347 struct fontface_desc desc;
4348 WCHAR familyW[255];
4349 UINT32 index;
4351 desc.factory = factory;
4352 desc.face_type = face_type;
4353 desc.files = &file;
4354 desc.stream = stream;
4355 desc.files_number = 1;
4356 desc.index = i;
4357 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4358 desc.font_data = NULL;
4360 /* Allocate an initialize new font data structure. */
4361 hr = init_font_data(&desc, &font_data);
4362 if (FAILED(hr))
4364 /* move to next one */
4365 hr = S_OK;
4366 continue;
4369 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4371 /* ignore dot named faces */
4372 if (familyW[0] == '.')
4374 WARN("Ignoring face %s\n", debugstr_w(familyW));
4375 release_font_data(font_data);
4376 continue;
4379 index = collection_find_family(collection, familyW);
4380 if (index != ~0u)
4381 hr = fontfamily_add_font(collection->family_data[index], font_data);
4382 else {
4383 struct dwrite_fontfamily_data *family_data;
4385 /* create and init new family */
4386 hr = init_fontfamily_data(font_data->family_names, &family_data);
4387 if (hr == S_OK) {
4388 /* add font to family, family - to collection */
4389 hr = fontfamily_add_font(family_data, font_data);
4390 if (hr == S_OK)
4391 hr = fontcollection_add_family(collection, family_data);
4393 if (FAILED(hr))
4394 release_fontfamily_data(family_data);
4398 if (FAILED(hr))
4399 break;
4402 IDWriteFontFileStream_Release(stream);
4405 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4406 IDWriteFontFile_Release(fileenum->file);
4407 list_remove(&fileenum->entry);
4408 heap_free(fileenum);
4411 for (i = 0; i < collection->count; ++i)
4413 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4414 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4417 if (is_system)
4418 fontcollection_add_replacements(collection);
4420 collection->factory = factory;
4421 IDWriteFactory7_AddRef(factory);
4423 return hr;
4426 struct system_fontfile_enumerator
4428 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4429 LONG ref;
4431 IDWriteFactory7 *factory;
4432 HKEY hkey;
4433 int index;
4435 WCHAR *filename;
4436 DWORD filename_size;
4439 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4441 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4444 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4446 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4447 IDWriteFontFileEnumerator_AddRef(iface);
4448 *obj = iface;
4449 return S_OK;
4452 WARN("%s not implemented.\n", debugstr_guid(riid));
4454 *obj = NULL;
4456 return E_NOINTERFACE;
4459 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4461 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4462 return InterlockedIncrement(&enumerator->ref);
4465 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4467 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4468 ULONG ref = InterlockedDecrement(&enumerator->ref);
4470 if (!ref)
4472 IDWriteFactory7_Release(enumerator->factory);
4473 RegCloseKey(enumerator->hkey);
4474 heap_free(enumerator->filename);
4475 heap_free(enumerator);
4478 return ref;
4481 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4483 HRESULT hr;
4485 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4486 if (!strchrW(filename, '\\')) {
4487 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4488 WCHAR fullpathW[MAX_PATH];
4490 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4491 strcatW(fullpathW, fontsW);
4492 strcatW(fullpathW, filename);
4494 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4496 else
4497 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4499 return hr;
4502 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4504 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4506 *file = NULL;
4508 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4509 return E_FAIL;
4511 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4514 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4516 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4517 WCHAR name_buf[256], *name = name_buf;
4518 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4519 HRESULT hr = S_OK;
4520 LONG r;
4522 *current = FALSE;
4523 enumerator->index++;
4525 /* iterate until we find next string value */
4526 for (;;) {
4527 do {
4528 name_count = max_name_count;
4529 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4531 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4532 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4533 if (r == ERROR_MORE_DATA) {
4534 if (name_count >= max_name_count) {
4535 if (name != name_buf) heap_free(name);
4536 max_name_count *= 2;
4537 name = heap_alloc(max_name_count * sizeof(*name));
4538 if (!name) return E_OUTOFMEMORY;
4540 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4541 heap_free(enumerator->filename);
4542 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4543 enumerator->filename = heap_alloc(enumerator->filename_size);
4544 if (!enumerator->filename) {
4545 hr = E_OUTOFMEMORY;
4546 goto err;
4550 } while (r == ERROR_MORE_DATA);
4552 if (r != ERROR_SUCCESS) {
4553 enumerator->filename[0] = 0;
4554 break;
4556 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4557 if (type == REG_SZ && *name != '@') {
4558 *current = TRUE;
4559 break;
4561 enumerator->index++;
4563 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4565 err:
4566 if (name != name_buf) heap_free(name);
4567 return hr;
4570 static const IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4572 systemfontfileenumerator_QueryInterface,
4573 systemfontfileenumerator_AddRef,
4574 systemfontfileenumerator_Release,
4575 systemfontfileenumerator_MoveNext,
4576 systemfontfileenumerator_GetCurrentFontFile
4579 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4581 struct system_fontfile_enumerator *enumerator;
4582 static const WCHAR fontslistW[] = {
4583 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4584 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4585 'F','o','n','t','s',0
4588 *ret = NULL;
4590 enumerator = heap_alloc(sizeof(*enumerator));
4591 if (!enumerator)
4592 return E_OUTOFMEMORY;
4594 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4595 enumerator->ref = 1;
4596 enumerator->factory = factory;
4597 enumerator->index = -1;
4598 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4599 enumerator->filename = heap_alloc(enumerator->filename_size);
4600 if (!enumerator->filename) {
4601 heap_free(enumerator);
4602 return E_OUTOFMEMORY;
4605 IDWriteFactory7_AddRef(factory);
4607 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4609 ERR("failed to open fonts list key\n");
4610 IDWriteFactory7_Release(factory);
4611 heap_free(enumerator->filename);
4612 heap_free(enumerator);
4613 return E_FAIL;
4616 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4618 return S_OK;
4621 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4623 IDWriteFontFileEnumerator *enumerator;
4624 HRESULT hr;
4626 *collection = NULL;
4628 hr = create_system_fontfile_enumerator(factory, &enumerator);
4629 if (FAILED(hr))
4630 return hr;
4632 TRACE("building system font collection for factory %p\n", factory);
4633 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4634 IDWriteFontFileEnumerator_Release(enumerator);
4635 return hr;
4638 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4639 const WCHAR *keynameW, const WCHAR *pathW)
4641 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};
4642 static const WCHAR emptyW[] = {0};
4643 struct dwrite_fontfamily_data *family_data;
4644 IDWriteLocalizedStrings *names;
4645 DWRITE_FONT_FACE_TYPE face_type;
4646 DWRITE_FONT_FILE_TYPE file_type;
4647 IDWriteFontFileStream *stream;
4648 IDWriteFontFile *file;
4649 UINT32 face_count, i;
4650 BOOL supported;
4651 HRESULT hr;
4653 /* create font file from this path */
4654 hr = create_local_file_reference(factory, pathW, &file);
4655 if (FAILED(hr))
4656 return S_FALSE;
4658 if (FAILED(get_filestream_from_file(file, &stream))) {
4659 IDWriteFontFile_Release(file);
4660 return S_FALSE;
4663 /* Unsupported formats are skipped. */
4664 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4665 if (FAILED(hr) || !supported || face_count == 0) {
4666 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4667 IDWriteFontFileStream_Release(stream);
4668 IDWriteFontFile_Release(file);
4669 return S_FALSE;
4672 /* create and init new family */
4674 /* Family names are added for non-specific locale, represented with empty string.
4675 Default family appears with empty family name. */
4676 create_localizedstrings(&names);
4677 if (!strcmpiW(keynameW, defaultfontW))
4678 add_localizedstring(names, emptyW, emptyW);
4679 else
4680 add_localizedstring(names, emptyW, keynameW);
4682 hr = init_fontfamily_data(names, &family_data);
4683 IDWriteLocalizedStrings_Release(names);
4684 if (hr != S_OK) {
4685 IDWriteFontFile_Release(file);
4686 return hr;
4689 /* fill with faces */
4690 for (i = 0; i < face_count; i++) {
4691 struct dwrite_font_data *font_data;
4692 struct fontface_desc desc;
4694 /* alloc and init new font data structure */
4695 desc.factory = factory;
4696 desc.face_type = face_type;
4697 desc.index = i;
4698 desc.files = &file;
4699 desc.stream = stream;
4700 desc.files_number = 1;
4701 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4702 desc.font_data = NULL;
4704 hr = init_font_data(&desc, &font_data);
4705 if (FAILED(hr))
4706 continue;
4708 /* add font to family */
4709 hr = fontfamily_add_font(family_data, font_data);
4710 if (hr != S_OK)
4711 release_font_data(font_data);
4714 /* add family to collection */
4715 hr = fontcollection_add_family(collection, family_data);
4716 if (FAILED(hr))
4717 release_fontfamily_data(family_data);
4718 IDWriteFontFileStream_Release(stream);
4719 IDWriteFontFile_Release(file);
4721 return hr;
4724 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4726 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4727 struct dwrite_fontcollection *collection;
4728 static const WCHAR emptyW[] = {0};
4729 WCHAR eudckeypathW[16];
4730 HKEY eudckey;
4731 DWORD index;
4732 BOOL exists;
4733 LONG retval;
4734 HRESULT hr;
4735 size_t i;
4737 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4739 *ret = NULL;
4741 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4742 if (!collection) return E_OUTOFMEMORY;
4744 hr = init_font_collection(collection, FALSE);
4745 if (FAILED(hr)) {
4746 heap_free(collection);
4747 return hr;
4750 *ret = &collection->IDWriteFontCollection3_iface;
4751 collection->factory = factory;
4752 IDWriteFactory7_AddRef(factory);
4754 /* return empty collection if EUDC fonts are not configured */
4755 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4756 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4757 return S_OK;
4759 retval = ERROR_SUCCESS;
4760 index = 0;
4761 while (retval != ERROR_NO_MORE_ITEMS) {
4762 WCHAR keynameW[64], pathW[MAX_PATH];
4763 DWORD type, path_len, name_len;
4765 path_len = ARRAY_SIZE(pathW);
4766 name_len = ARRAY_SIZE(keynameW);
4767 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4768 if (retval || type != REG_SZ)
4769 continue;
4771 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4772 if (hr != S_OK)
4773 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4775 RegCloseKey(eudckey);
4777 /* try to add global default if not defined for specific codepage */
4778 exists = FALSE;
4779 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4780 &index, &exists);
4781 if (FAILED(hr) || !exists) {
4782 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4783 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4784 if (hr != S_OK)
4785 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4788 /* EUDC collection offers simulated faces too */
4789 for (i = 0; i < collection->count; ++i)
4791 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4792 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4795 return S_OK;
4798 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4800 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
4802 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4804 *obj = iface;
4805 IDWriteFontFile_AddRef(iface);
4806 return S_OK;
4809 WARN("%s not implemented.\n", debugstr_guid(riid));
4811 *obj = NULL;
4812 return E_NOINTERFACE;
4815 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4817 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4818 ULONG refcount = InterlockedIncrement(&file->refcount);
4820 TRACE("%p, refcount %d.\n", iface, refcount);
4822 return refcount;
4825 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4827 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4828 ULONG refcount = InterlockedDecrement(&file->refcount);
4830 TRACE("%p, refcount %d.\n", iface, refcount);
4832 if (!refcount)
4834 IDWriteFontFileLoader_Release(file->loader);
4835 if (file->stream)
4836 IDWriteFontFileStream_Release(file->stream);
4837 heap_free(file->reference_key);
4838 heap_free(file);
4841 return refcount;
4844 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **key, UINT32 *key_size)
4846 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4848 TRACE("%p, %p, %p.\n", iface, key, key_size);
4850 *key = file->reference_key;
4851 *key_size = file->key_size;
4853 return S_OK;
4856 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **loader)
4858 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4860 TRACE("%p, %p.\n", iface, loader);
4862 *loader = file->loader;
4863 IDWriteFontFileLoader_AddRef(*loader);
4865 return S_OK;
4868 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4869 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4871 struct dwrite_fontfile *file = impl_from_IDWriteFontFile(iface);
4872 IDWriteFontFileStream *stream;
4873 HRESULT hr;
4875 TRACE("%p, %p, %p, %p, %p.\n", iface, is_supported, file_type, face_type, face_count);
4877 *is_supported = FALSE;
4878 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4879 if (face_type)
4880 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4881 *face_count = 0;
4883 hr = IDWriteFontFileLoader_CreateStreamFromKey(file->loader, file->reference_key, file->key_size, &stream);
4884 if (FAILED(hr))
4885 return hr;
4887 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4889 /* TODO: Further Analysis */
4890 IDWriteFontFileStream_Release(stream);
4891 return S_OK;
4894 static const IDWriteFontFileVtbl dwritefontfilevtbl =
4896 dwritefontfile_QueryInterface,
4897 dwritefontfile_AddRef,
4898 dwritefontfile_Release,
4899 dwritefontfile_GetReferenceKey,
4900 dwritefontfile_GetLoader,
4901 dwritefontfile_Analyze,
4904 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4905 IDWriteFontFile **ret)
4907 struct dwrite_fontfile *file;
4908 void *key;
4910 *ret = NULL;
4912 file = heap_alloc(sizeof(*file));
4913 key = heap_alloc(key_size);
4914 if (!file || !key) {
4915 heap_free(file);
4916 heap_free(key);
4917 return E_OUTOFMEMORY;
4920 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4921 file->refcount = 1;
4922 IDWriteFontFileLoader_AddRef(loader);
4923 file->loader = loader;
4924 file->stream = NULL;
4925 file->reference_key = key;
4926 memcpy(file->reference_key, reference_key, key_size);
4927 file->key_size = key_size;
4929 *ret = &file->IDWriteFontFile_iface;
4931 return S_OK;
4934 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4936 struct file_stream_desc stream_desc;
4937 struct dwrite_font_data *font_data;
4938 struct dwrite_fontface *fontface;
4939 HRESULT hr;
4940 int i;
4942 *ret = NULL;
4944 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4945 if (!fontface)
4946 return E_OUTOFMEMORY;
4948 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4949 if (!fontface->files) {
4950 heap_free(fontface);
4951 return E_OUTOFMEMORY;
4954 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4955 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
4956 fontface->refcount = 1;
4957 fontface->type = desc->face_type;
4958 fontface->file_count = desc->files_number;
4959 fontface->vdmx.exists = TRUE;
4960 fontface->gasp.exists = TRUE;
4961 fontface->cpal.exists = TRUE;
4962 fontface->colr.exists = TRUE;
4963 fontface->index = desc->index;
4964 fontface->simulations = desc->simulations;
4965 fontface->factory = desc->factory;
4966 IDWriteFactory7_AddRef(fontface->factory);
4968 for (i = 0; i < fontface->file_count; i++) {
4969 fontface->files[i] = desc->files[i];
4970 IDWriteFontFile_AddRef(fontface->files[i]);
4972 fontface->stream = desc->stream;
4973 IDWriteFontFileStream_AddRef(fontface->stream);
4975 stream_desc.stream = fontface->stream;
4976 stream_desc.face_type = desc->face_type;
4977 stream_desc.face_index = desc->index;
4978 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4979 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4980 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4981 /* TODO: test what happens if caret is already slanted */
4982 if (fontface->caret.slopeRise == 1) {
4983 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4984 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4988 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4989 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4990 if (opentype_has_vertical_variants(fontface))
4991 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4992 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4994 /* Font properties are reused from font object when 'normal' face creation path is used:
4995 collection -> family -> matching font -> fontface.
4997 If face is created directly from factory we have to go through properties resolution.
4999 if (desc->font_data)
5001 font_data = desc->font_data;
5002 addref_font_data(font_data);
5004 else
5006 hr = init_font_data(desc, &font_data);
5007 if (FAILED(hr))
5009 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
5010 return hr;
5014 fontface->weight = font_data->weight;
5015 fontface->style = font_data->style;
5016 fontface->stretch = font_data->stretch;
5017 fontface->panose = font_data->panose;
5018 fontface->fontsig = font_data->fontsig;
5019 fontface->lf = font_data->lf;
5020 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
5021 fontface->names = font_data->names;
5022 if (fontface->names)
5023 IDWriteLocalizedStrings_AddRef(fontface->names);
5024 fontface->family_names = font_data->family_names;
5025 if (fontface->family_names)
5026 IDWriteLocalizedStrings_AddRef(fontface->family_names);
5027 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
5028 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
5030 if (fontface->info_strings[i])
5031 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5033 fontface->cmap.stream = fontface->stream;
5034 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5035 release_font_data(font_data);
5037 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5039 *ret = &fontface->IDWriteFontFace5_iface;
5041 return S_OK;
5044 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5045 struct local_refkey
5047 FILETIME writetime;
5048 WCHAR name[1];
5051 struct local_cached_stream
5053 struct list entry;
5054 IDWriteFontFileStream *stream;
5055 struct local_refkey *key;
5056 UINT32 key_size;
5059 struct dwrite_localfontfilestream
5061 IDWriteFontFileStream IDWriteFontFileStream_iface;
5062 LONG refcount;
5064 struct local_cached_stream *entry;
5065 const void *file_ptr;
5066 UINT64 size;
5069 struct dwrite_localfontfileloader
5071 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5072 LONG refcount;
5074 struct list streams;
5075 CRITICAL_SECTION cs;
5078 static struct dwrite_localfontfileloader local_fontfile_loader;
5080 struct dwrite_inmemory_stream_data
5082 LONG ref;
5083 IUnknown *owner;
5084 void *data;
5085 UINT32 size;
5088 struct dwrite_inmemory_filestream
5090 IDWriteFontFileStream IDWriteFontFileStream_iface;
5091 LONG ref;
5093 struct dwrite_inmemory_stream_data *data;
5096 struct dwrite_inmemory_fileloader
5098 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5099 LONG ref;
5101 struct dwrite_inmemory_stream_data **streams;
5102 size_t size;
5103 size_t count;
5106 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5108 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5111 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5113 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5116 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5118 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5121 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5123 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5126 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5128 if (InterlockedDecrement(&stream->ref) == 0) {
5129 if (stream->owner)
5130 IUnknown_Release(stream->owner);
5131 else
5132 heap_free(stream->data);
5133 heap_free(stream);
5137 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5139 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5141 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5143 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5144 IsEqualIID(riid, &IID_IUnknown))
5146 *obj = iface;
5147 if (InterlockedIncrement(&stream->refcount) == 1)
5149 InterlockedDecrement(&stream->refcount);
5150 *obj = NULL;
5151 return E_FAIL;
5153 return S_OK;
5156 WARN("%s not implemented.\n", debugstr_guid(riid));
5158 *obj = NULL;
5159 return E_NOINTERFACE;
5162 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5164 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5165 ULONG refcount = InterlockedIncrement(&stream->refcount);
5167 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5169 return refcount;
5172 static inline void release_cached_stream(struct local_cached_stream *stream)
5174 list_remove(&stream->entry);
5175 heap_free(stream->key);
5176 heap_free(stream);
5179 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5181 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5182 ULONG refcount = InterlockedDecrement(&stream->refcount);
5184 TRACE_(dwrite_file)("%p, refcount %d.\n", iface, refcount);
5186 if (!refcount)
5188 UnmapViewOfFile(stream->file_ptr);
5190 EnterCriticalSection(&local_fontfile_loader.cs);
5191 release_cached_stream(stream->entry);
5192 LeaveCriticalSection(&local_fontfile_loader.cs);
5194 heap_free(stream);
5197 return refcount;
5200 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5201 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5203 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5205 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
5206 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5208 *fragment_context = NULL;
5210 if ((offset >= stream->size - 1) || (fragment_size > stream->size - offset))
5212 *fragment_start = NULL;
5213 return E_FAIL;
5216 *fragment_start = (char *)stream->file_ptr + offset;
5217 return S_OK;
5220 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5222 TRACE_(dwrite_file)("%p, %p.\n", iface, fragment_context);
5225 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5227 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5229 TRACE_(dwrite_file)("%p, %p.\n", iface, size);
5231 *size = stream->size;
5232 return S_OK;
5235 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5237 struct dwrite_localfontfilestream *stream = impl_from_IDWriteFontFileStream(iface);
5238 ULARGE_INTEGER li;
5240 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
5242 li.u.LowPart = stream->entry->key->writetime.dwLowDateTime;
5243 li.u.HighPart = stream->entry->key->writetime.dwHighDateTime;
5244 *last_writetime = li.QuadPart;
5246 return S_OK;
5249 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5251 localfontfilestream_QueryInterface,
5252 localfontfilestream_AddRef,
5253 localfontfilestream_Release,
5254 localfontfilestream_ReadFileFragment,
5255 localfontfilestream_ReleaseFileFragment,
5256 localfontfilestream_GetFileSize,
5257 localfontfilestream_GetLastWriteTime
5260 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry,
5261 IDWriteFontFileStream **ret)
5263 struct dwrite_localfontfilestream *object;
5265 *ret = NULL;
5267 if (!(object = heap_alloc(sizeof(*object))))
5268 return E_OUTOFMEMORY;
5270 object->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5271 object->refcount = 1;
5273 object->file_ptr = file_ptr;
5274 object->size = size;
5275 object->entry = entry;
5277 *ret = &object->IDWriteFontFileStream_iface;
5279 return S_OK;
5282 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5284 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
5286 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5287 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5288 IsEqualIID(riid, &IID_IUnknown))
5290 *obj = iface;
5291 IDWriteLocalFontFileLoader_AddRef(iface);
5292 return S_OK;
5295 WARN("%s not implemented.\n", debugstr_guid(riid));
5297 *obj = NULL;
5298 return E_NOINTERFACE;
5301 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5303 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5304 ULONG refcount = InterlockedIncrement(&loader->refcount);
5306 TRACE("%p, refcount %d.\n", iface, refcount);
5308 return refcount;
5311 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5313 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5314 ULONG refcount = InterlockedDecrement(&loader->refcount);
5316 TRACE("%p, refcount %d.\n", iface, refcount);
5318 return refcount;
5321 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5323 const struct local_refkey *refkey = key;
5324 struct local_cached_stream *stream;
5325 IDWriteFontFileStream *filestream;
5326 HANDLE file, mapping;
5327 LARGE_INTEGER size;
5328 void *file_ptr;
5329 HRESULT hr = S_OK;
5331 *ret = NULL;
5333 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5334 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5335 if (file == INVALID_HANDLE_VALUE) {
5336 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5337 return E_FAIL;
5340 GetFileSizeEx(file, &size);
5341 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5342 CloseHandle(file);
5343 if (!mapping)
5344 return E_FAIL;
5346 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5347 CloseHandle(mapping);
5348 if (!file_ptr) {
5349 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5350 return E_FAIL;
5353 stream = heap_alloc(sizeof(*stream));
5354 if (!stream) {
5355 UnmapViewOfFile(file_ptr);
5356 return E_OUTOFMEMORY;
5359 stream->key = heap_alloc(key_size);
5360 if (!stream->key) {
5361 UnmapViewOfFile(file_ptr);
5362 heap_free(stream);
5363 return E_OUTOFMEMORY;
5366 stream->key_size = key_size;
5367 memcpy(stream->key, key, key_size);
5369 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5370 if (FAILED(hr)) {
5371 UnmapViewOfFile(file_ptr);
5372 heap_free(stream->key);
5373 heap_free(stream);
5374 return hr;
5377 stream->stream = filestream;
5379 *ret = stream;
5381 return S_OK;
5384 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5385 UINT32 key_size, IDWriteFontFileStream **ret)
5387 struct dwrite_localfontfileloader *loader = impl_from_IDWriteLocalFontFileLoader(iface);
5388 struct local_cached_stream *stream;
5389 HRESULT hr = S_OK;
5391 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
5393 EnterCriticalSection(&loader->cs);
5395 *ret = NULL;
5397 /* search cache first */
5398 LIST_FOR_EACH_ENTRY(stream, &loader->streams, struct local_cached_stream, entry)
5400 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5401 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5402 break;
5406 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK)
5408 list_add_head(&loader->streams, &stream->entry);
5409 *ret = stream->stream;
5412 LeaveCriticalSection(&loader->cs);
5414 return hr;
5417 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5418 UINT32 key_size, UINT32 *length)
5420 const struct local_refkey *refkey = key;
5422 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, length);
5424 *length = strlenW(refkey->name);
5425 return S_OK;
5428 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5429 UINT32 key_size, WCHAR *path, UINT32 length)
5431 const struct local_refkey *refkey = key;
5433 TRACE("%p, %p, %u, %p, %u.\n", iface, key, key_size, path, length);
5435 if (length < strlenW(refkey->name))
5436 return E_INVALIDARG;
5438 strcpyW(path, refkey->name);
5439 return S_OK;
5442 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5443 UINT32 key_size, FILETIME *writetime)
5445 const struct local_refkey *refkey = key;
5447 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, writetime);
5449 *writetime = refkey->writetime;
5450 return S_OK;
5453 static const IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl =
5455 localfontfileloader_QueryInterface,
5456 localfontfileloader_AddRef,
5457 localfontfileloader_Release,
5458 localfontfileloader_CreateStreamFromKey,
5459 localfontfileloader_GetFilePathLengthFromKey,
5460 localfontfileloader_GetFilePathFromKey,
5461 localfontfileloader_GetLastWriteTimeFromKey
5464 void init_local_fontfile_loader(void)
5466 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5467 local_fontfile_loader.refcount = 1;
5468 list_init(&local_fontfile_loader.streams);
5469 InitializeCriticalSection(&local_fontfile_loader.cs);
5470 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5473 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5475 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5478 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5480 struct local_refkey *refkey;
5482 if (!path)
5483 return E_INVALIDARG;
5485 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5486 *key = NULL;
5488 refkey = heap_alloc(*size);
5489 if (!refkey)
5490 return E_OUTOFMEMORY;
5492 if (writetime)
5493 refkey->writetime = *writetime;
5494 else {
5495 WIN32_FILE_ATTRIBUTE_DATA info;
5497 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5498 refkey->writetime = info.ftLastWriteTime;
5499 else
5500 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5502 strcpyW(refkey->name, path);
5504 *key = refkey;
5506 return S_OK;
5509 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5511 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5513 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5514 IsEqualIID(riid, &IID_IUnknown))
5516 *ppv = iface;
5517 IDWriteGlyphRunAnalysis_AddRef(iface);
5518 return S_OK;
5521 WARN("%s not implemented.\n", debugstr_guid(riid));
5523 *ppv = NULL;
5524 return E_NOINTERFACE;
5527 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5529 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5530 ULONG refcount = InterlockedIncrement(&analysis->refcount);
5532 TRACE("%p, refcount %d.\n", iface, refcount);
5534 return refcount;
5537 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5539 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5540 ULONG refcount = InterlockedDecrement(&analysis->refcount);
5542 TRACE("%p, refcount %d.\n", iface, refcount);
5544 if (!refcount)
5546 if (analysis->run.fontFace)
5547 IDWriteFontFace_Release(analysis->run.fontFace);
5548 heap_free(analysis->glyphs);
5549 heap_free(analysis->origins);
5550 heap_free(analysis->bitmap);
5551 heap_free(analysis);
5554 return refcount;
5557 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5559 switch (mode)
5561 case DWRITE_RENDERING_MODE1_NATURAL:
5562 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5563 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5564 return TRUE;
5565 default:
5566 return FALSE;
5570 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5572 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5575 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5577 struct dwrite_glyphbitmap glyph_bitmap;
5578 IDWriteFontFace4 *fontface;
5579 HRESULT hr;
5580 UINT32 i;
5582 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5583 *bounds = analysis->bounds;
5584 return;
5587 if (analysis->run.isSideways)
5588 FIXME("sideways runs are not supported.\n");
5590 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5591 if (FAILED(hr))
5592 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5594 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5595 glyph_bitmap.fontface = fontface;
5596 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5597 glyph_bitmap.emsize = analysis->run.fontEmSize;
5598 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5599 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5600 glyph_bitmap.m = &analysis->m;
5602 for (i = 0; i < analysis->run.glyphCount; i++) {
5603 RECT *bbox = &glyph_bitmap.bbox;
5604 UINT32 bitmap_size;
5606 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5607 freetype_get_glyph_bbox(&glyph_bitmap);
5609 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5610 (bbox->bottom - bbox->top);
5611 if (bitmap_size > analysis->max_glyph_bitmap_size)
5612 analysis->max_glyph_bitmap_size = bitmap_size;
5614 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5615 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5618 IDWriteFontFace4_Release(fontface);
5620 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5621 *bounds = analysis->bounds;
5624 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface,
5625 DWRITE_TEXTURE_TYPE type, RECT *bounds)
5627 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5629 TRACE("%p, %d, %p.\n", iface, type, bounds);
5631 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5632 SetRectEmpty(bounds);
5633 return E_INVALIDARG;
5636 if (type != analysis->texture_type)
5638 SetRectEmpty(bounds);
5639 return S_OK;
5642 glyphrunanalysis_get_texturebounds(analysis, bounds);
5643 return S_OK;
5646 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5648 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5649 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5650 (runbounds->left - bounds->left) * 3;
5651 else
5652 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5653 runbounds->left - bounds->left;
5656 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5658 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5659 struct dwrite_glyphbitmap glyph_bitmap;
5660 IDWriteFontFace4 *fontface;
5661 D2D_POINT_2F origin;
5662 UINT32 i, size;
5663 HRESULT hr;
5664 RECT *bbox;
5666 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5667 if (FAILED(hr)) {
5668 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5669 return hr;
5672 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5673 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5674 size *= 3;
5675 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5676 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5677 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5678 IDWriteFontFace4_Release(fontface);
5679 return E_OUTOFMEMORY;
5682 origin.x = origin.y = 0.0f;
5684 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5685 glyph_bitmap.fontface = fontface;
5686 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5687 glyph_bitmap.emsize = analysis->run.fontEmSize;
5688 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5689 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5690 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5691 glyph_bitmap.m = &analysis->m;
5692 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5693 IDWriteFontFace4_Release(fontface);
5694 return E_OUTOFMEMORY;
5697 bbox = &glyph_bitmap.bbox;
5699 for (i = 0; i < analysis->run.glyphCount; i++) {
5700 BYTE *src = glyph_bitmap.buf, *dst;
5701 int x, y, width, height;
5702 BOOL is_1bpp;
5704 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5705 freetype_get_glyph_bbox(&glyph_bitmap);
5707 if (IsRectEmpty(bbox))
5708 continue;
5710 width = bbox->right - bbox->left;
5711 height = bbox->bottom - bbox->top;
5713 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5714 memset(src, 0, height * glyph_bitmap.pitch);
5715 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5717 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5719 /* blit to analysis bitmap */
5720 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5722 if (is_1bpp) {
5723 /* convert 1bpp to 8bpp/24bpp */
5724 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5725 for (y = 0; y < height; y++) {
5726 for (x = 0; x < width; x++)
5727 if (src[x / 8] & masks[x % 8])
5728 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5729 src += glyph_bitmap.pitch;
5730 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5733 else {
5734 for (y = 0; y < height; y++) {
5735 for (x = 0; x < width; x++)
5736 if (src[x / 8] & masks[x % 8])
5737 dst[x] = DWRITE_ALPHA_MAX;
5738 src += glyph_bitmap.pitch;
5739 dst += analysis->bounds.right - analysis->bounds.left;
5743 else {
5744 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5745 for (y = 0; y < height; y++) {
5746 for (x = 0; x < width; x++)
5747 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5748 src += glyph_bitmap.pitch;
5749 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5752 else {
5753 for (y = 0; y < height; y++) {
5754 for (x = 0; x < width; x++)
5755 dst[x] |= src[x];
5756 src += glyph_bitmap.pitch;
5757 dst += analysis->bounds.right - analysis->bounds.left;
5762 heap_free(glyph_bitmap.buf);
5764 IDWriteFontFace4_Release(fontface);
5766 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5768 /* we don't need this anymore */
5769 heap_free(analysis->glyphs);
5770 heap_free(analysis->origins);
5771 IDWriteFontFace_Release(analysis->run.fontFace);
5773 analysis->glyphs = NULL;
5774 analysis->origins = NULL;
5775 analysis->run.glyphIndices = NULL;
5776 analysis->run.fontFace = NULL;
5778 return S_OK;
5781 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5782 RECT const *bounds, BYTE *bitmap, UINT32 size)
5784 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5785 UINT32 required;
5786 RECT runbounds;
5788 TRACE("%p, %d, %s, %p, %u.\n", iface, type, wine_dbgstr_rect(bounds), bitmap, size);
5790 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5791 return E_INVALIDARG;
5793 /* make sure buffer is large enough for requested texture type */
5794 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5795 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5796 required *= 3;
5798 if (size < required)
5799 return E_NOT_SUFFICIENT_BUFFER;
5801 /* validate requested texture type */
5802 if (analysis->texture_type != type)
5803 return DWRITE_E_UNSUPPORTEDOPERATION;
5805 memset(bitmap, 0, size);
5806 glyphrunanalysis_get_texturebounds(analysis, &runbounds);
5807 if (IntersectRect(&runbounds, &runbounds, bounds))
5809 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5810 int src_width = (analysis->bounds.right - analysis->bounds.left) * pixel_size;
5811 int dst_width = (bounds->right - bounds->left) * pixel_size;
5812 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5813 BYTE *src, *dst;
5814 int y;
5816 if (!(analysis->flags & RUNANALYSIS_BITMAP_READY))
5818 HRESULT hr;
5820 if (FAILED(hr = glyphrunanalysis_render(analysis)))
5821 return hr;
5824 src = get_pixel_ptr(analysis->bitmap, type, &runbounds, &analysis->bounds);
5825 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5827 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5828 memcpy(dst, src, draw_width);
5829 src += src_width;
5830 dst += dst_width;
5834 return S_OK;
5837 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5838 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5840 struct dwrite_glyphrunanalysis *analysis = impl_from_IDWriteGlyphRunAnalysis(iface);
5842 TRACE("%p, %p, %p, %p, %p.\n", iface, params, gamma, contrast, cleartypelevel);
5844 if (!params)
5845 return E_INVALIDARG;
5847 switch (analysis->rendering_mode)
5849 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5850 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5852 UINT value = 0;
5853 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5854 *gamma = (FLOAT)value / 1000.0f;
5855 *contrast = 0.0f;
5856 *cleartypelevel = 1.0f;
5857 break;
5859 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5860 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5861 /* fallthrough */
5862 case DWRITE_RENDERING_MODE1_ALIASED:
5863 case DWRITE_RENDERING_MODE1_NATURAL:
5864 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5865 *gamma = IDWriteRenderingParams_GetGamma(params);
5866 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5867 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5868 break;
5869 default:
5873 return S_OK;
5876 static const IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl =
5878 glyphrunanalysis_QueryInterface,
5879 glyphrunanalysis_AddRef,
5880 glyphrunanalysis_Release,
5881 glyphrunanalysis_GetAlphaTextureBounds,
5882 glyphrunanalysis_CreateAlphaTexture,
5883 glyphrunanalysis_GetAlphaBlendParams
5886 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5888 D2D_POINT_2F ret;
5889 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5890 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5891 *point = ret;
5894 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5895 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5897 unsigned int upem = fontface->metrics.designUnitsPerEm;
5898 int advance;
5900 if (is_sideways)
5901 FIXME("Sideways mode is not supported.\n");
5903 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5905 switch (measuring_mode)
5907 case DWRITE_MEASURING_MODE_NATURAL:
5908 return (float)advance * emsize / (float)upem;
5909 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5910 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5911 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5912 default:
5913 WARN("Unknown measuring mode %u.\n", measuring_mode);
5914 return 0.0f;
5918 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5920 struct dwrite_glyphrunanalysis *analysis;
5921 struct dwrite_fontface *fontface;
5922 D2D_POINT_2F origin;
5923 FLOAT rtl_factor;
5924 UINT32 i;
5926 *ret = NULL;
5928 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5929 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5930 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5931 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5932 return E_INVALIDARG;
5934 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5935 return E_INVALIDARG;
5937 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5938 return E_INVALIDARG;
5940 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5941 return E_INVALIDARG;
5943 analysis = heap_alloc_zero(sizeof(*analysis));
5944 if (!analysis)
5945 return E_OUTOFMEMORY;
5947 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5948 analysis->refcount = 1;
5949 analysis->rendering_mode = desc->rendering_mode;
5951 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5952 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5953 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5954 else
5955 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5957 analysis->run = *desc->run;
5958 IDWriteFontFace_AddRef(analysis->run.fontFace);
5959 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5960 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5962 if (!analysis->glyphs || !analysis->origins) {
5963 heap_free(analysis->glyphs);
5964 heap_free(analysis->origins);
5966 analysis->glyphs = NULL;
5967 analysis->origins = NULL;
5969 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5970 return E_OUTOFMEMORY;
5973 /* check if transform is usable */
5974 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5975 analysis->m = *desc->transform;
5976 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5979 analysis->run.glyphIndices = analysis->glyphs;
5981 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5983 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5985 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5987 origin.x = desc->origin.x;
5988 origin.y = desc->origin.y;
5989 for (i = 0; i < desc->run->glyphCount; ++i)
5991 float advance;
5993 /* Use nominal advances if not provided by caller. */
5994 if (desc->run->glyphAdvances)
5995 advance = rtl_factor * desc->run->glyphAdvances[i];
5996 else
5997 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5998 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
6000 analysis->origins[i] = origin;
6001 if (desc->run->bidiLevel & 1)
6003 if (desc->run->isSideways)
6004 analysis->origins[i].y += advance;
6005 else
6006 analysis->origins[i].x += advance;
6009 /* Offsets are optional, appled to pre-transformed origin. */
6010 if (desc->run->glyphOffsets) {
6011 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
6012 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
6014 if (desc->run->isSideways) {
6015 analysis->origins[i].x += ascenderoffset;
6016 analysis->origins[i].y += advanceoffset;
6018 else {
6019 analysis->origins[i].x += advanceoffset;
6020 analysis->origins[i].y += ascenderoffset;
6024 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
6025 transform_point(analysis->origins + i, &analysis->m);
6027 if (desc->run->isSideways)
6028 origin.y += advance;
6029 else
6030 origin.x += advance;
6033 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
6034 return S_OK;
6037 /* IDWriteColorGlyphRunEnumerator1 */
6038 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6040 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6042 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6043 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6044 IsEqualIID(riid, &IID_IUnknown))
6046 *ppv = iface;
6047 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6048 return S_OK;
6051 WARN("%s not implemented.\n", debugstr_guid(riid));
6053 *ppv = NULL;
6054 return E_NOINTERFACE;
6057 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6059 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6060 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6062 TRACE("%p, refcount %u.\n", iface, refcount);
6064 return refcount;
6067 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6069 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6070 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6072 TRACE("%p, refcount %u.\n", iface, refcount);
6074 if (!refcount)
6076 heap_free(glyphenum->advances);
6077 heap_free(glyphenum->color_advances);
6078 heap_free(glyphenum->offsets);
6079 heap_free(glyphenum->color_offsets);
6080 heap_free(glyphenum->glyphindices);
6081 heap_free(glyphenum->glyphs);
6082 if (glyphenum->colr.context)
6083 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6084 IDWriteFontFace5_Release(glyphenum->fontface);
6085 heap_free(glyphenum);
6088 return refcount;
6091 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6093 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6094 FLOAT origin = 0.0f;
6096 if (g == 0)
6097 return 0.0f;
6099 while (g--)
6100 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6101 return origin;
6104 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6106 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6107 FLOAT advance_adj = 0.0f;
6108 BOOL got_palette_index;
6109 UINT32 g;
6111 /* start with regular glyphs */
6112 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6113 UINT32 first_glyph = 0;
6115 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6116 if (glyphenum->glyphs[g].num_layers == 0) {
6117 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6118 first_glyph = min(first_glyph, g);
6120 else
6121 glyphenum->glyphindices[g] = 1;
6122 glyphenum->color_advances[g] = glyphenum->advances[g];
6123 if (glyphenum->color_offsets)
6124 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6127 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6128 colorrun->baselineOriginY = glyphenum->origin_y;
6129 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6130 colorrun->paletteIndex = 0xffff;
6131 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6132 glyphenum->has_regular_glyphs = FALSE;
6133 return TRUE;
6135 else {
6136 colorrun->glyphRun.glyphCount = 0;
6137 got_palette_index = FALSE;
6140 advance_adj = 0.0f;
6141 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6143 glyphenum->glyphindices[g] = 1;
6145 /* all glyph layers were returned */
6146 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6147 advance_adj += glyphenum->advances[g];
6148 continue;
6151 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6152 UINT32 index = colorrun->glyphRun.glyphCount;
6153 if (!got_palette_index) {
6154 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6155 /* use foreground color or request one from the font */
6156 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6157 if (colorrun->paletteIndex != 0xffff)
6159 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6160 colorrun->paletteIndex, 1, &colorrun->runColor);
6161 if (FAILED(hr))
6162 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6163 glyphenum->palette, colorrun->paletteIndex, hr);
6165 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6166 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6167 colorrun->baselineOriginY = glyphenum->origin_y;
6168 glyphenum->color_advances[index] = glyphenum->advances[g];
6169 got_palette_index = TRUE;
6172 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6173 /* offsets are relative to glyph origin, nothing to fix up */
6174 if (glyphenum->color_offsets)
6175 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6176 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6177 if (index)
6178 glyphenum->color_advances[index-1] += advance_adj;
6179 colorrun->glyphRun.glyphCount++;
6180 advance_adj = 0.0f;
6182 else
6183 advance_adj += glyphenum->advances[g];
6186 /* reset last advance */
6187 if (colorrun->glyphRun.glyphCount)
6188 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6190 return colorrun->glyphRun.glyphCount > 0;
6193 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6195 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6197 TRACE("%p, %p.\n", iface, has_run);
6199 *has_run = FALSE;
6201 glyphenum->colorrun.glyphRun.glyphCount = 0;
6202 while (glyphenum->current_layer < glyphenum->max_layer_num)
6204 if (colorglyphenum_build_color_run(glyphenum))
6205 break;
6206 else
6207 glyphenum->current_layer++;
6210 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6212 return S_OK;
6215 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6216 DWRITE_COLOR_GLYPH_RUN1 const **run)
6218 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6220 *run = NULL;
6221 return E_NOT_VALID_STATE;
6224 *run = &glyphenum->colorrun;
6225 return S_OK;
6228 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6229 DWRITE_COLOR_GLYPH_RUN const **run)
6231 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6233 TRACE("%p, %p.\n", iface, run);
6235 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6238 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6239 DWRITE_COLOR_GLYPH_RUN1 const **run)
6241 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6243 TRACE("%p, %p.\n", iface, run);
6245 return colorglyphenum_get_current_run(glyphenum, run);
6248 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6250 colorglyphenum_QueryInterface,
6251 colorglyphenum_AddRef,
6252 colorglyphenum_Release,
6253 colorglyphenum_MoveNext,
6254 colorglyphenum_GetCurrentRun,
6255 colorglyphenum1_GetCurrentRun,
6258 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6259 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6260 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6262 struct dwrite_colorglyphenum *colorglyphenum;
6263 BOOL colorfont, has_colored_glyph;
6264 struct dwrite_fontface *fontface;
6265 unsigned int i;
6267 *ret = NULL;
6269 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6271 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6272 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6273 if (!colorfont)
6274 return DWRITE_E_NOCOLOR;
6276 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6277 if (!colorglyphenum)
6278 return E_OUTOFMEMORY;
6280 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6281 colorglyphenum->refcount = 1;
6282 colorglyphenum->origin_x = originX;
6283 colorglyphenum->origin_y = originY;
6284 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6285 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6286 colorglyphenum->glyphs = NULL;
6287 colorglyphenum->run = *run;
6288 colorglyphenum->run.glyphIndices = NULL;
6289 colorglyphenum->run.glyphAdvances = NULL;
6290 colorglyphenum->run.glyphOffsets = NULL;
6291 colorglyphenum->palette = palette;
6292 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6293 colorglyphenum->colr.exists = TRUE;
6294 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6295 colorglyphenum->current_layer = 0;
6296 colorglyphenum->max_layer_num = 0;
6298 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6300 has_colored_glyph = FALSE;
6301 colorglyphenum->has_regular_glyphs = FALSE;
6302 for (i = 0; i < run->glyphCount; i++) {
6303 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6304 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6305 has_colored_glyph = TRUE;
6307 if (colorglyphenum->glyphs[i].num_layers == 0)
6308 colorglyphenum->has_regular_glyphs = TRUE;
6311 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6312 is supposed to proceed normally, like if font had no color info at all. */
6313 if (!has_colored_glyph) {
6314 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6315 return DWRITE_E_NOCOLOR;
6318 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6319 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6320 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6321 if (run->glyphOffsets) {
6322 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6323 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6324 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6327 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6328 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6329 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6330 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6331 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6332 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6333 colorglyphenum->colorrun.measuringMode = measuring_mode;
6334 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6336 if (run->glyphAdvances)
6337 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6338 else
6340 for (i = 0; i < run->glyphCount; ++i)
6341 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6342 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6345 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6347 return S_OK;
6350 /* IDWriteFontFaceReference */
6351 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6353 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6355 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6356 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6357 IsEqualIID(riid, &IID_IUnknown))
6359 *obj = iface;
6360 IDWriteFontFaceReference1_AddRef(iface);
6361 return S_OK;
6364 WARN("%s not implemented.\n", debugstr_guid(riid));
6366 *obj = NULL;
6368 return E_NOINTERFACE;
6371 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6373 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6374 ULONG refcount = InterlockedIncrement(&reference->refcount);
6376 TRACE("%p, refcount %u.\n", iface, refcount);
6378 return refcount;
6381 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6383 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6384 ULONG refcount = InterlockedDecrement(&reference->refcount);
6386 TRACE("%p, refcount %u.\n", iface, refcount);
6388 if (!refcount)
6390 IDWriteFontFile_Release(reference->file);
6391 IDWriteFactory7_Release(reference->factory);
6392 heap_free(reference->axis_values);
6393 heap_free(reference);
6396 return refcount;
6399 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6401 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6403 TRACE("%p, %p.\n", iface, fontface);
6405 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6408 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6409 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6411 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6412 DWRITE_FONT_FILE_TYPE file_type;
6413 DWRITE_FONT_FACE_TYPE face_type;
6414 IDWriteFontFace *fontface;
6415 BOOL is_supported;
6416 UINT32 face_num;
6417 HRESULT hr;
6419 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6421 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6422 if (FAILED(hr))
6423 return hr;
6425 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6426 simulations, &fontface);
6427 if (SUCCEEDED(hr))
6429 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6430 IDWriteFontFace_Release(fontface);
6433 return hr;
6436 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6438 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6439 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6440 BOOL ret;
6442 TRACE("%p, %p.\n", iface, ref);
6444 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6445 reference->simulations == other->simulations;
6446 if (reference->axis_values_count)
6448 ret &= reference->axis_values_count == other->axis_values_count &&
6449 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6452 return ret;
6455 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6457 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6459 TRACE("%p.\n", iface);
6461 return reference->index;
6464 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6466 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6468 TRACE("%p.\n", iface);
6470 return reference->simulations;
6473 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6475 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6476 IDWriteFontFileLoader *loader;
6477 const void *key;
6478 UINT32 key_size;
6479 HRESULT hr;
6481 TRACE("%p, %p.\n", iface, file);
6483 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6484 if (FAILED(hr))
6485 return hr;
6487 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6488 if (FAILED(hr))
6489 return hr;
6491 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6492 IDWriteFontFileLoader_Release(loader);
6494 return hr;
6497 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6499 FIXME("%p.\n", iface);
6501 return 0;
6504 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6506 FIXME("%p.\n", iface);
6508 return 0;
6511 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6513 FIXME("%p, %p.\n", iface, writetime);
6515 return E_NOTIMPL;
6518 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6520 FIXME("%p.\n", iface);
6522 return DWRITE_LOCALITY_LOCAL;
6525 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6527 FIXME("%p.\n", iface);
6529 return E_NOTIMPL;
6532 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6533 WCHAR const *chars, UINT32 count)
6535 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6537 return E_NOTIMPL;
6540 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6541 UINT16 const *glyphs, UINT32 count)
6543 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6545 return E_NOTIMPL;
6548 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6549 UINT64 offset, UINT64 size)
6551 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6553 return E_NOTIMPL;
6556 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6558 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6559 IDWriteFontFace3 *fontface3;
6560 HRESULT hr;
6562 TRACE("%p, %p.\n", iface, fontface);
6564 /* FIXME: created instance should likely respect given axis. */
6565 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6566 &fontface3)))
6568 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6569 IDWriteFontFace3_Release(fontface3);
6572 return hr;
6575 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6577 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6579 TRACE("%p.\n", iface);
6581 return reference->axis_values_count;
6584 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6585 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6587 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6589 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6591 if (value_count < reference->axis_values_count)
6592 return E_NOT_SUFFICIENT_BUFFER;
6594 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6596 return S_OK;
6599 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6601 fontfacereference_QueryInterface,
6602 fontfacereference_AddRef,
6603 fontfacereference_Release,
6604 fontfacereference_CreateFontFace,
6605 fontfacereference_CreateFontFaceWithSimulations,
6606 fontfacereference_Equals,
6607 fontfacereference_GetFontFaceIndex,
6608 fontfacereference_GetSimulations,
6609 fontfacereference_GetFontFile,
6610 fontfacereference_GetLocalFileSize,
6611 fontfacereference_GetFileSize,
6612 fontfacereference_GetFileTime,
6613 fontfacereference_GetLocality,
6614 fontfacereference_EnqueueFontDownloadRequest,
6615 fontfacereference_EnqueueCharacterDownloadRequest,
6616 fontfacereference_EnqueueGlyphDownloadRequest,
6617 fontfacereference_EnqueueFileFragmentDownloadRequest,
6618 fontfacereference1_CreateFontFace,
6619 fontfacereference1_GetFontAxisValueCount,
6620 fontfacereference1_GetFontAxisValues,
6623 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6624 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6625 IDWriteFontFaceReference1 **ret)
6627 struct dwrite_fontfacereference *object;
6629 *ret = NULL;
6631 if (!is_simulation_valid(simulations))
6632 return E_INVALIDARG;
6634 object = heap_alloc_zero(sizeof(*object));
6635 if (!object)
6636 return E_OUTOFMEMORY;
6638 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6639 object->refcount = 1;
6641 object->factory = factory;
6642 IDWriteFactory7_AddRef(object->factory);
6643 object->file = file;
6644 IDWriteFontFile_AddRef(object->file);
6645 object->index = index;
6646 object->simulations = simulations;
6647 if (axis_values_count)
6649 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6651 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6652 return E_OUTOFMEMORY;
6654 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6655 object->axis_values_count = axis_values_count;
6658 *ret = &object->IDWriteFontFaceReference1_iface;
6660 return S_OK;
6663 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6665 TRACE_(dwrite_file)("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6667 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6668 *obj = iface;
6669 IDWriteFontFileStream_AddRef(iface);
6670 return S_OK;
6673 *obj = NULL;
6675 WARN("%s not implemented.\n", debugstr_guid(riid));
6676 return E_NOINTERFACE;
6679 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6681 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6682 ULONG refcount = InterlockedIncrement(&stream->ref);
6684 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6686 return refcount;
6689 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6691 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6692 ULONG refcount = InterlockedDecrement(&stream->ref);
6694 TRACE_(dwrite_file)("%p, refcount %u.\n", iface, refcount);
6696 if (!refcount)
6698 release_inmemory_stream(stream->data);
6699 heap_free(stream);
6702 return refcount;
6705 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6706 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6708 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6710 TRACE_(dwrite_file)("%p, %p, 0x%s, 0x%s, %p.\n", iface, fragment_start,
6711 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6713 *fragment_context = NULL;
6715 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6716 *fragment_start = NULL;
6717 return E_FAIL;
6720 *fragment_start = (char *)stream->data->data + offset;
6721 return S_OK;
6724 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6726 TRACE_(dwrite_file)("%p, %p.\n", iface, 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", iface, size);
6735 *size = stream->data->size;
6737 return S_OK;
6740 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6742 TRACE_(dwrite_file)("%p, %p.\n", iface, last_writetime);
6744 *last_writetime = 0;
6746 return E_NOTIMPL;
6749 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6750 inmemoryfilestream_QueryInterface,
6751 inmemoryfilestream_AddRef,
6752 inmemoryfilestream_Release,
6753 inmemoryfilestream_ReadFileFragment,
6754 inmemoryfilestream_ReleaseFileFragment,
6755 inmemoryfilestream_GetFileSize,
6756 inmemoryfilestream_GetLastWriteTime,
6759 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6760 REFIID riid, void **obj)
6762 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6764 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6765 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6766 IsEqualIID(riid, &IID_IUnknown))
6768 *obj = iface;
6769 IDWriteInMemoryFontFileLoader_AddRef(iface);
6770 return S_OK;
6773 WARN("%s not implemented.\n", debugstr_guid(riid));
6775 *obj = NULL;
6777 return E_NOINTERFACE;
6780 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6782 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6783 ULONG refcount = InterlockedIncrement(&loader->ref);
6785 TRACE("%p, refcount %u.\n", iface, refcount);
6787 return refcount;
6790 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6792 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6793 ULONG refcount = InterlockedDecrement(&loader->ref);
6794 size_t i;
6796 TRACE("%p, refcount %u.\n", iface, refcount);
6798 if (!refcount)
6800 for (i = 0; i < loader->count; ++i)
6801 release_inmemory_stream(loader->streams[i]);
6802 heap_free(loader->streams);
6803 heap_free(loader);
6806 return refcount;
6809 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6810 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6812 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6813 struct dwrite_inmemory_filestream *stream;
6814 DWORD index;
6816 TRACE("%p, %p, %u, %p.\n", iface, key, key_size, ret);
6818 *ret = NULL;
6820 if (key_size != sizeof(DWORD))
6821 return E_INVALIDARG;
6823 index = *(DWORD *)key;
6825 if (index >= loader->count)
6826 return E_INVALIDARG;
6828 if (!(stream = heap_alloc(sizeof(*stream))))
6829 return E_OUTOFMEMORY;
6831 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6832 stream->ref = 1;
6833 stream->data = loader->streams[index];
6834 InterlockedIncrement(&stream->data->ref);
6836 *ret = &stream->IDWriteFontFileStream_iface;
6838 return S_OK;
6841 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6842 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6844 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6845 struct dwrite_inmemory_stream_data *stream;
6846 DWORD key;
6848 TRACE("%p, %p, %p, %u, %p, %p.\n", iface, factory, data, data_size, owner, fontfile);
6850 *fontfile = NULL;
6852 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6853 return E_OUTOFMEMORY;
6855 if (!(stream = heap_alloc(sizeof(*stream))))
6856 return E_OUTOFMEMORY;
6858 stream->ref = 1;
6859 stream->size = data_size;
6860 stream->owner = owner;
6861 if (stream->owner) {
6862 IUnknown_AddRef(stream->owner);
6863 stream->data = (void *)data;
6865 else {
6866 if (!(stream->data = heap_alloc(data_size))) {
6867 heap_free(stream);
6868 return E_OUTOFMEMORY;
6870 memcpy(stream->data, data, data_size);
6873 key = loader->count;
6874 loader->streams[loader->count++] = stream;
6876 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6877 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6880 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6882 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6884 TRACE("%p.\n", iface);
6886 return loader->count;
6889 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6891 inmemoryfontfileloader_QueryInterface,
6892 inmemoryfontfileloader_AddRef,
6893 inmemoryfontfileloader_Release,
6894 inmemoryfontfileloader_CreateStreamFromKey,
6895 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6896 inmemoryfontfileloader_GetFileCount,
6899 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6901 struct dwrite_inmemory_fileloader *loader;
6903 *ret = NULL;
6905 loader = heap_alloc_zero(sizeof(*loader));
6906 if (!loader)
6907 return E_OUTOFMEMORY;
6909 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6910 loader->ref = 1;
6912 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6914 return S_OK;
6917 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6919 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6921 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6922 IsEqualIID(riid, &IID_IUnknown))
6924 *obj = iface;
6925 IDWriteFontResource_AddRef(iface);
6926 return S_OK;
6929 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6931 return E_NOINTERFACE;
6934 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6936 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6937 ULONG refcount = InterlockedIncrement(&resource->refcount);
6939 TRACE("%p, refcount %u.\n", iface, refcount);
6941 return refcount;
6944 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6946 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6947 ULONG refcount = InterlockedDecrement(&resource->refcount);
6949 TRACE("%p, refcount %u.\n", iface, refcount);
6951 if (!refcount)
6953 IDWriteFactory7_Release(resource->factory);
6954 IDWriteFontFile_Release(resource->file);
6955 heap_free(resource);
6958 return refcount;
6961 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6963 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6965 TRACE("%p, %p.\n", iface, fontfile);
6967 *fontfile = resource->file;
6968 IDWriteFontFile_AddRef(*fontfile);
6970 return S_OK;
6973 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6975 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6977 TRACE("%p.\n", iface);
6979 return resource->face_index;
6982 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6984 FIXME("%p.\n", iface);
6986 return 0;
6989 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6990 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6992 FIXME("%p, %p, %u.\n", iface, values, num_values);
6994 return E_NOTIMPL;
6997 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6998 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
7000 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
7002 return E_NOTIMPL;
7005 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
7006 UINT32 axis)
7008 FIXME("%p, %u.\n", iface, axis);
7010 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
7013 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
7014 IDWriteLocalizedStrings **names)
7016 FIXME("%p, %u, %p.\n", iface, axis, names);
7018 return E_NOTIMPL;
7021 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
7023 FIXME("%p, %u.\n", iface, axis);
7025 return 0;
7028 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
7029 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
7031 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
7033 return E_NOTIMPL;
7036 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7038 FIXME("%p.\n", iface);
7040 return FALSE;
7043 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7044 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7045 IDWriteFontFace5 **fontface)
7047 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7048 IDWriteFontFaceReference1 *reference;
7049 HRESULT hr;
7051 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7053 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7054 simulations, axis_values, num_values, &reference);
7055 if (SUCCEEDED(hr))
7057 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7058 IDWriteFontFaceReference1_Release(reference);
7061 return hr;
7064 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7065 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7066 IDWriteFontFaceReference1 **reference)
7068 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7070 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7072 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7073 simulations, axis_values, num_values, reference);
7076 static const IDWriteFontResourceVtbl fontresourcevtbl =
7078 dwritefontresource_QueryInterface,
7079 dwritefontresource_AddRef,
7080 dwritefontresource_Release,
7081 dwritefontresource_GetFontFile,
7082 dwritefontresource_GetFontFaceIndex,
7083 dwritefontresource_GetFontAxisCount,
7084 dwritefontresource_GetDefaultFontAxisValues,
7085 dwritefontresource_GetFontAxisRanges,
7086 dwritefontresource_GetFontAxisAttributes,
7087 dwritefontresource_GetAxisNames,
7088 dwritefontresource_GetAxisValueNameCount,
7089 dwritefontresource_GetAxisValueNames,
7090 dwritefontresource_HasVariations,
7091 dwritefontresource_CreateFontFace,
7092 dwritefontresource_CreateFontFaceReference,
7095 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7096 IDWriteFontResource **ret)
7098 struct dwrite_fontresource *resource;
7100 *ret = NULL;
7102 resource = heap_alloc_zero(sizeof(*resource));
7103 if (!resource)
7104 return E_OUTOFMEMORY;
7106 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7107 resource->refcount = 1;
7108 resource->face_index = face_index;
7109 resource->file = file;
7110 IDWriteFontFile_AddRef(resource->file);
7111 resource->factory = factory;
7112 IDWriteFactory7_AddRef(resource->factory);
7114 *ret = &resource->IDWriteFontResource_iface;
7116 return S_OK;
7119 static HRESULT WINAPI dwritefontsetbuilder_QueryInterface(IDWriteFontSetBuilder2 *iface,
7120 REFIID riid, void **obj)
7122 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
7124 if (IsEqualIID(riid, &IID_IDWriteFontSetBuilder2) ||
7125 IsEqualIID(riid, &IID_IDWriteFontSetBuilder1) ||
7126 IsEqualIID(riid, &IID_IDWriteFontSetBuilder) ||
7127 IsEqualIID(riid, &IID_IUnknown))
7129 *obj = iface;
7130 IDWriteFontSetBuilder2_AddRef(iface);
7131 return S_OK;
7134 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
7135 *obj = NULL;
7136 return E_NOINTERFACE;
7139 static ULONG WINAPI dwritefontsetbuilder_AddRef(IDWriteFontSetBuilder2 *iface)
7141 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7142 ULONG refcount = InterlockedIncrement(&builder->refcount);
7144 TRACE("%p, refcount %u.\n", iface, refcount);
7146 return refcount;
7149 static ULONG WINAPI dwritefontsetbuilder_Release(IDWriteFontSetBuilder2 *iface)
7151 struct dwrite_fontset_builder *builder = impl_from_IDWriteFontSetBuilder2(iface);
7152 ULONG refcount = InterlockedDecrement(&builder->refcount);
7154 TRACE("%p, refcount %u.\n", iface, refcount);
7156 if (!refcount)
7158 IDWriteFactory7_Release(builder->factory);
7159 heap_free(builder);
7162 return refcount;
7165 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference_(IDWriteFontSetBuilder2 *iface,
7166 IDWriteFontFaceReference *ref, DWRITE_FONT_PROPERTY const *props, UINT32 prop_count)
7168 FIXME("%p, %p, %p, %u.\n", iface, ref, props, prop_count);
7170 return E_NOTIMPL;
7173 static HRESULT WINAPI dwritefontsetbuilder_AddFontFaceReference(IDWriteFontSetBuilder2 *iface,
7174 IDWriteFontFaceReference *ref)
7176 FIXME("%p, %p.\n", iface, ref);
7178 return E_NOTIMPL;
7181 static HRESULT WINAPI dwritefontsetbuilder_AddFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet *fontset)
7183 FIXME("%p, %p.\n", iface, fontset);
7185 return E_NOTIMPL;
7188 static HRESULT WINAPI dwritefontsetbuilder_CreateFontSet(IDWriteFontSetBuilder2 *iface, IDWriteFontSet **fontset)
7190 FIXME("%p, %p.\n", iface, fontset);
7192 return E_NOTIMPL;
7195 static HRESULT WINAPI dwritefontsetbuilder1_AddFontFile(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file)
7197 FIXME("%p, %p.\n", iface, file);
7199 return E_NOTIMPL;
7202 static HRESULT WINAPI dwritefontsetbuilder2_AddFont(IDWriteFontSetBuilder2 *iface, IDWriteFontFile *file,
7203 unsigned int face_index, DWRITE_FONT_SIMULATIONS simulations, const DWRITE_FONT_AXIS_VALUE *axis_values,
7204 unsigned int num_values, const DWRITE_FONT_AXIS_RANGE *axis_ranges, unsigned int num_ranges,
7205 const DWRITE_FONT_PROPERTY *props, unsigned int num_properties)
7207 FIXME("%p, %p, %u, %#x, %p, %u, %p, %u, %p, %u.\n", iface, file, face_index, simulations, axis_values, num_values,
7208 axis_ranges, num_ranges, props, num_properties);
7210 return E_NOTIMPL;
7213 static HRESULT WINAPI dwritefontsetbuilder2_AddFontFile(IDWriteFontSetBuilder2 *iface, const WCHAR *filepath)
7215 FIXME("%p, %s.\n", iface, debugstr_w(filepath));
7217 return E_NOTIMPL;
7220 static const IDWriteFontSetBuilder2Vtbl fontsetbuildervtbl =
7222 dwritefontsetbuilder_QueryInterface,
7223 dwritefontsetbuilder_AddRef,
7224 dwritefontsetbuilder_Release,
7225 dwritefontsetbuilder_AddFontFaceReference_,
7226 dwritefontsetbuilder_AddFontFaceReference,
7227 dwritefontsetbuilder_AddFontSet,
7228 dwritefontsetbuilder_CreateFontSet,
7229 dwritefontsetbuilder1_AddFontFile,
7230 dwritefontsetbuilder2_AddFont,
7231 dwritefontsetbuilder2_AddFontFile,
7234 HRESULT create_fontset_builder(IDWriteFactory7 *factory, IDWriteFontSetBuilder2 **ret)
7236 struct dwrite_fontset_builder *builder;
7238 *ret = NULL;
7240 if (!(builder = heap_alloc_zero(sizeof(*builder))))
7241 return E_OUTOFMEMORY;
7243 builder->IDWriteFontSetBuilder2_iface.lpVtbl = &fontsetbuildervtbl;
7244 builder->refcount = 1;
7245 builder->factory = factory;
7246 IDWriteFactory7_AddRef(builder->factory);
7248 *ret = &builder->IDWriteFontSetBuilder2_iface;
7250 return S_OK;