dwrite: Add support for dlng/slng metadata.
[wine.git] / dlls / dwrite / font.c
blob847070816b3e480a9bc63c6d3703e432c4e4cc4f
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;
84 DWRITE_FONT_METRICS1 metrics;
85 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
86 IDWriteLocalizedStrings *family_names;
87 IDWriteLocalizedStrings *names;
89 /* data needed to create fontface instance */
90 DWRITE_FONT_FACE_TYPE face_type;
91 IDWriteFontFile *file;
92 UINT32 face_index;
94 WCHAR *facename;
96 USHORT simulations;
98 LOGFONTW lf;
100 /* used to mark font as tested when scanning for simulation candidate */
101 BOOL bold_sim_tested : 1;
102 BOOL oblique_sim_tested : 1;
105 struct dwrite_fontfamily_data
107 LONG refcount;
109 IDWriteLocalizedStrings *familyname;
111 struct dwrite_font_data **fonts;
112 size_t size;
113 size_t count;
115 BOOL has_normal_face : 1;
116 BOOL has_oblique_face : 1;
117 BOOL has_italic_face : 1;
120 struct dwrite_fontcollection
122 IDWriteFontCollection3 IDWriteFontCollection3_iface;
123 LONG refcount;
125 IDWriteFactory7 *factory;
126 struct dwrite_fontfamily_data **family_data;
127 size_t size;
128 size_t count;
131 struct dwrite_fontfamily
133 IDWriteFontFamily2 IDWriteFontFamily2_iface;
134 IDWriteFontList2 IDWriteFontList2_iface;
135 LONG refcount;
137 struct dwrite_fontfamily_data *data;
138 struct dwrite_fontcollection *collection;
141 struct dwrite_fontlist
143 IDWriteFontList2 IDWriteFontList2_iface;
144 LONG refcount;
146 struct dwrite_font_data **fonts;
147 UINT32 font_count;
148 struct dwrite_fontfamily *family;
151 struct dwrite_font {
152 IDWriteFont3 IDWriteFont3_iface;
153 LONG ref;
155 DWRITE_FONT_STYLE style;
156 struct dwrite_font_data *data;
157 struct dwrite_fontfamily *family;
160 enum runanalysis_flags {
161 RUNANALYSIS_BOUNDS_READY = 1 << 0,
162 RUNANALYSIS_BITMAP_READY = 1 << 1,
163 RUNANALYSIS_USE_TRANSFORM = 1 << 2
166 struct dwrite_glyphrunanalysis {
167 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
168 LONG ref;
170 DWRITE_RENDERING_MODE1 rendering_mode;
171 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
172 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
173 DWRITE_MATRIX m;
174 UINT16 *glyphs;
175 D2D_POINT_2F *origins;
177 UINT8 flags;
178 RECT bounds;
179 BYTE *bitmap;
180 UINT32 max_glyph_bitmap_size;
183 struct dwrite_colorglyphenum
185 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
186 LONG refcount;
188 FLOAT origin_x; /* original run origin */
189 FLOAT origin_y;
191 IDWriteFontFace5 *fontface; /* for convenience */
192 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
193 DWRITE_GLYPH_RUN run; /* base run */
194 UINT32 palette; /* palette index to get layer color from */
195 FLOAT *advances; /* original or measured advances for base glyphs */
196 FLOAT *color_advances; /* returned color run points to this */
197 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
198 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
199 UINT16 *glyphindices; /* returned color run points to this */
200 struct dwrite_colorglyph *glyphs; /* current glyph color info */
201 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
202 UINT16 current_layer; /* enumerator position, updated with MoveNext */
203 UINT16 max_layer_num; /* max number of layers for this run */
204 struct dwrite_fonttable colr; /* used to access layers */
207 #define GLYPH_BLOCK_SHIFT 8
208 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
209 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
210 #define GLYPH_MAX 65536
212 struct dwrite_fontfile {
213 IDWriteFontFile IDWriteFontFile_iface;
214 LONG ref;
216 IDWriteFontFileLoader *loader;
217 void *reference_key;
218 UINT32 key_size;
219 IDWriteFontFileStream *stream;
222 struct dwrite_fontfacereference
224 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
225 LONG refcount;
227 IDWriteFontFile *file;
228 UINT32 index;
229 USHORT simulations;
230 DWRITE_FONT_AXIS_VALUE *axis_values;
231 UINT32 axis_values_count;
232 IDWriteFactory7 *factory;
235 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
237 struct dwrite_fontresource
239 IDWriteFontResource IDWriteFontResource_iface;
240 LONG refcount;
242 IDWriteFontFile *file;
243 UINT32 face_index;
244 IDWriteFactory7 *factory;
247 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
249 struct dwrite_fontface *fontface = context;
250 BOOL exists = FALSE;
252 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
253 size, data_context, &exists)) || !exists)
255 *data = NULL;
256 *size = 0;
257 *data_context = NULL;
261 static void dwrite_release_font_table(void *context, void *data_context)
263 struct dwrite_fontface *fontface = context;
264 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
267 static UINT16 dwrite_get_font_upem(void *context)
269 struct dwrite_fontface *fontface = context;
270 return fontface->metrics.designUnitsPerEm;
273 static const struct shaping_font_ops dwrite_font_ops =
275 dwrite_grab_font_table,
276 dwrite_release_font_table,
277 dwrite_get_font_upem,
280 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
282 if (fontface->shaping_cache)
283 return fontface->shaping_cache;
285 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
288 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
290 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
293 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
295 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
298 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
300 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
303 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
305 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
308 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
310 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
313 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
315 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
318 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
320 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
323 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
325 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
328 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
330 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
333 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
338 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
343 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
345 static const DWRITE_GLYPH_METRICS nil;
346 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
348 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
349 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
350 return S_OK;
353 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
355 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
357 if (!*block) {
358 /* start new block */
359 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
360 if (!*block)
361 return E_OUTOFMEMORY;
364 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
365 return S_OK;
368 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
370 HRESULT hr;
372 if (table->data || !table->exists)
373 return table->data;
375 table->exists = FALSE;
376 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
377 &table->exists);
378 if (FAILED(hr) || !table->exists) {
379 TRACE("Font does not have %s table\n", debugstr_tag(tag));
380 return NULL;
383 return table->data;
386 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
387 struct dwrite_font_propvec *vec)
389 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
390 vec->style = style * 7.0f;
391 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
394 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
396 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
399 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
401 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
404 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
406 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
407 return &fontface->vdmx;
410 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
412 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
413 return &fontface->gasp;
416 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
418 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
419 return &fontface->cpal;
422 static void addref_font_data(struct dwrite_font_data *data)
424 InterlockedIncrement(&data->ref);
427 static void release_font_data(struct dwrite_font_data *data)
429 int i;
431 if (InterlockedDecrement(&data->ref) > 0)
432 return;
434 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
436 if (data->info_strings[i])
437 IDWriteLocalizedStrings_Release(data->info_strings[i]);
439 if (data->names)
440 IDWriteLocalizedStrings_Release(data->names);
442 if (data->family_names)
443 IDWriteLocalizedStrings_Release(data->family_names);
445 IDWriteFontFile_Release(data->file);
446 heap_free(data->facename);
447 heap_free(data);
450 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
452 size_t i;
454 if (InterlockedDecrement(&data->refcount) > 0)
455 return;
457 for (i = 0; i < data->count; ++i)
458 release_font_data(data->fonts[i]);
459 heap_free(data->fonts);
460 IDWriteLocalizedStrings_Release(data->familyname);
461 heap_free(data);
464 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
466 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
467 fontface->cached = NULL;
470 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
472 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
474 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
476 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
477 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
478 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
479 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
480 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
481 IsEqualIID(riid, &IID_IDWriteFontFace) ||
482 IsEqualIID(riid, &IID_IUnknown))
484 *obj = iface;
485 if (InterlockedIncrement(&fontface->refcount) == 1)
487 InterlockedDecrement(&fontface->refcount);
488 *obj = NULL;
489 return E_FAIL;
491 return S_OK;
494 WARN("%s not implemented.\n", debugstr_guid(riid));
496 *obj = NULL;
497 return E_NOINTERFACE;
500 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
502 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
503 ULONG refcount = InterlockedIncrement(&fontface->refcount);
505 TRACE("%p, refcount %u.\n", iface, refcount);
507 return refcount;
510 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
512 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
513 ULONG refcount = InterlockedDecrement(&fontface->refcount);
515 TRACE("%p, refcount %u.\n", iface, refcount);
517 if (!refcount)
519 UINT32 i;
521 if (fontface->cached)
523 factory_lock(fontface->factory);
524 list_remove(&fontface->cached->entry);
525 factory_unlock(fontface->factory);
526 heap_free(fontface->cached);
528 release_scriptshaping_cache(fontface->shaping_cache);
529 if (fontface->cmap.context)
530 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cmap.context);
531 if (fontface->vdmx.context)
532 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
533 if (fontface->gasp.context)
534 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
535 if (fontface->cpal.context)
536 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
537 if (fontface->colr.context)
538 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
539 for (i = 0; i < fontface->file_count; i++)
541 if (fontface->files[i])
542 IDWriteFontFile_Release(fontface->files[i]);
544 if (fontface->stream)
545 IDWriteFontFileStream_Release(fontface->stream);
546 heap_free(fontface->files);
547 if (fontface->names)
548 IDWriteLocalizedStrings_Release(fontface->names);
549 if (fontface->family_names)
550 IDWriteLocalizedStrings_Release(fontface->family_names);
551 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
553 if (fontface->info_strings[i])
554 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
557 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
558 heap_free(fontface->glyphs[i]);
560 freetype_notify_cacheremove(iface);
562 IDWriteFactory7_Release(fontface->factory);
563 heap_free(fontface);
566 return refcount;
569 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
571 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
573 TRACE("%p.\n", iface);
575 return fontface->type;
578 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
579 IDWriteFontFile **fontfiles)
581 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
582 int i;
584 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
586 if (fontfiles == NULL)
588 *number_of_files = fontface->file_count;
589 return S_OK;
592 if (*number_of_files < fontface->file_count)
593 return E_INVALIDARG;
595 for (i = 0; i < fontface->file_count; i++)
597 IDWriteFontFile_AddRef(fontface->files[i]);
598 fontfiles[i] = fontface->files[i];
601 return S_OK;
604 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
606 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
608 TRACE("%p.\n", iface);
610 return fontface->index;
613 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
615 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
617 TRACE("%p.\n", iface);
619 return fontface->simulations;
622 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
624 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
626 TRACE("%p.\n", iface);
628 return !!(fontface->flags & FONT_IS_SYMBOL);
631 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
633 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
635 TRACE("%p, %p.\n", iface, metrics);
637 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
640 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
642 TRACE("%p.\n", iface);
644 return freetype_get_glyphcount(iface);
647 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
648 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
650 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
651 unsigned int i;
652 HRESULT hr;
654 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
656 if (!glyphs)
657 return E_INVALIDARG;
659 if (is_sideways)
660 FIXME("sideways metrics are not supported.\n");
662 for (i = 0; i < glyph_count; i++) {
663 DWRITE_GLYPH_METRICS metrics;
665 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
666 if (hr != S_OK) {
667 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
668 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
669 if (FAILED(hr))
670 return hr;
672 ret[i] = metrics;
675 return S_OK;
678 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
679 UINT32 count, UINT16 *glyphs)
681 if (!glyphs)
682 return E_INVALIDARG;
684 if (!codepoints) {
685 memset(glyphs, 0, count * sizeof(*glyphs));
686 return E_INVALIDARG;
689 freetype_get_glyphs(&fontface->IDWriteFontFace5_iface, fontface->charmap, codepoints, count, glyphs);
690 return S_OK;
693 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
694 UINT32 count, UINT16 *glyphs)
696 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
698 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
700 return fontface_get_glyphs(fontface, codepoints, count, glyphs);
703 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
704 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
706 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
707 struct file_stream_desc stream_desc;
709 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
711 stream_desc.stream = fontface->stream;
712 stream_desc.face_type = fontface->type;
713 stream_desc.face_index = fontface->index;
714 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
717 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
719 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
721 TRACE("%p, %p.\n", iface, table_context);
723 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
726 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
727 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
728 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
730 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
731 count, is_sideways, is_rtl, sink);
733 if (!glyphs || !sink)
734 return E_INVALIDARG;
736 if (is_sideways)
737 FIXME("sideways mode is not supported.\n");
739 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
742 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
743 float ppem, unsigned int gasp)
745 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
747 switch (measuring)
749 case DWRITE_MEASURING_MODE_NATURAL:
751 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
752 mode = DWRITE_RENDERING_MODE_NATURAL;
753 else
754 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
755 break;
757 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
758 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
759 break;
760 case DWRITE_MEASURING_MODE_GDI_NATURAL:
761 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
762 break;
763 default:
767 return mode;
770 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
771 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
773 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
774 unsigned int flags;
775 FLOAT ppem;
777 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
779 if (!params) {
780 *mode = DWRITE_RENDERING_MODE_DEFAULT;
781 return E_INVALIDARG;
784 *mode = IDWriteRenderingParams_GetRenderingMode(params);
785 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
786 return S_OK;
788 ppem = emSize * ppdip;
790 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
791 *mode = DWRITE_RENDERING_MODE_OUTLINE;
792 return S_OK;
795 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
796 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
797 return S_OK;
800 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
801 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
803 DWRITE_FONT_METRICS1 metrics1;
804 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
805 memcpy(metrics, &metrics1, sizeof(*metrics));
806 return hr;
809 static inline int round_metric(FLOAT metric)
811 return (int)floorf(metric + 0.5f);
814 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
816 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
817 return 0;
819 return (fontface->metrics.designUnitsPerEm + 49) / 50;
822 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
823 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
824 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
826 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
827 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
828 DWRITE_MEASURING_MODE mode;
829 FLOAT scale, size;
830 HRESULT hr;
831 UINT32 i;
833 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
834 glyph_count, metrics, is_sideways);
836 if (m && memcmp(m, &identity, sizeof(*m)))
837 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
839 size = emSize * ppdip;
840 scale = size / fontface->metrics.designUnitsPerEm;
841 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
843 for (i = 0; i < glyph_count; i++) {
844 DWRITE_GLYPH_METRICS *ret = metrics + i;
845 DWRITE_GLYPH_METRICS design;
846 BOOL has_contours;
848 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
849 if (FAILED(hr))
850 return hr;
852 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
853 if (has_contours)
854 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
855 else
856 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
858 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
859 SCALE_METRIC(leftSideBearing);
860 SCALE_METRIC(rightSideBearing);
861 SCALE_METRIC(topSideBearing);
862 SCALE_METRIC(advanceHeight);
863 SCALE_METRIC(bottomSideBearing);
864 SCALE_METRIC(verticalOriginY);
865 #undef SCALE_METRIC
868 return S_OK;
871 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
873 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
875 TRACE("%p, %p.\n", iface, metrics);
877 *metrics = fontface->metrics;
880 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
881 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
883 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
884 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
885 UINT16 ascent, descent;
886 FLOAT scale;
888 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
890 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
891 memset(metrics, 0, sizeof(*metrics));
892 return E_INVALIDARG;
895 em_size *= pixels_per_dip;
896 if (m && m->m22 != 0.0f)
897 em_size *= fabs(m->m22);
899 scale = em_size / design->designUnitsPerEm;
900 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
902 ascent = round_metric(design->ascent * scale);
903 descent = round_metric(design->descent * scale);
906 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
907 metrics->designUnitsPerEm = design->designUnitsPerEm;
908 metrics->ascent = round_metric(ascent / scale);
909 metrics->descent = round_metric(descent / scale);
911 SCALE_METRIC(lineGap);
912 SCALE_METRIC(capHeight);
913 SCALE_METRIC(xHeight);
914 SCALE_METRIC(underlinePosition);
915 SCALE_METRIC(underlineThickness);
916 SCALE_METRIC(strikethroughPosition);
917 SCALE_METRIC(strikethroughThickness);
918 SCALE_METRIC(glyphBoxLeft);
919 SCALE_METRIC(glyphBoxTop);
920 SCALE_METRIC(glyphBoxRight);
921 SCALE_METRIC(glyphBoxBottom);
922 SCALE_METRIC(subscriptPositionX);
923 SCALE_METRIC(subscriptPositionY);
924 SCALE_METRIC(subscriptSizeX);
925 SCALE_METRIC(subscriptSizeY);
926 SCALE_METRIC(superscriptPositionX);
927 SCALE_METRIC(superscriptPositionY);
928 SCALE_METRIC(superscriptSizeX);
929 SCALE_METRIC(superscriptSizeY);
931 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
932 #undef SCALE_METRIC
934 return S_OK;
937 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
939 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
941 TRACE("%p, %p.\n", iface, metrics);
943 *metrics = fontface->caret;
946 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
947 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
949 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
951 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
953 *count = 0;
954 if (max_count && !ranges)
955 return E_INVALIDARG;
957 get_fontface_table(iface, MS_CMAP_TAG, &fontface->cmap);
958 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
961 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
963 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
965 TRACE("%p.\n", iface);
967 return !!(fontface->flags & FONT_IS_MONOSPACED);
970 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
971 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
973 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
974 BOOL has_contours;
975 int advance;
977 if (is_sideways)
978 FIXME("Sideways mode is not supported.\n");
980 switch (measuring_mode)
982 case DWRITE_MEASURING_MODE_NATURAL:
983 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
984 glyph, measuring_mode, &has_contours);
985 if (has_contours)
986 advance += adjustment;
988 return advance;
989 case DWRITE_MEASURING_MODE_GDI_NATURAL:
990 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
991 emsize *= ppdip;
992 if (emsize == 0.0f)
993 return 0.0f;
995 if (transform && memcmp(transform, &identity, sizeof(*transform)))
996 FIXME("Transform is not supported.\n");
998 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
999 &has_contours);
1000 if (has_contours)
1001 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1002 else
1003 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1005 return advance;
1006 default:
1007 WARN("Unknown measuring mode %u.\n", measuring_mode);
1008 return 0;
1012 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1013 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1015 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1016 unsigned int i;
1018 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1020 if (is_sideways)
1021 FIXME("sideways mode not supported\n");
1023 for (i = 0; i < glyph_count; ++i)
1025 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1026 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1029 return S_OK;
1032 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1033 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1034 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1036 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1037 DWRITE_MEASURING_MODE measuring_mode;
1038 UINT32 i;
1040 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1041 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1043 if (em_size < 0.0f || ppdip <= 0.0f) {
1044 memset(advances, 0, sizeof(*advances) * glyph_count);
1045 return E_INVALIDARG;
1048 if (em_size == 0.0f) {
1049 memset(advances, 0, sizeof(*advances) * glyph_count);
1050 return S_OK;
1053 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1054 for (i = 0; i < glyph_count; ++i)
1056 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1057 glyphs[i], is_sideways);
1060 return S_OK;
1063 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1064 const UINT16 *indices, INT32 *adjustments)
1066 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1067 UINT32 i;
1069 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1071 if (!(indices || adjustments) || !count)
1072 return E_INVALIDARG;
1074 if (!indices || count == 1) {
1075 memset(adjustments, 0, count*sizeof(INT32));
1076 return E_INVALIDARG;
1079 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1081 memset(adjustments, 0, count*sizeof(INT32));
1082 return S_OK;
1085 for (i = 0; i < count-1; i++)
1086 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1087 adjustments[count-1] = 0;
1089 return S_OK;
1092 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1094 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1096 TRACE("%p.\n", iface);
1098 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1101 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1102 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1103 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1105 DWRITE_GRID_FIT_MODE gridfitmode;
1106 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1107 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1110 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1111 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1113 FIXME("%p, %u, %p, %p: stub\n", iface, glyph_count, nominal_indices, vertical_indices);
1115 return E_NOTIMPL;
1118 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1120 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1122 TRACE("%p.\n", iface);
1124 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1127 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1129 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1131 TRACE("%p.\n", iface);
1133 return !!(fontface->flags & FONT_IS_COLORED);
1136 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1138 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1140 TRACE("%p.\n", iface);
1142 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1145 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1147 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1149 TRACE("%p.\n", iface);
1151 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1154 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1155 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1157 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1159 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1161 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1164 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1165 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1166 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1167 DWRITE_GRID_FIT_MODE *gridfitmode)
1169 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1170 unsigned int flags;
1171 FLOAT emthreshold;
1173 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1174 measuringmode, params, renderingmode, gridfitmode);
1176 if (m)
1177 FIXME("transform not supported %s\n", debugstr_matrix(m));
1179 if (is_sideways)
1180 FIXME("sideways mode not supported\n");
1182 emSize *= max(dpiX, dpiY) / 96.0f;
1184 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1185 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1186 if (params) {
1187 IDWriteRenderingParams2 *params2;
1188 HRESULT hr;
1190 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1191 if (hr == S_OK) {
1192 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1193 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1194 IDWriteRenderingParams2_Release(params2);
1196 else
1197 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1200 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1202 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1204 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1205 if (emSize >= emthreshold)
1206 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1207 else
1208 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1211 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1212 if (emSize >= emthreshold)
1213 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1214 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1215 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1216 else
1217 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1218 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1221 return S_OK;
1224 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface, IDWriteFontFaceReference **ref)
1226 FIXME("%p, %p: stub\n", iface, ref);
1228 return E_NOTIMPL;
1231 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1233 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1235 TRACE("%p, %p.\n", iface, panose);
1237 *panose = fontface->panose;
1240 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1242 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1244 TRACE("%p.\n", iface);
1246 return fontface->weight;
1249 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1251 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1253 TRACE("%p.\n", iface);
1255 return fontface->stretch;
1258 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1260 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1262 TRACE("%p.\n", iface);
1264 return fontface->style;
1267 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1269 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1271 TRACE("%p, %p.\n", iface, names);
1273 return clone_localizedstrings(fontface->family_names, names);
1276 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1278 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1280 TRACE("%p, %p.\n", iface, names);
1282 return clone_localizedstrings(fontface->names, names);
1285 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1286 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1287 IDWriteLocalizedStrings **ret, BOOL *exists)
1289 HRESULT hr = S_OK;
1291 *exists = FALSE;
1292 *ret = NULL;
1294 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1295 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1297 return S_OK;
1300 if (!strings_cache[stringid])
1302 struct file_stream_desc desc = *stream_desc;
1304 if (!desc.stream)
1305 hr = get_filestream_from_file(file, &desc.stream);
1306 if (SUCCEEDED(hr))
1307 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1309 if (!stream_desc->stream && desc.stream)
1310 IDWriteFontFileStream_Release(desc.stream);
1313 if (SUCCEEDED(hr) && strings_cache[stringid])
1315 hr = clone_localizedstrings(strings_cache[stringid], ret);
1316 if (SUCCEEDED(hr))
1317 *exists = TRUE;
1320 return hr;
1323 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1324 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1326 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1327 struct file_stream_desc stream_desc;
1329 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1331 stream_desc.stream = fontface->stream;
1332 stream_desc.face_index = fontface->index;
1333 stream_desc.face_type = fontface->type;
1334 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1337 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1339 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1340 UINT16 index;
1342 TRACE("%p, %#x.\n", iface, ch);
1344 index = 0;
1345 if (FAILED(fontface_get_glyphs(fontface, &ch, 1, &index)))
1346 return FALSE;
1348 return index != 0;
1351 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1352 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1353 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1355 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1356 unsigned int flags;
1357 FLOAT emthreshold;
1359 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1360 measuring_mode, params, rendering_mode, gridfit_mode);
1362 if (m)
1363 FIXME("transform not supported %s\n", debugstr_matrix(m));
1365 if (is_sideways)
1366 FIXME("sideways mode not supported\n");
1368 emSize *= max(dpiX, dpiY) / 96.0f;
1370 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1371 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1372 if (params) {
1373 IDWriteRenderingParams3 *params3;
1374 HRESULT hr;
1376 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1377 if (hr == S_OK) {
1378 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1379 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1380 IDWriteRenderingParams3_Release(params3);
1382 else
1383 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1386 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1388 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1390 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1391 if (emSize >= emthreshold)
1392 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1393 else
1394 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1397 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1398 if (emSize >= emthreshold)
1399 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1400 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1401 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1402 else
1403 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1404 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1407 return S_OK;
1410 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1412 FIXME("%p, %#x: stub\n", iface, ch);
1414 return FALSE;
1417 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1419 FIXME("%p, %u: stub\n", iface, glyph);
1421 return FALSE;
1424 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1425 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1427 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1429 return E_NOTIMPL;
1432 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1433 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1435 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1437 return E_NOTIMPL;
1440 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1441 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1443 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1445 return E_NOTIMPL;
1448 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1450 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1452 TRACE("%p.\n", iface);
1454 return fontface->glyph_image_formats;
1457 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1458 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1460 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1462 return E_NOTIMPL;
1465 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1467 FIXME("%p, %p: stub\n", iface, context);
1470 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1472 FIXME("%p: stub\n", iface);
1474 return 0;
1477 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1478 UINT32 value_count)
1480 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1482 return E_NOTIMPL;
1485 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1487 FIXME("%p: stub\n", iface);
1489 return FALSE;
1492 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1494 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1496 TRACE("%p, %p.\n", iface, resource);
1498 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1501 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1503 dwritefontface_QueryInterface,
1504 dwritefontface_AddRef,
1505 dwritefontface_Release,
1506 dwritefontface_GetType,
1507 dwritefontface_GetFiles,
1508 dwritefontface_GetIndex,
1509 dwritefontface_GetSimulations,
1510 dwritefontface_IsSymbolFont,
1511 dwritefontface_GetMetrics,
1512 dwritefontface_GetGlyphCount,
1513 dwritefontface_GetDesignGlyphMetrics,
1514 dwritefontface_GetGlyphIndices,
1515 dwritefontface_TryGetFontTable,
1516 dwritefontface_ReleaseFontTable,
1517 dwritefontface_GetGlyphRunOutline,
1518 dwritefontface_GetRecommendedRenderingMode,
1519 dwritefontface_GetGdiCompatibleMetrics,
1520 dwritefontface_GetGdiCompatibleGlyphMetrics,
1521 dwritefontface1_GetMetrics,
1522 dwritefontface1_GetGdiCompatibleMetrics,
1523 dwritefontface1_GetCaretMetrics,
1524 dwritefontface1_GetUnicodeRanges,
1525 dwritefontface1_IsMonospacedFont,
1526 dwritefontface1_GetDesignGlyphAdvances,
1527 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1528 dwritefontface1_GetKerningPairAdjustments,
1529 dwritefontface1_HasKerningPairs,
1530 dwritefontface1_GetRecommendedRenderingMode,
1531 dwritefontface1_GetVerticalGlyphVariants,
1532 dwritefontface1_HasVerticalGlyphVariants,
1533 dwritefontface2_IsColorFont,
1534 dwritefontface2_GetColorPaletteCount,
1535 dwritefontface2_GetPaletteEntryCount,
1536 dwritefontface2_GetPaletteEntries,
1537 dwritefontface2_GetRecommendedRenderingMode,
1538 dwritefontface3_GetFontFaceReference,
1539 dwritefontface3_GetPanose,
1540 dwritefontface3_GetWeight,
1541 dwritefontface3_GetStretch,
1542 dwritefontface3_GetStyle,
1543 dwritefontface3_GetFamilyNames,
1544 dwritefontface3_GetFaceNames,
1545 dwritefontface3_GetInformationalStrings,
1546 dwritefontface3_HasCharacter,
1547 dwritefontface3_GetRecommendedRenderingMode,
1548 dwritefontface3_IsCharacterLocal,
1549 dwritefontface3_IsGlyphLocal,
1550 dwritefontface3_AreCharactersLocal,
1551 dwritefontface3_AreGlyphsLocal,
1552 dwritefontface4_GetGlyphImageFormats_,
1553 dwritefontface4_GetGlyphImageFormats,
1554 dwritefontface4_GetGlyphImageData,
1555 dwritefontface4_ReleaseGlyphImageData,
1556 dwritefontface5_GetFontAxisValueCount,
1557 dwritefontface5_GetFontAxisValues,
1558 dwritefontface5_HasVariations,
1559 dwritefontface5_GetFontResource,
1562 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1564 struct dwrite_font_data *data = font->data;
1565 struct fontface_desc desc;
1566 struct list *cached_list;
1567 HRESULT hr;
1569 *fontface = NULL;
1571 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1572 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1573 if (hr == S_OK)
1574 return hr;
1576 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1577 return hr;
1579 desc.factory = font->family->collection->factory;
1580 desc.face_type = data->face_type;
1581 desc.files = &data->file;
1582 desc.files_number = 1;
1583 desc.index = data->face_index;
1584 desc.simulations = data->simulations;
1585 desc.font_data = data;
1586 hr = create_fontface(&desc, cached_list, fontface);
1588 IDWriteFontFileStream_Release(desc.stream);
1589 return hr;
1592 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1594 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1596 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1598 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1599 IsEqualIID(riid, &IID_IDWriteFont2) ||
1600 IsEqualIID(riid, &IID_IDWriteFont1) ||
1601 IsEqualIID(riid, &IID_IDWriteFont) ||
1602 IsEqualIID(riid, &IID_IUnknown))
1604 *obj = iface;
1605 IDWriteFont3_AddRef(iface);
1606 return S_OK;
1609 WARN("%s not implemented.\n", debugstr_guid(riid));
1611 *obj = NULL;
1612 return E_NOINTERFACE;
1615 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1617 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1618 ULONG ref = InterlockedIncrement(&This->ref);
1619 TRACE("(%p)->(%d)\n", This, ref);
1620 return ref;
1623 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1625 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1626 ULONG ref = InterlockedDecrement(&This->ref);
1628 TRACE("(%p)->(%d)\n", This, ref);
1630 if (!ref) {
1631 IDWriteFontFamily2_Release(&This->family->IDWriteFontFamily2_iface);
1632 release_font_data(This->data);
1633 heap_free(This);
1636 return ref;
1639 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1641 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1642 TRACE("(%p)->(%p)\n", This, family);
1644 *family = (IDWriteFontFamily*)This->family;
1645 IDWriteFontFamily_AddRef(*family);
1646 return S_OK;
1649 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1651 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1652 TRACE("(%p)\n", This);
1653 return This->data->weight;
1656 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1658 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1659 TRACE("(%p)\n", This);
1660 return This->data->stretch;
1663 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1665 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1666 TRACE("(%p)\n", This);
1667 return This->style;
1670 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1672 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1674 TRACE("%p.\n", iface);
1676 return !!(font->data->flags & FONT_IS_SYMBOL);
1679 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1681 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1683 TRACE("%p, %p.\n", iface, names);
1685 return clone_localizedstrings(font->data->names, names);
1688 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1689 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1691 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1692 struct dwrite_font_data *data = font->data;
1693 struct file_stream_desc stream_desc;
1695 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1697 /* Stream will be created if necessary. */
1698 stream_desc.stream = NULL;
1699 stream_desc.face_index = data->face_index;
1700 stream_desc.face_type = data->face_type;
1701 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1704 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1706 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1707 TRACE("(%p)\n", This);
1708 return This->data->simulations;
1711 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1713 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1715 TRACE("(%p)->(%p)\n", This, metrics);
1716 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1719 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1721 IDWriteFontFace5 *fontface;
1722 UINT16 index;
1723 HRESULT hr;
1725 *exists = FALSE;
1727 hr = get_fontface_from_font(font, &fontface);
1728 if (FAILED(hr))
1729 return hr;
1731 index = 0;
1732 hr = IDWriteFontFace5_GetGlyphIndices(fontface, &ch, 1, &index);
1733 IDWriteFontFace5_Release(fontface);
1734 if (FAILED(hr))
1735 return hr;
1737 *exists = index != 0;
1738 return S_OK;
1741 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1743 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1745 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1747 return font_has_character(This, ch, exists);
1750 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1752 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1754 TRACE("%p, %p.\n", iface, fontface);
1756 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
1759 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1761 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1762 TRACE("(%p)->(%p)\n", This, metrics);
1763 *metrics = This->data->metrics;
1766 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1768 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1769 TRACE("(%p)->(%p)\n", This, panose);
1770 *panose = This->data->panose;
1773 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1775 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1776 IDWriteFontFace5 *fontface;
1777 HRESULT hr;
1779 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1781 hr = get_fontface_from_font(font, &fontface);
1782 if (FAILED(hr))
1783 return hr;
1785 hr = IDWriteFontFace5_GetUnicodeRanges(fontface, max_count, ranges, count);
1786 IDWriteFontFace5_Release(fontface);
1787 return hr;
1790 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1792 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1794 TRACE("%p.\n", iface);
1796 return !!(font->data->flags & FONT_IS_MONOSPACED);
1799 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1801 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1803 TRACE("%p.\n", iface);
1805 return !!(font->data->flags & FONT_IS_COLORED);
1808 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1810 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1812 TRACE("%p, %p.\n", iface, fontface);
1814 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
1817 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1819 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1820 FIXME("(%p)->(%p): stub\n", This, font);
1821 return FALSE;
1824 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1826 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1828 TRACE("%p, %p.\n", iface, reference);
1830 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)font->family->collection->factory,
1831 font->data->file, font->data->face_index, font->data->simulations, reference);
1834 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1836 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1837 BOOL ret;
1839 TRACE("(%p)->(%#x)\n", This, ch);
1841 return font_has_character(This, ch, &ret) == S_OK && ret;
1844 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1846 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1847 FIXME("(%p): stub\n", This);
1848 return DWRITE_LOCALITY_LOCAL;
1851 static const IDWriteFont3Vtbl dwritefontvtbl = {
1852 dwritefont_QueryInterface,
1853 dwritefont_AddRef,
1854 dwritefont_Release,
1855 dwritefont_GetFontFamily,
1856 dwritefont_GetWeight,
1857 dwritefont_GetStretch,
1858 dwritefont_GetStyle,
1859 dwritefont_IsSymbolFont,
1860 dwritefont_GetFaceNames,
1861 dwritefont_GetInformationalStrings,
1862 dwritefont_GetSimulations,
1863 dwritefont_GetMetrics,
1864 dwritefont_HasCharacter,
1865 dwritefont_CreateFontFace,
1866 dwritefont1_GetMetrics,
1867 dwritefont1_GetPanose,
1868 dwritefont1_GetUnicodeRanges,
1869 dwritefont1_IsMonospacedFont,
1870 dwritefont2_IsColorFont,
1871 dwritefont3_CreateFontFace,
1872 dwritefont3_Equals,
1873 dwritefont3_GetFontFaceReference,
1874 dwritefont3_HasCharacter,
1875 dwritefont3_GetLocality
1878 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1880 if (!iface)
1881 return NULL;
1882 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1883 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1886 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1888 if (!iface)
1889 return NULL;
1890 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1891 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
1894 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
1896 if (!iface)
1897 return NULL;
1898 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
1899 return NULL;
1900 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
1901 IDWriteFontFaceReference1_iface);
1904 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1906 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1907 *lf = font->data->lf;
1910 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1912 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1913 *lf = fontface->lf;
1916 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
1918 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1919 *fontsig = font->data->fontsig;
1920 return S_OK;
1923 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
1925 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1926 *fontsig = fontface->fontsig;
1927 return S_OK;
1930 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1932 struct dwrite_font *This;
1934 *font = NULL;
1936 This = heap_alloc(sizeof(*This));
1937 if (!This)
1938 return E_OUTOFMEMORY;
1940 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1941 This->ref = 1;
1942 This->family = family;
1943 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
1944 This->data = family->data->fonts[index];
1945 This->style = This->data->style;
1946 addref_font_data(This->data);
1948 *font = &This->IDWriteFont3_iface;
1950 return S_OK;
1953 /* IDWriteFontList2 */
1954 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
1956 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1958 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
1959 IsEqualIID(riid, &IID_IDWriteFontList1) ||
1960 IsEqualIID(riid, &IID_IDWriteFontList) ||
1961 IsEqualIID(riid, &IID_IUnknown))
1963 *obj = iface;
1964 IDWriteFontList2_AddRef(iface);
1965 return S_OK;
1968 WARN("%s not implemented.\n", debugstr_guid(riid));
1970 *obj = NULL;
1971 return E_NOINTERFACE;
1974 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
1976 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
1977 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
1979 TRACE("%p, refcount %u.\n", iface, refcount);
1981 return refcount;
1984 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
1986 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
1987 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
1989 TRACE("%p, refcount %u.\n", iface, refcount);
1991 if (!refcount)
1993 UINT32 i;
1995 for (i = 0; i < fontlist->font_count; i++)
1996 release_font_data(fontlist->fonts[i]);
1997 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
1998 heap_free(fontlist->fonts);
1999 heap_free(fontlist);
2002 return refcount;
2005 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2007 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2008 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2011 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2013 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2015 TRACE("%p.\n", iface);
2017 return fontlist->font_count;
2020 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2022 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2024 TRACE("%p, %u, %p.\n", iface, index, font);
2026 *font = NULL;
2028 if (fontlist->font_count == 0)
2029 return S_FALSE;
2031 if (index >= fontlist->font_count)
2032 return E_INVALIDARG;
2034 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2037 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2039 FIXME("%p, %u.\n", iface, index);
2041 return DWRITE_LOCALITY_LOCAL;
2044 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2046 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2048 TRACE("%p, %u, %p.\n", iface, index, font);
2050 *font = NULL;
2052 if (fontlist->font_count == 0)
2053 return S_FALSE;
2055 if (index >= fontlist->font_count)
2056 return E_FAIL;
2058 return create_font(fontlist->family, index, font);
2061 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2062 IDWriteFontFaceReference **reference)
2064 IDWriteFont3 *font;
2065 HRESULT hr;
2067 TRACE("%p, %u, %p.\n", iface, index, reference);
2069 *reference = NULL;
2071 hr = IDWriteFontList2_GetFont(iface, index, &font);
2072 if (FAILED(hr))
2073 return hr;
2075 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2076 IDWriteFont3_Release(font);
2078 return hr;
2081 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2083 FIXME("%p, %p.\n", iface, fontset);
2085 return E_NOTIMPL;
2088 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2090 dwritefontlist_QueryInterface,
2091 dwritefontlist_AddRef,
2092 dwritefontlist_Release,
2093 dwritefontlist_GetFontCollection,
2094 dwritefontlist_GetFontCount,
2095 dwritefontlist_GetFont,
2096 dwritefontlist1_GetFontLocality,
2097 dwritefontlist1_GetFont,
2098 dwritefontlist1_GetFontFaceReference,
2099 dwritefontlist2_GetFontSet,
2102 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2104 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2106 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2108 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2109 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2110 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2111 IsEqualIID(riid, &IID_IUnknown))
2113 *obj = iface;
2115 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2116 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2117 IsEqualIID(riid, &IID_IDWriteFontList))
2119 *obj = &family->IDWriteFontList2_iface;
2121 else
2123 WARN("%s not implemented.\n", debugstr_guid(riid));
2124 *obj = NULL;
2125 return E_NOINTERFACE;
2128 IUnknown_AddRef((IUnknown *)*obj);
2129 return S_OK;
2132 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2134 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2135 ULONG refcount = InterlockedIncrement(&family->refcount);
2137 TRACE("%p, %u.\n", iface, refcount);
2139 return refcount;
2142 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2144 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2145 ULONG refcount = InterlockedDecrement(&family->refcount);
2147 TRACE("%p, %u.\n", iface, refcount);
2149 if (!refcount)
2151 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2152 release_fontfamily_data(family->data);
2153 heap_free(family);
2156 return refcount;
2159 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2161 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2163 TRACE("%p, %p.\n", iface, collection);
2165 *collection = (IDWriteFontCollection *)family->collection;
2166 IDWriteFontCollection_AddRef(*collection);
2167 return S_OK;
2170 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2172 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2174 TRACE("%p.\n", iface);
2176 return family->data->count;
2179 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2181 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2183 TRACE("%p, %u, %p.\n", iface, index, font);
2185 *font = NULL;
2187 if (!family->data->count)
2188 return S_FALSE;
2190 if (index >= family->data->count)
2191 return E_INVALIDARG;
2193 return create_font(family, index, (IDWriteFont3 **)font);
2196 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2198 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2200 TRACE("%p, %p.\n", iface, names);
2202 return clone_localizedstrings(family->data->familyname, names);
2205 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2206 const struct dwrite_font_propvec *req)
2208 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2209 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2210 FLOAT cur_req_prod, next_req_prod;
2212 if (next_to_req < cur_to_req)
2213 return TRUE;
2215 if (next_to_req > cur_to_req)
2216 return FALSE;
2218 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2219 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2221 if (next_req_prod > cur_req_prod)
2222 return TRUE;
2224 if (next_req_prod < cur_req_prod)
2225 return FALSE;
2227 if (next->stretch > cur->stretch)
2228 return TRUE;
2229 if (next->stretch < cur->stretch)
2230 return FALSE;
2232 if (next->style > cur->style)
2233 return TRUE;
2234 if (next->style < cur->style)
2235 return FALSE;
2237 if (next->weight > cur->weight)
2238 return TRUE;
2239 if (next->weight < cur->weight)
2240 return FALSE;
2242 /* full match, no reason to prefer new variant */
2243 return FALSE;
2246 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2247 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2249 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2250 struct dwrite_font_propvec req;
2251 size_t i, match;
2253 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2255 if (!family->data->count)
2257 *font = NULL;
2258 return DWRITE_E_NOFONT;
2261 init_font_prop_vec(weight, stretch, style, &req);
2262 match = 0;
2264 for (i = 1; i < family->data->count; ++i)
2266 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2267 match = i;
2270 return create_font(family, match, (IDWriteFont3 **)font);
2273 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2275 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2277 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2280 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2282 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2285 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2287 UINT32 b = fonts->font_count - 1, j, t;
2289 while (1) {
2290 t = b;
2292 for (j = 0; j < b; j++) {
2293 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2294 struct dwrite_font_data *s = fonts->fonts[j];
2295 fonts->fonts[j] = fonts->fonts[j+1];
2296 fonts->fonts[j+1] = s;
2297 t = j;
2301 if (t == b)
2302 break;
2303 b = t;
2307 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2308 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2310 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2311 matching_filter_func func = NULL;
2312 struct dwrite_font_propvec req;
2313 struct dwrite_fontlist *fonts;
2314 size_t i;
2316 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2318 *ret = NULL;
2320 fonts = heap_alloc(sizeof(*fonts));
2321 if (!fonts)
2322 return E_OUTOFMEMORY;
2324 /* Allocate as many as family has, not all of them will be necessary used. */
2325 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2326 if (!fonts->fonts) {
2327 heap_free(fonts);
2328 return E_OUTOFMEMORY;
2331 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2332 fonts->refcount = 1;
2333 fonts->family = family;
2334 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2335 fonts->font_count = 0;
2337 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2338 if (style == DWRITE_FONT_STYLE_NORMAL) {
2339 if (family->data->has_normal_face || family->data->has_italic_face)
2340 func = is_font_acceptable_for_normal;
2342 else /* requested oblique or italic */ {
2343 if (family->data->has_oblique_face || family->data->has_italic_face)
2344 func = is_font_acceptable_for_oblique_italic;
2347 for (i = 0; i < family->data->count; ++i)
2349 if (!func || func(family->data->fonts[i]))
2351 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2352 addref_font_data(family->data->fonts[i]);
2353 fonts->font_count++;
2357 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2358 init_font_prop_vec(weight, stretch, style, &req);
2359 matchingfonts_sort(fonts, &req);
2361 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2362 return S_OK;
2365 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2367 FIXME("%p, %u.\n", iface, index);
2369 return DWRITE_LOCALITY_LOCAL;
2372 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2374 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2376 TRACE("%p, %u, %p.\n", iface, index, font);
2378 *font = NULL;
2380 if (!family->data->count)
2381 return S_FALSE;
2383 if (index >= family->data->count)
2384 return E_FAIL;
2386 return create_font(family, index, font);
2389 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2390 IDWriteFontFaceReference **reference)
2392 IDWriteFont3 *font;
2393 HRESULT hr;
2395 TRACE("%p, %u, %p.\n", iface, index, reference);
2397 *reference = NULL;
2399 hr = IDWriteFontFamily2_GetFont(iface, index, &font);
2400 if (FAILED(hr))
2401 return hr;
2403 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2404 IDWriteFont3_Release(font);
2406 return hr;
2409 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2410 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2412 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2414 return E_NOTIMPL;
2417 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2419 FIXME("%p, %p.\n", iface, fontset);
2421 return E_NOTIMPL;
2424 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2426 dwritefontfamily_QueryInterface,
2427 dwritefontfamily_AddRef,
2428 dwritefontfamily_Release,
2429 dwritefontfamily_GetFontCollection,
2430 dwritefontfamily_GetFontCount,
2431 dwritefontfamily_GetFont,
2432 dwritefontfamily_GetFamilyNames,
2433 dwritefontfamily_GetFirstMatchingFont,
2434 dwritefontfamily_GetMatchingFonts,
2435 dwritefontfamily1_GetFontLocality,
2436 dwritefontfamily1_GetFont,
2437 dwritefontfamily1_GetFontFaceReference,
2438 dwritefontfamily2_GetMatchingFonts,
2439 dwritefontfamily2_GetFontSet,
2442 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2444 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2445 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2448 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2450 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2451 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2454 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2456 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2457 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2460 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2461 IDWriteFontCollection **collection)
2463 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2464 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2467 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2469 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2470 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2473 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2475 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2476 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2479 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2481 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2482 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2485 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2487 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2488 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2491 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2492 IDWriteFontFaceReference **reference)
2494 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2495 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2498 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2500 FIXME("%p, %p.\n", iface, fontset);
2502 return E_NOTIMPL;
2505 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2507 dwritefontfamilylist_QueryInterface,
2508 dwritefontfamilylist_AddRef,
2509 dwritefontfamilylist_Release,
2510 dwritefontfamilylist_GetFontCollection,
2511 dwritefontfamilylist_GetFontCount,
2512 dwritefontfamilylist_GetFont,
2513 dwritefontfamilylist1_GetFontLocality,
2514 dwritefontfamilylist1_GetFont,
2515 dwritefontfamilylist1_GetFontFaceReference,
2516 dwritefontfamilylist2_GetFontSet,
2519 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2520 struct dwrite_fontfamily **family)
2522 struct dwrite_fontfamily *object;
2524 *family = NULL;
2526 object = heap_alloc(sizeof(*object));
2527 if (!object)
2528 return E_OUTOFMEMORY;
2530 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2531 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2532 object->refcount = 1;
2533 object->collection = collection;
2534 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2535 object->data = collection->family_data[index];
2536 InterlockedIncrement(&object->data->refcount);
2538 *family = object;
2540 return S_OK;
2543 BOOL is_system_collection(IDWriteFontCollection *collection)
2545 void *obj;
2546 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2549 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2551 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2553 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2555 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2556 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2557 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2558 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2559 IsEqualIID(riid, &IID_IUnknown))
2561 *obj = iface;
2562 IDWriteFontCollection3_AddRef(iface);
2563 return S_OK;
2566 *obj = NULL;
2568 if (IsEqualIID(riid, &IID_issystemcollection))
2569 return S_OK;
2571 WARN("%s not implemented.\n", debugstr_guid(riid));
2573 return E_NOINTERFACE;
2576 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2578 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2580 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2581 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2582 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2583 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2584 IsEqualIID(riid, &IID_IUnknown))
2586 *obj = iface;
2587 IDWriteFontCollection3_AddRef(iface);
2588 return S_OK;
2591 WARN("%s not implemented.\n", debugstr_guid(riid));
2593 *obj = NULL;
2595 return E_NOINTERFACE;
2598 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2600 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2601 ULONG refcount = InterlockedIncrement(&collection->refcount);
2603 TRACE("%p, refcount %d.\n", collection, refcount);
2605 return refcount;
2608 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2610 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2611 ULONG refcount = InterlockedDecrement(&collection->refcount);
2612 size_t i;
2614 TRACE("%p, refcount %d.\n", iface, refcount);
2616 if (!refcount)
2618 factory_detach_fontcollection(collection->factory, iface);
2619 for (i = 0; i < collection->count; ++i)
2620 release_fontfamily_data(collection->family_data[i]);
2621 heap_free(collection->family_data);
2622 heap_free(collection);
2625 return refcount;
2628 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2630 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2632 TRACE("%p.\n", iface);
2634 return collection->count;
2637 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2638 IDWriteFontFamily **ret)
2640 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2641 struct dwrite_fontfamily *family;
2642 HRESULT hr;
2644 TRACE("%p, %u, %p.\n", iface, index, ret);
2646 *ret = NULL;
2648 if (index >= collection->count)
2649 return E_FAIL;
2651 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2652 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2654 return hr;
2657 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2659 size_t i;
2661 for (i = 0; i < collection->count; ++i)
2663 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2664 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2665 HRESULT hr;
2667 for (j = 0; j < count; j++) {
2668 WCHAR buffer[255];
2669 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2670 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2671 return i;
2675 return ~0u;
2678 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2679 UINT32 *index, BOOL *exists)
2681 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2683 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2685 *index = collection_find_family(collection, name);
2686 *exists = *index != ~0u;
2687 return S_OK;
2690 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2692 UINT32 left_key_size, right_key_size;
2693 const void *left_key, *right_key;
2694 HRESULT hr;
2696 if (left == right)
2697 return TRUE;
2699 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2700 if (FAILED(hr))
2701 return FALSE;
2703 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2704 if (FAILED(hr))
2705 return FALSE;
2707 if (left_key_size != right_key_size)
2708 return FALSE;
2710 return !memcmp(left_key, right_key, left_key_size);
2713 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2714 IDWriteFont **font)
2716 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2717 struct dwrite_fontfamily *family;
2718 BOOL found_font = FALSE;
2719 IDWriteFontFile *file;
2720 UINT32 face_index, count;
2721 size_t i, j;
2722 HRESULT hr;
2724 TRACE("%p, %p, %p.\n", iface, face, font);
2726 *font = NULL;
2728 if (!face)
2729 return E_INVALIDARG;
2731 count = 1;
2732 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2733 if (FAILED(hr))
2734 return hr;
2735 face_index = IDWriteFontFace_GetIndex(face);
2737 found_font = FALSE;
2738 for (i = 0; i < collection->count; ++i)
2740 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2742 for (j = 0; j < family_data->count; ++j)
2744 struct dwrite_font_data *font_data = family_data->fonts[j];
2746 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2747 found_font = TRUE;
2748 break;
2752 if (found_font)
2753 break;
2755 IDWriteFontFile_Release(file);
2757 if (!found_font)
2758 return DWRITE_E_NOFONT;
2760 hr = create_fontfamily(collection, i, &family);
2761 if (FAILED(hr))
2762 return hr;
2764 hr = create_font(family, j, (IDWriteFont3 **)font);
2765 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
2766 return hr;
2769 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
2771 FIXME("%p, %p.\n", iface, fontset);
2773 return E_NOTIMPL;
2776 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2777 IDWriteFontFamily1 **ret)
2779 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2780 struct dwrite_fontfamily *family;
2781 HRESULT hr;
2783 TRACE("%p, %u, %p.\n", iface, index, ret);
2785 *ret = NULL;
2787 if (index >= collection->count)
2788 return E_FAIL;
2790 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2791 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
2793 return hr;
2796 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
2797 UINT32 index, IDWriteFontFamily2 **family)
2799 FIXME("%p, %u, %p.\n", iface, index, family);
2801 return E_NOTIMPL;
2804 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
2805 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
2806 IDWriteFontList2 **fontlist)
2808 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
2810 return E_NOTIMPL;
2813 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
2815 FIXME("%p.\n", iface);
2817 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
2820 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
2822 FIXME("%p, %p.\n", iface, fontset);
2824 return E_NOTIMPL;
2827 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
2829 FIXME("%p.\n", iface);
2831 return NULL;
2834 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
2836 dwritefontcollection_QueryInterface,
2837 dwritefontcollection_AddRef,
2838 dwritefontcollection_Release,
2839 dwritefontcollection_GetFontFamilyCount,
2840 dwritefontcollection_GetFontFamily,
2841 dwritefontcollection_FindFamilyName,
2842 dwritefontcollection_GetFontFromFontFace,
2843 dwritefontcollection1_GetFontSet,
2844 dwritefontcollection1_GetFontFamily,
2845 dwritefontcollection2_GetFontFamily,
2846 dwritefontcollection2_GetMatchingFonts,
2847 dwritefontcollection2_GetFontFamilyModel,
2848 dwritefontcollection2_GetFontSet,
2849 dwritefontcollection3_GetExpirationEvent,
2852 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
2854 dwritesystemfontcollection_QueryInterface,
2855 dwritefontcollection_AddRef,
2856 dwritefontcollection_Release,
2857 dwritefontcollection_GetFontFamilyCount,
2858 dwritefontcollection_GetFontFamily,
2859 dwritefontcollection_FindFamilyName,
2860 dwritefontcollection_GetFontFromFontFace,
2861 dwritefontcollection1_GetFontSet,
2862 dwritefontcollection1_GetFontFamily,
2863 dwritefontcollection2_GetFontFamily,
2864 dwritefontcollection2_GetMatchingFonts,
2865 dwritefontcollection2_GetFontFamilyModel,
2866 dwritefontcollection2_GetFontSet,
2867 dwritefontcollection3_GetExpirationEvent,
2870 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2872 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
2873 sizeof(*family_data->fonts)))
2875 return E_OUTOFMEMORY;
2878 family_data->fonts[family_data->count++] = font_data;
2879 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2880 family_data->has_normal_face = 1;
2881 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2882 family_data->has_oblique_face = 1;
2883 else
2884 family_data->has_italic_face = 1;
2885 return S_OK;
2888 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
2889 struct dwrite_fontfamily_data *family)
2891 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
2892 sizeof(*collection->family_data)))
2894 return E_OUTOFMEMORY;
2897 collection->family_data[collection->count++] = family;
2898 return S_OK;
2901 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2903 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2904 collection->refcount = 1;
2905 collection->count = 0;
2906 collection->size = 0;
2907 collection->family_data = NULL;
2909 return S_OK;
2912 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2914 IDWriteFontFileLoader *loader;
2915 const void *key;
2916 UINT32 key_size;
2917 HRESULT hr;
2919 *stream = NULL;
2921 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2922 if (FAILED(hr))
2923 return hr;
2925 hr = IDWriteFontFile_GetLoader(file, &loader);
2926 if (FAILED(hr))
2927 return hr;
2929 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2930 IDWriteFontFileLoader_Release(loader);
2931 if (FAILED(hr))
2932 return hr;
2934 return hr;
2937 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2939 BOOL exists = FALSE;
2940 UINT32 index;
2941 HRESULT hr;
2943 buffer[0] = 0;
2944 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2945 if (FAILED(hr) || !exists)
2946 return;
2948 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2951 static int trim_spaces(WCHAR *in, WCHAR *ret)
2953 int len;
2955 while (isspaceW(*in))
2956 in++;
2958 ret[0] = 0;
2959 if (!(len = strlenW(in)))
2960 return 0;
2962 while (isspaceW(in[len-1]))
2963 len--;
2965 memcpy(ret, in, len*sizeof(WCHAR));
2966 ret[len] = 0;
2968 return len;
2971 struct name_token {
2972 struct list entry;
2973 const WCHAR *ptr;
2974 INT len; /* token length */
2975 INT fulllen; /* full length including following separators */
2978 static inline BOOL is_name_separator_char(WCHAR ch)
2980 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2983 struct name_pattern {
2984 const WCHAR *part1; /* NULL indicates end of list */
2985 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2988 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2990 const struct name_pattern *pattern;
2991 struct name_token *token;
2992 int i = 0;
2994 while ((pattern = &patterns[i++])->part1) {
2995 int len_part1 = strlenW(pattern->part1);
2996 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2998 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2999 if (len_part2 == 0) {
3000 /* simple case with single part pattern */
3001 if (token->len != len_part1)
3002 continue;
3004 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3005 if (match) *match = *token;
3006 list_remove(&token->entry);
3007 heap_free(token);
3008 return TRUE;
3011 else {
3012 struct name_token *next_token;
3013 struct list *next_entry;
3015 /* pattern parts are stored in reading order, tokens list is reversed */
3016 if (token->len < len_part2)
3017 continue;
3019 /* it's possible to have combined string as a token, like ExtraCondensed */
3020 if (token->len == len_part1 + len_part2) {
3021 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3022 continue;
3024 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3025 continue;
3027 /* combined string match */
3028 if (match) *match = *token;
3029 list_remove(&token->entry);
3030 heap_free(token);
3031 return TRUE;
3034 /* now it's only possible to have two tokens matched to respective pattern parts */
3035 if (token->len != len_part2)
3036 continue;
3038 next_entry = list_next(tokens, &token->entry);
3039 if (next_entry) {
3040 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3041 if (next_token->len != len_part1)
3042 continue;
3044 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3045 continue;
3047 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3048 continue;
3050 /* both parts matched, remove tokens */
3051 if (match) {
3052 match->ptr = next_token->ptr;
3053 match->len = (token->ptr - next_token->ptr) + token->len;
3055 list_remove(&token->entry);
3056 list_remove(&next_token->entry);
3057 heap_free(next_token);
3058 heap_free(token);
3059 return TRUE;
3065 if (match) {
3066 match->ptr = NULL;
3067 match->len = 0;
3069 return FALSE;
3072 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3074 static const WCHAR itaW[] = {'i','t','a',0};
3075 static const WCHAR italW[] = {'i','t','a','l',0};
3076 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3077 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3079 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3080 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3081 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3082 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3084 static const struct name_pattern italic_patterns[] = {
3085 { itaW },
3086 { italW },
3087 { italicW },
3088 { cursiveW },
3089 { kursivW },
3090 { NULL }
3093 static const struct name_pattern oblique_patterns[] = {
3094 { inclinedW },
3095 { obliqueW },
3096 { backslantedW },
3097 { backslantW },
3098 { slantedW },
3099 { NULL }
3102 /* italic patterns first */
3103 if (match_pattern_list(tokens, italic_patterns, match))
3104 return DWRITE_FONT_STYLE_ITALIC;
3106 /* oblique patterns */
3107 if (match_pattern_list(tokens, oblique_patterns, match))
3108 return DWRITE_FONT_STYLE_OBLIQUE;
3110 return style;
3113 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3114 struct name_token *match)
3116 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3117 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3118 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3119 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3120 static const WCHAR wideW[] = {'w','i','d','e',0};
3121 static const WCHAR condW[] = {'c','o','n','d',0};
3123 static const struct name_pattern ultracondensed_patterns[] = {
3124 { extraW, compressedW },
3125 { extW, compressedW },
3126 { ultraW, compressedW },
3127 { ultraW, condensedW },
3128 { ultraW, condW },
3129 { NULL }
3132 static const struct name_pattern extracondensed_patterns[] = {
3133 { compressedW },
3134 { extraW, condensedW },
3135 { extW, condensedW },
3136 { extraW, condW },
3137 { extW, condW },
3138 { NULL }
3141 static const struct name_pattern semicondensed_patterns[] = {
3142 { narrowW },
3143 { compactW },
3144 { semiW, condensedW },
3145 { semiW, condW },
3146 { NULL }
3149 static const struct name_pattern semiexpanded_patterns[] = {
3150 { wideW },
3151 { semiW, expandedW },
3152 { semiW, extendedW },
3153 { NULL }
3156 static const struct name_pattern extraexpanded_patterns[] = {
3157 { extraW, expandedW },
3158 { extW, expandedW },
3159 { extraW, extendedW },
3160 { extW, extendedW },
3161 { NULL }
3164 static const struct name_pattern ultraexpanded_patterns[] = {
3165 { ultraW, expandedW },
3166 { ultraW, extendedW },
3167 { NULL }
3170 static const struct name_pattern condensed_patterns[] = {
3171 { condensedW },
3172 { condW },
3173 { NULL }
3176 static const struct name_pattern expanded_patterns[] = {
3177 { expandedW },
3178 { extendedW },
3179 { NULL }
3182 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3183 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3185 if (match_pattern_list(tokens, extracondensed_patterns, match))
3186 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3188 if (match_pattern_list(tokens, semicondensed_patterns, match))
3189 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3191 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3192 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3194 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3195 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3197 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3198 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3200 if (match_pattern_list(tokens, condensed_patterns, match))
3201 return DWRITE_FONT_STRETCH_CONDENSED;
3203 if (match_pattern_list(tokens, expanded_patterns, match))
3204 return DWRITE_FONT_STRETCH_EXPANDED;
3206 return stretch;
3209 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3210 struct name_token *match)
3212 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3213 static const WCHAR nordW[] = {'n','o','r','d',0};
3215 static const struct name_pattern thin_patterns[] = {
3216 { extraW, thinW },
3217 { extW, thinW },
3218 { ultraW, thinW },
3219 { NULL }
3222 static const struct name_pattern extralight_patterns[] = {
3223 { extraW, lightW },
3224 { extW, lightW },
3225 { ultraW, lightW },
3226 { NULL }
3229 static const struct name_pattern semilight_patterns[] = {
3230 { semiW, lightW },
3231 { NULL }
3234 static const struct name_pattern demibold_patterns[] = {
3235 { semiW, boldW },
3236 { demiW, boldW },
3237 { NULL }
3240 static const struct name_pattern extrabold_patterns[] = {
3241 { extraW, boldW },
3242 { extW, boldW },
3243 { ultraW, boldW },
3244 { NULL }
3247 static const struct name_pattern extrablack_patterns[] = {
3248 { extraW, blackW },
3249 { extW, blackW },
3250 { ultraW, blackW },
3251 { NULL }
3254 static const struct name_pattern bold_patterns[] = {
3255 { boldW },
3256 { NULL }
3259 static const struct name_pattern thin2_patterns[] = {
3260 { thinW },
3261 { NULL }
3264 static const struct name_pattern light_patterns[] = {
3265 { lightW },
3266 { NULL }
3269 static const struct name_pattern medium_patterns[] = {
3270 { mediumW },
3271 { NULL }
3274 static const struct name_pattern black_patterns[] = {
3275 { blackW },
3276 { heavyW },
3277 { nordW },
3278 { NULL }
3281 static const struct name_pattern demibold2_patterns[] = {
3282 { demiW },
3283 { NULL }
3286 static const struct name_pattern extrabold2_patterns[] = {
3287 { ultraW },
3288 { NULL }
3291 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3292 matching pattern. */
3294 if (match_pattern_list(tokens, thin_patterns, match))
3295 return DWRITE_FONT_WEIGHT_THIN;
3297 if (match_pattern_list(tokens, extralight_patterns, match))
3298 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3300 if (match_pattern_list(tokens, semilight_patterns, match))
3301 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3303 if (match_pattern_list(tokens, demibold_patterns, match))
3304 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3306 if (match_pattern_list(tokens, extrabold_patterns, match))
3307 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3309 if (match_pattern_list(tokens, extrablack_patterns, match))
3310 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3312 if (match_pattern_list(tokens, bold_patterns, match))
3313 return DWRITE_FONT_WEIGHT_BOLD;
3315 if (match_pattern_list(tokens, thin2_patterns, match))
3316 return DWRITE_FONT_WEIGHT_THIN;
3318 if (match_pattern_list(tokens, light_patterns, match))
3319 return DWRITE_FONT_WEIGHT_LIGHT;
3321 if (match_pattern_list(tokens, medium_patterns, match))
3322 return DWRITE_FONT_WEIGHT_MEDIUM;
3324 if (match_pattern_list(tokens, black_patterns, match))
3325 return DWRITE_FONT_WEIGHT_BLACK;
3327 if (match_pattern_list(tokens, black_patterns, match))
3328 return DWRITE_FONT_WEIGHT_BLACK;
3330 if (match_pattern_list(tokens, demibold2_patterns, match))
3331 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3333 if (match_pattern_list(tokens, extrabold2_patterns, match))
3334 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3336 /* FIXME: use abbreviated names to extract weight */
3338 return weight;
3341 struct knownweight_entry {
3342 const WCHAR *nameW;
3343 DWRITE_FONT_WEIGHT weight;
3346 static int compare_knownweights(const void *a, const void* b)
3348 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3349 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3350 int ret = 0;
3352 if (target > entry->weight)
3353 ret = 1;
3354 else if (target < entry->weight)
3355 ret = -1;
3357 return ret;
3360 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3362 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3363 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3364 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3365 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3366 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3367 const struct knownweight_entry *ptr;
3369 static const struct knownweight_entry knownweights[] = {
3370 { thinW, DWRITE_FONT_WEIGHT_THIN },
3371 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3372 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3373 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3374 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3375 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3376 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3377 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3378 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3379 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3382 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3383 compare_knownweights);
3384 if (!ptr) {
3385 nameW[0] = 0;
3386 return FALSE;
3389 strcpyW(nameW, ptr->nameW);
3390 return TRUE;
3393 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3395 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3396 strW[name->len] = 0;
3399 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3400 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3402 static const WCHAR bookW[] = {'B','o','o','k',0};
3403 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3404 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3405 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3406 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3408 static const WCHAR *regular_patterns[] = {
3409 bookW,
3410 normalW,
3411 regularW,
3412 romanW,
3413 uprightW,
3414 NULL
3417 const WCHAR *regular_ptr = NULL, *ptr;
3418 int i = 0;
3420 if (len == -1)
3421 len = strlenW(facenameW);
3423 /* remove rightmost regular variant from face name */
3424 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3425 int pattern_len = strlenW(ptr);
3426 WCHAR *src;
3428 if (pattern_len > len)
3429 continue;
3431 src = facenameW + len - pattern_len;
3432 while (src >= facenameW) {
3433 if (!strncmpiW(src, ptr, pattern_len)) {
3434 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3435 len = strlenW(facenameW);
3436 regular_ptr = ptr;
3437 break;
3439 else
3440 src--;
3444 return regular_ptr;
3447 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3449 const WCHAR *ptr;
3451 list_init(tokens);
3452 ptr = nameW;
3454 while (*ptr) {
3455 struct name_token *token = heap_alloc(sizeof(*token));
3456 token->ptr = ptr;
3457 token->len = 0;
3458 token->fulllen = 0;
3460 while (*ptr && !is_name_separator_char(*ptr)) {
3461 token->len++;
3462 token->fulllen++;
3463 ptr++;
3466 /* skip separators */
3467 while (is_name_separator_char(*ptr)) {
3468 token->fulllen++;
3469 ptr++;
3472 list_add_head(tokens, &token->entry);
3476 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3478 struct name_token *token, *token2;
3479 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3480 int len;
3482 list_remove(&token->entry);
3484 /* don't include last separator */
3485 len = list_empty(tokens) ? token->len : token->fulllen;
3486 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3487 nameW += len;
3489 heap_free(token);
3491 *nameW = 0;
3494 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3496 struct name_token stretch_name, weight_name, style_name;
3497 WCHAR familynameW[255], facenameW[255], finalW[255];
3498 WCHAR weightW[32], stretchW[32], styleW[32];
3499 const WCHAR *regular_ptr = NULL;
3500 DWRITE_FONT_STRETCH stretch;
3501 DWRITE_FONT_WEIGHT weight;
3502 struct list tokens;
3503 int len;
3505 /* remove leading and trailing spaces from family and face name */
3506 trim_spaces(familyW, familynameW);
3507 len = trim_spaces(faceW, facenameW);
3509 /* remove rightmost regular variant from face name */
3510 regular_ptr = facename_remove_regular_term(facenameW, len);
3512 /* append face name to family name, FIXME check if face name is a substring of family name */
3513 if (*facenameW) {
3514 strcatW(familynameW, spaceW);
3515 strcatW(familynameW, facenameW);
3518 /* tokenize with " .-_" */
3519 fontname_tokenize(&tokens, familynameW);
3521 /* extract and resolve style */
3522 font->style = font_extract_style(&tokens, font->style, &style_name);
3524 /* extract stretch */
3525 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3527 /* extract weight */
3528 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3530 /* resolve weight */
3531 if (weight != font->weight) {
3532 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3533 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3534 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3535 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3536 !(abs(weight - font->weight) <= 150 &&
3537 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3538 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3539 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3541 font->weight = weight;
3545 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3546 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3547 stretch itself is normal (extracted stretch is never normal). */
3548 if (stretch != font->stretch) {
3549 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3550 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3551 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3553 font->stretch = stretch;
3557 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3559 /* get final combined string from what's left in token list, list is released */
3560 fontname_tokens_to_str(&tokens, finalW);
3562 if (!strcmpW(familyW, finalW))
3563 return FALSE;
3565 /* construct face name */
3566 strcpyW(familyW, finalW);
3568 /* resolved weight name */
3569 if (weight_name.ptr)
3570 font_name_token_to_str(&weight_name, weightW);
3571 /* ignore normal weight */
3572 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3573 weightW[0] = 0;
3574 /* for known weight values use appropriate names */
3575 else if (is_known_weight_value(font->weight, weightW)) {
3577 /* use Wnnn format as a fallback in case weight is not one of known values */
3578 else {
3579 static const WCHAR fmtW[] = {'W','%','d',0};
3580 sprintfW(weightW, fmtW, font->weight);
3583 /* resolved stretch name */
3584 if (stretch_name.ptr)
3585 font_name_token_to_str(&stretch_name, stretchW);
3586 /* ignore normal stretch */
3587 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3588 stretchW[0] = 0;
3589 /* use predefined stretch names */
3590 else {
3591 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3592 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3593 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3594 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3595 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3596 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3598 static const WCHAR *stretchnamesW[] = {
3599 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3600 ultracondensedW,
3601 extracondensedW,
3602 condensedW,
3603 semicondensedW,
3604 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3605 semiexpandedW,
3606 expandedW,
3607 extraexpandedW,
3608 ultraexpandedW
3610 strcpyW(stretchW, stretchnamesW[font->stretch]);
3613 /* resolved style name */
3614 if (style_name.ptr)
3615 font_name_token_to_str(&style_name, styleW);
3616 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3617 styleW[0] = 0;
3618 /* use predefined names */
3619 else {
3620 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3621 strcpyW(styleW, italicW);
3622 else
3623 strcpyW(styleW, obliqueW);
3626 /* use Regular match if it was found initially */
3627 if (!*weightW && !*stretchW && !*styleW)
3628 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3629 else {
3630 faceW[0] = 0;
3631 if (*stretchW)
3632 strcpyW(faceW, stretchW);
3633 if (*weightW) {
3634 if (*faceW)
3635 strcatW(faceW, spaceW);
3636 strcatW(faceW, weightW);
3638 if (*styleW) {
3639 if (*faceW)
3640 strcatW(faceW, spaceW);
3641 strcatW(faceW, styleW);
3645 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3646 return TRUE;
3649 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3651 struct file_stream_desc stream_desc;
3652 struct dwrite_font_props props;
3653 struct dwrite_font_data *data;
3654 WCHAR familyW[255], faceW[255];
3655 HRESULT hr;
3657 *ret = NULL;
3659 data = heap_alloc_zero(sizeof(*data));
3660 if (!data)
3661 return E_OUTOFMEMORY;
3663 data->ref = 1;
3664 data->file = desc->files[0];
3665 data->face_index = desc->index;
3666 data->face_type = desc->face_type;
3667 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3668 data->bold_sim_tested = 0;
3669 data->oblique_sim_tested = 0;
3670 IDWriteFontFile_AddRef(data->file);
3672 stream_desc.stream = desc->stream;
3673 stream_desc.face_type = desc->face_type;
3674 stream_desc.face_index = desc->index;
3675 opentype_get_font_properties(&stream_desc, &props);
3676 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3677 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3679 /* get family name from font file */
3680 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3681 if (FAILED(hr)) {
3682 WARN("unable to get family name from font\n");
3683 release_font_data(data);
3684 return hr;
3687 data->style = props.style;
3688 data->stretch = props.stretch;
3689 data->weight = props.weight;
3690 data->panose = props.panose;
3691 data->fontsig = props.fontsig;
3692 data->lf = props.lf;
3693 data->flags = props.flags;
3695 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3696 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3697 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3698 set_en_localizedstring(data->family_names, familyW);
3699 set_en_localizedstring(data->names, faceW);
3702 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3704 *ret = data;
3705 return S_OK;
3708 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3709 const WCHAR *facenameW, struct dwrite_font_data **ret)
3711 struct dwrite_font_data *data;
3713 *ret = NULL;
3715 data = heap_alloc_zero(sizeof(*data));
3716 if (!data)
3717 return E_OUTOFMEMORY;
3719 *data = *src;
3720 data->ref = 1;
3721 data->simulations |= sim;
3722 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3723 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3724 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3725 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3726 memset(data->info_strings, 0, sizeof(data->info_strings));
3727 data->names = NULL;
3728 IDWriteFontFile_AddRef(data->file);
3729 IDWriteLocalizedStrings_AddRef(data->family_names);
3731 create_localizedstrings(&data->names);
3732 add_localizedstring(data->names, enusW, facenameW);
3734 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3736 *ret = data;
3737 return S_OK;
3740 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3742 struct dwrite_fontfamily_data *data;
3744 data = heap_alloc_zero(sizeof(*data));
3745 if (!data)
3746 return E_OUTOFMEMORY;
3748 data->refcount = 1;
3749 data->familyname = familyname;
3750 IDWriteLocalizedStrings_AddRef(familyname);
3752 *ret = data;
3754 return S_OK;
3757 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3759 size_t i, j, heaviest;
3761 for (i = 0; i < family->count; ++i)
3763 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3764 heaviest = i;
3766 if (family->fonts[i]->bold_sim_tested)
3767 continue;
3769 family->fonts[i]->bold_sim_tested = 1;
3770 for (j = i; j < family->count; ++j)
3772 if (family->fonts[j]->bold_sim_tested)
3773 continue;
3775 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3776 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3777 if (family->fonts[j]->weight > weight) {
3778 weight = family->fonts[j]->weight;
3779 heaviest = j;
3781 family->fonts[j]->bold_sim_tested = 1;
3785 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3786 static const struct name_pattern weightsim_patterns[] = {
3787 { extraW, lightW },
3788 { extW, lightW },
3789 { ultraW, lightW },
3790 { semiW, lightW },
3791 { semiW, boldW },
3792 { demiW, boldW },
3793 { boldW },
3794 { thinW },
3795 { lightW },
3796 { mediumW },
3797 { demiW },
3798 { NULL }
3801 WCHAR facenameW[255], initialW[255];
3802 struct dwrite_font_data *boldface;
3803 struct list tokens;
3805 /* add Bold simulation based on heaviest face data */
3807 /* Simulated face name should only contain Bold as weight term,
3808 so remove existing regular and weight terms. */
3809 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
3810 facename_remove_regular_term(initialW, -1);
3812 /* remove current weight pattern */
3813 fontname_tokenize(&tokens, initialW);
3814 match_pattern_list(&tokens, weightsim_patterns, NULL);
3815 fontname_tokens_to_str(&tokens, facenameW);
3817 /* Bold suffix for new name */
3818 if (*facenameW)
3819 strcatW(facenameW, spaceW);
3820 strcatW(facenameW, boldW);
3822 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3823 boldface->bold_sim_tested = 1;
3824 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3825 fontfamily_add_font(family, boldface);
3831 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3833 size_t i, j;
3835 for (i = 0; i < family->count; ++i)
3837 UINT32 regular = ~0u, oblique = ~0u;
3838 struct dwrite_font_data *obliqueface;
3839 WCHAR facenameW[255];
3841 if (family->fonts[i]->oblique_sim_tested)
3842 continue;
3844 family->fonts[i]->oblique_sim_tested = 1;
3845 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3846 regular = i;
3847 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3848 oblique = i;
3850 /* find regular style with same weight/stretch values */
3851 for (j = i; j < family->count; ++j)
3853 if (family->fonts[j]->oblique_sim_tested)
3854 continue;
3856 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3857 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3859 family->fonts[j]->oblique_sim_tested = 1;
3860 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3861 regular = j;
3863 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3864 oblique = j;
3867 if (regular != ~0u && oblique != ~0u)
3868 break;
3871 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3872 if (regular == ~0u)
3873 continue;
3875 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3876 if (oblique != ~0u)
3877 continue;
3879 /* add oblique simulation based on this regular face */
3881 /* remove regular term if any, append 'Oblique' */
3882 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
3883 facename_remove_regular_term(facenameW, -1);
3885 if (*facenameW)
3886 strcatW(facenameW, spaceW);
3887 strcatW(facenameW, obliqueW);
3889 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3890 obliqueface->oblique_sim_tested = 1;
3891 obliqueface->lf.lfItalic = 1;
3892 fontfamily_add_font(family, obliqueface);
3897 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3898 const WCHAR *replacement_name)
3900 UINT32 i = collection_find_family(collection, replacement_name);
3901 struct dwrite_fontfamily_data *target;
3902 IDWriteLocalizedStrings *strings;
3903 HRESULT hr;
3905 /* replacement does not exist */
3906 if (i == ~0u)
3907 return FALSE;
3909 hr = create_localizedstrings(&strings);
3910 if (FAILED(hr))
3911 return FALSE;
3913 /* add a new family with target name, reuse font data from replacement */
3914 add_localizedstring(strings, enusW, target_name);
3915 hr = init_fontfamily_data(strings, &target);
3916 if (hr == S_OK) {
3917 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3918 WCHAR nameW[255];
3920 for (i = 0; i < replacement->count; ++i)
3922 fontfamily_add_font(target, replacement->fonts[i]);
3923 addref_font_data(replacement->fonts[i]);
3926 fontcollection_add_family(collection, target);
3927 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
3928 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3930 IDWriteLocalizedStrings_Release(strings);
3931 return TRUE;
3934 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3935 system font collections. */
3936 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3938 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3939 WCHAR *name;
3940 void *data;
3941 HKEY hkey;
3943 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3944 return;
3946 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3947 RegCloseKey(hkey);
3948 return;
3951 max_namelen++; /* returned value doesn't include room for '\0' */
3952 name = heap_alloc(max_namelen * sizeof(WCHAR));
3953 data = heap_alloc(max_datalen);
3955 datalen = max_datalen;
3956 namelen = max_namelen;
3957 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3958 if (collection_find_family(collection, name) == ~0u) {
3959 if (type == REG_MULTI_SZ) {
3960 WCHAR *replacement = data;
3961 while (*replacement) {
3962 if (fontcollection_add_replacement(collection, name, replacement))
3963 break;
3964 replacement += strlenW(replacement) + 1;
3967 else if (type == REG_SZ)
3968 fontcollection_add_replacement(collection, name, data);
3970 else
3971 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3973 datalen = max_datalen;
3974 namelen = max_namelen;
3977 heap_free(data);
3978 heap_free(name);
3979 RegCloseKey(hkey);
3982 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3983 IDWriteFontCollection3 **ret)
3985 struct fontfile_enum {
3986 struct list entry;
3987 IDWriteFontFile *file;
3989 struct fontfile_enum *fileenum, *fileenum2;
3990 struct dwrite_fontcollection *collection;
3991 struct list scannedfiles;
3992 BOOL current = FALSE;
3993 HRESULT hr = S_OK;
3994 size_t i;
3996 *ret = NULL;
3998 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3999 if (!collection) return E_OUTOFMEMORY;
4001 hr = init_font_collection(collection, is_system);
4002 if (FAILED(hr)) {
4003 heap_free(collection);
4004 return hr;
4007 *ret = &collection->IDWriteFontCollection3_iface;
4009 TRACE("building font collection:\n");
4011 list_init(&scannedfiles);
4012 while (hr == S_OK) {
4013 DWRITE_FONT_FACE_TYPE face_type;
4014 DWRITE_FONT_FILE_TYPE file_type;
4015 BOOL supported, same = FALSE;
4016 IDWriteFontFileStream *stream;
4017 IDWriteFontFile *file;
4018 UINT32 face_count;
4020 current = FALSE;
4021 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4022 if (FAILED(hr) || !current)
4023 break;
4025 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4026 if (FAILED(hr))
4027 break;
4029 /* check if we've scanned this file already */
4030 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4031 if ((same = is_same_fontfile(fileenum->file, file)))
4032 break;
4035 if (same) {
4036 IDWriteFontFile_Release(file);
4037 continue;
4040 if (FAILED(get_filestream_from_file(file, &stream))) {
4041 IDWriteFontFile_Release(file);
4042 continue;
4045 /* Unsupported formats are skipped. */
4046 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4047 if (FAILED(hr) || !supported || face_count == 0) {
4048 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4049 IDWriteFontFileStream_Release(stream);
4050 IDWriteFontFile_Release(file);
4051 hr = S_OK;
4052 continue;
4055 /* add to scanned list */
4056 fileenum = heap_alloc(sizeof(*fileenum));
4057 fileenum->file = file;
4058 list_add_tail(&scannedfiles, &fileenum->entry);
4060 for (i = 0; i < face_count; ++i)
4062 struct dwrite_font_data *font_data;
4063 struct fontface_desc desc;
4064 WCHAR familyW[255];
4065 UINT32 index;
4067 desc.factory = factory;
4068 desc.face_type = face_type;
4069 desc.files = &file;
4070 desc.stream = stream;
4071 desc.files_number = 1;
4072 desc.index = i;
4073 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4074 desc.font_data = NULL;
4076 /* Allocate an initialize new font data structure. */
4077 hr = init_font_data(&desc, &font_data);
4078 if (FAILED(hr))
4080 /* move to next one */
4081 hr = S_OK;
4082 continue;
4085 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4087 /* ignore dot named faces */
4088 if (familyW[0] == '.')
4090 WARN("Ignoring face %s\n", debugstr_w(familyW));
4091 release_font_data(font_data);
4092 continue;
4095 index = collection_find_family(collection, familyW);
4096 if (index != ~0u)
4097 hr = fontfamily_add_font(collection->family_data[index], font_data);
4098 else {
4099 struct dwrite_fontfamily_data *family_data;
4101 /* create and init new family */
4102 hr = init_fontfamily_data(font_data->family_names, &family_data);
4103 if (hr == S_OK) {
4104 /* add font to family, family - to collection */
4105 hr = fontfamily_add_font(family_data, font_data);
4106 if (hr == S_OK)
4107 hr = fontcollection_add_family(collection, family_data);
4109 if (FAILED(hr))
4110 release_fontfamily_data(family_data);
4114 if (FAILED(hr))
4115 break;
4118 IDWriteFontFileStream_Release(stream);
4121 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4122 IDWriteFontFile_Release(fileenum->file);
4123 list_remove(&fileenum->entry);
4124 heap_free(fileenum);
4127 for (i = 0; i < collection->count; ++i)
4129 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4130 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4133 if (is_system)
4134 fontcollection_add_replacements(collection);
4136 collection->factory = factory;
4137 IDWriteFactory7_AddRef(factory);
4139 return hr;
4142 struct system_fontfile_enumerator
4144 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4145 LONG ref;
4147 IDWriteFactory7 *factory;
4148 HKEY hkey;
4149 int index;
4151 WCHAR *filename;
4152 DWORD filename_size;
4155 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4157 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4160 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4162 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4163 IDWriteFontFileEnumerator_AddRef(iface);
4164 *obj = iface;
4165 return S_OK;
4168 WARN("%s not implemented.\n", debugstr_guid(riid));
4170 *obj = NULL;
4172 return E_NOINTERFACE;
4175 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4177 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4178 return InterlockedIncrement(&enumerator->ref);
4181 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4183 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4184 ULONG ref = InterlockedDecrement(&enumerator->ref);
4186 if (!ref)
4188 IDWriteFactory7_Release(enumerator->factory);
4189 RegCloseKey(enumerator->hkey);
4190 heap_free(enumerator->filename);
4191 heap_free(enumerator);
4194 return ref;
4197 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4199 HRESULT hr;
4201 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4202 if (!strchrW(filename, '\\')) {
4203 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4204 WCHAR fullpathW[MAX_PATH];
4206 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4207 strcatW(fullpathW, fontsW);
4208 strcatW(fullpathW, filename);
4210 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4212 else
4213 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4215 return hr;
4218 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4220 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4222 *file = NULL;
4224 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4225 return E_FAIL;
4227 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4230 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4232 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4233 WCHAR name_buf[256], *name = name_buf;
4234 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4235 HRESULT hr = S_OK;
4236 LONG r;
4238 *current = FALSE;
4239 enumerator->index++;
4241 /* iterate until we find next string value */
4242 for (;;) {
4243 do {
4244 name_count = max_name_count;
4245 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4247 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4248 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4249 if (r == ERROR_MORE_DATA) {
4250 if (name_count >= max_name_count) {
4251 if (name != name_buf) heap_free(name);
4252 max_name_count *= 2;
4253 name = heap_alloc(max_name_count * sizeof(*name));
4254 if (!name) return E_OUTOFMEMORY;
4256 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4257 heap_free(enumerator->filename);
4258 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4259 enumerator->filename = heap_alloc(enumerator->filename_size);
4260 if (!enumerator->filename) {
4261 hr = E_OUTOFMEMORY;
4262 goto err;
4266 } while (r == ERROR_MORE_DATA);
4268 if (r != ERROR_SUCCESS) {
4269 enumerator->filename[0] = 0;
4270 break;
4272 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4273 if (type == REG_SZ && *name != '@') {
4274 *current = TRUE;
4275 break;
4277 enumerator->index++;
4279 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4281 err:
4282 if (name != name_buf) heap_free(name);
4283 return hr;
4286 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4288 systemfontfileenumerator_QueryInterface,
4289 systemfontfileenumerator_AddRef,
4290 systemfontfileenumerator_Release,
4291 systemfontfileenumerator_MoveNext,
4292 systemfontfileenumerator_GetCurrentFontFile
4295 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4297 struct system_fontfile_enumerator *enumerator;
4298 static const WCHAR fontslistW[] = {
4299 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4300 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4301 'F','o','n','t','s',0
4304 *ret = NULL;
4306 enumerator = heap_alloc(sizeof(*enumerator));
4307 if (!enumerator)
4308 return E_OUTOFMEMORY;
4310 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4311 enumerator->ref = 1;
4312 enumerator->factory = factory;
4313 enumerator->index = -1;
4314 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4315 enumerator->filename = heap_alloc(enumerator->filename_size);
4316 if (!enumerator->filename) {
4317 heap_free(enumerator);
4318 return E_OUTOFMEMORY;
4321 IDWriteFactory7_AddRef(factory);
4323 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4325 ERR("failed to open fonts list key\n");
4326 IDWriteFactory7_Release(factory);
4327 heap_free(enumerator->filename);
4328 heap_free(enumerator);
4329 return E_FAIL;
4332 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4334 return S_OK;
4337 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4339 IDWriteFontFileEnumerator *enumerator;
4340 HRESULT hr;
4342 *collection = NULL;
4344 hr = create_system_fontfile_enumerator(factory, &enumerator);
4345 if (FAILED(hr))
4346 return hr;
4348 TRACE("building system font collection for factory %p\n", factory);
4349 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4350 IDWriteFontFileEnumerator_Release(enumerator);
4351 return hr;
4354 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4355 const WCHAR *keynameW, const WCHAR *pathW)
4357 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};
4358 static const WCHAR emptyW[] = {0};
4359 struct dwrite_fontfamily_data *family_data;
4360 IDWriteLocalizedStrings *names;
4361 DWRITE_FONT_FACE_TYPE face_type;
4362 DWRITE_FONT_FILE_TYPE file_type;
4363 IDWriteFontFileStream *stream;
4364 IDWriteFontFile *file;
4365 UINT32 face_count, i;
4366 BOOL supported;
4367 HRESULT hr;
4369 /* create font file from this path */
4370 hr = create_local_file_reference(factory, pathW, &file);
4371 if (FAILED(hr))
4372 return S_FALSE;
4374 if (FAILED(get_filestream_from_file(file, &stream))) {
4375 IDWriteFontFile_Release(file);
4376 return S_FALSE;
4379 /* Unsupported formats are skipped. */
4380 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4381 if (FAILED(hr) || !supported || face_count == 0) {
4382 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4383 IDWriteFontFileStream_Release(stream);
4384 IDWriteFontFile_Release(file);
4385 return S_FALSE;
4388 /* create and init new family */
4390 /* Family names are added for non-specific locale, represented with empty string.
4391 Default family appears with empty family name. */
4392 create_localizedstrings(&names);
4393 if (!strcmpiW(keynameW, defaultfontW))
4394 add_localizedstring(names, emptyW, emptyW);
4395 else
4396 add_localizedstring(names, emptyW, keynameW);
4398 hr = init_fontfamily_data(names, &family_data);
4399 IDWriteLocalizedStrings_Release(names);
4400 if (hr != S_OK) {
4401 IDWriteFontFile_Release(file);
4402 return hr;
4405 /* fill with faces */
4406 for (i = 0; i < face_count; i++) {
4407 struct dwrite_font_data *font_data;
4408 struct fontface_desc desc;
4410 /* alloc and init new font data structure */
4411 desc.factory = factory;
4412 desc.face_type = face_type;
4413 desc.index = i;
4414 desc.files = &file;
4415 desc.stream = stream;
4416 desc.files_number = 1;
4417 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4418 desc.font_data = NULL;
4420 hr = init_font_data(&desc, &font_data);
4421 if (FAILED(hr))
4422 continue;
4424 /* add font to family */
4425 hr = fontfamily_add_font(family_data, font_data);
4426 if (hr != S_OK)
4427 release_font_data(font_data);
4430 /* add family to collection */
4431 hr = fontcollection_add_family(collection, family_data);
4432 if (FAILED(hr))
4433 release_fontfamily_data(family_data);
4434 IDWriteFontFileStream_Release(stream);
4435 IDWriteFontFile_Release(file);
4437 return hr;
4440 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4442 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4443 struct dwrite_fontcollection *collection;
4444 static const WCHAR emptyW[] = {0};
4445 WCHAR eudckeypathW[16];
4446 HKEY eudckey;
4447 DWORD index;
4448 BOOL exists;
4449 LONG retval;
4450 HRESULT hr;
4451 size_t i;
4453 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4455 *ret = NULL;
4457 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4458 if (!collection) return E_OUTOFMEMORY;
4460 hr = init_font_collection(collection, FALSE);
4461 if (FAILED(hr)) {
4462 heap_free(collection);
4463 return hr;
4466 *ret = &collection->IDWriteFontCollection3_iface;
4467 collection->factory = factory;
4468 IDWriteFactory7_AddRef(factory);
4470 /* return empty collection if EUDC fonts are not configured */
4471 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4472 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4473 return S_OK;
4475 retval = ERROR_SUCCESS;
4476 index = 0;
4477 while (retval != ERROR_NO_MORE_ITEMS) {
4478 WCHAR keynameW[64], pathW[MAX_PATH];
4479 DWORD type, path_len, name_len;
4481 path_len = ARRAY_SIZE(pathW);
4482 name_len = ARRAY_SIZE(keynameW);
4483 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4484 if (retval || type != REG_SZ)
4485 continue;
4487 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4488 if (hr != S_OK)
4489 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4491 RegCloseKey(eudckey);
4493 /* try to add global default if not defined for specific codepage */
4494 exists = FALSE;
4495 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4496 &index, &exists);
4497 if (FAILED(hr) || !exists) {
4498 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4499 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4500 if (hr != S_OK)
4501 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4504 /* EUDC collection offers simulated faces too */
4505 for (i = 0; i < collection->count; ++i)
4507 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4508 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4511 return S_OK;
4514 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4516 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4518 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4520 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4522 *obj = iface;
4523 IDWriteFontFile_AddRef(iface);
4524 return S_OK;
4527 WARN("%s not implemented.\n", debugstr_guid(riid));
4529 *obj = NULL;
4530 return E_NOINTERFACE;
4533 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4535 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4536 ULONG ref = InterlockedIncrement(&This->ref);
4537 TRACE("(%p)->(%d)\n", This, ref);
4538 return ref;
4541 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4543 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4544 ULONG ref = InterlockedDecrement(&This->ref);
4546 TRACE("(%p)->(%d)\n", This, ref);
4548 if (!ref)
4550 IDWriteFontFileLoader_Release(This->loader);
4551 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4552 heap_free(This->reference_key);
4553 heap_free(This);
4556 return ref;
4559 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4561 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4562 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4563 *fontFileReferenceKey = This->reference_key;
4564 *fontFileReferenceKeySize = This->key_size;
4566 return S_OK;
4569 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4571 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4572 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4573 *fontFileLoader = This->loader;
4574 IDWriteFontFileLoader_AddRef(This->loader);
4576 return S_OK;
4579 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4580 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4582 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4583 IDWriteFontFileStream *stream;
4584 HRESULT hr;
4586 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4588 *is_supported = FALSE;
4589 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4590 if (face_type)
4591 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4592 *face_count = 0;
4594 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4595 if (FAILED(hr))
4596 return hr;
4598 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4600 /* TODO: Further Analysis */
4601 IDWriteFontFileStream_Release(stream);
4602 return S_OK;
4605 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4606 dwritefontfile_QueryInterface,
4607 dwritefontfile_AddRef,
4608 dwritefontfile_Release,
4609 dwritefontfile_GetReferenceKey,
4610 dwritefontfile_GetLoader,
4611 dwritefontfile_Analyze,
4614 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4615 IDWriteFontFile **ret)
4617 struct dwrite_fontfile *file;
4618 void *key;
4620 *ret = NULL;
4622 file = heap_alloc(sizeof(*file));
4623 key = heap_alloc(key_size);
4624 if (!file || !key) {
4625 heap_free(file);
4626 heap_free(key);
4627 return E_OUTOFMEMORY;
4630 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4631 file->ref = 1;
4632 IDWriteFontFileLoader_AddRef(loader);
4633 file->loader = loader;
4634 file->stream = NULL;
4635 file->reference_key = key;
4636 memcpy(file->reference_key, reference_key, key_size);
4637 file->key_size = key_size;
4639 *ret = &file->IDWriteFontFile_iface;
4641 return S_OK;
4644 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4646 struct file_stream_desc stream_desc;
4647 struct dwrite_font_data *font_data;
4648 struct dwrite_fontface *fontface;
4649 HRESULT hr;
4650 int i;
4652 *ret = NULL;
4654 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4655 if (!fontface)
4656 return E_OUTOFMEMORY;
4658 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4659 if (!fontface->files) {
4660 heap_free(fontface);
4661 return E_OUTOFMEMORY;
4664 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4665 fontface->refcount = 1;
4666 fontface->type = desc->face_type;
4667 fontface->file_count = desc->files_number;
4668 fontface->cmap.exists = TRUE;
4669 fontface->vdmx.exists = TRUE;
4670 fontface->gasp.exists = TRUE;
4671 fontface->cpal.exists = TRUE;
4672 fontface->colr.exists = TRUE;
4673 fontface->index = desc->index;
4674 fontface->simulations = desc->simulations;
4675 fontface->factory = desc->factory;
4676 IDWriteFactory7_AddRef(fontface->factory);
4678 for (i = 0; i < fontface->file_count; i++) {
4679 fontface->files[i] = desc->files[i];
4680 IDWriteFontFile_AddRef(fontface->files[i]);
4682 fontface->stream = desc->stream;
4683 IDWriteFontFileStream_AddRef(fontface->stream);
4685 stream_desc.stream = fontface->stream;
4686 stream_desc.face_type = desc->face_type;
4687 stream_desc.face_index = desc->index;
4688 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4689 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4690 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4691 /* TODO: test what happens if caret is already slanted */
4692 if (fontface->caret.slopeRise == 1) {
4693 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4694 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4698 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace5_iface);
4699 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4700 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4701 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace5_iface))
4702 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4703 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4705 /* Font properties are reused from font object when 'normal' face creation path is used:
4706 collection -> family -> matching font -> fontface.
4708 If face is created directly from factory we have to go through properties resolution.
4710 if (desc->font_data)
4712 font_data = desc->font_data;
4713 addref_font_data(font_data);
4715 else
4717 hr = init_font_data(desc, &font_data);
4718 if (FAILED(hr))
4720 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
4721 return hr;
4725 fontface->weight = font_data->weight;
4726 fontface->style = font_data->style;
4727 fontface->stretch = font_data->stretch;
4728 fontface->panose = font_data->panose;
4729 fontface->fontsig = font_data->fontsig;
4730 fontface->lf = font_data->lf;
4731 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
4732 fontface->names = font_data->names;
4733 if (fontface->names)
4734 IDWriteLocalizedStrings_AddRef(fontface->names);
4735 fontface->family_names = font_data->family_names;
4736 if (fontface->family_names)
4737 IDWriteLocalizedStrings_AddRef(fontface->family_names);
4738 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
4739 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
4741 if (fontface->info_strings[i])
4742 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
4744 release_font_data(font_data);
4746 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
4748 *ret = &fontface->IDWriteFontFace5_iface;
4750 return S_OK;
4753 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4754 struct local_refkey
4756 FILETIME writetime;
4757 WCHAR name[1];
4760 struct local_cached_stream
4762 struct list entry;
4763 IDWriteFontFileStream *stream;
4764 struct local_refkey *key;
4765 UINT32 key_size;
4768 struct dwrite_localfontfilestream
4770 IDWriteFontFileStream IDWriteFontFileStream_iface;
4771 LONG ref;
4773 struct local_cached_stream *entry;
4774 const void *file_ptr;
4775 UINT64 size;
4778 struct dwrite_localfontfileloader {
4779 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4780 LONG ref;
4782 struct list streams;
4783 CRITICAL_SECTION cs;
4786 static struct dwrite_localfontfileloader local_fontfile_loader;
4788 struct dwrite_inmemory_stream_data
4790 LONG ref;
4791 IUnknown *owner;
4792 void *data;
4793 UINT32 size;
4796 struct dwrite_inmemory_filestream
4798 IDWriteFontFileStream IDWriteFontFileStream_iface;
4799 LONG ref;
4801 struct dwrite_inmemory_stream_data *data;
4804 struct dwrite_inmemory_fileloader
4806 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
4807 LONG ref;
4809 struct dwrite_inmemory_stream_data **streams;
4810 size_t size;
4811 size_t count;
4814 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4816 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4819 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4821 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4824 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
4826 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
4829 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4831 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
4834 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
4836 if (InterlockedDecrement(&stream->ref) == 0) {
4837 if (stream->owner)
4838 IUnknown_Release(stream->owner);
4839 else
4840 heap_free(stream->data);
4841 heap_free(stream);
4845 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4847 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4849 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4851 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
4852 IsEqualIID(riid, &IID_IUnknown))
4854 *obj = iface;
4855 if (InterlockedIncrement(&This->ref) == 1) {
4856 InterlockedDecrement(&This->ref);
4857 *obj = NULL;
4858 return E_FAIL;
4860 return S_OK;
4863 WARN("%s not implemented.\n", debugstr_guid(riid));
4865 *obj = NULL;
4866 return E_NOINTERFACE;
4869 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4871 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4872 ULONG ref = InterlockedIncrement(&This->ref);
4873 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4874 return ref;
4877 static inline void release_cached_stream(struct local_cached_stream *stream)
4879 list_remove(&stream->entry);
4880 heap_free(stream->key);
4881 heap_free(stream);
4884 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4886 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4887 ULONG ref = InterlockedDecrement(&This->ref);
4889 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4891 if (!ref) {
4892 UnmapViewOfFile(This->file_ptr);
4894 EnterCriticalSection(&local_fontfile_loader.cs);
4895 release_cached_stream(This->entry);
4896 LeaveCriticalSection(&local_fontfile_loader.cs);
4898 heap_free(This);
4901 return ref;
4904 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4905 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4907 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4909 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4910 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4912 *fragment_context = NULL;
4914 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4915 *fragment_start = NULL;
4916 return E_FAIL;
4919 *fragment_start = (char*)This->file_ptr + offset;
4920 return S_OK;
4923 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4925 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4926 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4929 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4931 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4932 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4933 *size = This->size;
4934 return S_OK;
4937 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4939 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4940 ULARGE_INTEGER li;
4942 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4944 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4945 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4946 *last_writetime = li.QuadPart;
4948 return S_OK;
4951 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4953 localfontfilestream_QueryInterface,
4954 localfontfilestream_AddRef,
4955 localfontfilestream_Release,
4956 localfontfilestream_ReadFileFragment,
4957 localfontfilestream_ReleaseFileFragment,
4958 localfontfilestream_GetFileSize,
4959 localfontfilestream_GetLastWriteTime
4962 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4964 struct dwrite_localfontfilestream *This;
4966 *ret = NULL;
4968 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4969 if (!This)
4970 return E_OUTOFMEMORY;
4972 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4973 This->ref = 1;
4975 This->file_ptr = file_ptr;
4976 This->size = size;
4977 This->entry = entry;
4979 *ret = &This->IDWriteFontFileStream_iface;
4980 return S_OK;
4983 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4985 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4987 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4989 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
4990 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
4991 IsEqualIID(riid, &IID_IUnknown))
4993 *obj = iface;
4994 IDWriteLocalFontFileLoader_AddRef(iface);
4995 return S_OK;
4998 WARN("%s not implemented.\n", debugstr_guid(riid));
5000 *obj = NULL;
5001 return E_NOINTERFACE;
5004 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5006 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5007 ULONG ref = InterlockedIncrement(&This->ref);
5008 TRACE("(%p)->(%d)\n", This, ref);
5009 return ref;
5012 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5014 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5015 ULONG ref = InterlockedDecrement(&This->ref);
5017 TRACE("(%p)->(%d)\n", This, ref);
5019 return ref;
5022 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5024 const struct local_refkey *refkey = key;
5025 struct local_cached_stream *stream;
5026 IDWriteFontFileStream *filestream;
5027 HANDLE file, mapping;
5028 LARGE_INTEGER size;
5029 void *file_ptr;
5030 HRESULT hr = S_OK;
5032 *ret = NULL;
5034 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5035 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5036 if (file == INVALID_HANDLE_VALUE) {
5037 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5038 return E_FAIL;
5041 GetFileSizeEx(file, &size);
5042 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5043 CloseHandle(file);
5044 if (!mapping)
5045 return E_FAIL;
5047 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5048 CloseHandle(mapping);
5049 if (!file_ptr) {
5050 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5051 return E_FAIL;
5054 stream = heap_alloc(sizeof(*stream));
5055 if (!stream) {
5056 UnmapViewOfFile(file_ptr);
5057 return E_OUTOFMEMORY;
5060 stream->key = heap_alloc(key_size);
5061 if (!stream->key) {
5062 UnmapViewOfFile(file_ptr);
5063 heap_free(stream);
5064 return E_OUTOFMEMORY;
5067 stream->key_size = key_size;
5068 memcpy(stream->key, key, key_size);
5070 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5071 if (FAILED(hr)) {
5072 UnmapViewOfFile(file_ptr);
5073 heap_free(stream->key);
5074 heap_free(stream);
5075 return hr;
5078 stream->stream = filestream;
5080 *ret = stream;
5082 return S_OK;
5085 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5086 UINT32 key_size, IDWriteFontFileStream **ret)
5088 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5089 const struct local_refkey *refkey = key;
5090 struct local_cached_stream *stream;
5091 HRESULT hr = S_OK;
5093 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
5094 TRACE("name: %s\n", debugstr_w(refkey->name));
5096 EnterCriticalSection(&This->cs);
5098 *ret = NULL;
5100 /* search cache first */
5101 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
5102 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5103 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5104 break;
5108 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
5109 list_add_head(&This->streams, &stream->entry);
5110 *ret = stream->stream;
5113 LeaveCriticalSection(&This->cs);
5115 return hr;
5118 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
5120 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5121 const struct local_refkey *refkey = key;
5123 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
5125 *length = strlenW(refkey->name);
5126 return S_OK;
5129 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
5131 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5132 const struct local_refkey *refkey = key;
5134 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
5136 if (length < strlenW(refkey->name))
5137 return E_INVALIDARG;
5139 strcpyW(path, refkey->name);
5140 return S_OK;
5143 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5144 UINT32 key_size, FILETIME *writetime)
5146 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5147 const struct local_refkey *refkey = key;
5149 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
5151 *writetime = refkey->writetime;
5152 return S_OK;
5155 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
5156 localfontfileloader_QueryInterface,
5157 localfontfileloader_AddRef,
5158 localfontfileloader_Release,
5159 localfontfileloader_CreateStreamFromKey,
5160 localfontfileloader_GetFilePathLengthFromKey,
5161 localfontfileloader_GetFilePathFromKey,
5162 localfontfileloader_GetLastWriteTimeFromKey
5165 void init_local_fontfile_loader(void)
5167 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5168 local_fontfile_loader.ref = 1;
5169 list_init(&local_fontfile_loader.streams);
5170 InitializeCriticalSection(&local_fontfile_loader.cs);
5171 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5174 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5176 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5179 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5181 struct local_refkey *refkey;
5183 if (!path)
5184 return E_INVALIDARG;
5186 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5187 *key = NULL;
5189 refkey = heap_alloc(*size);
5190 if (!refkey)
5191 return E_OUTOFMEMORY;
5193 if (writetime)
5194 refkey->writetime = *writetime;
5195 else {
5196 WIN32_FILE_ATTRIBUTE_DATA info;
5198 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5199 refkey->writetime = info.ftLastWriteTime;
5200 else
5201 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5203 strcpyW(refkey->name, path);
5205 *key = refkey;
5207 return S_OK;
5210 /* IDWriteGlyphRunAnalysis */
5211 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5213 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5215 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5217 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5218 IsEqualIID(riid, &IID_IUnknown))
5220 *ppv = iface;
5221 IDWriteGlyphRunAnalysis_AddRef(iface);
5222 return S_OK;
5225 WARN("%s not implemented.\n", debugstr_guid(riid));
5227 *ppv = NULL;
5228 return E_NOINTERFACE;
5231 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5233 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5234 ULONG ref = InterlockedIncrement(&This->ref);
5235 TRACE("(%p)->(%u)\n", This, ref);
5236 return ref;
5239 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5241 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5242 ULONG ref = InterlockedDecrement(&This->ref);
5244 TRACE("(%p)->(%u)\n", This, ref);
5246 if (!ref) {
5247 if (This->run.fontFace)
5248 IDWriteFontFace_Release(This->run.fontFace);
5249 heap_free(This->glyphs);
5250 heap_free(This->origins);
5251 heap_free(This->bitmap);
5252 heap_free(This);
5255 return ref;
5258 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5260 switch (mode)
5262 case DWRITE_RENDERING_MODE1_NATURAL:
5263 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5264 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5265 return TRUE;
5266 default:
5267 return FALSE;
5271 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5273 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5276 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5278 struct dwrite_glyphbitmap glyph_bitmap;
5279 IDWriteFontFace4 *fontface;
5280 HRESULT hr;
5281 UINT32 i;
5283 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5284 *bounds = analysis->bounds;
5285 return;
5288 if (analysis->run.isSideways)
5289 FIXME("sideways runs are not supported.\n");
5291 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5292 if (FAILED(hr))
5293 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5295 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5296 glyph_bitmap.fontface = fontface;
5297 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5298 glyph_bitmap.emsize = analysis->run.fontEmSize;
5299 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5300 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5301 glyph_bitmap.m = &analysis->m;
5303 for (i = 0; i < analysis->run.glyphCount; i++) {
5304 RECT *bbox = &glyph_bitmap.bbox;
5305 UINT32 bitmap_size;
5307 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5308 freetype_get_glyph_bbox(&glyph_bitmap);
5310 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5311 (bbox->bottom - bbox->top);
5312 if (bitmap_size > analysis->max_glyph_bitmap_size)
5313 analysis->max_glyph_bitmap_size = bitmap_size;
5315 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5316 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5319 IDWriteFontFace4_Release(fontface);
5321 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5322 *bounds = analysis->bounds;
5325 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5327 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5329 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5331 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5332 SetRectEmpty(bounds);
5333 return E_INVALIDARG;
5336 if (type != This->texture_type) {
5337 SetRectEmpty(bounds);
5338 return S_OK;
5341 glyphrunanalysis_get_texturebounds(This, bounds);
5342 return S_OK;
5345 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5347 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5348 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5349 (runbounds->left - bounds->left) * 3;
5350 else
5351 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5352 runbounds->left - bounds->left;
5355 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5357 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5358 struct dwrite_glyphbitmap glyph_bitmap;
5359 IDWriteFontFace4 *fontface;
5360 D2D_POINT_2F origin;
5361 UINT32 i, size;
5362 HRESULT hr;
5363 RECT *bbox;
5365 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5366 if (FAILED(hr)) {
5367 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5368 return hr;
5371 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5372 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5373 size *= 3;
5374 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5375 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5376 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5377 IDWriteFontFace4_Release(fontface);
5378 return E_OUTOFMEMORY;
5381 origin.x = origin.y = 0.0f;
5383 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5384 glyph_bitmap.fontface = fontface;
5385 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5386 glyph_bitmap.emsize = analysis->run.fontEmSize;
5387 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5388 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5389 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5390 glyph_bitmap.m = &analysis->m;
5391 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5392 IDWriteFontFace4_Release(fontface);
5393 return E_OUTOFMEMORY;
5396 bbox = &glyph_bitmap.bbox;
5398 for (i = 0; i < analysis->run.glyphCount; i++) {
5399 BYTE *src = glyph_bitmap.buf, *dst;
5400 int x, y, width, height;
5401 BOOL is_1bpp;
5403 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5404 freetype_get_glyph_bbox(&glyph_bitmap);
5406 if (IsRectEmpty(bbox))
5407 continue;
5409 width = bbox->right - bbox->left;
5410 height = bbox->bottom - bbox->top;
5412 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5413 memset(src, 0, height * glyph_bitmap.pitch);
5414 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5416 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5418 /* blit to analysis bitmap */
5419 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5421 if (is_1bpp) {
5422 /* convert 1bpp to 8bpp/24bpp */
5423 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5424 for (y = 0; y < height; y++) {
5425 for (x = 0; x < width; x++)
5426 if (src[x / 8] & masks[x % 8])
5427 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5428 src += glyph_bitmap.pitch;
5429 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5432 else {
5433 for (y = 0; y < height; y++) {
5434 for (x = 0; x < width; x++)
5435 if (src[x / 8] & masks[x % 8])
5436 dst[x] = DWRITE_ALPHA_MAX;
5437 src += glyph_bitmap.pitch;
5438 dst += analysis->bounds.right - analysis->bounds.left;
5442 else {
5443 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5444 for (y = 0; y < height; y++) {
5445 for (x = 0; x < width; x++)
5446 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5447 src += glyph_bitmap.pitch;
5448 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5451 else {
5452 for (y = 0; y < height; y++) {
5453 for (x = 0; x < width; x++)
5454 dst[x] |= src[x];
5455 src += glyph_bitmap.pitch;
5456 dst += analysis->bounds.right - analysis->bounds.left;
5461 heap_free(glyph_bitmap.buf);
5463 IDWriteFontFace4_Release(fontface);
5465 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5467 /* we don't need this anymore */
5468 heap_free(analysis->glyphs);
5469 heap_free(analysis->origins);
5470 IDWriteFontFace_Release(analysis->run.fontFace);
5472 analysis->glyphs = NULL;
5473 analysis->origins = NULL;
5474 analysis->run.glyphIndices = NULL;
5475 analysis->run.fontFace = NULL;
5477 return S_OK;
5480 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5481 RECT const *bounds, BYTE *bitmap, UINT32 size)
5483 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5484 UINT32 required;
5485 RECT runbounds;
5487 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5489 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5490 return E_INVALIDARG;
5492 /* make sure buffer is large enough for requested texture type */
5493 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5494 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5495 required *= 3;
5497 if (size < required)
5498 return E_NOT_SUFFICIENT_BUFFER;
5500 /* validate requested texture type */
5501 if (This->texture_type != type)
5502 return DWRITE_E_UNSUPPORTEDOPERATION;
5504 memset(bitmap, 0, size);
5505 glyphrunanalysis_get_texturebounds(This, &runbounds);
5506 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5507 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5508 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5509 int dst_width = (bounds->right - bounds->left) * pixel_size;
5510 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5511 BYTE *src, *dst;
5512 int y;
5514 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5515 HRESULT hr;
5517 if (FAILED(hr = glyphrunanalysis_render(This)))
5518 return hr;
5521 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5522 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5524 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5525 memcpy(dst, src, draw_width);
5526 src += src_width;
5527 dst += dst_width;
5531 return S_OK;
5534 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5535 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5537 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5539 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5541 if (!params)
5542 return E_INVALIDARG;
5544 switch (This->rendering_mode)
5546 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5547 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5549 UINT value = 0;
5550 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5551 *gamma = (FLOAT)value / 1000.0f;
5552 *contrast = 0.0f;
5553 *cleartypelevel = 1.0f;
5554 break;
5556 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5557 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5558 /* fallthrough */
5559 case DWRITE_RENDERING_MODE1_ALIASED:
5560 case DWRITE_RENDERING_MODE1_NATURAL:
5561 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5562 *gamma = IDWriteRenderingParams_GetGamma(params);
5563 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5564 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5565 break;
5566 default:
5570 return S_OK;
5573 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5574 glyphrunanalysis_QueryInterface,
5575 glyphrunanalysis_AddRef,
5576 glyphrunanalysis_Release,
5577 glyphrunanalysis_GetAlphaTextureBounds,
5578 glyphrunanalysis_CreateAlphaTexture,
5579 glyphrunanalysis_GetAlphaBlendParams
5582 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5584 D2D_POINT_2F ret;
5585 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5586 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5587 *point = ret;
5590 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5591 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5593 unsigned int upem = fontface->metrics.designUnitsPerEm;
5594 int advance;
5596 if (is_sideways)
5597 FIXME("Sideways mode is not supported.\n");
5599 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5601 switch (measuring_mode)
5603 case DWRITE_MEASURING_MODE_NATURAL:
5604 return (float)advance * emsize / (float)upem;
5605 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5606 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5607 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5608 default:
5609 WARN("Unknown measuring mode %u.\n", measuring_mode);
5610 return 0.0f;
5614 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5616 struct dwrite_glyphrunanalysis *analysis;
5617 struct dwrite_fontface *fontface;
5618 D2D_POINT_2F origin;
5619 FLOAT rtl_factor;
5620 UINT32 i;
5622 *ret = NULL;
5624 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5625 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5626 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5627 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5628 return E_INVALIDARG;
5630 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5631 return E_INVALIDARG;
5633 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5634 return E_INVALIDARG;
5636 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5637 return E_INVALIDARG;
5639 analysis = heap_alloc(sizeof(*analysis));
5640 if (!analysis)
5641 return E_OUTOFMEMORY;
5643 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5644 analysis->ref = 1;
5645 analysis->rendering_mode = desc->rendering_mode;
5647 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5648 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5649 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5650 else
5651 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5653 analysis->flags = 0;
5654 analysis->bitmap = NULL;
5655 analysis->max_glyph_bitmap_size = 0;
5656 SetRectEmpty(&analysis->bounds);
5657 analysis->run = *desc->run;
5658 IDWriteFontFace_AddRef(analysis->run.fontFace);
5659 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5660 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5662 if (!analysis->glyphs || !analysis->origins) {
5663 heap_free(analysis->glyphs);
5664 heap_free(analysis->origins);
5666 analysis->glyphs = NULL;
5667 analysis->origins = NULL;
5669 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5670 return E_OUTOFMEMORY;
5673 /* check if transform is usable */
5674 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5675 analysis->m = *desc->transform;
5676 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5678 else
5679 memset(&analysis->m, 0, sizeof(analysis->m));
5681 analysis->run.glyphIndices = analysis->glyphs;
5682 analysis->run.glyphAdvances = NULL;
5683 analysis->run.glyphOffsets = NULL;
5685 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5687 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5689 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5691 origin.x = desc->origin.x;
5692 origin.y = desc->origin.y;
5693 for (i = 0; i < desc->run->glyphCount; ++i)
5695 float advance;
5697 /* Use nominal advances if not provided by caller. */
5698 if (desc->run->glyphAdvances)
5699 advance = rtl_factor * desc->run->glyphAdvances[i];
5700 else
5701 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5702 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5704 analysis->origins[i] = origin;
5705 if (desc->run->bidiLevel & 1)
5707 if (desc->run->isSideways)
5708 analysis->origins[i].y += advance;
5709 else
5710 analysis->origins[i].x += advance;
5713 /* Offsets are optional, appled to pre-transformed origin. */
5714 if (desc->run->glyphOffsets) {
5715 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5716 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5718 if (desc->run->isSideways) {
5719 analysis->origins[i].x += ascenderoffset;
5720 analysis->origins[i].y += advanceoffset;
5722 else {
5723 analysis->origins[i].x += advanceoffset;
5724 analysis->origins[i].y += ascenderoffset;
5728 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5729 transform_point(analysis->origins + i, &analysis->m);
5731 if (desc->run->isSideways)
5732 origin.y += advance;
5733 else
5734 origin.x += advance;
5737 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5738 return S_OK;
5741 /* IDWriteColorGlyphRunEnumerator1 */
5742 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
5744 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
5746 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
5747 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5748 IsEqualIID(riid, &IID_IUnknown))
5750 *ppv = iface;
5751 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
5752 return S_OK;
5755 WARN("%s not implemented.\n", debugstr_guid(riid));
5757 *ppv = NULL;
5758 return E_NOINTERFACE;
5761 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
5763 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5764 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
5766 TRACE("%p, refcount %u.\n", iface, refcount);
5768 return refcount;
5771 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
5773 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5774 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
5776 TRACE("%p, refcount %u.\n", iface, refcount);
5778 if (!refcount)
5780 heap_free(glyphenum->advances);
5781 heap_free(glyphenum->color_advances);
5782 heap_free(glyphenum->offsets);
5783 heap_free(glyphenum->color_offsets);
5784 heap_free(glyphenum->glyphindices);
5785 heap_free(glyphenum->glyphs);
5786 if (glyphenum->colr.context)
5787 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
5788 IDWriteFontFace5_Release(glyphenum->fontface);
5789 heap_free(glyphenum);
5792 return refcount;
5795 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5797 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5798 FLOAT origin = 0.0f;
5800 if (g == 0)
5801 return 0.0f;
5803 while (g--)
5804 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5805 return origin;
5808 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5810 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
5811 FLOAT advance_adj = 0.0f;
5812 BOOL got_palette_index;
5813 UINT32 g;
5815 /* start with regular glyphs */
5816 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5817 UINT32 first_glyph = 0;
5819 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5820 if (glyphenum->glyphs[g].num_layers == 0) {
5821 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5822 first_glyph = min(first_glyph, g);
5824 else
5825 glyphenum->glyphindices[g] = 1;
5826 glyphenum->color_advances[g] = glyphenum->advances[g];
5827 if (glyphenum->color_offsets)
5828 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5831 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5832 colorrun->baselineOriginY = glyphenum->origin_y;
5833 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5834 colorrun->paletteIndex = 0xffff;
5835 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5836 glyphenum->has_regular_glyphs = FALSE;
5837 return TRUE;
5839 else {
5840 colorrun->glyphRun.glyphCount = 0;
5841 got_palette_index = FALSE;
5844 advance_adj = 0.0f;
5845 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5847 glyphenum->glyphindices[g] = 1;
5849 /* all glyph layers were returned */
5850 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5851 advance_adj += glyphenum->advances[g];
5852 continue;
5855 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5856 UINT32 index = colorrun->glyphRun.glyphCount;
5857 if (!got_palette_index) {
5858 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5859 /* use foreground color or request one from the font */
5860 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5861 if (colorrun->paletteIndex != 0xffff)
5863 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
5864 colorrun->paletteIndex, 1, &colorrun->runColor);
5865 if (FAILED(hr))
5866 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5867 glyphenum->palette, colorrun->paletteIndex, hr);
5869 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5870 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5871 colorrun->baselineOriginY = glyphenum->origin_y;
5872 glyphenum->color_advances[index] = glyphenum->advances[g];
5873 got_palette_index = TRUE;
5876 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5877 /* offsets are relative to glyph origin, nothing to fix up */
5878 if (glyphenum->color_offsets)
5879 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5880 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
5881 if (index)
5882 glyphenum->color_advances[index-1] += advance_adj;
5883 colorrun->glyphRun.glyphCount++;
5884 advance_adj = 0.0f;
5886 else
5887 advance_adj += glyphenum->advances[g];
5890 /* reset last advance */
5891 if (colorrun->glyphRun.glyphCount)
5892 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5894 return colorrun->glyphRun.glyphCount > 0;
5897 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
5899 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5901 TRACE("%p, %p.\n", iface, has_run);
5903 *has_run = FALSE;
5905 glyphenum->colorrun.glyphRun.glyphCount = 0;
5906 while (glyphenum->current_layer < glyphenum->max_layer_num)
5908 if (colorglyphenum_build_color_run(glyphenum))
5909 break;
5910 else
5911 glyphenum->current_layer++;
5914 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
5916 return S_OK;
5919 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
5920 DWRITE_COLOR_GLYPH_RUN1 const **run)
5922 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
5924 *run = NULL;
5925 return E_NOT_VALID_STATE;
5928 *run = &glyphenum->colorrun;
5929 return S_OK;
5932 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
5933 DWRITE_COLOR_GLYPH_RUN const **run)
5935 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5937 TRACE("%p, %p.\n", iface, run);
5939 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
5942 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
5943 DWRITE_COLOR_GLYPH_RUN1 const **run)
5945 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
5947 TRACE("%p, %p.\n", iface, run);
5949 return colorglyphenum_get_current_run(glyphenum, run);
5952 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
5954 colorglyphenum_QueryInterface,
5955 colorglyphenum_AddRef,
5956 colorglyphenum_Release,
5957 colorglyphenum_MoveNext,
5958 colorglyphenum_GetCurrentRun,
5959 colorglyphenum1_GetCurrentRun,
5962 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
5963 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
5964 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
5966 struct dwrite_colorglyphenum *colorglyphenum;
5967 BOOL colorfont, has_colored_glyph;
5968 struct dwrite_fontface *fontface;
5969 unsigned int i;
5971 *ret = NULL;
5973 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
5975 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
5976 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
5977 if (!colorfont)
5978 return DWRITE_E_NOCOLOR;
5980 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5981 if (!colorglyphenum)
5982 return E_OUTOFMEMORY;
5984 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
5985 colorglyphenum->refcount = 1;
5986 colorglyphenum->origin_x = originX;
5987 colorglyphenum->origin_y = originY;
5988 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
5989 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
5990 colorglyphenum->glyphs = NULL;
5991 colorglyphenum->run = *run;
5992 colorglyphenum->run.glyphIndices = NULL;
5993 colorglyphenum->run.glyphAdvances = NULL;
5994 colorglyphenum->run.glyphOffsets = NULL;
5995 colorglyphenum->palette = palette;
5996 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5997 colorglyphenum->colr.exists = TRUE;
5998 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
5999 colorglyphenum->current_layer = 0;
6000 colorglyphenum->max_layer_num = 0;
6002 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6004 has_colored_glyph = FALSE;
6005 colorglyphenum->has_regular_glyphs = FALSE;
6006 for (i = 0; i < run->glyphCount; i++) {
6007 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6008 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6009 has_colored_glyph = TRUE;
6011 if (colorglyphenum->glyphs[i].num_layers == 0)
6012 colorglyphenum->has_regular_glyphs = TRUE;
6015 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6016 is supposed to proceed normally, like if font had no color info at all. */
6017 if (!has_colored_glyph) {
6018 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6019 return DWRITE_E_NOCOLOR;
6022 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6023 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6024 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6025 if (run->glyphOffsets) {
6026 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6027 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6028 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6031 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6032 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6033 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6034 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6035 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6036 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6037 colorglyphenum->colorrun.measuringMode = measuring_mode;
6038 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6040 if (run->glyphAdvances)
6041 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6042 else
6044 for (i = 0; i < run->glyphCount; ++i)
6045 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6046 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6049 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6051 return S_OK;
6054 /* IDWriteFontFaceReference */
6055 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6057 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6059 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6060 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6061 IsEqualIID(riid, &IID_IUnknown))
6063 *obj = iface;
6064 IDWriteFontFaceReference1_AddRef(iface);
6065 return S_OK;
6068 WARN("%s not implemented.\n", debugstr_guid(riid));
6070 *obj = NULL;
6072 return E_NOINTERFACE;
6075 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6077 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6078 ULONG refcount = InterlockedIncrement(&reference->refcount);
6080 TRACE("%p, refcount %u.\n", iface, refcount);
6082 return refcount;
6085 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6087 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6088 ULONG refcount = InterlockedDecrement(&reference->refcount);
6090 TRACE("%p, refcount %u.\n", iface, refcount);
6092 if (!refcount)
6094 IDWriteFontFile_Release(reference->file);
6095 IDWriteFactory7_Release(reference->factory);
6096 heap_free(reference->axis_values);
6097 heap_free(reference);
6100 return refcount;
6103 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6105 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6107 TRACE("%p, %p.\n", iface, fontface);
6109 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6112 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6113 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6115 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6116 DWRITE_FONT_FILE_TYPE file_type;
6117 DWRITE_FONT_FACE_TYPE face_type;
6118 IDWriteFontFace *fontface;
6119 BOOL is_supported;
6120 UINT32 face_num;
6121 HRESULT hr;
6123 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6125 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6126 if (FAILED(hr))
6127 return hr;
6129 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6130 simulations, &fontface);
6131 if (SUCCEEDED(hr))
6133 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6134 IDWriteFontFace_Release(fontface);
6137 return hr;
6140 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6142 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6143 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6144 BOOL ret;
6146 TRACE("%p, %p.\n", iface, ref);
6148 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6149 reference->simulations == other->simulations;
6150 if (reference->axis_values_count)
6152 ret &= reference->axis_values_count == other->axis_values_count &&
6153 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6156 return ret;
6159 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6161 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6163 TRACE("%p.\n", iface);
6165 return reference->index;
6168 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6170 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6172 TRACE("%p.\n", iface);
6174 return reference->simulations;
6177 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6179 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6180 IDWriteFontFileLoader *loader;
6181 const void *key;
6182 UINT32 key_size;
6183 HRESULT hr;
6185 TRACE("%p, %p.\n", iface, file);
6187 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6188 if (FAILED(hr))
6189 return hr;
6191 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6192 if (FAILED(hr))
6193 return hr;
6195 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6196 IDWriteFontFileLoader_Release(loader);
6198 return hr;
6201 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6203 FIXME("%p.\n", iface);
6205 return 0;
6208 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6210 FIXME("%p.\n", iface);
6212 return 0;
6215 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6217 FIXME("%p, %p.\n", iface, writetime);
6219 return E_NOTIMPL;
6222 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6224 FIXME("%p.\n", iface);
6226 return DWRITE_LOCALITY_LOCAL;
6229 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6231 FIXME("%p.\n", iface);
6233 return E_NOTIMPL;
6236 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6237 WCHAR const *chars, UINT32 count)
6239 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6241 return E_NOTIMPL;
6244 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6245 UINT16 const *glyphs, UINT32 count)
6247 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6249 return E_NOTIMPL;
6252 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6253 UINT64 offset, UINT64 size)
6255 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6257 return E_NOTIMPL;
6260 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6262 FIXME("%p, %p.\n", iface, fontface);
6264 return E_NOTIMPL;
6267 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6269 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6271 TRACE("%p.\n", iface);
6273 return reference->axis_values_count;
6276 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6277 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6279 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6281 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6283 if (value_count < reference->axis_values_count)
6284 return E_NOT_SUFFICIENT_BUFFER;
6286 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6288 return S_OK;
6291 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6293 fontfacereference_QueryInterface,
6294 fontfacereference_AddRef,
6295 fontfacereference_Release,
6296 fontfacereference_CreateFontFace,
6297 fontfacereference_CreateFontFaceWithSimulations,
6298 fontfacereference_Equals,
6299 fontfacereference_GetFontFaceIndex,
6300 fontfacereference_GetSimulations,
6301 fontfacereference_GetFontFile,
6302 fontfacereference_GetLocalFileSize,
6303 fontfacereference_GetFileSize,
6304 fontfacereference_GetFileTime,
6305 fontfacereference_GetLocality,
6306 fontfacereference_EnqueueFontDownloadRequest,
6307 fontfacereference_EnqueueCharacterDownloadRequest,
6308 fontfacereference_EnqueueGlyphDownloadRequest,
6309 fontfacereference_EnqueueFileFragmentDownloadRequest,
6310 fontfacereference1_CreateFontFace,
6311 fontfacereference1_GetFontAxisValueCount,
6312 fontfacereference1_GetFontAxisValues,
6315 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6316 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6317 IDWriteFontFaceReference1 **ret)
6319 struct dwrite_fontfacereference *object;
6321 *ret = NULL;
6323 if (!is_simulation_valid(simulations))
6324 return E_INVALIDARG;
6326 object = heap_alloc_zero(sizeof(*object));
6327 if (!object)
6328 return E_OUTOFMEMORY;
6330 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6331 object->refcount = 1;
6333 object->factory = factory;
6334 IDWriteFactory7_AddRef(object->factory);
6335 object->file = file;
6336 IDWriteFontFile_AddRef(object->file);
6337 object->index = index;
6338 object->simulations = simulations;
6339 if (axis_values_count)
6341 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6343 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6344 return E_OUTOFMEMORY;
6346 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6347 object->axis_values_count = axis_values_count;
6350 *ret = &object->IDWriteFontFaceReference1_iface;
6352 return S_OK;
6355 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6357 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6359 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6361 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6362 *obj = iface;
6363 IDWriteFontFileStream_AddRef(iface);
6364 return S_OK;
6367 *obj = NULL;
6369 WARN("%s not implemented.\n", debugstr_guid(riid));
6370 return E_NOINTERFACE;
6373 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6375 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6376 ULONG ref = InterlockedIncrement(&stream->ref);
6377 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6378 return ref;
6381 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6383 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6384 ULONG ref = InterlockedDecrement(&stream->ref);
6386 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6388 if (!ref) {
6389 release_inmemory_stream(stream->data);
6390 heap_free(stream);
6393 return ref;
6396 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6397 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6399 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6401 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6402 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6404 *fragment_context = NULL;
6406 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6407 *fragment_start = NULL;
6408 return E_FAIL;
6411 *fragment_start = (char *)stream->data->data + offset;
6412 return S_OK;
6415 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6417 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6419 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6422 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6424 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6426 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6428 *size = stream->data->size;
6430 return S_OK;
6433 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6435 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6437 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6439 *last_writetime = 0;
6441 return E_NOTIMPL;
6444 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6445 inmemoryfilestream_QueryInterface,
6446 inmemoryfilestream_AddRef,
6447 inmemoryfilestream_Release,
6448 inmemoryfilestream_ReadFileFragment,
6449 inmemoryfilestream_ReleaseFileFragment,
6450 inmemoryfilestream_GetFileSize,
6451 inmemoryfilestream_GetLastWriteTime,
6454 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6455 REFIID riid, void **obj)
6457 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6459 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6461 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6462 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6463 IsEqualIID(riid, &IID_IUnknown))
6465 *obj = iface;
6466 IDWriteInMemoryFontFileLoader_AddRef(iface);
6467 return S_OK;
6470 WARN("%s not implemented.\n", debugstr_guid(riid));
6472 *obj = NULL;
6474 return E_NOINTERFACE;
6477 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6479 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6480 ULONG ref = InterlockedIncrement(&loader->ref);
6481 TRACE("(%p)->(%u)\n", loader, ref);
6482 return ref;
6485 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6487 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6488 ULONG ref = InterlockedDecrement(&loader->ref);
6489 size_t i;
6491 TRACE("(%p)->(%u)\n", loader, ref);
6493 if (!ref) {
6494 for (i = 0; i < loader->count; ++i)
6495 release_inmemory_stream(loader->streams[i]);
6496 heap_free(loader->streams);
6497 heap_free(loader);
6500 return ref;
6503 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6504 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6506 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6507 struct dwrite_inmemory_filestream *stream;
6508 DWORD index;
6510 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6512 *ret = NULL;
6514 if (key_size != sizeof(DWORD))
6515 return E_INVALIDARG;
6517 index = *(DWORD *)key;
6519 if (index >= loader->count)
6520 return E_INVALIDARG;
6522 if (!(stream = heap_alloc(sizeof(*stream))))
6523 return E_OUTOFMEMORY;
6525 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6526 stream->ref = 1;
6527 stream->data = loader->streams[index];
6528 InterlockedIncrement(&stream->data->ref);
6530 *ret = &stream->IDWriteFontFileStream_iface;
6532 return S_OK;
6535 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6536 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6538 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6539 struct dwrite_inmemory_stream_data *stream;
6540 DWORD key;
6542 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6544 *fontfile = NULL;
6546 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6547 return E_OUTOFMEMORY;
6549 if (!(stream = heap_alloc(sizeof(*stream))))
6550 return E_OUTOFMEMORY;
6552 stream->ref = 1;
6553 stream->size = data_size;
6554 stream->owner = owner;
6555 if (stream->owner) {
6556 IUnknown_AddRef(stream->owner);
6557 stream->data = (void *)data;
6559 else {
6560 if (!(stream->data = heap_alloc(data_size))) {
6561 heap_free(stream);
6562 return E_OUTOFMEMORY;
6564 memcpy(stream->data, data, data_size);
6567 key = loader->count;
6568 loader->streams[loader->count++] = stream;
6570 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6571 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6574 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6576 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6578 TRACE("%p.\n", iface);
6580 return loader->count;
6583 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6585 inmemoryfontfileloader_QueryInterface,
6586 inmemoryfontfileloader_AddRef,
6587 inmemoryfontfileloader_Release,
6588 inmemoryfontfileloader_CreateStreamFromKey,
6589 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6590 inmemoryfontfileloader_GetFileCount,
6593 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6595 struct dwrite_inmemory_fileloader *loader;
6597 *ret = NULL;
6599 loader = heap_alloc_zero(sizeof(*loader));
6600 if (!loader)
6601 return E_OUTOFMEMORY;
6603 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6604 loader->ref = 1;
6606 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6608 return S_OK;
6611 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6613 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6615 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6616 IsEqualIID(riid, &IID_IUnknown))
6618 *obj = iface;
6619 IDWriteFontResource_AddRef(iface);
6620 return S_OK;
6623 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6625 return E_NOINTERFACE;
6628 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6630 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6631 ULONG refcount = InterlockedIncrement(&resource->refcount);
6633 TRACE("%p, refcount %u.\n", iface, refcount);
6635 return refcount;
6638 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6640 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6641 ULONG refcount = InterlockedDecrement(&resource->refcount);
6643 TRACE("%p, refcount %u.\n", iface, refcount);
6645 if (!refcount)
6647 IDWriteFactory7_Release(resource->factory);
6648 IDWriteFontFile_Release(resource->file);
6649 heap_free(resource);
6652 return refcount;
6655 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6657 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6659 TRACE("%p, %p.\n", iface, fontfile);
6661 *fontfile = resource->file;
6662 IDWriteFontFile_AddRef(*fontfile);
6664 return S_OK;
6667 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6669 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6671 TRACE("%p.\n", iface);
6673 return resource->face_index;
6676 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6678 FIXME("%p.\n", iface);
6680 return 0;
6683 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6684 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6686 FIXME("%p, %p, %u.\n", iface, values, num_values);
6688 return E_NOTIMPL;
6691 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6692 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
6694 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
6696 return E_NOTIMPL;
6699 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
6700 UINT32 axis)
6702 FIXME("%p, %u.\n", iface, axis);
6704 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
6707 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
6708 IDWriteLocalizedStrings **names)
6710 FIXME("%p, %u, %p.\n", iface, axis, names);
6712 return E_NOTIMPL;
6715 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
6717 FIXME("%p, %u.\n", iface, axis);
6719 return 0;
6722 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
6723 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
6725 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
6727 return E_NOTIMPL;
6730 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
6732 FIXME("%p.\n", iface);
6734 return FALSE;
6737 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
6738 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
6739 IDWriteFontFace5 **fontface)
6741 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6742 IDWriteFontFaceReference1 *reference;
6743 HRESULT hr;
6745 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
6747 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
6748 simulations, axis_values, num_values, &reference);
6749 if (SUCCEEDED(hr))
6751 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
6752 IDWriteFontFaceReference1_Release(reference);
6755 return hr;
6758 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
6759 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
6760 IDWriteFontFaceReference1 **reference)
6762 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6764 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
6766 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
6767 simulations, axis_values, num_values, reference);
6770 static const IDWriteFontResourceVtbl fontresourcevtbl =
6772 dwritefontresource_QueryInterface,
6773 dwritefontresource_AddRef,
6774 dwritefontresource_Release,
6775 dwritefontresource_GetFontFile,
6776 dwritefontresource_GetFontFaceIndex,
6777 dwritefontresource_GetFontAxisCount,
6778 dwritefontresource_GetDefaultFontAxisValues,
6779 dwritefontresource_GetFontAxisRanges,
6780 dwritefontresource_GetFontAxisAttributes,
6781 dwritefontresource_GetAxisNames,
6782 dwritefontresource_GetAxisValueNameCount,
6783 dwritefontresource_GetAxisValueNames,
6784 dwritefontresource_HasVariations,
6785 dwritefontresource_CreateFontFace,
6786 dwritefontresource_CreateFontFaceReference,
6789 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
6790 IDWriteFontResource **ret)
6792 struct dwrite_fontresource *resource;
6794 *ret = NULL;
6796 resource = heap_alloc_zero(sizeof(*resource));
6797 if (!resource)
6798 return E_OUTOFMEMORY;
6800 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
6801 resource->refcount = 1;
6802 resource->face_index = face_index;
6803 resource->file = file;
6804 IDWriteFontFile_AddRef(resource->file);
6805 resource->factory = factory;
6806 IDWriteFactory7_AddRef(resource->factory);
6808 *ret = &resource->IDWriteFontResource_iface;
6810 return S_OK;