msvcp90: Remove MSVCP_bool type.
[wine.git] / dlls / dwrite / font.c
blobaa51c7442973046594aa9dd7a18ef0e97632fe4e
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
31 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
33 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
34 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
44 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
45 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
46 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
48 static const WCHAR extraW[] = {'e','x','t','r','a',0};
49 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
50 static const WCHAR semiW[] = {'s','e','m','i',0};
51 static const WCHAR extW[] = {'e','x','t',0};
52 static const WCHAR thinW[] = {'t','h','i','n',0};
53 static const WCHAR lightW[] = {'l','i','g','h','t',0};
54 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
55 static const WCHAR blackW[] = {'b','l','a','c','k',0};
56 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
57 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
58 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
59 static const WCHAR boldW[] = {'B','o','l','d',0};
60 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
61 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
62 static const WCHAR demiW[] = {'d','e','m','i',0};
63 static const WCHAR spaceW[] = {' ',0};
64 static const WCHAR enusW[] = {'e','n','-','u','s',0};
66 struct dwrite_font_propvec {
67 FLOAT stretch;
68 FLOAT style;
69 FLOAT weight;
72 struct dwrite_font_data
74 LONG ref;
76 DWRITE_FONT_STYLE style;
77 DWRITE_FONT_STRETCH stretch;
78 DWRITE_FONT_WEIGHT weight;
79 DWRITE_PANOSE panose;
80 FONTSIGNATURE fontsig;
81 UINT32 flags; /* enum font_flags */
82 struct dwrite_font_propvec propvec;
83 struct dwrite_cmap cmap;
84 /* Static axis for weight/width/italic. */
85 DWRITE_FONT_AXIS_VALUE axis[3];
87 DWRITE_FONT_METRICS1 metrics;
88 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG + 1];
89 IDWriteLocalizedStrings *family_names;
90 IDWriteLocalizedStrings *names;
92 /* data needed to create fontface instance */
93 DWRITE_FONT_FACE_TYPE face_type;
94 IDWriteFontFile *file;
95 UINT32 face_index;
97 WCHAR *facename;
99 USHORT simulations;
101 LOGFONTW lf;
103 /* used to mark font as tested when scanning for simulation candidate */
104 unsigned int bold_sim_tested : 1;
105 unsigned int oblique_sim_tested : 1;
108 struct dwrite_fontfamily_data
110 LONG refcount;
112 IDWriteLocalizedStrings *familyname;
114 struct dwrite_font_data **fonts;
115 size_t size;
116 size_t count;
118 unsigned int has_normal_face : 1;
119 unsigned int has_oblique_face : 1;
120 unsigned int has_italic_face : 1;
123 struct dwrite_fontcollection
125 IDWriteFontCollection3 IDWriteFontCollection3_iface;
126 LONG refcount;
128 IDWriteFactory7 *factory;
129 struct dwrite_fontfamily_data **family_data;
130 size_t size;
131 size_t count;
134 struct dwrite_fontfamily
136 IDWriteFontFamily2 IDWriteFontFamily2_iface;
137 IDWriteFontList2 IDWriteFontList2_iface;
138 LONG refcount;
140 struct dwrite_fontfamily_data *data;
141 struct dwrite_fontcollection *collection;
144 struct dwrite_fontlist
146 IDWriteFontList2 IDWriteFontList2_iface;
147 LONG refcount;
149 struct dwrite_font_data **fonts;
150 UINT32 font_count;
151 struct dwrite_fontfamily *family;
154 struct dwrite_font {
155 IDWriteFont3 IDWriteFont3_iface;
156 LONG ref;
158 DWRITE_FONT_STYLE style;
159 struct dwrite_font_data *data;
160 struct dwrite_fontfamily *family;
163 enum runanalysis_flags {
164 RUNANALYSIS_BOUNDS_READY = 1 << 0,
165 RUNANALYSIS_BITMAP_READY = 1 << 1,
166 RUNANALYSIS_USE_TRANSFORM = 1 << 2
169 struct dwrite_glyphrunanalysis {
170 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
171 LONG ref;
173 DWRITE_RENDERING_MODE1 rendering_mode;
174 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
175 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
176 DWRITE_MATRIX m;
177 UINT16 *glyphs;
178 D2D_POINT_2F *origins;
180 UINT8 flags;
181 RECT bounds;
182 BYTE *bitmap;
183 UINT32 max_glyph_bitmap_size;
186 struct dwrite_colorglyphenum
188 IDWriteColorGlyphRunEnumerator1 IDWriteColorGlyphRunEnumerator1_iface;
189 LONG refcount;
191 FLOAT origin_x; /* original run origin */
192 FLOAT origin_y;
194 IDWriteFontFace5 *fontface; /* for convenience */
195 DWRITE_COLOR_GLYPH_RUN1 colorrun; /* returned with GetCurrentRun() */
196 DWRITE_GLYPH_RUN run; /* base run */
197 UINT32 palette; /* palette index to get layer color from */
198 FLOAT *advances; /* original or measured advances for base glyphs */
199 FLOAT *color_advances; /* returned color run points to this */
200 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
201 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
202 UINT16 *glyphindices; /* returned color run points to this */
203 struct dwrite_colorglyph *glyphs; /* current glyph color info */
204 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
205 UINT16 current_layer; /* enumerator position, updated with MoveNext */
206 UINT16 max_layer_num; /* max number of layers for this run */
207 struct dwrite_fonttable colr; /* used to access layers */
210 #define GLYPH_BLOCK_SHIFT 8
211 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
212 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
213 #define GLYPH_MAX 65536
215 struct dwrite_fontfile {
216 IDWriteFontFile IDWriteFontFile_iface;
217 LONG ref;
219 IDWriteFontFileLoader *loader;
220 void *reference_key;
221 UINT32 key_size;
222 IDWriteFontFileStream *stream;
225 struct dwrite_fontfacereference
227 IDWriteFontFaceReference1 IDWriteFontFaceReference1_iface;
228 LONG refcount;
230 IDWriteFontFile *file;
231 UINT32 index;
232 USHORT simulations;
233 DWRITE_FONT_AXIS_VALUE *axis_values;
234 UINT32 axis_values_count;
235 IDWriteFactory7 *factory;
238 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl;
240 struct dwrite_fontresource
242 IDWriteFontResource IDWriteFontResource_iface;
243 LONG refcount;
245 IDWriteFontFile *file;
246 UINT32 face_index;
247 IDWriteFactory7 *factory;
250 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
252 struct dwrite_fontface *fontface = context;
253 BOOL exists = FALSE;
255 if (FAILED(IDWriteFontFace5_TryGetFontTable(&fontface->IDWriteFontFace5_iface, table, (const void **)data,
256 size, data_context, &exists)) || !exists)
258 *data = NULL;
259 *size = 0;
260 *data_context = NULL;
264 static void dwrite_release_font_table(void *context, void *data_context)
266 struct dwrite_fontface *fontface = context;
267 IDWriteFontFace5_ReleaseFontTable(&fontface->IDWriteFontFace5_iface, data_context);
270 static UINT16 dwrite_get_font_upem(void *context)
272 struct dwrite_fontface *fontface = context;
273 return fontface->metrics.designUnitsPerEm;
276 static UINT16 dwritefontface_get_glyph(struct dwrite_fontface *fontface, unsigned int ch)
278 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
279 return opentype_cmap_get_glyph(&fontface->cmap, ch);
282 static BOOL dwrite_has_glyph(void *context, unsigned int codepoint)
284 struct dwrite_fontface *fontface = context;
285 return !!dwritefontface_get_glyph(fontface, codepoint);
288 static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint)
290 struct dwrite_fontface *fontface = context;
291 return dwritefontface_get_glyph(fontface, codepoint);
294 static const struct shaping_font_ops dwrite_font_ops =
296 dwrite_grab_font_table,
297 dwrite_release_font_table,
298 dwrite_get_font_upem,
299 dwrite_has_glyph,
300 dwrite_get_glyph,
303 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
305 if (fontface->shaping_cache)
306 return fontface->shaping_cache;
308 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
311 static inline struct dwrite_fontface *impl_from_IDWriteFontFace5(IDWriteFontFace5 *iface)
313 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
316 static struct dwrite_fontface *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
318 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFaceReference_iface);
321 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
323 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
326 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface);
328 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
330 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
333 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily2(IDWriteFontFamily2 *iface)
335 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily2_iface);
338 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList2(IDWriteFontList2 *iface)
340 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList2_iface);
343 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection3(IDWriteFontCollection3 *iface)
345 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection3_iface);
348 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
350 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
353 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator1(IDWriteColorGlyphRunEnumerator1 *iface)
355 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator1_iface);
358 static inline struct dwrite_fontlist *impl_from_IDWriteFontList2(IDWriteFontList2 *iface)
360 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList2_iface);
363 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference1(IDWriteFontFaceReference1 *iface)
365 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference1_iface);
368 static struct dwrite_fontresource *impl_from_IDWriteFontResource(IDWriteFontResource *iface)
370 return CONTAINING_RECORD(iface, struct dwrite_fontresource, IDWriteFontResource_iface);
373 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
375 static const DWRITE_GLYPH_METRICS nil;
376 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
378 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
379 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
380 return S_OK;
383 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
385 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
387 if (!*block) {
388 /* start new block */
389 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
390 if (!*block)
391 return E_OUTOFMEMORY;
394 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
395 return S_OK;
398 const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table)
400 HRESULT hr;
402 if (table->data || !table->exists)
403 return table->data;
405 table->exists = FALSE;
406 hr = IDWriteFontFace5_TryGetFontTable(fontface, tag, (const void **)&table->data, &table->size, &table->context,
407 &table->exists);
408 if (FAILED(hr) || !table->exists) {
409 TRACE("Font does not have %s table\n", debugstr_tag(tag));
410 return NULL;
413 return table->data;
416 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
417 struct dwrite_font_propvec *vec)
419 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
420 vec->style = style * 7.0f;
421 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
424 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
426 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
429 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
431 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
434 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
436 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_VDMX_TAG, &fontface->vdmx);
437 return &fontface->vdmx;
440 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
442 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_GASP_TAG, &fontface->gasp);
443 return &fontface->gasp;
446 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
448 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_CPAL_TAG, &fontface->cpal);
449 return &fontface->cpal;
452 static void addref_font_data(struct dwrite_font_data *data)
454 InterlockedIncrement(&data->ref);
457 static void release_font_data(struct dwrite_font_data *data)
459 int i;
461 if (InterlockedDecrement(&data->ref) > 0)
462 return;
464 for (i = 0; i < ARRAY_SIZE(data->info_strings); ++i)
466 if (data->info_strings[i])
467 IDWriteLocalizedStrings_Release(data->info_strings[i]);
469 if (data->names)
470 IDWriteLocalizedStrings_Release(data->names);
472 if (data->family_names)
473 IDWriteLocalizedStrings_Release(data->family_names);
475 dwrite_cmap_release(&data->cmap);
476 IDWriteFontFile_Release(data->file);
477 heap_free(data->facename);
478 heap_free(data);
481 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
483 size_t i;
485 if (InterlockedDecrement(&data->refcount) > 0)
486 return;
488 for (i = 0; i < data->count; ++i)
489 release_font_data(data->fonts[i]);
490 heap_free(data->fonts);
491 IDWriteLocalizedStrings_Release(data->familyname);
492 heap_free(data);
495 void fontface_detach_from_cache(IDWriteFontFace5 *iface)
497 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
498 fontface->cached = NULL;
501 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
503 UINT32 left_key_size, right_key_size;
504 const void *left_key, *right_key;
505 HRESULT hr;
507 if (left == right)
508 return TRUE;
510 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
511 if (FAILED(hr))
512 return FALSE;
514 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
515 if (FAILED(hr))
516 return FALSE;
518 if (left_key_size != right_key_size)
519 return FALSE;
521 return !memcmp(left_key, right_key, left_key_size);
524 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace5 *iface, REFIID riid, void **obj)
526 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
528 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
530 if (IsEqualIID(riid, &IID_IDWriteFontFace5) ||
531 IsEqualIID(riid, &IID_IDWriteFontFace4) ||
532 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
533 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
534 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
535 IsEqualIID(riid, &IID_IDWriteFontFace) ||
536 IsEqualIID(riid, &IID_IUnknown))
538 *obj = iface;
540 else if (IsEqualIID(riid, &IID_IDWriteFontFaceReference))
541 *obj = &fontface->IDWriteFontFaceReference_iface;
542 else
543 *obj = NULL;
545 if (*obj)
547 if (InterlockedIncrement(&fontface->refcount) == 1)
549 InterlockedDecrement(&fontface->refcount);
550 *obj = NULL;
551 return E_FAIL;
553 return S_OK;
556 WARN("%s not implemented.\n", debugstr_guid(riid));
558 return E_NOINTERFACE;
561 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace5 *iface)
563 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
564 ULONG refcount = InterlockedIncrement(&fontface->refcount);
566 TRACE("%p, refcount %u.\n", iface, refcount);
568 return refcount;
571 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace5 *iface)
573 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
574 ULONG refcount = InterlockedDecrement(&fontface->refcount);
576 TRACE("%p, refcount %u.\n", iface, refcount);
578 if (!refcount)
580 UINT32 i;
582 if (fontface->cached)
584 factory_lock(fontface->factory);
585 list_remove(&fontface->cached->entry);
586 factory_unlock(fontface->factory);
587 heap_free(fontface->cached);
589 release_scriptshaping_cache(fontface->shaping_cache);
590 if (fontface->vdmx.context)
591 IDWriteFontFace5_ReleaseFontTable(iface, fontface->vdmx.context);
592 if (fontface->gasp.context)
593 IDWriteFontFace5_ReleaseFontTable(iface, fontface->gasp.context);
594 if (fontface->cpal.context)
595 IDWriteFontFace5_ReleaseFontTable(iface, fontface->cpal.context);
596 if (fontface->colr.context)
597 IDWriteFontFace5_ReleaseFontTable(iface, fontface->colr.context);
598 for (i = 0; i < fontface->file_count; i++)
600 if (fontface->files[i])
601 IDWriteFontFile_Release(fontface->files[i]);
603 if (fontface->stream)
604 IDWriteFontFileStream_Release(fontface->stream);
605 heap_free(fontface->files);
606 if (fontface->names)
607 IDWriteLocalizedStrings_Release(fontface->names);
608 if (fontface->family_names)
609 IDWriteLocalizedStrings_Release(fontface->family_names);
610 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
612 if (fontface->info_strings[i])
613 IDWriteLocalizedStrings_Release(fontface->info_strings[i]);
616 for (i = 0; i < ARRAY_SIZE(fontface->glyphs); i++)
617 heap_free(fontface->glyphs[i]);
619 freetype_notify_cacheremove(iface);
621 dwrite_cmap_release(&fontface->cmap);
622 IDWriteFactory7_Release(fontface->factory);
623 heap_free(fontface);
626 return refcount;
629 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace5 *iface)
631 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
633 TRACE("%p.\n", iface);
635 return fontface->type;
638 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace5 *iface, UINT32 *number_of_files,
639 IDWriteFontFile **fontfiles)
641 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
642 int i;
644 TRACE("%p, %p, %p.\n", iface, number_of_files, fontfiles);
646 if (fontfiles == NULL)
648 *number_of_files = fontface->file_count;
649 return S_OK;
652 if (*number_of_files < fontface->file_count)
653 return E_INVALIDARG;
655 for (i = 0; i < fontface->file_count; i++)
657 IDWriteFontFile_AddRef(fontface->files[i]);
658 fontfiles[i] = fontface->files[i];
661 return S_OK;
664 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace5 *iface)
666 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
668 TRACE("%p.\n", iface);
670 return fontface->index;
673 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace5 *iface)
675 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
677 TRACE("%p.\n", iface);
679 return fontface->simulations;
682 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace5 *iface)
684 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
686 TRACE("%p.\n", iface);
688 return !!(fontface->flags & FONT_IS_SYMBOL);
691 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS *metrics)
693 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
695 TRACE("%p, %p.\n", iface, metrics);
697 memcpy(metrics, &fontface->metrics, sizeof(*metrics));
700 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace5 *iface)
702 TRACE("%p.\n", iface);
704 return freetype_get_glyphcount(iface);
707 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *iface,
708 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
710 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
711 unsigned int i;
712 HRESULT hr;
714 TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways);
716 if (!glyphs)
717 return E_INVALIDARG;
719 if (is_sideways)
720 FIXME("sideways metrics are not supported.\n");
722 for (i = 0; i < glyph_count; i++) {
723 DWRITE_GLYPH_METRICS metrics;
725 hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics);
726 if (hr != S_OK) {
727 freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics);
728 hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics);
729 if (FAILED(hr))
730 return hr;
732 ret[i] = metrics;
735 return S_OK;
738 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UINT32 const *codepoints,
739 UINT32 count, UINT16 *glyphs)
741 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
742 unsigned int i;
744 TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs);
746 if (!glyphs)
747 return E_INVALIDARG;
749 if (!codepoints)
751 memset(glyphs, 0, count * sizeof(*glyphs));
752 return E_INVALIDARG;
755 for (i = 0; i < count; ++i)
756 glyphs[i] = dwritefontface_get_glyph(fontface, codepoints[i]);
758 return S_OK;
761 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace5 *iface, UINT32 table_tag,
762 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
764 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
765 struct file_stream_desc stream_desc;
767 TRACE("%p, %s, %p, %p, %p, %p.\n", iface, debugstr_tag(table_tag), table_data, table_size, context, exists);
769 stream_desc.stream = fontface->stream;
770 stream_desc.face_type = fontface->type;
771 stream_desc.face_index = fontface->index;
772 return opentype_try_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
775 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void *table_context)
777 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
779 TRACE("%p, %p.\n", iface, table_context);
781 IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
784 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
785 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
786 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
788 TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
789 count, is_sideways, is_rtl, sink);
791 if (!glyphs || !sink)
792 return E_INVALIDARG;
794 if (is_sideways)
795 FIXME("sideways mode is not supported.\n");
797 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
800 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
801 float ppem, unsigned int gasp)
803 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
805 switch (measuring)
807 case DWRITE_MEASURING_MODE_NATURAL:
809 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
810 mode = DWRITE_RENDERING_MODE_NATURAL;
811 else
812 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
813 break;
815 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
816 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
817 break;
818 case DWRITE_MEASURING_MODE_GDI_NATURAL:
819 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
820 break;
821 default:
825 return mode;
828 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
829 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
831 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
832 unsigned int flags;
833 FLOAT ppem;
835 TRACE("%p, %.8e, %.8e, %d, %p, %p.\n", iface, emSize, ppdip, measuring, params, mode);
837 if (!params) {
838 *mode = DWRITE_RENDERING_MODE_DEFAULT;
839 return E_INVALIDARG;
842 *mode = IDWriteRenderingParams_GetRenderingMode(params);
843 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
844 return S_OK;
846 ppem = emSize * ppdip;
848 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
849 *mode = DWRITE_RENDERING_MODE_OUTLINE;
850 return S_OK;
853 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), ppem);
854 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
855 return S_OK;
858 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT pixels_per_dip,
859 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
861 DWRITE_FONT_METRICS1 metrics1;
862 HRESULT hr = IDWriteFontFace5_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
863 memcpy(metrics, &metrics1, sizeof(*metrics));
864 return hr;
867 static inline int round_metric(FLOAT metric)
869 return (int)floorf(metric + 0.5f);
872 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
874 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
875 return 0;
877 return (fontface->metrics.designUnitsPerEm + 49) / 50;
880 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT ppdip,
881 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
882 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
884 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
885 UINT32 adjustment = fontface_get_horz_metric_adjustment(fontface);
886 DWRITE_MEASURING_MODE mode;
887 FLOAT scale, size;
888 HRESULT hr;
889 UINT32 i;
891 TRACE("%p, %.8e, %.8e, %p, %d, %p, %u, %p, %d.\n", iface, emSize, ppdip, m, use_gdi_natural, glyphs,
892 glyph_count, metrics, is_sideways);
894 if (m && memcmp(m, &identity, sizeof(*m)))
895 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
897 size = emSize * ppdip;
898 scale = size / fontface->metrics.designUnitsPerEm;
899 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
901 for (i = 0; i < glyph_count; i++) {
902 DWRITE_GLYPH_METRICS *ret = metrics + i;
903 DWRITE_GLYPH_METRICS design;
904 BOOL has_contours;
906 hr = IDWriteFontFace5_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
907 if (FAILED(hr))
908 return hr;
910 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
911 if (has_contours)
912 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size + adjustment);
913 else
914 ret->advanceWidth = round_metric(ret->advanceWidth * fontface->metrics.designUnitsPerEm / size);
916 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
917 SCALE_METRIC(leftSideBearing);
918 SCALE_METRIC(rightSideBearing);
919 SCALE_METRIC(topSideBearing);
920 SCALE_METRIC(advanceHeight);
921 SCALE_METRIC(bottomSideBearing);
922 SCALE_METRIC(verticalOriginY);
923 #undef SCALE_METRIC
926 return S_OK;
929 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace5 *iface, DWRITE_FONT_METRICS1 *metrics)
931 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
933 TRACE("%p, %p.\n", iface, metrics);
935 *metrics = fontface->metrics;
938 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace5 *iface, FLOAT em_size,
939 FLOAT pixels_per_dip, const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
941 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
942 const DWRITE_FONT_METRICS1 *design = &fontface->metrics;
943 UINT16 ascent, descent;
944 FLOAT scale;
946 TRACE("%p, %.8e, %.8e, %p, %p.\n", iface, em_size, pixels_per_dip, m, metrics);
948 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
949 memset(metrics, 0, sizeof(*metrics));
950 return E_INVALIDARG;
953 em_size *= pixels_per_dip;
954 if (m && m->m22 != 0.0f)
955 em_size *= fabs(m->m22);
957 scale = em_size / design->designUnitsPerEm;
958 if (!opentype_get_vdmx_size(get_fontface_vdmx(fontface), em_size, &ascent, &descent))
960 ascent = round_metric(design->ascent * scale);
961 descent = round_metric(design->descent * scale);
964 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
965 metrics->designUnitsPerEm = design->designUnitsPerEm;
966 metrics->ascent = round_metric(ascent / scale);
967 metrics->descent = round_metric(descent / scale);
969 SCALE_METRIC(lineGap);
970 SCALE_METRIC(capHeight);
971 SCALE_METRIC(xHeight);
972 SCALE_METRIC(underlinePosition);
973 SCALE_METRIC(underlineThickness);
974 SCALE_METRIC(strikethroughPosition);
975 SCALE_METRIC(strikethroughThickness);
976 SCALE_METRIC(glyphBoxLeft);
977 SCALE_METRIC(glyphBoxTop);
978 SCALE_METRIC(glyphBoxRight);
979 SCALE_METRIC(glyphBoxBottom);
980 SCALE_METRIC(subscriptPositionX);
981 SCALE_METRIC(subscriptPositionY);
982 SCALE_METRIC(subscriptSizeX);
983 SCALE_METRIC(subscriptSizeY);
984 SCALE_METRIC(superscriptPositionX);
985 SCALE_METRIC(superscriptPositionY);
986 SCALE_METRIC(superscriptSizeX);
987 SCALE_METRIC(superscriptSizeY);
989 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
990 #undef SCALE_METRIC
992 return S_OK;
995 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace5 *iface, DWRITE_CARET_METRICS *metrics)
997 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
999 TRACE("%p, %p.\n", iface, metrics);
1001 *metrics = fontface->caret;
1004 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, UINT32 max_count,
1005 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1007 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1009 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
1011 *count = 0;
1012 if (max_count && !ranges)
1013 return E_INVALIDARG;
1015 dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type);
1016 return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count);
1019 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface)
1021 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1023 TRACE("%p.\n", iface);
1025 return !!(fontface->flags & FONT_IS_MONOSPACED);
1028 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
1029 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
1031 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
1032 BOOL has_contours;
1033 int advance;
1035 if (is_sideways)
1036 FIXME("Sideways mode is not supported.\n");
1038 switch (measuring_mode)
1040 case DWRITE_MEASURING_MODE_NATURAL:
1041 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, fontface->metrics.designUnitsPerEm,
1042 glyph, measuring_mode, &has_contours);
1043 if (has_contours)
1044 advance += adjustment;
1046 return advance;
1047 case DWRITE_MEASURING_MODE_GDI_NATURAL:
1048 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
1049 emsize *= ppdip;
1050 if (emsize == 0.0f)
1051 return 0.0f;
1053 if (transform && memcmp(transform, &identity, sizeof(*transform)))
1054 FIXME("Transform is not supported.\n");
1056 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace5_iface, emsize, glyph, measuring_mode,
1057 &has_contours);
1058 if (has_contours)
1059 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
1060 else
1061 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
1063 return advance;
1064 default:
1065 WARN("Unknown measuring mode %u.\n", measuring_mode);
1066 return 0;
1070 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace5 *iface,
1071 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
1073 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1074 unsigned int i;
1076 TRACE("%p, %u, %p, %p, %d.\n", iface, glyph_count, glyphs, advances, is_sideways);
1078 if (is_sideways)
1079 FIXME("sideways mode not supported\n");
1081 for (i = 0; i < glyph_count; ++i)
1083 advances[i] = fontface_get_design_advance(fontface, DWRITE_MEASURING_MODE_NATURAL,
1084 fontface->metrics.designUnitsPerEm, 1.0f, NULL, glyphs[i], is_sideways);
1087 return S_OK;
1090 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace5 *iface,
1091 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1092 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1094 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1095 DWRITE_MEASURING_MODE measuring_mode;
1096 UINT32 i;
1098 TRACE("%p, %.8e, %.8e, %p, %d, %d, %u, %p, %p.\n", iface, em_size, ppdip, transform,
1099 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1101 if (em_size < 0.0f || ppdip <= 0.0f) {
1102 memset(advances, 0, sizeof(*advances) * glyph_count);
1103 return E_INVALIDARG;
1106 if (em_size == 0.0f) {
1107 memset(advances, 0, sizeof(*advances) * glyph_count);
1108 return S_OK;
1111 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1112 for (i = 0; i < glyph_count; ++i)
1114 advances[i] = fontface_get_design_advance(fontface, measuring_mode, em_size, ppdip, transform,
1115 glyphs[i], is_sideways);
1118 return S_OK;
1121 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace5 *iface, UINT32 count,
1122 const UINT16 *indices, INT32 *adjustments)
1124 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1125 UINT32 i;
1127 TRACE("%p, %u, %p, %p.\n", iface, count, indices, adjustments);
1129 if (!(indices || adjustments) || !count)
1130 return E_INVALIDARG;
1132 if (!indices || count == 1) {
1133 memset(adjustments, 0, count*sizeof(INT32));
1134 return E_INVALIDARG;
1137 if (!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS))
1139 memset(adjustments, 0, count*sizeof(INT32));
1140 return S_OK;
1143 for (i = 0; i < count-1; i++)
1144 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1145 adjustments[count-1] = 0;
1147 return S_OK;
1150 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace5 *iface)
1152 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1154 TRACE("%p.\n", iface);
1156 return !!(fontface->flags & FONTFACE_HAS_KERNING_PAIRS);
1159 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace5 *iface,
1160 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1161 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1163 DWRITE_GRID_FIT_MODE gridfitmode;
1164 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2 *)iface, font_emsize, dpiX, dpiY, transform,
1165 is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1168 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace5 *iface, UINT32 glyph_count,
1169 const UINT16 *nominal_glyphs, UINT16 *glyphs)
1171 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1173 TRACE("%p, %u, %p, %p.\n", iface, glyph_count, nominal_glyphs, glyphs);
1175 return opentype_get_vertical_glyph_variants(fontface, glyph_count, nominal_glyphs, glyphs);
1178 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace5 *iface)
1180 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1182 TRACE("%p.\n", iface);
1184 return !!(fontface->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1187 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace5 *iface)
1189 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1191 TRACE("%p.\n", iface);
1193 return !!(fontface->flags & FONT_IS_COLORED);
1196 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace5 *iface)
1198 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1200 TRACE("%p.\n", iface);
1202 return opentype_get_cpal_palettecount(get_fontface_cpal(fontface));
1205 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace5 *iface)
1207 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1209 TRACE("%p.\n", iface);
1211 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(fontface));
1214 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace5 *iface, UINT32 palette_index,
1215 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1217 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1219 TRACE("%p, %u, %u, %u, %p.\n", iface, palette_index, first_entry_index, entry_count, entries);
1221 return opentype_get_cpal_entries(get_fontface_cpal(fontface), palette_index, first_entry_index, entry_count, entries);
1224 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize,
1225 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1226 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1227 DWRITE_GRID_FIT_MODE *gridfitmode)
1229 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1230 unsigned int flags;
1231 FLOAT emthreshold;
1233 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1234 measuringmode, params, renderingmode, gridfitmode);
1236 if (m)
1237 FIXME("transform not supported %s\n", debugstr_matrix(m));
1239 if (is_sideways)
1240 FIXME("sideways mode not supported\n");
1242 emSize *= max(dpiX, dpiY) / 96.0f;
1244 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1245 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1246 if (params) {
1247 IDWriteRenderingParams2 *params2;
1248 HRESULT hr;
1250 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1251 if (hr == S_OK) {
1252 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1253 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1254 IDWriteRenderingParams2_Release(params2);
1256 else
1257 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1260 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1262 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1264 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1265 if (emSize >= emthreshold)
1266 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1267 else
1268 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1271 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1272 if (emSize >= emthreshold)
1273 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1274 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1275 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1276 else
1277 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1278 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1281 return S_OK;
1284 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace5 *iface,
1285 IDWriteFontFaceReference **reference)
1287 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1289 TRACE("%p, %p.\n", iface, reference);
1291 *reference = &fontface->IDWriteFontFaceReference_iface;
1292 IDWriteFontFaceReference_AddRef(*reference);
1294 return S_OK;
1297 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace5 *iface, DWRITE_PANOSE *panose)
1299 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1301 TRACE("%p, %p.\n", iface, panose);
1303 *panose = fontface->panose;
1306 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace5 *iface)
1308 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1310 TRACE("%p.\n", iface);
1312 return fontface->weight;
1315 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace5 *iface)
1317 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1319 TRACE("%p.\n", iface);
1321 return fontface->stretch;
1324 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace5 *iface)
1326 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1328 TRACE("%p.\n", iface);
1330 return fontface->style;
1333 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1335 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1337 TRACE("%p, %p.\n", iface, names);
1339 return clone_localizedstrings(fontface->family_names, names);
1342 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace5 *iface, IDWriteLocalizedStrings **names)
1344 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1346 TRACE("%p, %p.\n", iface, names);
1348 return clone_localizedstrings(fontface->names, names);
1351 static HRESULT get_font_info_strings(const struct file_stream_desc *stream_desc, IDWriteFontFile *file,
1352 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings_cache,
1353 IDWriteLocalizedStrings **ret, BOOL *exists)
1355 HRESULT hr = S_OK;
1357 *exists = FALSE;
1358 *ret = NULL;
1360 if (stringid > DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG
1361 || stringid <= DWRITE_INFORMATIONAL_STRING_NONE)
1363 return S_OK;
1366 if (!strings_cache[stringid])
1368 struct file_stream_desc desc = *stream_desc;
1370 if (!desc.stream)
1371 hr = get_filestream_from_file(file, &desc.stream);
1372 if (SUCCEEDED(hr))
1373 opentype_get_font_info_strings(&desc, stringid, &strings_cache[stringid]);
1375 if (!stream_desc->stream && desc.stream)
1376 IDWriteFontFileStream_Release(desc.stream);
1379 if (SUCCEEDED(hr) && strings_cache[stringid])
1381 hr = clone_localizedstrings(strings_cache[stringid], ret);
1382 if (SUCCEEDED(hr))
1383 *exists = TRUE;
1386 return hr;
1389 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace5 *iface,
1390 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1392 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1393 struct file_stream_desc stream_desc;
1395 TRACE("%p, %u, %p, %p.\n", iface, stringid, strings, exists);
1397 stream_desc.stream = fontface->stream;
1398 stream_desc.face_index = fontface->index;
1399 stream_desc.face_type = fontface->type;
1400 return get_font_info_strings(&stream_desc, NULL, stringid, fontface->info_strings, strings, exists);
1403 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 ch)
1405 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1407 TRACE("%p, %#x.\n", iface, ch);
1409 return !!dwritefontface_get_glyph(fontface, ch);
1412 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace5 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1413 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1414 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1416 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1417 unsigned int flags;
1418 FLOAT emthreshold;
1420 TRACE("%p, %.8e, %.8e, %.8e, %p, %d, %d, %d, %p, %p, %p.\n", iface, emSize, dpiX, dpiY, m, is_sideways, threshold,
1421 measuring_mode, params, rendering_mode, gridfit_mode);
1423 if (m)
1424 FIXME("transform not supported %s\n", debugstr_matrix(m));
1426 if (is_sideways)
1427 FIXME("sideways mode not supported\n");
1429 emSize *= max(dpiX, dpiY) / 96.0f;
1431 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1432 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1433 if (params) {
1434 IDWriteRenderingParams3 *params3;
1435 HRESULT hr;
1437 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1438 if (hr == S_OK) {
1439 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1440 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1441 IDWriteRenderingParams3_Release(params3);
1443 else
1444 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1447 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1449 flags = opentype_get_gasp_flags(get_fontface_gasp(fontface), emSize);
1451 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1452 if (emSize >= emthreshold)
1453 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1454 else
1455 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1458 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1459 if (emSize >= emthreshold)
1460 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1461 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1462 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1463 else
1464 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1465 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1468 return S_OK;
1471 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace5 *iface, UINT32 ch)
1473 FIXME("%p, %#x: stub\n", iface, ch);
1475 return FALSE;
1478 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace5 *iface, UINT16 glyph)
1480 FIXME("%p, %u: stub\n", iface, glyph);
1482 return FALSE;
1485 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace5 *iface, WCHAR const *text,
1486 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1488 FIXME("%p, %s:%u, %d %p: stub\n", iface, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1490 return E_NOTIMPL;
1493 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace5 *iface, UINT16 const *glyphs,
1494 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1496 FIXME("%p, %p, %u, %d, %p: stub\n", iface, glyphs, count, enqueue_if_not, are_local);
1498 return E_NOTIMPL;
1501 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace5 *iface, UINT16 glyph,
1502 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1504 FIXME("%p, %u, %u, %u, %p: stub\n", iface, glyph, ppem_first, ppem_last, formats);
1506 return E_NOTIMPL;
1509 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace5 *iface)
1511 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1513 TRACE("%p.\n", iface);
1515 return fontface->glyph_image_formats;
1518 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace5 *iface, UINT16 glyph,
1519 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1521 FIXME("%p, %u, %u, %d, %p, %p: stub\n", iface, glyph, ppem, format, data, context);
1523 return E_NOTIMPL;
1526 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace5 *iface, void *context)
1528 FIXME("%p, %p: stub\n", iface, context);
1531 static UINT32 WINAPI dwritefontface5_GetFontAxisValueCount(IDWriteFontFace5 *iface)
1533 FIXME("%p: stub\n", iface);
1535 return 0;
1538 static HRESULT WINAPI dwritefontface5_GetFontAxisValues(IDWriteFontFace5 *iface, DWRITE_FONT_AXIS_VALUE *axis_values,
1539 UINT32 value_count)
1541 FIXME("%p, %p, %u: stub\n", iface, axis_values, value_count);
1543 return E_NOTIMPL;
1546 static BOOL WINAPI dwritefontface5_HasVariations(IDWriteFontFace5 *iface)
1548 static int once;
1550 if (!once++)
1551 FIXME("%p: stub\n", iface);
1553 return FALSE;
1556 static HRESULT WINAPI dwritefontface5_GetFontResource(IDWriteFontFace5 *iface, IDWriteFontResource **resource)
1558 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface);
1560 TRACE("%p, %p.\n", iface, resource);
1562 return IDWriteFactory7_CreateFontResource(fontface->factory, fontface->files[0], fontface->index, resource);
1565 static BOOL WINAPI dwritefontface5_Equals(IDWriteFontFace5 *iface, IDWriteFontFace *other)
1567 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface), *other_face;
1569 TRACE("%p, %p.\n", iface, other);
1571 if (!(other_face = unsafe_impl_from_IDWriteFontFace(other)))
1572 return FALSE;
1574 /* TODO: add variations support */
1576 return fontface->index == other_face->index &&
1577 fontface->simulations == other_face->simulations &&
1578 is_same_fontfile(fontface->files[0], other_face->files[0]);
1581 static const IDWriteFontFace5Vtbl dwritefontfacevtbl =
1583 dwritefontface_QueryInterface,
1584 dwritefontface_AddRef,
1585 dwritefontface_Release,
1586 dwritefontface_GetType,
1587 dwritefontface_GetFiles,
1588 dwritefontface_GetIndex,
1589 dwritefontface_GetSimulations,
1590 dwritefontface_IsSymbolFont,
1591 dwritefontface_GetMetrics,
1592 dwritefontface_GetGlyphCount,
1593 dwritefontface_GetDesignGlyphMetrics,
1594 dwritefontface_GetGlyphIndices,
1595 dwritefontface_TryGetFontTable,
1596 dwritefontface_ReleaseFontTable,
1597 dwritefontface_GetGlyphRunOutline,
1598 dwritefontface_GetRecommendedRenderingMode,
1599 dwritefontface_GetGdiCompatibleMetrics,
1600 dwritefontface_GetGdiCompatibleGlyphMetrics,
1601 dwritefontface1_GetMetrics,
1602 dwritefontface1_GetGdiCompatibleMetrics,
1603 dwritefontface1_GetCaretMetrics,
1604 dwritefontface1_GetUnicodeRanges,
1605 dwritefontface1_IsMonospacedFont,
1606 dwritefontface1_GetDesignGlyphAdvances,
1607 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1608 dwritefontface1_GetKerningPairAdjustments,
1609 dwritefontface1_HasKerningPairs,
1610 dwritefontface1_GetRecommendedRenderingMode,
1611 dwritefontface1_GetVerticalGlyphVariants,
1612 dwritefontface1_HasVerticalGlyphVariants,
1613 dwritefontface2_IsColorFont,
1614 dwritefontface2_GetColorPaletteCount,
1615 dwritefontface2_GetPaletteEntryCount,
1616 dwritefontface2_GetPaletteEntries,
1617 dwritefontface2_GetRecommendedRenderingMode,
1618 dwritefontface3_GetFontFaceReference,
1619 dwritefontface3_GetPanose,
1620 dwritefontface3_GetWeight,
1621 dwritefontface3_GetStretch,
1622 dwritefontface3_GetStyle,
1623 dwritefontface3_GetFamilyNames,
1624 dwritefontface3_GetFaceNames,
1625 dwritefontface3_GetInformationalStrings,
1626 dwritefontface3_HasCharacter,
1627 dwritefontface3_GetRecommendedRenderingMode,
1628 dwritefontface3_IsCharacterLocal,
1629 dwritefontface3_IsGlyphLocal,
1630 dwritefontface3_AreCharactersLocal,
1631 dwritefontface3_AreGlyphsLocal,
1632 dwritefontface4_GetGlyphImageFormats_,
1633 dwritefontface4_GetGlyphImageFormats,
1634 dwritefontface4_GetGlyphImageData,
1635 dwritefontface4_ReleaseGlyphImageData,
1636 dwritefontface5_GetFontAxisValueCount,
1637 dwritefontface5_GetFontAxisValues,
1638 dwritefontface5_HasVariations,
1639 dwritefontface5_GetFontResource,
1640 dwritefontface5_Equals,
1643 static HRESULT WINAPI dwritefontface_reference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
1645 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1646 return IDWriteFontFace5_QueryInterface(&fontface->IDWriteFontFace5_iface, riid, obj);
1649 static ULONG WINAPI dwritefontface_reference_AddRef(IDWriteFontFaceReference *iface)
1651 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1652 return IDWriteFontFace5_AddRef(&fontface->IDWriteFontFace5_iface);
1655 static ULONG WINAPI dwritefontface_reference_Release(IDWriteFontFaceReference *iface)
1657 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1658 return IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
1661 static HRESULT WINAPI dwritefontface_reference_CreateFontFace(IDWriteFontFaceReference *iface,
1662 IDWriteFontFace3 **ret)
1664 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1666 TRACE("%p, %p.\n", iface, ret);
1668 *ret = (IDWriteFontFace3 *)&fontface->IDWriteFontFace5_iface;
1669 IDWriteFontFace3_AddRef(*ret);
1671 return S_OK;
1674 static HRESULT WINAPI dwritefontface_reference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
1675 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
1677 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1678 DWRITE_FONT_FILE_TYPE file_type;
1679 DWRITE_FONT_FACE_TYPE face_type;
1680 IDWriteFontFace *face;
1681 BOOL is_supported;
1682 UINT32 face_num;
1683 HRESULT hr;
1685 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
1687 hr = IDWriteFontFile_Analyze(fontface->files[0], &is_supported, &file_type, &face_type, &face_num);
1688 if (FAILED(hr))
1689 return hr;
1691 hr = IDWriteFactory7_CreateFontFace(fontface->factory, face_type, 1, fontface->files, fontface->index,
1692 simulations, &face);
1693 if (SUCCEEDED(hr))
1695 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void **)ret);
1696 IDWriteFontFace_Release(face);
1699 return hr;
1702 static BOOL WINAPI dwritefontface_reference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
1704 FIXME("%p, %p.\n", iface, ref);
1706 return E_NOTIMPL;
1709 static UINT32 WINAPI dwritefontface_reference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
1711 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1713 TRACE("%p.\n", iface);
1715 return fontface->index;
1718 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_reference_GetSimulations(IDWriteFontFaceReference *iface)
1720 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1722 TRACE("%p.\n", iface);
1724 return fontface->simulations;
1727 static HRESULT WINAPI dwritefontface_reference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
1729 struct dwrite_fontface *fontface = impl_from_IDWriteFontFaceReference(iface);
1731 TRACE("%p, %p.\n", iface, file);
1733 *file = fontface->files[0];
1734 IDWriteFontFile_AddRef(*file);
1736 return S_OK;
1739 static UINT64 WINAPI dwritefontface_reference_GetLocalFileSize(IDWriteFontFaceReference *iface)
1741 FIXME("%p.\n", iface);
1743 return 0;
1746 static UINT64 WINAPI dwritefontface_reference_GetFileSize(IDWriteFontFaceReference *iface)
1748 FIXME("%p.\n", iface);
1750 return 0;
1753 static HRESULT WINAPI dwritefontface_reference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
1755 FIXME("%p, %p.\n", iface, writetime);
1757 return E_NOTIMPL;
1760 static DWRITE_LOCALITY WINAPI dwritefontface_reference_GetLocality(IDWriteFontFaceReference *iface)
1762 FIXME("%p.\n", iface);
1764 return DWRITE_LOCALITY_LOCAL;
1767 static HRESULT WINAPI dwritefontface_reference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
1769 FIXME("%p.\n", iface);
1771 return E_NOTIMPL;
1774 static HRESULT WINAPI dwritefontface_reference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface,
1775 WCHAR const *chars, UINT32 count)
1777 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
1779 return E_NOTIMPL;
1782 static HRESULT WINAPI dwritefontface_reference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface,
1783 UINT16 const *glyphs, UINT32 count)
1785 FIXME("%p, %p, %u.\n", iface, glyphs, count);
1787 return E_NOTIMPL;
1790 static HRESULT WINAPI dwritefontface_reference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
1791 UINT64 offset, UINT64 size)
1793 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
1795 return E_NOTIMPL;
1798 static const IDWriteFontFaceReferenceVtbl dwritefontface_reference_vtbl =
1800 dwritefontface_reference_QueryInterface,
1801 dwritefontface_reference_AddRef,
1802 dwritefontface_reference_Release,
1803 dwritefontface_reference_CreateFontFace,
1804 dwritefontface_reference_CreateFontFaceWithSimulations,
1805 dwritefontface_reference_Equals,
1806 dwritefontface_reference_GetFontFaceIndex,
1807 dwritefontface_reference_GetSimulations,
1808 dwritefontface_reference_GetFontFile,
1809 dwritefontface_reference_GetLocalFileSize,
1810 dwritefontface_reference_GetFileSize,
1811 dwritefontface_reference_GetFileTime,
1812 dwritefontface_reference_GetLocality,
1813 dwritefontface_reference_EnqueueFontDownloadRequest,
1814 dwritefontface_reference_EnqueueCharacterDownloadRequest,
1815 dwritefontface_reference_EnqueueGlyphDownloadRequest,
1816 dwritefontface_reference_EnqueueFileFragmentDownloadRequest,
1819 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace5 **fontface)
1821 struct dwrite_font_data *data = font->data;
1822 struct fontface_desc desc;
1823 struct list *cached_list;
1824 HRESULT hr;
1826 *fontface = NULL;
1828 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1829 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1830 if (hr == S_OK)
1831 return hr;
1833 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1834 return hr;
1836 desc.factory = font->family->collection->factory;
1837 desc.face_type = data->face_type;
1838 desc.files = &data->file;
1839 desc.files_number = 1;
1840 desc.index = data->face_index;
1841 desc.simulations = data->simulations;
1842 desc.font_data = data;
1843 hr = create_fontface(&desc, cached_list, fontface);
1845 IDWriteFontFileStream_Release(desc.stream);
1846 return hr;
1849 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1851 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1853 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1855 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1856 IsEqualIID(riid, &IID_IDWriteFont2) ||
1857 IsEqualIID(riid, &IID_IDWriteFont1) ||
1858 IsEqualIID(riid, &IID_IDWriteFont) ||
1859 IsEqualIID(riid, &IID_IUnknown))
1861 *obj = iface;
1862 IDWriteFont3_AddRef(iface);
1863 return S_OK;
1866 WARN("%s not implemented.\n", debugstr_guid(riid));
1868 *obj = NULL;
1869 return E_NOINTERFACE;
1872 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1874 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1875 ULONG ref = InterlockedIncrement(&This->ref);
1876 TRACE("(%p)->(%d)\n", This, ref);
1877 return ref;
1880 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1882 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1883 ULONG ref = InterlockedDecrement(&This->ref);
1885 TRACE("(%p)->(%d)\n", This, ref);
1887 if (!ref) {
1888 IDWriteFontFamily2_Release(&This->family->IDWriteFontFamily2_iface);
1889 release_font_data(This->data);
1890 heap_free(This);
1893 return ref;
1896 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1898 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1899 TRACE("(%p)->(%p)\n", This, family);
1901 *family = (IDWriteFontFamily*)This->family;
1902 IDWriteFontFamily_AddRef(*family);
1903 return S_OK;
1906 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1908 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1909 TRACE("(%p)\n", This);
1910 return This->data->weight;
1913 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1915 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1916 TRACE("(%p)\n", This);
1917 return This->data->stretch;
1920 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1922 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1923 TRACE("(%p)\n", This);
1924 return This->style;
1927 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1929 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1931 TRACE("%p.\n", iface);
1933 return !!(font->data->flags & FONT_IS_SYMBOL);
1936 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1938 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1940 TRACE("%p, %p.\n", iface, names);
1942 return clone_localizedstrings(font->data->names, names);
1945 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1946 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1948 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1949 struct dwrite_font_data *data = font->data;
1950 struct file_stream_desc stream_desc;
1952 TRACE("%p, %d, %p, %p.\n", iface, stringid, strings, exists);
1954 /* Stream will be created if necessary. */
1955 stream_desc.stream = NULL;
1956 stream_desc.face_index = data->face_index;
1957 stream_desc.face_type = data->face_type;
1958 return get_font_info_strings(&stream_desc, data->file, stringid, data->info_strings, strings, exists);
1961 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1963 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1964 TRACE("(%p)\n", This);
1965 return This->data->simulations;
1968 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1970 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1972 TRACE("(%p)->(%p)\n", This, metrics);
1973 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1976 static BOOL dwritefont_has_character(struct dwrite_font *font, UINT32 ch)
1978 UINT16 glyph;
1979 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
1980 glyph = opentype_cmap_get_glyph(&font->data->cmap, ch);
1981 return glyph != 0;
1984 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1986 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1988 TRACE("%p, %#x, %p.\n", iface, ch, exists);
1990 *exists = dwritefont_has_character(font, ch);
1992 return S_OK;
1995 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1997 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
1999 TRACE("%p, %p.\n", iface, fontface);
2001 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2004 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
2006 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
2007 TRACE("(%p)->(%p)\n", This, metrics);
2008 *metrics = This->data->metrics;
2011 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
2013 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
2014 TRACE("(%p)->(%p)\n", This, panose);
2015 *panose = This->data->panose;
2018 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges,
2019 UINT32 *count)
2021 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2023 TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count);
2025 *count = 0;
2026 if (max_count && !ranges)
2027 return E_INVALIDARG;
2029 dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type);
2030 return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count);
2033 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
2035 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2037 TRACE("%p.\n", iface);
2039 return !!(font->data->flags & FONT_IS_MONOSPACED);
2042 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
2044 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2046 TRACE("%p.\n", iface);
2048 return !!(font->data->flags & FONT_IS_COLORED);
2051 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
2053 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2055 TRACE("%p, %p.\n", iface, fontface);
2057 return get_fontface_from_font(font, (IDWriteFontFace5 **)fontface);
2060 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *other)
2062 struct dwrite_font *font = impl_from_IDWriteFont3(iface), *other_font;
2064 TRACE("%p, %p.\n", iface, other);
2066 if (!(other_font = unsafe_impl_from_IDWriteFont(other)))
2067 return FALSE;
2069 return font->data->face_index == other_font->data->face_index
2070 && font->data->simulations == other_font->data->simulations
2071 && is_same_fontfile(font->data->file, other_font->data->file);
2074 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
2076 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2078 TRACE("%p, %p.\n", iface, reference);
2080 return IDWriteFactory7_CreateFontFaceReference(font->family->collection->factory, font->data->file,
2081 font->data->face_index, font->data->simulations, font->data->axis, ARRAY_SIZE(font->data->axis),
2082 (IDWriteFontFaceReference1 **)reference);
2085 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
2087 struct dwrite_font *font = impl_from_IDWriteFont3(iface);
2089 TRACE("%p, %#x.\n", iface, ch);
2091 return dwritefont_has_character(font, ch);
2094 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
2096 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
2097 FIXME("(%p): stub\n", This);
2098 return DWRITE_LOCALITY_LOCAL;
2101 static const IDWriteFont3Vtbl dwritefontvtbl = {
2102 dwritefont_QueryInterface,
2103 dwritefont_AddRef,
2104 dwritefont_Release,
2105 dwritefont_GetFontFamily,
2106 dwritefont_GetWeight,
2107 dwritefont_GetStretch,
2108 dwritefont_GetStyle,
2109 dwritefont_IsSymbolFont,
2110 dwritefont_GetFaceNames,
2111 dwritefont_GetInformationalStrings,
2112 dwritefont_GetSimulations,
2113 dwritefont_GetMetrics,
2114 dwritefont_HasCharacter,
2115 dwritefont_CreateFontFace,
2116 dwritefont1_GetMetrics,
2117 dwritefont1_GetPanose,
2118 dwritefont1_GetUnicodeRanges,
2119 dwritefont1_IsMonospacedFont,
2120 dwritefont2_IsColorFont,
2121 dwritefont3_CreateFontFace,
2122 dwritefont3_Equals,
2123 dwritefont3_GetFontFaceReference,
2124 dwritefont3_HasCharacter,
2125 dwritefont3_GetLocality
2128 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
2130 if (!iface)
2131 return NULL;
2132 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
2133 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
2136 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
2138 if (!iface)
2139 return NULL;
2140 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
2141 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace5_iface);
2144 static struct dwrite_fontfacereference *unsafe_impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
2146 if (!iface)
2147 return NULL;
2148 if (iface->lpVtbl != (IDWriteFontFaceReferenceVtbl *)&fontfacereferencevtbl)
2149 return NULL;
2150 return CONTAINING_RECORD((IDWriteFontFaceReference1 *)iface, struct dwrite_fontfacereference,
2151 IDWriteFontFaceReference1_iface);
2154 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
2156 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2157 *lf = font->data->lf;
2160 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
2162 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2163 *lf = fontface->lf;
2166 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
2168 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
2169 *fontsig = font->data->fontsig;
2170 return S_OK;
2173 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
2175 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
2176 *fontsig = fontface->fontsig;
2177 return S_OK;
2180 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
2182 struct dwrite_font *This;
2184 *font = NULL;
2186 This = heap_alloc(sizeof(*This));
2187 if (!This)
2188 return E_OUTOFMEMORY;
2190 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
2191 This->ref = 1;
2192 This->family = family;
2193 IDWriteFontFamily2_AddRef(&family->IDWriteFontFamily2_iface);
2194 This->data = family->data->fonts[index];
2195 This->style = This->data->style;
2196 addref_font_data(This->data);
2198 *font = &This->IDWriteFont3_iface;
2200 return S_OK;
2203 /* IDWriteFontList2 */
2204 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2206 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2208 if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2209 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2210 IsEqualIID(riid, &IID_IDWriteFontList) ||
2211 IsEqualIID(riid, &IID_IUnknown))
2213 *obj = iface;
2214 IDWriteFontList2_AddRef(iface);
2215 return S_OK;
2218 WARN("%s not implemented.\n", debugstr_guid(riid));
2220 *obj = NULL;
2221 return E_NOINTERFACE;
2224 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList2 *iface)
2226 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2227 ULONG refcount = InterlockedIncrement(&fontlist->refcount);
2229 TRACE("%p, refcount %u.\n", iface, refcount);
2231 return refcount;
2234 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList2 *iface)
2236 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2237 ULONG refcount = InterlockedDecrement(&fontlist->refcount);
2239 TRACE("%p, refcount %u.\n", iface, refcount);
2241 if (!refcount)
2243 UINT32 i;
2245 for (i = 0; i < fontlist->font_count; i++)
2246 release_font_data(fontlist->fonts[i]);
2247 IDWriteFontFamily2_Release(&fontlist->family->IDWriteFontFamily2_iface);
2248 heap_free(fontlist->fonts);
2249 heap_free(fontlist);
2252 return refcount;
2255 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList2 *iface, IDWriteFontCollection **collection)
2257 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2258 return IDWriteFontFamily2_GetFontCollection(&fontlist->family->IDWriteFontFamily2_iface, collection);
2261 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList2 *iface)
2263 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2265 TRACE("%p.\n", iface);
2267 return fontlist->font_count;
2270 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2272 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2274 TRACE("%p, %u, %p.\n", iface, index, font);
2276 *font = NULL;
2278 if (fontlist->font_count == 0)
2279 return S_FALSE;
2281 if (index >= fontlist->font_count)
2282 return E_INVALIDARG;
2284 return create_font(fontlist->family, index, (IDWriteFont3 **)font);
2287 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2289 FIXME("%p, %u.\n", iface, index);
2291 return DWRITE_LOCALITY_LOCAL;
2294 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2296 struct dwrite_fontlist *fontlist = impl_from_IDWriteFontList2(iface);
2298 TRACE("%p, %u, %p.\n", iface, index, font);
2300 *font = NULL;
2302 if (fontlist->font_count == 0)
2303 return S_FALSE;
2305 if (index >= fontlist->font_count)
2306 return E_FAIL;
2308 return create_font(fontlist->family, index, font);
2311 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2312 IDWriteFontFaceReference **reference)
2314 IDWriteFont3 *font;
2315 HRESULT hr;
2317 TRACE("%p, %u, %p.\n", iface, index, reference);
2319 *reference = NULL;
2321 hr = IDWriteFontList2_GetFont(iface, index, &font);
2322 if (FAILED(hr))
2323 return hr;
2325 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2326 IDWriteFont3_Release(font);
2328 return hr;
2331 static HRESULT WINAPI dwritefontlist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2333 FIXME("%p, %p.\n", iface, fontset);
2335 return E_NOTIMPL;
2338 static const IDWriteFontList2Vtbl dwritefontlistvtbl =
2340 dwritefontlist_QueryInterface,
2341 dwritefontlist_AddRef,
2342 dwritefontlist_Release,
2343 dwritefontlist_GetFontCollection,
2344 dwritefontlist_GetFontCount,
2345 dwritefontlist_GetFont,
2346 dwritefontlist1_GetFontLocality,
2347 dwritefontlist1_GetFont,
2348 dwritefontlist1_GetFontFaceReference,
2349 dwritefontlist2_GetFontSet,
2352 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily2 *iface, REFIID riid, void **obj)
2354 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2356 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2358 if (IsEqualIID(riid, &IID_IDWriteFontFamily2) ||
2359 IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2360 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2361 IsEqualIID(riid, &IID_IUnknown))
2363 *obj = iface;
2365 else if (IsEqualIID(riid, &IID_IDWriteFontList2) ||
2366 IsEqualIID(riid, &IID_IDWriteFontList1) ||
2367 IsEqualIID(riid, &IID_IDWriteFontList))
2369 *obj = &family->IDWriteFontList2_iface;
2371 else
2373 WARN("%s not implemented.\n", debugstr_guid(riid));
2374 *obj = NULL;
2375 return E_NOINTERFACE;
2378 IUnknown_AddRef((IUnknown *)*obj);
2379 return S_OK;
2382 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily2 *iface)
2384 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2385 ULONG refcount = InterlockedIncrement(&family->refcount);
2387 TRACE("%p, %u.\n", iface, refcount);
2389 return refcount;
2392 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily2 *iface)
2394 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2395 ULONG refcount = InterlockedDecrement(&family->refcount);
2397 TRACE("%p, %u.\n", iface, refcount);
2399 if (!refcount)
2401 IDWriteFontCollection3_Release(&family->collection->IDWriteFontCollection3_iface);
2402 release_fontfamily_data(family->data);
2403 heap_free(family);
2406 return refcount;
2409 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily2 *iface, IDWriteFontCollection **collection)
2411 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2413 TRACE("%p, %p.\n", iface, collection);
2415 *collection = (IDWriteFontCollection *)family->collection;
2416 IDWriteFontCollection_AddRef(*collection);
2417 return S_OK;
2420 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily2 *iface)
2422 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2424 TRACE("%p.\n", iface);
2426 return family->data->count;
2429 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont **font)
2431 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2433 TRACE("%p, %u, %p.\n", iface, index, font);
2435 *font = NULL;
2437 if (!family->data->count)
2438 return S_FALSE;
2440 if (index >= family->data->count)
2441 return E_INVALIDARG;
2443 return create_font(family, index, (IDWriteFont3 **)font);
2446 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily2 *iface, IDWriteLocalizedStrings **names)
2448 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2450 TRACE("%p, %p.\n", iface, names);
2452 return clone_localizedstrings(family->data->familyname, names);
2455 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2456 const struct dwrite_font_propvec *req)
2458 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2459 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2460 FLOAT cur_req_prod, next_req_prod;
2462 if (next_to_req < cur_to_req)
2463 return TRUE;
2465 if (next_to_req > cur_to_req)
2466 return FALSE;
2468 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2469 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2471 if (next_req_prod > cur_req_prod)
2472 return TRUE;
2474 if (next_req_prod < cur_req_prod)
2475 return FALSE;
2477 if (next->stretch > cur->stretch)
2478 return TRUE;
2479 if (next->stretch < cur->stretch)
2480 return FALSE;
2482 if (next->style > cur->style)
2483 return TRUE;
2484 if (next->style < cur->style)
2485 return FALSE;
2487 if (next->weight > cur->weight)
2488 return TRUE;
2489 if (next->weight < cur->weight)
2490 return FALSE;
2492 /* full match, no reason to prefer new variant */
2493 return FALSE;
2496 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2497 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2499 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2500 struct dwrite_font_propvec req;
2501 size_t i, match;
2503 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, font);
2505 if (!family->data->count)
2507 *font = NULL;
2508 return DWRITE_E_NOFONT;
2511 init_font_prop_vec(weight, stretch, style, &req);
2512 match = 0;
2514 for (i = 1; i < family->data->count; ++i)
2516 if (is_better_font_match(&family->data->fonts[i]->propvec, &family->data->fonts[match]->propvec, &req))
2517 match = i;
2520 return create_font(family, match, (IDWriteFont3 **)font);
2523 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2525 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2527 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2530 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2532 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2535 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2537 UINT32 b = fonts->font_count - 1, j, t;
2539 while (1) {
2540 t = b;
2542 for (j = 0; j < b; j++) {
2543 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2544 struct dwrite_font_data *s = fonts->fonts[j];
2545 fonts->fonts[j] = fonts->fonts[j+1];
2546 fonts->fonts[j+1] = s;
2547 t = j;
2551 if (t == b)
2552 break;
2553 b = t;
2557 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily2 *iface, DWRITE_FONT_WEIGHT weight,
2558 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2560 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2561 matching_filter_func func = NULL;
2562 struct dwrite_font_propvec req;
2563 struct dwrite_fontlist *fonts;
2564 size_t i;
2566 TRACE("%p, %d, %d, %d, %p.\n", iface, weight, stretch, style, ret);
2568 *ret = NULL;
2570 fonts = heap_alloc(sizeof(*fonts));
2571 if (!fonts)
2572 return E_OUTOFMEMORY;
2574 /* Allocate as many as family has, not all of them will be necessary used. */
2575 fonts->fonts = heap_calloc(family->data->count, sizeof(*fonts->fonts));
2576 if (!fonts->fonts) {
2577 heap_free(fonts);
2578 return E_OUTOFMEMORY;
2581 fonts->IDWriteFontList2_iface.lpVtbl = &dwritefontlistvtbl;
2582 fonts->refcount = 1;
2583 fonts->family = family;
2584 IDWriteFontFamily2_AddRef(&fonts->family->IDWriteFontFamily2_iface);
2585 fonts->font_count = 0;
2587 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2588 if (style == DWRITE_FONT_STYLE_NORMAL) {
2589 if (family->data->has_normal_face || family->data->has_italic_face)
2590 func = is_font_acceptable_for_normal;
2592 else /* requested oblique or italic */ {
2593 if (family->data->has_oblique_face || family->data->has_italic_face)
2594 func = is_font_acceptable_for_oblique_italic;
2597 for (i = 0; i < family->data->count; ++i)
2599 if (!func || func(family->data->fonts[i]))
2601 fonts->fonts[fonts->font_count] = family->data->fonts[i];
2602 addref_font_data(family->data->fonts[i]);
2603 fonts->font_count++;
2607 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2608 init_font_prop_vec(weight, stretch, style, &req);
2609 matchingfonts_sort(fonts, &req);
2611 *ret = (IDWriteFontList *)&fonts->IDWriteFontList2_iface;
2612 return S_OK;
2615 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily2 *iface, UINT32 index)
2617 FIXME("%p, %u.\n", iface, index);
2619 return DWRITE_LOCALITY_LOCAL;
2622 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily2 *iface, UINT32 index, IDWriteFont3 **font)
2624 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2626 TRACE("%p, %u, %p.\n", iface, index, font);
2628 *font = NULL;
2630 if (!family->data->count)
2631 return S_FALSE;
2633 if (index >= family->data->count)
2634 return E_FAIL;
2636 return create_font(family, index, font);
2639 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily2 *iface, UINT32 index,
2640 IDWriteFontFaceReference **reference)
2642 struct dwrite_fontfamily *family = impl_from_IDWriteFontFamily2(iface);
2643 const struct dwrite_font_data *font;
2645 TRACE("%p, %u, %p.\n", iface, index, reference);
2647 *reference = NULL;
2649 if (index >= family->data->count)
2650 return E_FAIL;
2652 font = family->data->fonts[index];
2653 return IDWriteFactory5_CreateFontFaceReference_((IDWriteFactory5 *)family->collection->factory,
2654 font->file, font->face_index, font->simulations, reference);
2657 static HRESULT WINAPI dwritefontfamily2_GetMatchingFonts(IDWriteFontFamily2 *iface,
2658 DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values, IDWriteFontList2 **fontlist)
2660 FIXME("%p, %p, %u, %p.\n", iface, axis_values, num_values, fontlist);
2662 return E_NOTIMPL;
2665 static HRESULT WINAPI dwritefontfamily2_GetFontSet(IDWriteFontFamily2 *iface, IDWriteFontSet1 **fontset)
2667 FIXME("%p, %p.\n", iface, fontset);
2669 return E_NOTIMPL;
2672 static const IDWriteFontFamily2Vtbl fontfamilyvtbl =
2674 dwritefontfamily_QueryInterface,
2675 dwritefontfamily_AddRef,
2676 dwritefontfamily_Release,
2677 dwritefontfamily_GetFontCollection,
2678 dwritefontfamily_GetFontCount,
2679 dwritefontfamily_GetFont,
2680 dwritefontfamily_GetFamilyNames,
2681 dwritefontfamily_GetFirstMatchingFont,
2682 dwritefontfamily_GetMatchingFonts,
2683 dwritefontfamily1_GetFontLocality,
2684 dwritefontfamily1_GetFont,
2685 dwritefontfamily1_GetFontFaceReference,
2686 dwritefontfamily2_GetMatchingFonts,
2687 dwritefontfamily2_GetFontSet,
2690 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList2 *iface, REFIID riid, void **obj)
2692 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2693 return dwritefontfamily_QueryInterface(&family->IDWriteFontFamily2_iface, riid, obj);
2696 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList2 *iface)
2698 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2699 return dwritefontfamily_AddRef(&family->IDWriteFontFamily2_iface);
2702 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList2 *iface)
2704 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2705 return dwritefontfamily_Release(&family->IDWriteFontFamily2_iface);
2708 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList2 *iface,
2709 IDWriteFontCollection **collection)
2711 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2712 return dwritefontfamily_GetFontCollection(&family->IDWriteFontFamily2_iface, collection);
2715 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList2 *iface)
2717 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2718 return dwritefontfamily_GetFontCount(&family->IDWriteFontFamily2_iface);
2721 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont **font)
2723 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2724 return dwritefontfamily_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2727 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList2 *iface, UINT32 index)
2729 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2730 return dwritefontfamily1_GetFontLocality(&family->IDWriteFontFamily2_iface, index);
2733 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList2 *iface, UINT32 index, IDWriteFont3 **font)
2735 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2736 return dwritefontfamily1_GetFont(&family->IDWriteFontFamily2_iface, index, font);
2739 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList2 *iface, UINT32 index,
2740 IDWriteFontFaceReference **reference)
2742 struct dwrite_fontfamily *family = impl_family_from_IDWriteFontList2(iface);
2743 return dwritefontfamily1_GetFontFaceReference(&family->IDWriteFontFamily2_iface, index, reference);
2746 static HRESULT WINAPI dwritefontfamilylist2_GetFontSet(IDWriteFontList2 *iface, IDWriteFontSet1 **fontset)
2748 FIXME("%p, %p.\n", iface, fontset);
2750 return E_NOTIMPL;
2753 static const IDWriteFontList2Vtbl fontfamilylistvtbl =
2755 dwritefontfamilylist_QueryInterface,
2756 dwritefontfamilylist_AddRef,
2757 dwritefontfamilylist_Release,
2758 dwritefontfamilylist_GetFontCollection,
2759 dwritefontfamilylist_GetFontCount,
2760 dwritefontfamilylist_GetFont,
2761 dwritefontfamilylist1_GetFontLocality,
2762 dwritefontfamilylist1_GetFont,
2763 dwritefontfamilylist1_GetFontFaceReference,
2764 dwritefontfamilylist2_GetFontSet,
2767 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index,
2768 struct dwrite_fontfamily **family)
2770 struct dwrite_fontfamily *object;
2772 *family = NULL;
2774 object = heap_alloc(sizeof(*object));
2775 if (!object)
2776 return E_OUTOFMEMORY;
2778 object->IDWriteFontFamily2_iface.lpVtbl = &fontfamilyvtbl;
2779 object->IDWriteFontList2_iface.lpVtbl = &fontfamilylistvtbl;
2780 object->refcount = 1;
2781 object->collection = collection;
2782 IDWriteFontCollection3_AddRef(&collection->IDWriteFontCollection3_iface);
2783 object->data = collection->family_data[index];
2784 InterlockedIncrement(&object->data->refcount);
2786 *family = object;
2788 return S_OK;
2791 BOOL is_system_collection(IDWriteFontCollection *collection)
2793 void *obj;
2794 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2797 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2799 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2801 TRACE("%p, %s, %p.\n", collection, debugstr_guid(riid), obj);
2803 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2804 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2805 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2806 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2807 IsEqualIID(riid, &IID_IUnknown))
2809 *obj = iface;
2810 IDWriteFontCollection3_AddRef(iface);
2811 return S_OK;
2814 *obj = NULL;
2816 if (IsEqualIID(riid, &IID_issystemcollection))
2817 return S_OK;
2819 WARN("%s not implemented.\n", debugstr_guid(riid));
2821 return E_NOINTERFACE;
2824 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection3 *iface, REFIID riid, void **obj)
2826 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
2828 if (IsEqualIID(riid, &IID_IDWriteFontCollection3) ||
2829 IsEqualIID(riid, &IID_IDWriteFontCollection2) ||
2830 IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2831 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2832 IsEqualIID(riid, &IID_IUnknown))
2834 *obj = iface;
2835 IDWriteFontCollection3_AddRef(iface);
2836 return S_OK;
2839 WARN("%s not implemented.\n", debugstr_guid(riid));
2841 *obj = NULL;
2843 return E_NOINTERFACE;
2846 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection3 *iface)
2848 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2849 ULONG refcount = InterlockedIncrement(&collection->refcount);
2851 TRACE("%p, refcount %d.\n", collection, refcount);
2853 return refcount;
2856 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection3 *iface)
2858 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2859 ULONG refcount = InterlockedDecrement(&collection->refcount);
2860 size_t i;
2862 TRACE("%p, refcount %d.\n", iface, refcount);
2864 if (!refcount)
2866 factory_detach_fontcollection(collection->factory, iface);
2867 for (i = 0; i < collection->count; ++i)
2868 release_fontfamily_data(collection->family_data[i]);
2869 heap_free(collection->family_data);
2870 heap_free(collection);
2873 return refcount;
2876 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection3 *iface)
2878 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2880 TRACE("%p.\n", iface);
2882 return collection->count;
2885 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
2886 IDWriteFontFamily **ret)
2888 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2889 struct dwrite_fontfamily *family;
2890 HRESULT hr;
2892 TRACE("%p, %u, %p.\n", iface, index, ret);
2894 *ret = NULL;
2896 if (index >= collection->count)
2897 return E_FAIL;
2899 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
2900 *ret = (IDWriteFontFamily *)&family->IDWriteFontFamily2_iface;
2902 return hr;
2905 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2907 size_t i;
2909 for (i = 0; i < collection->count; ++i)
2911 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2912 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2913 HRESULT hr;
2915 for (j = 0; j < count; j++) {
2916 WCHAR buffer[255];
2917 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, ARRAY_SIZE(buffer));
2918 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2919 return i;
2923 return ~0u;
2926 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection3 *iface, const WCHAR *name,
2927 UINT32 *index, BOOL *exists)
2929 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2931 TRACE("%p, %s, %p, %p.\n", iface, debugstr_w(name), index, exists);
2933 *index = collection_find_family(collection, name);
2934 *exists = *index != ~0u;
2935 return S_OK;
2938 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection3 *iface, IDWriteFontFace *face,
2939 IDWriteFont **font)
2941 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
2942 struct dwrite_fontfamily *family;
2943 BOOL found_font = FALSE;
2944 IDWriteFontFile *file;
2945 UINT32 face_index, count;
2946 size_t i, j;
2947 HRESULT hr;
2949 TRACE("%p, %p, %p.\n", iface, face, font);
2951 *font = NULL;
2953 if (!face)
2954 return E_INVALIDARG;
2956 count = 1;
2957 hr = IDWriteFontFace_GetFiles(face, &count, &file);
2958 if (FAILED(hr))
2959 return hr;
2960 face_index = IDWriteFontFace_GetIndex(face);
2962 found_font = FALSE;
2963 for (i = 0; i < collection->count; ++i)
2965 struct dwrite_fontfamily_data *family_data = collection->family_data[i];
2967 for (j = 0; j < family_data->count; ++j)
2969 struct dwrite_font_data *font_data = family_data->fonts[j];
2971 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2972 found_font = TRUE;
2973 break;
2977 if (found_font)
2978 break;
2980 IDWriteFontFile_Release(file);
2982 if (!found_font)
2983 return DWRITE_E_NOFONT;
2985 hr = create_fontfamily(collection, i, &family);
2986 if (FAILED(hr))
2987 return hr;
2989 hr = create_font(family, j, (IDWriteFont3 **)font);
2990 IDWriteFontFamily2_Release(&family->IDWriteFontFamily2_iface);
2991 return hr;
2994 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet **fontset)
2996 FIXME("%p, %p.\n", iface, fontset);
2998 return E_NOTIMPL;
3001 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection3 *iface, UINT32 index,
3002 IDWriteFontFamily1 **ret)
3004 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3005 struct dwrite_fontfamily *family;
3006 HRESULT hr;
3008 TRACE("%p, %u, %p.\n", iface, index, ret);
3010 *ret = NULL;
3012 if (index >= collection->count)
3013 return E_FAIL;
3015 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3016 *ret = (IDWriteFontFamily1 *)&family->IDWriteFontFamily2_iface;
3018 return hr;
3021 static HRESULT WINAPI dwritefontcollection2_GetFontFamily(IDWriteFontCollection3 *iface,
3022 UINT32 index, IDWriteFontFamily2 **ret)
3024 struct dwrite_fontcollection *collection = impl_from_IDWriteFontCollection3(iface);
3025 struct dwrite_fontfamily *family;
3026 HRESULT hr;
3028 TRACE("%p, %u, %p.\n", iface, index, ret);
3030 *ret = NULL;
3032 if (index >= collection->count)
3033 return E_FAIL;
3035 if (SUCCEEDED(hr = create_fontfamily(collection, index, &family)))
3036 *ret = &family->IDWriteFontFamily2_iface;
3038 return hr;
3041 static HRESULT WINAPI dwritefontcollection2_GetMatchingFonts(IDWriteFontCollection3 *iface,
3042 const WCHAR *familyname, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
3043 IDWriteFontList2 **fontlist)
3045 FIXME("%p, %s, %p, %u, %p.\n", iface, debugstr_w(familyname), axis_values, num_values, fontlist);
3047 return E_NOTIMPL;
3050 static DWRITE_FONT_FAMILY_MODEL WINAPI dwritefontcollection2_GetFontFamilyModel(IDWriteFontCollection3 *iface)
3052 FIXME("%p.\n", iface);
3054 return DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE;
3057 static HRESULT WINAPI dwritefontcollection2_GetFontSet(IDWriteFontCollection3 *iface, IDWriteFontSet1 **fontset)
3059 FIXME("%p, %p.\n", iface, fontset);
3061 return E_NOTIMPL;
3064 static HANDLE WINAPI dwritefontcollection3_GetExpirationEvent(IDWriteFontCollection3 *iface)
3066 FIXME("%p.\n", iface);
3068 return NULL;
3071 static const IDWriteFontCollection3Vtbl fontcollectionvtbl =
3073 dwritefontcollection_QueryInterface,
3074 dwritefontcollection_AddRef,
3075 dwritefontcollection_Release,
3076 dwritefontcollection_GetFontFamilyCount,
3077 dwritefontcollection_GetFontFamily,
3078 dwritefontcollection_FindFamilyName,
3079 dwritefontcollection_GetFontFromFontFace,
3080 dwritefontcollection1_GetFontSet,
3081 dwritefontcollection1_GetFontFamily,
3082 dwritefontcollection2_GetFontFamily,
3083 dwritefontcollection2_GetMatchingFonts,
3084 dwritefontcollection2_GetFontFamilyModel,
3085 dwritefontcollection2_GetFontSet,
3086 dwritefontcollection3_GetExpirationEvent,
3089 static const IDWriteFontCollection3Vtbl systemfontcollectionvtbl =
3091 dwritesystemfontcollection_QueryInterface,
3092 dwritefontcollection_AddRef,
3093 dwritefontcollection_Release,
3094 dwritefontcollection_GetFontFamilyCount,
3095 dwritefontcollection_GetFontFamily,
3096 dwritefontcollection_FindFamilyName,
3097 dwritefontcollection_GetFontFromFontFace,
3098 dwritefontcollection1_GetFontSet,
3099 dwritefontcollection1_GetFontFamily,
3100 dwritefontcollection2_GetFontFamily,
3101 dwritefontcollection2_GetMatchingFonts,
3102 dwritefontcollection2_GetFontFamilyModel,
3103 dwritefontcollection2_GetFontSet,
3104 dwritefontcollection3_GetExpirationEvent,
3107 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
3109 if (!dwrite_array_reserve((void **)&family_data->fonts, &family_data->size, family_data->count + 1,
3110 sizeof(*family_data->fonts)))
3112 return E_OUTOFMEMORY;
3115 family_data->fonts[family_data->count++] = font_data;
3116 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
3117 family_data->has_normal_face = 1;
3118 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
3119 family_data->has_oblique_face = 1;
3120 else
3121 family_data->has_italic_face = 1;
3122 return S_OK;
3125 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection,
3126 struct dwrite_fontfamily_data *family)
3128 if (!dwrite_array_reserve((void **)&collection->family_data, &collection->size, collection->count + 1,
3129 sizeof(*collection->family_data)))
3131 return E_OUTOFMEMORY;
3134 collection->family_data[collection->count++] = family;
3135 return S_OK;
3138 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
3140 collection->IDWriteFontCollection3_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
3141 collection->refcount = 1;
3142 collection->count = 0;
3143 collection->size = 0;
3144 collection->family_data = NULL;
3146 return S_OK;
3149 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3151 IDWriteFontFileLoader *loader;
3152 const void *key;
3153 UINT32 key_size;
3154 HRESULT hr;
3156 *stream = NULL;
3158 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3159 if (FAILED(hr))
3160 return hr;
3162 hr = IDWriteFontFile_GetLoader(file, &loader);
3163 if (FAILED(hr))
3164 return hr;
3166 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3167 IDWriteFontFileLoader_Release(loader);
3168 if (FAILED(hr))
3169 return hr;
3171 return hr;
3174 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
3176 BOOL exists = FALSE;
3177 UINT32 index;
3178 HRESULT hr;
3180 buffer[0] = 0;
3181 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3182 if (FAILED(hr) || !exists)
3183 return;
3185 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
3188 static int trim_spaces(WCHAR *in, WCHAR *ret)
3190 int len;
3192 while (isspaceW(*in))
3193 in++;
3195 ret[0] = 0;
3196 if (!(len = strlenW(in)))
3197 return 0;
3199 while (isspaceW(in[len-1]))
3200 len--;
3202 memcpy(ret, in, len*sizeof(WCHAR));
3203 ret[len] = 0;
3205 return len;
3208 struct name_token {
3209 struct list entry;
3210 const WCHAR *ptr;
3211 INT len; /* token length */
3212 INT fulllen; /* full length including following separators */
3215 static inline BOOL is_name_separator_char(WCHAR ch)
3217 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
3220 struct name_pattern {
3221 const WCHAR *part1; /* NULL indicates end of list */
3222 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
3225 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
3227 const struct name_pattern *pattern;
3228 struct name_token *token;
3229 int i = 0;
3231 while ((pattern = &patterns[i++])->part1) {
3232 int len_part1 = strlenW(pattern->part1);
3233 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
3235 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
3236 if (len_part2 == 0) {
3237 /* simple case with single part pattern */
3238 if (token->len != len_part1)
3239 continue;
3241 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
3242 if (match) *match = *token;
3243 list_remove(&token->entry);
3244 heap_free(token);
3245 return TRUE;
3248 else {
3249 struct name_token *next_token;
3250 struct list *next_entry;
3252 /* pattern parts are stored in reading order, tokens list is reversed */
3253 if (token->len < len_part2)
3254 continue;
3256 /* it's possible to have combined string as a token, like ExtraCondensed */
3257 if (token->len == len_part1 + len_part2) {
3258 if (strncmpiW(token->ptr, pattern->part1, len_part1))
3259 continue;
3261 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
3262 continue;
3264 /* combined string match */
3265 if (match) *match = *token;
3266 list_remove(&token->entry);
3267 heap_free(token);
3268 return TRUE;
3271 /* now it's only possible to have two tokens matched to respective pattern parts */
3272 if (token->len != len_part2)
3273 continue;
3275 next_entry = list_next(tokens, &token->entry);
3276 if (next_entry) {
3277 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
3278 if (next_token->len != len_part1)
3279 continue;
3281 if (strncmpiW(token->ptr, pattern->part2, len_part2))
3282 continue;
3284 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
3285 continue;
3287 /* both parts matched, remove tokens */
3288 if (match) {
3289 match->ptr = next_token->ptr;
3290 match->len = (token->ptr - next_token->ptr) + token->len;
3292 list_remove(&token->entry);
3293 list_remove(&next_token->entry);
3294 heap_free(next_token);
3295 heap_free(token);
3296 return TRUE;
3302 if (match) {
3303 match->ptr = NULL;
3304 match->len = 0;
3306 return FALSE;
3309 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
3311 static const WCHAR itaW[] = {'i','t','a',0};
3312 static const WCHAR italW[] = {'i','t','a','l',0};
3313 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
3314 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
3316 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
3317 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
3318 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
3319 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
3321 static const struct name_pattern italic_patterns[] = {
3322 { itaW },
3323 { italW },
3324 { italicW },
3325 { cursiveW },
3326 { kursivW },
3327 { NULL }
3330 static const struct name_pattern oblique_patterns[] = {
3331 { inclinedW },
3332 { obliqueW },
3333 { backslantedW },
3334 { backslantW },
3335 { slantedW },
3336 { NULL }
3339 /* italic patterns first */
3340 if (match_pattern_list(tokens, italic_patterns, match))
3341 return DWRITE_FONT_STYLE_ITALIC;
3343 /* oblique patterns */
3344 if (match_pattern_list(tokens, oblique_patterns, match))
3345 return DWRITE_FONT_STYLE_OBLIQUE;
3347 return style;
3350 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
3351 struct name_token *match)
3353 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
3354 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
3355 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
3356 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
3357 static const WCHAR wideW[] = {'w','i','d','e',0};
3358 static const WCHAR condW[] = {'c','o','n','d',0};
3360 static const struct name_pattern ultracondensed_patterns[] = {
3361 { extraW, compressedW },
3362 { extW, compressedW },
3363 { ultraW, compressedW },
3364 { ultraW, condensedW },
3365 { ultraW, condW },
3366 { NULL }
3369 static const struct name_pattern extracondensed_patterns[] = {
3370 { compressedW },
3371 { extraW, condensedW },
3372 { extW, condensedW },
3373 { extraW, condW },
3374 { extW, condW },
3375 { NULL }
3378 static const struct name_pattern semicondensed_patterns[] = {
3379 { narrowW },
3380 { compactW },
3381 { semiW, condensedW },
3382 { semiW, condW },
3383 { NULL }
3386 static const struct name_pattern semiexpanded_patterns[] = {
3387 { wideW },
3388 { semiW, expandedW },
3389 { semiW, extendedW },
3390 { NULL }
3393 static const struct name_pattern extraexpanded_patterns[] = {
3394 { extraW, expandedW },
3395 { extW, expandedW },
3396 { extraW, extendedW },
3397 { extW, extendedW },
3398 { NULL }
3401 static const struct name_pattern ultraexpanded_patterns[] = {
3402 { ultraW, expandedW },
3403 { ultraW, extendedW },
3404 { NULL }
3407 static const struct name_pattern condensed_patterns[] = {
3408 { condensedW },
3409 { condW },
3410 { NULL }
3413 static const struct name_pattern expanded_patterns[] = {
3414 { expandedW },
3415 { extendedW },
3416 { NULL }
3419 if (match_pattern_list(tokens, ultracondensed_patterns, match))
3420 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3422 if (match_pattern_list(tokens, extracondensed_patterns, match))
3423 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3425 if (match_pattern_list(tokens, semicondensed_patterns, match))
3426 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3428 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3429 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3431 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3432 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3434 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3435 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3437 if (match_pattern_list(tokens, condensed_patterns, match))
3438 return DWRITE_FONT_STRETCH_CONDENSED;
3440 if (match_pattern_list(tokens, expanded_patterns, match))
3441 return DWRITE_FONT_STRETCH_EXPANDED;
3443 return stretch;
3446 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3447 struct name_token *match)
3449 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3450 static const WCHAR nordW[] = {'n','o','r','d',0};
3452 static const struct name_pattern thin_patterns[] = {
3453 { extraW, thinW },
3454 { extW, thinW },
3455 { ultraW, thinW },
3456 { NULL }
3459 static const struct name_pattern extralight_patterns[] = {
3460 { extraW, lightW },
3461 { extW, lightW },
3462 { ultraW, lightW },
3463 { NULL }
3466 static const struct name_pattern semilight_patterns[] = {
3467 { semiW, lightW },
3468 { NULL }
3471 static const struct name_pattern demibold_patterns[] = {
3472 { semiW, boldW },
3473 { demiW, boldW },
3474 { NULL }
3477 static const struct name_pattern extrabold_patterns[] = {
3478 { extraW, boldW },
3479 { extW, boldW },
3480 { ultraW, boldW },
3481 { NULL }
3484 static const struct name_pattern extrablack_patterns[] = {
3485 { extraW, blackW },
3486 { extW, blackW },
3487 { ultraW, blackW },
3488 { NULL }
3491 static const struct name_pattern bold_patterns[] = {
3492 { boldW },
3493 { NULL }
3496 static const struct name_pattern thin2_patterns[] = {
3497 { thinW },
3498 { NULL }
3501 static const struct name_pattern light_patterns[] = {
3502 { lightW },
3503 { NULL }
3506 static const struct name_pattern medium_patterns[] = {
3507 { mediumW },
3508 { NULL }
3511 static const struct name_pattern black_patterns[] = {
3512 { blackW },
3513 { heavyW },
3514 { nordW },
3515 { NULL }
3518 static const struct name_pattern demibold2_patterns[] = {
3519 { demiW },
3520 { NULL }
3523 static const struct name_pattern extrabold2_patterns[] = {
3524 { ultraW },
3525 { NULL }
3528 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3529 matching pattern. */
3531 if (match_pattern_list(tokens, thin_patterns, match))
3532 return DWRITE_FONT_WEIGHT_THIN;
3534 if (match_pattern_list(tokens, extralight_patterns, match))
3535 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3537 if (match_pattern_list(tokens, semilight_patterns, match))
3538 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3540 if (match_pattern_list(tokens, demibold_patterns, match))
3541 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3543 if (match_pattern_list(tokens, extrabold_patterns, match))
3544 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3546 if (match_pattern_list(tokens, extrablack_patterns, match))
3547 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3549 if (match_pattern_list(tokens, bold_patterns, match))
3550 return DWRITE_FONT_WEIGHT_BOLD;
3552 if (match_pattern_list(tokens, thin2_patterns, match))
3553 return DWRITE_FONT_WEIGHT_THIN;
3555 if (match_pattern_list(tokens, light_patterns, match))
3556 return DWRITE_FONT_WEIGHT_LIGHT;
3558 if (match_pattern_list(tokens, medium_patterns, match))
3559 return DWRITE_FONT_WEIGHT_MEDIUM;
3561 if (match_pattern_list(tokens, black_patterns, match))
3562 return DWRITE_FONT_WEIGHT_BLACK;
3564 if (match_pattern_list(tokens, black_patterns, match))
3565 return DWRITE_FONT_WEIGHT_BLACK;
3567 if (match_pattern_list(tokens, demibold2_patterns, match))
3568 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3570 if (match_pattern_list(tokens, extrabold2_patterns, match))
3571 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3573 /* FIXME: use abbreviated names to extract weight */
3575 return weight;
3578 struct knownweight_entry {
3579 const WCHAR *nameW;
3580 DWRITE_FONT_WEIGHT weight;
3583 static int compare_knownweights(const void *a, const void* b)
3585 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3586 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3587 int ret = 0;
3589 if (target > entry->weight)
3590 ret = 1;
3591 else if (target < entry->weight)
3592 ret = -1;
3594 return ret;
3597 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3599 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3600 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3601 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3602 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3603 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3604 const struct knownweight_entry *ptr;
3606 static const struct knownweight_entry knownweights[] = {
3607 { thinW, DWRITE_FONT_WEIGHT_THIN },
3608 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3609 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3610 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3611 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3612 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3613 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3614 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3615 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3616 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3619 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3620 compare_knownweights);
3621 if (!ptr) {
3622 nameW[0] = 0;
3623 return FALSE;
3626 strcpyW(nameW, ptr->nameW);
3627 return TRUE;
3630 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3632 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3633 strW[name->len] = 0;
3636 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3637 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3639 static const WCHAR bookW[] = {'B','o','o','k',0};
3640 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3641 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3642 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3643 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3645 static const WCHAR *regular_patterns[] = {
3646 bookW,
3647 normalW,
3648 regularW,
3649 romanW,
3650 uprightW,
3651 NULL
3654 const WCHAR *regular_ptr = NULL, *ptr;
3655 int i = 0;
3657 if (len == -1)
3658 len = strlenW(facenameW);
3660 /* remove rightmost regular variant from face name */
3661 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3662 int pattern_len = strlenW(ptr);
3663 WCHAR *src;
3665 if (pattern_len > len)
3666 continue;
3668 src = facenameW + len - pattern_len;
3669 while (src >= facenameW) {
3670 if (!strncmpiW(src, ptr, pattern_len)) {
3671 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3672 len = strlenW(facenameW);
3673 regular_ptr = ptr;
3674 break;
3676 else
3677 src--;
3681 return regular_ptr;
3684 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3686 const WCHAR *ptr;
3688 list_init(tokens);
3689 ptr = nameW;
3691 while (*ptr) {
3692 struct name_token *token = heap_alloc(sizeof(*token));
3693 token->ptr = ptr;
3694 token->len = 0;
3695 token->fulllen = 0;
3697 while (*ptr && !is_name_separator_char(*ptr)) {
3698 token->len++;
3699 token->fulllen++;
3700 ptr++;
3703 /* skip separators */
3704 while (is_name_separator_char(*ptr)) {
3705 token->fulllen++;
3706 ptr++;
3709 list_add_head(tokens, &token->entry);
3713 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3715 struct name_token *token, *token2;
3716 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3717 int len;
3719 list_remove(&token->entry);
3721 /* don't include last separator */
3722 len = list_empty(tokens) ? token->len : token->fulllen;
3723 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3724 nameW += len;
3726 heap_free(token);
3728 *nameW = 0;
3731 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3733 struct name_token stretch_name, weight_name, style_name;
3734 WCHAR familynameW[255], facenameW[255], finalW[255];
3735 WCHAR weightW[32], stretchW[32], styleW[32];
3736 const WCHAR *regular_ptr = NULL;
3737 DWRITE_FONT_STRETCH stretch;
3738 DWRITE_FONT_WEIGHT weight;
3739 struct list tokens;
3740 int len;
3742 /* remove leading and trailing spaces from family and face name */
3743 trim_spaces(familyW, familynameW);
3744 len = trim_spaces(faceW, facenameW);
3746 /* remove rightmost regular variant from face name */
3747 regular_ptr = facename_remove_regular_term(facenameW, len);
3749 /* append face name to family name, FIXME check if face name is a substring of family name */
3750 if (*facenameW) {
3751 strcatW(familynameW, spaceW);
3752 strcatW(familynameW, facenameW);
3755 /* tokenize with " .-_" */
3756 fontname_tokenize(&tokens, familynameW);
3758 /* extract and resolve style */
3759 font->style = font_extract_style(&tokens, font->style, &style_name);
3761 /* extract stretch */
3762 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3764 /* extract weight */
3765 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3767 /* resolve weight */
3768 if (weight != font->weight) {
3769 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3770 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3771 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3772 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3773 !(abs(weight - font->weight) <= 150 &&
3774 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3775 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3776 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3778 font->weight = weight;
3782 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3783 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3784 stretch itself is normal (extracted stretch is never normal). */
3785 if (stretch != font->stretch) {
3786 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3787 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3788 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3790 font->stretch = stretch;
3794 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3796 /* get final combined string from what's left in token list, list is released */
3797 fontname_tokens_to_str(&tokens, finalW);
3799 if (!strcmpW(familyW, finalW))
3800 return FALSE;
3802 /* construct face name */
3803 strcpyW(familyW, finalW);
3805 /* resolved weight name */
3806 if (weight_name.ptr)
3807 font_name_token_to_str(&weight_name, weightW);
3808 /* ignore normal weight */
3809 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3810 weightW[0] = 0;
3811 /* for known weight values use appropriate names */
3812 else if (is_known_weight_value(font->weight, weightW)) {
3814 /* use Wnnn format as a fallback in case weight is not one of known values */
3815 else {
3816 static const WCHAR fmtW[] = {'W','%','d',0};
3817 sprintfW(weightW, fmtW, font->weight);
3820 /* resolved stretch name */
3821 if (stretch_name.ptr)
3822 font_name_token_to_str(&stretch_name, stretchW);
3823 /* ignore normal stretch */
3824 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3825 stretchW[0] = 0;
3826 /* use predefined stretch names */
3827 else {
3828 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3829 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3830 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3831 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3832 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3833 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3835 static const WCHAR *stretchnamesW[] = {
3836 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3837 ultracondensedW,
3838 extracondensedW,
3839 condensedW,
3840 semicondensedW,
3841 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3842 semiexpandedW,
3843 expandedW,
3844 extraexpandedW,
3845 ultraexpandedW
3847 strcpyW(stretchW, stretchnamesW[font->stretch]);
3850 /* resolved style name */
3851 if (style_name.ptr)
3852 font_name_token_to_str(&style_name, styleW);
3853 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3854 styleW[0] = 0;
3855 /* use predefined names */
3856 else {
3857 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3858 strcpyW(styleW, italicW);
3859 else
3860 strcpyW(styleW, obliqueW);
3863 /* use Regular match if it was found initially */
3864 if (!*weightW && !*stretchW && !*styleW)
3865 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3866 else {
3867 faceW[0] = 0;
3868 if (*stretchW)
3869 strcpyW(faceW, stretchW);
3870 if (*weightW) {
3871 if (*faceW)
3872 strcatW(faceW, spaceW);
3873 strcatW(faceW, weightW);
3875 if (*styleW) {
3876 if (*faceW)
3877 strcatW(faceW, spaceW);
3878 strcatW(faceW, styleW);
3882 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3883 return TRUE;
3886 static HRESULT init_font_data(const struct fontface_desc *desc, struct dwrite_font_data **ret)
3888 static const float width_axis_values[] =
3890 0.0f, /* DWRITE_FONT_STRETCH_UNDEFINED */
3891 50.0f, /* DWRITE_FONT_STRETCH_ULTRA_CONDENSED */
3892 62.5f, /* DWRITE_FONT_STRETCH_EXTRA_CONDENSED */
3893 75.0f, /* DWRITE_FONT_STRETCH_CONDENSED */
3894 87.5f, /* DWRITE_FONT_STRETCH_SEMI_CONDENSED */
3895 100.0f, /* DWRITE_FONT_STRETCH_NORMAL */
3896 112.5f, /* DWRITE_FONT_STRETCH_SEMI_EXPANDED */
3897 125.0f, /* DWRITE_FONT_STRETCH_EXPANDED */
3898 150.0f, /* DWRITE_FONT_STRETCH_EXTRA_EXPANDED */
3899 200.0f, /* DWRITE_FONT_STRETCH_ULTRA_EXPANDED */
3902 struct file_stream_desc stream_desc;
3903 struct dwrite_font_props props;
3904 struct dwrite_font_data *data;
3905 WCHAR familyW[255], faceW[255];
3906 HRESULT hr;
3908 *ret = NULL;
3910 data = heap_alloc_zero(sizeof(*data));
3911 if (!data)
3912 return E_OUTOFMEMORY;
3914 data->ref = 1;
3915 data->file = desc->files[0];
3916 data->face_index = desc->index;
3917 data->face_type = desc->face_type;
3918 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3919 data->bold_sim_tested = 0;
3920 data->oblique_sim_tested = 0;
3921 IDWriteFontFile_AddRef(data->file);
3923 stream_desc.stream = desc->stream;
3924 stream_desc.face_type = desc->face_type;
3925 stream_desc.face_index = desc->index;
3926 opentype_get_font_properties(&stream_desc, &props);
3927 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3928 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3930 /* get family name from font file */
3931 hr = opentype_get_font_familyname(&stream_desc, &data->family_names);
3932 if (FAILED(hr)) {
3933 WARN("unable to get family name from font\n");
3934 release_font_data(data);
3935 return hr;
3938 data->style = props.style;
3939 data->stretch = props.stretch;
3940 data->weight = props.weight;
3941 data->panose = props.panose;
3942 data->fontsig = props.fontsig;
3943 data->lf = props.lf;
3944 data->flags = props.flags;
3946 fontstrings_get_en_string(data->family_names, familyW, ARRAY_SIZE(familyW));
3947 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3948 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3949 set_en_localizedstring(data->family_names, familyW);
3950 set_en_localizedstring(data->names, faceW);
3953 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3955 data->axis[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
3956 data->axis[0].value = props.weight;
3957 data->axis[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
3958 data->axis[1].value = width_axis_values[props.stretch];
3959 data->axis[2].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
3960 data->axis[2].value = data->style == DWRITE_FONT_STYLE_ITALIC ? 1.0f : 0.0f;
3962 *ret = data;
3963 return S_OK;
3966 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3967 const WCHAR *facenameW, struct dwrite_font_data **ret)
3969 struct dwrite_font_data *data;
3971 *ret = NULL;
3973 data = heap_alloc_zero(sizeof(*data));
3974 if (!data)
3975 return E_OUTOFMEMORY;
3977 *data = *src;
3978 data->ref = 1;
3979 data->simulations |= sim;
3980 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3981 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3982 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3983 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3984 memset(data->info_strings, 0, sizeof(data->info_strings));
3985 data->names = NULL;
3986 IDWriteFontFile_AddRef(data->file);
3987 IDWriteLocalizedStrings_AddRef(data->family_names);
3989 create_localizedstrings(&data->names);
3990 add_localizedstring(data->names, enusW, facenameW);
3992 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3994 *ret = data;
3995 return S_OK;
3998 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
4000 struct dwrite_fontfamily_data *data;
4002 data = heap_alloc_zero(sizeof(*data));
4003 if (!data)
4004 return E_OUTOFMEMORY;
4006 data->refcount = 1;
4007 data->familyname = familyname;
4008 IDWriteLocalizedStrings_AddRef(familyname);
4010 *ret = data;
4012 return S_OK;
4015 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
4017 size_t i, j, heaviest;
4019 for (i = 0; i < family->count; ++i)
4021 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
4022 heaviest = i;
4024 if (family->fonts[i]->bold_sim_tested)
4025 continue;
4027 family->fonts[i]->bold_sim_tested = 1;
4028 for (j = i; j < family->count; ++j)
4030 if (family->fonts[j]->bold_sim_tested)
4031 continue;
4033 if ((family->fonts[i]->style == family->fonts[j]->style) &&
4034 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4035 if (family->fonts[j]->weight > weight) {
4036 weight = family->fonts[j]->weight;
4037 heaviest = j;
4039 family->fonts[j]->bold_sim_tested = 1;
4043 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
4044 static const struct name_pattern weightsim_patterns[] = {
4045 { extraW, lightW },
4046 { extW, lightW },
4047 { ultraW, lightW },
4048 { semiW, lightW },
4049 { semiW, boldW },
4050 { demiW, boldW },
4051 { boldW },
4052 { thinW },
4053 { lightW },
4054 { mediumW },
4055 { demiW },
4056 { NULL }
4059 WCHAR facenameW[255], initialW[255];
4060 struct dwrite_font_data *boldface;
4061 struct list tokens;
4063 /* add Bold simulation based on heaviest face data */
4065 /* Simulated face name should only contain Bold as weight term,
4066 so remove existing regular and weight terms. */
4067 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
4068 facename_remove_regular_term(initialW, -1);
4070 /* remove current weight pattern */
4071 fontname_tokenize(&tokens, initialW);
4072 match_pattern_list(&tokens, weightsim_patterns, NULL);
4073 fontname_tokens_to_str(&tokens, facenameW);
4075 /* Bold suffix for new name */
4076 if (*facenameW)
4077 strcatW(facenameW, spaceW);
4078 strcatW(facenameW, boldW);
4080 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
4081 boldface->bold_sim_tested = 1;
4082 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
4083 fontfamily_add_font(family, boldface);
4089 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
4091 size_t i, j;
4093 for (i = 0; i < family->count; ++i)
4095 UINT32 regular = ~0u, oblique = ~0u;
4096 struct dwrite_font_data *obliqueface;
4097 WCHAR facenameW[255];
4099 if (family->fonts[i]->oblique_sim_tested)
4100 continue;
4102 family->fonts[i]->oblique_sim_tested = 1;
4103 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
4104 regular = i;
4105 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
4106 oblique = i;
4108 /* find regular style with same weight/stretch values */
4109 for (j = i; j < family->count; ++j)
4111 if (family->fonts[j]->oblique_sim_tested)
4112 continue;
4114 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
4115 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
4117 family->fonts[j]->oblique_sim_tested = 1;
4118 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
4119 regular = j;
4121 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
4122 oblique = j;
4125 if (regular != ~0u && oblique != ~0u)
4126 break;
4129 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
4130 if (regular == ~0u)
4131 continue;
4133 /* regular face exists, and corresponding oblique is present as well, nothing to do */
4134 if (oblique != ~0u)
4135 continue;
4137 /* add oblique simulation based on this regular face */
4139 /* remove regular term if any, append 'Oblique' */
4140 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
4141 facename_remove_regular_term(facenameW, -1);
4143 if (*facenameW)
4144 strcatW(facenameW, spaceW);
4145 strcatW(facenameW, obliqueW);
4147 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
4148 obliqueface->oblique_sim_tested = 1;
4149 obliqueface->lf.lfItalic = 1;
4150 fontfamily_add_font(family, obliqueface);
4155 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
4156 const WCHAR *replacement_name)
4158 UINT32 i = collection_find_family(collection, replacement_name);
4159 struct dwrite_fontfamily_data *target;
4160 IDWriteLocalizedStrings *strings;
4161 HRESULT hr;
4163 /* replacement does not exist */
4164 if (i == ~0u)
4165 return FALSE;
4167 hr = create_localizedstrings(&strings);
4168 if (FAILED(hr))
4169 return FALSE;
4171 /* add a new family with target name, reuse font data from replacement */
4172 add_localizedstring(strings, enusW, target_name);
4173 hr = init_fontfamily_data(strings, &target);
4174 if (hr == S_OK) {
4175 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
4176 WCHAR nameW[255];
4178 for (i = 0; i < replacement->count; ++i)
4180 fontfamily_add_font(target, replacement->fonts[i]);
4181 addref_font_data(replacement->fonts[i]);
4184 fontcollection_add_family(collection, target);
4185 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
4186 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
4188 IDWriteLocalizedStrings_Release(strings);
4189 return TRUE;
4192 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
4193 system font collections. */
4194 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
4196 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
4197 WCHAR *name;
4198 void *data;
4199 HKEY hkey;
4201 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
4202 return;
4204 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
4205 RegCloseKey(hkey);
4206 return;
4209 max_namelen++; /* returned value doesn't include room for '\0' */
4210 name = heap_alloc(max_namelen * sizeof(WCHAR));
4211 data = heap_alloc(max_datalen);
4213 datalen = max_datalen;
4214 namelen = max_namelen;
4215 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
4216 if (collection_find_family(collection, name) == ~0u) {
4217 if (type == REG_MULTI_SZ) {
4218 WCHAR *replacement = data;
4219 while (*replacement) {
4220 if (fontcollection_add_replacement(collection, name, replacement))
4221 break;
4222 replacement += strlenW(replacement) + 1;
4225 else if (type == REG_SZ)
4226 fontcollection_add_replacement(collection, name, data);
4228 else
4229 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
4231 datalen = max_datalen;
4232 namelen = max_namelen;
4235 heap_free(data);
4236 heap_free(name);
4237 RegCloseKey(hkey);
4240 HRESULT create_font_collection(IDWriteFactory7 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
4241 IDWriteFontCollection3 **ret)
4243 struct fontfile_enum {
4244 struct list entry;
4245 IDWriteFontFile *file;
4247 struct fontfile_enum *fileenum, *fileenum2;
4248 struct dwrite_fontcollection *collection;
4249 struct list scannedfiles;
4250 BOOL current = FALSE;
4251 HRESULT hr = S_OK;
4252 size_t i;
4254 *ret = NULL;
4256 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4257 if (!collection) return E_OUTOFMEMORY;
4259 hr = init_font_collection(collection, is_system);
4260 if (FAILED(hr)) {
4261 heap_free(collection);
4262 return hr;
4265 *ret = &collection->IDWriteFontCollection3_iface;
4267 TRACE("building font collection:\n");
4269 list_init(&scannedfiles);
4270 while (hr == S_OK) {
4271 DWRITE_FONT_FACE_TYPE face_type;
4272 DWRITE_FONT_FILE_TYPE file_type;
4273 BOOL supported, same = FALSE;
4274 IDWriteFontFileStream *stream;
4275 IDWriteFontFile *file;
4276 UINT32 face_count;
4278 current = FALSE;
4279 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
4280 if (FAILED(hr) || !current)
4281 break;
4283 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
4284 if (FAILED(hr))
4285 break;
4287 /* check if we've scanned this file already */
4288 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
4289 if ((same = is_same_fontfile(fileenum->file, file)))
4290 break;
4293 if (same) {
4294 IDWriteFontFile_Release(file);
4295 continue;
4298 if (FAILED(get_filestream_from_file(file, &stream))) {
4299 IDWriteFontFile_Release(file);
4300 continue;
4303 /* Unsupported formats are skipped. */
4304 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4305 if (FAILED(hr) || !supported || face_count == 0) {
4306 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4307 IDWriteFontFileStream_Release(stream);
4308 IDWriteFontFile_Release(file);
4309 hr = S_OK;
4310 continue;
4313 /* add to scanned list */
4314 fileenum = heap_alloc(sizeof(*fileenum));
4315 fileenum->file = file;
4316 list_add_tail(&scannedfiles, &fileenum->entry);
4318 for (i = 0; i < face_count; ++i)
4320 struct dwrite_font_data *font_data;
4321 struct fontface_desc desc;
4322 WCHAR familyW[255];
4323 UINT32 index;
4325 desc.factory = factory;
4326 desc.face_type = face_type;
4327 desc.files = &file;
4328 desc.stream = stream;
4329 desc.files_number = 1;
4330 desc.index = i;
4331 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4332 desc.font_data = NULL;
4334 /* Allocate an initialize new font data structure. */
4335 hr = init_font_data(&desc, &font_data);
4336 if (FAILED(hr))
4338 /* move to next one */
4339 hr = S_OK;
4340 continue;
4343 fontstrings_get_en_string(font_data->family_names, familyW, ARRAY_SIZE(familyW));
4345 /* ignore dot named faces */
4346 if (familyW[0] == '.')
4348 WARN("Ignoring face %s\n", debugstr_w(familyW));
4349 release_font_data(font_data);
4350 continue;
4353 index = collection_find_family(collection, familyW);
4354 if (index != ~0u)
4355 hr = fontfamily_add_font(collection->family_data[index], font_data);
4356 else {
4357 struct dwrite_fontfamily_data *family_data;
4359 /* create and init new family */
4360 hr = init_fontfamily_data(font_data->family_names, &family_data);
4361 if (hr == S_OK) {
4362 /* add font to family, family - to collection */
4363 hr = fontfamily_add_font(family_data, font_data);
4364 if (hr == S_OK)
4365 hr = fontcollection_add_family(collection, family_data);
4367 if (FAILED(hr))
4368 release_fontfamily_data(family_data);
4372 if (FAILED(hr))
4373 break;
4376 IDWriteFontFileStream_Release(stream);
4379 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
4380 IDWriteFontFile_Release(fileenum->file);
4381 list_remove(&fileenum->entry);
4382 heap_free(fileenum);
4385 for (i = 0; i < collection->count; ++i)
4387 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4388 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4391 if (is_system)
4392 fontcollection_add_replacements(collection);
4394 collection->factory = factory;
4395 IDWriteFactory7_AddRef(factory);
4397 return hr;
4400 struct system_fontfile_enumerator
4402 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
4403 LONG ref;
4405 IDWriteFactory7 *factory;
4406 HKEY hkey;
4407 int index;
4409 WCHAR *filename;
4410 DWORD filename_size;
4413 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
4415 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
4418 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
4420 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
4421 IDWriteFontFileEnumerator_AddRef(iface);
4422 *obj = iface;
4423 return S_OK;
4426 WARN("%s not implemented.\n", debugstr_guid(riid));
4428 *obj = NULL;
4430 return E_NOINTERFACE;
4433 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
4435 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4436 return InterlockedIncrement(&enumerator->ref);
4439 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4441 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4442 ULONG ref = InterlockedDecrement(&enumerator->ref);
4444 if (!ref)
4446 IDWriteFactory7_Release(enumerator->factory);
4447 RegCloseKey(enumerator->hkey);
4448 heap_free(enumerator->filename);
4449 heap_free(enumerator);
4452 return ref;
4455 static HRESULT create_local_file_reference(IDWriteFactory7 *factory, const WCHAR *filename, IDWriteFontFile **file)
4457 HRESULT hr;
4459 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4460 if (!strchrW(filename, '\\')) {
4461 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4462 WCHAR fullpathW[MAX_PATH];
4464 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4465 strcatW(fullpathW, fontsW);
4466 strcatW(fullpathW, filename);
4468 hr = IDWriteFactory7_CreateFontFileReference(factory, fullpathW, NULL, file);
4470 else
4471 hr = IDWriteFactory7_CreateFontFileReference(factory, filename, NULL, file);
4473 return hr;
4476 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4478 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4480 *file = NULL;
4482 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4483 return E_FAIL;
4485 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4488 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4490 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4491 WCHAR name_buf[256], *name = name_buf;
4492 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4493 HRESULT hr = S_OK;
4494 LONG r;
4496 *current = FALSE;
4497 enumerator->index++;
4499 /* iterate until we find next string value */
4500 for (;;) {
4501 do {
4502 name_count = max_name_count;
4503 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4505 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4506 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4507 if (r == ERROR_MORE_DATA) {
4508 if (name_count >= max_name_count) {
4509 if (name != name_buf) heap_free(name);
4510 max_name_count *= 2;
4511 name = heap_alloc(max_name_count * sizeof(*name));
4512 if (!name) return E_OUTOFMEMORY;
4514 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4515 heap_free(enumerator->filename);
4516 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4517 enumerator->filename = heap_alloc(enumerator->filename_size);
4518 if (!enumerator->filename) {
4519 hr = E_OUTOFMEMORY;
4520 goto err;
4524 } while (r == ERROR_MORE_DATA);
4526 if (r != ERROR_SUCCESS) {
4527 enumerator->filename[0] = 0;
4528 break;
4530 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4531 if (type == REG_SZ && *name != '@') {
4532 *current = TRUE;
4533 break;
4535 enumerator->index++;
4537 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4539 err:
4540 if (name != name_buf) heap_free(name);
4541 return hr;
4544 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4546 systemfontfileenumerator_QueryInterface,
4547 systemfontfileenumerator_AddRef,
4548 systemfontfileenumerator_Release,
4549 systemfontfileenumerator_MoveNext,
4550 systemfontfileenumerator_GetCurrentFontFile
4553 static HRESULT create_system_fontfile_enumerator(IDWriteFactory7 *factory, IDWriteFontFileEnumerator **ret)
4555 struct system_fontfile_enumerator *enumerator;
4556 static const WCHAR fontslistW[] = {
4557 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4558 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4559 'F','o','n','t','s',0
4562 *ret = NULL;
4564 enumerator = heap_alloc(sizeof(*enumerator));
4565 if (!enumerator)
4566 return E_OUTOFMEMORY;
4568 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4569 enumerator->ref = 1;
4570 enumerator->factory = factory;
4571 enumerator->index = -1;
4572 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4573 enumerator->filename = heap_alloc(enumerator->filename_size);
4574 if (!enumerator->filename) {
4575 heap_free(enumerator);
4576 return E_OUTOFMEMORY;
4579 IDWriteFactory7_AddRef(factory);
4581 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey))
4583 ERR("failed to open fonts list key\n");
4584 IDWriteFactory7_Release(factory);
4585 heap_free(enumerator->filename);
4586 heap_free(enumerator);
4587 return E_FAIL;
4590 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4592 return S_OK;
4595 HRESULT get_system_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection1 **collection)
4597 IDWriteFontFileEnumerator *enumerator;
4598 HRESULT hr;
4600 *collection = NULL;
4602 hr = create_system_fontfile_enumerator(factory, &enumerator);
4603 if (FAILED(hr))
4604 return hr;
4606 TRACE("building system font collection for factory %p\n", factory);
4607 hr = create_font_collection(factory, enumerator, TRUE, (IDWriteFontCollection3 **)collection);
4608 IDWriteFontFileEnumerator_Release(enumerator);
4609 return hr;
4612 static HRESULT eudc_collection_add_family(IDWriteFactory7 *factory, struct dwrite_fontcollection *collection,
4613 const WCHAR *keynameW, const WCHAR *pathW)
4615 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};
4616 static const WCHAR emptyW[] = {0};
4617 struct dwrite_fontfamily_data *family_data;
4618 IDWriteLocalizedStrings *names;
4619 DWRITE_FONT_FACE_TYPE face_type;
4620 DWRITE_FONT_FILE_TYPE file_type;
4621 IDWriteFontFileStream *stream;
4622 IDWriteFontFile *file;
4623 UINT32 face_count, i;
4624 BOOL supported;
4625 HRESULT hr;
4627 /* create font file from this path */
4628 hr = create_local_file_reference(factory, pathW, &file);
4629 if (FAILED(hr))
4630 return S_FALSE;
4632 if (FAILED(get_filestream_from_file(file, &stream))) {
4633 IDWriteFontFile_Release(file);
4634 return S_FALSE;
4637 /* Unsupported formats are skipped. */
4638 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4639 if (FAILED(hr) || !supported || face_count == 0) {
4640 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4641 IDWriteFontFileStream_Release(stream);
4642 IDWriteFontFile_Release(file);
4643 return S_FALSE;
4646 /* create and init new family */
4648 /* Family names are added for non-specific locale, represented with empty string.
4649 Default family appears with empty family name. */
4650 create_localizedstrings(&names);
4651 if (!strcmpiW(keynameW, defaultfontW))
4652 add_localizedstring(names, emptyW, emptyW);
4653 else
4654 add_localizedstring(names, emptyW, keynameW);
4656 hr = init_fontfamily_data(names, &family_data);
4657 IDWriteLocalizedStrings_Release(names);
4658 if (hr != S_OK) {
4659 IDWriteFontFile_Release(file);
4660 return hr;
4663 /* fill with faces */
4664 for (i = 0; i < face_count; i++) {
4665 struct dwrite_font_data *font_data;
4666 struct fontface_desc desc;
4668 /* alloc and init new font data structure */
4669 desc.factory = factory;
4670 desc.face_type = face_type;
4671 desc.index = i;
4672 desc.files = &file;
4673 desc.stream = stream;
4674 desc.files_number = 1;
4675 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4676 desc.font_data = NULL;
4678 hr = init_font_data(&desc, &font_data);
4679 if (FAILED(hr))
4680 continue;
4682 /* add font to family */
4683 hr = fontfamily_add_font(family_data, font_data);
4684 if (hr != S_OK)
4685 release_font_data(font_data);
4688 /* add family to collection */
4689 hr = fontcollection_add_family(collection, family_data);
4690 if (FAILED(hr))
4691 release_fontfamily_data(family_data);
4692 IDWriteFontFileStream_Release(stream);
4693 IDWriteFontFile_Release(file);
4695 return hr;
4698 HRESULT get_eudc_fontcollection(IDWriteFactory7 *factory, IDWriteFontCollection3 **ret)
4700 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4701 struct dwrite_fontcollection *collection;
4702 static const WCHAR emptyW[] = {0};
4703 WCHAR eudckeypathW[16];
4704 HKEY eudckey;
4705 DWORD index;
4706 BOOL exists;
4707 LONG retval;
4708 HRESULT hr;
4709 size_t i;
4711 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4713 *ret = NULL;
4715 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4716 if (!collection) return E_OUTOFMEMORY;
4718 hr = init_font_collection(collection, FALSE);
4719 if (FAILED(hr)) {
4720 heap_free(collection);
4721 return hr;
4724 *ret = &collection->IDWriteFontCollection3_iface;
4725 collection->factory = factory;
4726 IDWriteFactory7_AddRef(factory);
4728 /* return empty collection if EUDC fonts are not configured */
4729 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4730 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4731 return S_OK;
4733 retval = ERROR_SUCCESS;
4734 index = 0;
4735 while (retval != ERROR_NO_MORE_ITEMS) {
4736 WCHAR keynameW[64], pathW[MAX_PATH];
4737 DWORD type, path_len, name_len;
4739 path_len = ARRAY_SIZE(pathW);
4740 name_len = ARRAY_SIZE(keynameW);
4741 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4742 if (retval || type != REG_SZ)
4743 continue;
4745 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4746 if (hr != S_OK)
4747 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4749 RegCloseKey(eudckey);
4751 /* try to add global default if not defined for specific codepage */
4752 exists = FALSE;
4753 hr = IDWriteFontCollection3_FindFamilyName(&collection->IDWriteFontCollection3_iface, emptyW,
4754 &index, &exists);
4755 if (FAILED(hr) || !exists) {
4756 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4757 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4758 if (hr != S_OK)
4759 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4762 /* EUDC collection offers simulated faces too */
4763 for (i = 0; i < collection->count; ++i)
4765 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4766 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4769 return S_OK;
4772 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4774 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4776 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4778 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4780 *obj = iface;
4781 IDWriteFontFile_AddRef(iface);
4782 return S_OK;
4785 WARN("%s not implemented.\n", debugstr_guid(riid));
4787 *obj = NULL;
4788 return E_NOINTERFACE;
4791 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4793 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4794 ULONG ref = InterlockedIncrement(&This->ref);
4795 TRACE("(%p)->(%d)\n", This, ref);
4796 return ref;
4799 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4801 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4802 ULONG ref = InterlockedDecrement(&This->ref);
4804 TRACE("(%p)->(%d)\n", This, ref);
4806 if (!ref)
4808 IDWriteFontFileLoader_Release(This->loader);
4809 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4810 heap_free(This->reference_key);
4811 heap_free(This);
4814 return ref;
4817 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4819 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4820 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4821 *fontFileReferenceKey = This->reference_key;
4822 *fontFileReferenceKeySize = This->key_size;
4824 return S_OK;
4827 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4829 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4830 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4831 *fontFileLoader = This->loader;
4832 IDWriteFontFileLoader_AddRef(This->loader);
4834 return S_OK;
4837 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4838 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4840 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4841 IDWriteFontFileStream *stream;
4842 HRESULT hr;
4844 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4846 *is_supported = FALSE;
4847 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4848 if (face_type)
4849 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4850 *face_count = 0;
4852 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4853 if (FAILED(hr))
4854 return hr;
4856 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4858 /* TODO: Further Analysis */
4859 IDWriteFontFileStream_Release(stream);
4860 return S_OK;
4863 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4864 dwritefontfile_QueryInterface,
4865 dwritefontfile_AddRef,
4866 dwritefontfile_Release,
4867 dwritefontfile_GetReferenceKey,
4868 dwritefontfile_GetLoader,
4869 dwritefontfile_Analyze,
4872 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4873 IDWriteFontFile **ret)
4875 struct dwrite_fontfile *file;
4876 void *key;
4878 *ret = NULL;
4880 file = heap_alloc(sizeof(*file));
4881 key = heap_alloc(key_size);
4882 if (!file || !key) {
4883 heap_free(file);
4884 heap_free(key);
4885 return E_OUTOFMEMORY;
4888 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4889 file->ref = 1;
4890 IDWriteFontFileLoader_AddRef(loader);
4891 file->loader = loader;
4892 file->stream = NULL;
4893 file->reference_key = key;
4894 memcpy(file->reference_key, reference_key, key_size);
4895 file->key_size = key_size;
4897 *ret = &file->IDWriteFontFile_iface;
4899 return S_OK;
4902 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace5 **ret)
4904 struct file_stream_desc stream_desc;
4905 struct dwrite_font_data *font_data;
4906 struct dwrite_fontface *fontface;
4907 HRESULT hr;
4908 int i;
4910 *ret = NULL;
4912 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4913 if (!fontface)
4914 return E_OUTOFMEMORY;
4916 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4917 if (!fontface->files) {
4918 heap_free(fontface);
4919 return E_OUTOFMEMORY;
4922 fontface->IDWriteFontFace5_iface.lpVtbl = &dwritefontfacevtbl;
4923 fontface->IDWriteFontFaceReference_iface.lpVtbl = &dwritefontface_reference_vtbl;
4924 fontface->refcount = 1;
4925 fontface->type = desc->face_type;
4926 fontface->file_count = desc->files_number;
4927 fontface->vdmx.exists = TRUE;
4928 fontface->gasp.exists = TRUE;
4929 fontface->cpal.exists = TRUE;
4930 fontface->colr.exists = TRUE;
4931 fontface->index = desc->index;
4932 fontface->simulations = desc->simulations;
4933 fontface->factory = desc->factory;
4934 IDWriteFactory7_AddRef(fontface->factory);
4936 for (i = 0; i < fontface->file_count; i++) {
4937 fontface->files[i] = desc->files[i];
4938 IDWriteFontFile_AddRef(fontface->files[i]);
4940 fontface->stream = desc->stream;
4941 IDWriteFontFileStream_AddRef(fontface->stream);
4943 stream_desc.stream = fontface->stream;
4944 stream_desc.face_type = desc->face_type;
4945 stream_desc.face_index = desc->index;
4946 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4947 opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent);
4948 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4949 /* TODO: test what happens if caret is already slanted */
4950 if (fontface->caret.slopeRise == 1) {
4951 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4952 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4956 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace5_iface))
4957 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4958 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace5_iface))
4959 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4960 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace5_iface);
4962 /* Font properties are reused from font object when 'normal' face creation path is used:
4963 collection -> family -> matching font -> fontface.
4965 If face is created directly from factory we have to go through properties resolution.
4967 if (desc->font_data)
4969 font_data = desc->font_data;
4970 addref_font_data(font_data);
4972 else
4974 hr = init_font_data(desc, &font_data);
4975 if (FAILED(hr))
4977 IDWriteFontFace5_Release(&fontface->IDWriteFontFace5_iface);
4978 return hr;
4982 fontface->weight = font_data->weight;
4983 fontface->style = font_data->style;
4984 fontface->stretch = font_data->stretch;
4985 fontface->panose = font_data->panose;
4986 fontface->fontsig = font_data->fontsig;
4987 fontface->lf = font_data->lf;
4988 fontface->flags |= font_data->flags & (FONT_IS_SYMBOL | FONT_IS_MONOSPACED | FONT_IS_COLORED);
4989 fontface->names = font_data->names;
4990 if (fontface->names)
4991 IDWriteLocalizedStrings_AddRef(fontface->names);
4992 fontface->family_names = font_data->family_names;
4993 if (fontface->family_names)
4994 IDWriteLocalizedStrings_AddRef(fontface->family_names);
4995 memcpy(fontface->info_strings, font_data->info_strings, sizeof(fontface->info_strings));
4996 for (i = 0; i < ARRAY_SIZE(fontface->info_strings); ++i)
4998 if (fontface->info_strings[i])
4999 IDWriteLocalizedStrings_AddRef(fontface->info_strings[i]);
5001 fontface->cmap.stream = fontface->stream;
5002 IDWriteFontFileStream_AddRef(fontface->cmap.stream);
5003 release_font_data(font_data);
5005 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace5_iface);
5007 *ret = &fontface->IDWriteFontFace5_iface;
5009 return S_OK;
5012 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
5013 struct local_refkey
5015 FILETIME writetime;
5016 WCHAR name[1];
5019 struct local_cached_stream
5021 struct list entry;
5022 IDWriteFontFileStream *stream;
5023 struct local_refkey *key;
5024 UINT32 key_size;
5027 struct dwrite_localfontfilestream
5029 IDWriteFontFileStream IDWriteFontFileStream_iface;
5030 LONG ref;
5032 struct local_cached_stream *entry;
5033 const void *file_ptr;
5034 UINT64 size;
5037 struct dwrite_localfontfileloader {
5038 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
5039 LONG ref;
5041 struct list streams;
5042 CRITICAL_SECTION cs;
5045 static struct dwrite_localfontfileloader local_fontfile_loader;
5047 struct dwrite_inmemory_stream_data
5049 LONG ref;
5050 IUnknown *owner;
5051 void *data;
5052 UINT32 size;
5055 struct dwrite_inmemory_filestream
5057 IDWriteFontFileStream IDWriteFontFileStream_iface;
5058 LONG ref;
5060 struct dwrite_inmemory_stream_data *data;
5063 struct dwrite_inmemory_fileloader
5065 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
5066 LONG ref;
5068 struct dwrite_inmemory_stream_data **streams;
5069 size_t size;
5070 size_t count;
5073 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
5075 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
5078 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5080 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
5083 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
5085 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
5088 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
5090 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
5093 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
5095 if (InterlockedDecrement(&stream->ref) == 0) {
5096 if (stream->owner)
5097 IUnknown_Release(stream->owner);
5098 else
5099 heap_free(stream->data);
5100 heap_free(stream);
5104 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
5106 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5108 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5110 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
5111 IsEqualIID(riid, &IID_IUnknown))
5113 *obj = iface;
5114 if (InterlockedIncrement(&This->ref) == 1) {
5115 InterlockedDecrement(&This->ref);
5116 *obj = NULL;
5117 return E_FAIL;
5119 return S_OK;
5122 WARN("%s not implemented.\n", debugstr_guid(riid));
5124 *obj = NULL;
5125 return E_NOINTERFACE;
5128 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
5130 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5131 ULONG ref = InterlockedIncrement(&This->ref);
5132 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5133 return ref;
5136 static inline void release_cached_stream(struct local_cached_stream *stream)
5138 list_remove(&stream->entry);
5139 heap_free(stream->key);
5140 heap_free(stream);
5143 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
5145 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5146 ULONG ref = InterlockedDecrement(&This->ref);
5148 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
5150 if (!ref) {
5151 UnmapViewOfFile(This->file_ptr);
5153 EnterCriticalSection(&local_fontfile_loader.cs);
5154 release_cached_stream(This->entry);
5155 LeaveCriticalSection(&local_fontfile_loader.cs);
5157 heap_free(This);
5160 return ref;
5163 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
5164 UINT64 offset, UINT64 fragment_size, void **fragment_context)
5166 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5168 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
5169 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
5171 *fragment_context = NULL;
5173 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
5174 *fragment_start = NULL;
5175 return E_FAIL;
5178 *fragment_start = (char*)This->file_ptr + offset;
5179 return S_OK;
5182 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
5184 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5185 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
5188 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
5190 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5191 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
5192 *size = This->size;
5193 return S_OK;
5196 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
5198 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
5199 ULARGE_INTEGER li;
5201 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
5203 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
5204 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
5205 *last_writetime = li.QuadPart;
5207 return S_OK;
5210 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
5212 localfontfilestream_QueryInterface,
5213 localfontfilestream_AddRef,
5214 localfontfilestream_Release,
5215 localfontfilestream_ReadFileFragment,
5216 localfontfilestream_ReleaseFileFragment,
5217 localfontfilestream_GetFileSize,
5218 localfontfilestream_GetLastWriteTime
5221 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
5223 struct dwrite_localfontfilestream *This;
5225 *ret = NULL;
5227 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
5228 if (!This)
5229 return E_OUTOFMEMORY;
5231 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
5232 This->ref = 1;
5234 This->file_ptr = file_ptr;
5235 This->size = size;
5236 This->entry = entry;
5238 *ret = &This->IDWriteFontFileStream_iface;
5239 return S_OK;
5242 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
5244 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5246 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5248 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
5249 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
5250 IsEqualIID(riid, &IID_IUnknown))
5252 *obj = iface;
5253 IDWriteLocalFontFileLoader_AddRef(iface);
5254 return S_OK;
5257 WARN("%s not implemented.\n", debugstr_guid(riid));
5259 *obj = NULL;
5260 return E_NOINTERFACE;
5263 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
5265 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5266 ULONG ref = InterlockedIncrement(&This->ref);
5267 TRACE("(%p)->(%d)\n", This, ref);
5268 return ref;
5271 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
5273 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5274 ULONG ref = InterlockedDecrement(&This->ref);
5276 TRACE("(%p)->(%d)\n", This, ref);
5278 return ref;
5281 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
5283 const struct local_refkey *refkey = key;
5284 struct local_cached_stream *stream;
5285 IDWriteFontFileStream *filestream;
5286 HANDLE file, mapping;
5287 LARGE_INTEGER size;
5288 void *file_ptr;
5289 HRESULT hr = S_OK;
5291 *ret = NULL;
5293 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
5294 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5295 if (file == INVALID_HANDLE_VALUE) {
5296 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
5297 return E_FAIL;
5300 GetFileSizeEx(file, &size);
5301 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
5302 CloseHandle(file);
5303 if (!mapping)
5304 return E_FAIL;
5306 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
5307 CloseHandle(mapping);
5308 if (!file_ptr) {
5309 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
5310 return E_FAIL;
5313 stream = heap_alloc(sizeof(*stream));
5314 if (!stream) {
5315 UnmapViewOfFile(file_ptr);
5316 return E_OUTOFMEMORY;
5319 stream->key = heap_alloc(key_size);
5320 if (!stream->key) {
5321 UnmapViewOfFile(file_ptr);
5322 heap_free(stream);
5323 return E_OUTOFMEMORY;
5326 stream->key_size = key_size;
5327 memcpy(stream->key, key, key_size);
5329 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
5330 if (FAILED(hr)) {
5331 UnmapViewOfFile(file_ptr);
5332 heap_free(stream->key);
5333 heap_free(stream);
5334 return hr;
5337 stream->stream = filestream;
5339 *ret = stream;
5341 return S_OK;
5344 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
5345 UINT32 key_size, IDWriteFontFileStream **ret)
5347 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5348 const struct local_refkey *refkey = key;
5349 struct local_cached_stream *stream;
5350 HRESULT hr = S_OK;
5352 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
5353 TRACE("name: %s\n", debugstr_w(refkey->name));
5355 EnterCriticalSection(&This->cs);
5357 *ret = NULL;
5359 /* search cache first */
5360 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
5361 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
5362 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
5363 break;
5367 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
5368 list_add_head(&This->streams, &stream->entry);
5369 *ret = stream->stream;
5372 LeaveCriticalSection(&This->cs);
5374 return hr;
5377 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
5379 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5380 const struct local_refkey *refkey = key;
5382 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
5384 *length = strlenW(refkey->name);
5385 return S_OK;
5388 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
5390 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5391 const struct local_refkey *refkey = key;
5393 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
5395 if (length < strlenW(refkey->name))
5396 return E_INVALIDARG;
5398 strcpyW(path, refkey->name);
5399 return S_OK;
5402 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
5403 UINT32 key_size, FILETIME *writetime)
5405 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
5406 const struct local_refkey *refkey = key;
5408 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
5410 *writetime = refkey->writetime;
5411 return S_OK;
5414 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
5415 localfontfileloader_QueryInterface,
5416 localfontfileloader_AddRef,
5417 localfontfileloader_Release,
5418 localfontfileloader_CreateStreamFromKey,
5419 localfontfileloader_GetFilePathLengthFromKey,
5420 localfontfileloader_GetFilePathFromKey,
5421 localfontfileloader_GetLastWriteTimeFromKey
5424 void init_local_fontfile_loader(void)
5426 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
5427 local_fontfile_loader.ref = 1;
5428 list_init(&local_fontfile_loader.streams);
5429 InitializeCriticalSection(&local_fontfile_loader.cs);
5430 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
5433 IDWriteFontFileLoader *get_local_fontfile_loader(void)
5435 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
5438 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
5440 struct local_refkey *refkey;
5442 if (!path)
5443 return E_INVALIDARG;
5445 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5446 *key = NULL;
5448 refkey = heap_alloc(*size);
5449 if (!refkey)
5450 return E_OUTOFMEMORY;
5452 if (writetime)
5453 refkey->writetime = *writetime;
5454 else {
5455 WIN32_FILE_ATTRIBUTE_DATA info;
5457 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5458 refkey->writetime = info.ftLastWriteTime;
5459 else
5460 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5462 strcpyW(refkey->name, path);
5464 *key = refkey;
5466 return S_OK;
5469 /* IDWriteGlyphRunAnalysis */
5470 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5472 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5474 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5476 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5477 IsEqualIID(riid, &IID_IUnknown))
5479 *ppv = iface;
5480 IDWriteGlyphRunAnalysis_AddRef(iface);
5481 return S_OK;
5484 WARN("%s not implemented.\n", debugstr_guid(riid));
5486 *ppv = NULL;
5487 return E_NOINTERFACE;
5490 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5492 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5493 ULONG ref = InterlockedIncrement(&This->ref);
5494 TRACE("(%p)->(%u)\n", This, ref);
5495 return ref;
5498 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5500 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5501 ULONG ref = InterlockedDecrement(&This->ref);
5503 TRACE("(%p)->(%u)\n", This, ref);
5505 if (!ref) {
5506 if (This->run.fontFace)
5507 IDWriteFontFace_Release(This->run.fontFace);
5508 heap_free(This->glyphs);
5509 heap_free(This->origins);
5510 heap_free(This->bitmap);
5511 heap_free(This);
5514 return ref;
5517 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5519 switch (mode)
5521 case DWRITE_RENDERING_MODE1_NATURAL:
5522 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5523 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5524 return TRUE;
5525 default:
5526 return FALSE;
5530 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5532 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5535 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5537 struct dwrite_glyphbitmap glyph_bitmap;
5538 IDWriteFontFace4 *fontface;
5539 HRESULT hr;
5540 UINT32 i;
5542 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5543 *bounds = analysis->bounds;
5544 return;
5547 if (analysis->run.isSideways)
5548 FIXME("sideways runs are not supported.\n");
5550 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5551 if (FAILED(hr))
5552 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5554 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5555 glyph_bitmap.fontface = fontface;
5556 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5557 glyph_bitmap.emsize = analysis->run.fontEmSize;
5558 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5559 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5560 glyph_bitmap.m = &analysis->m;
5562 for (i = 0; i < analysis->run.glyphCount; i++) {
5563 RECT *bbox = &glyph_bitmap.bbox;
5564 UINT32 bitmap_size;
5566 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5567 freetype_get_glyph_bbox(&glyph_bitmap);
5569 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5570 (bbox->bottom - bbox->top);
5571 if (bitmap_size > analysis->max_glyph_bitmap_size)
5572 analysis->max_glyph_bitmap_size = bitmap_size;
5574 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5575 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5578 IDWriteFontFace4_Release(fontface);
5580 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5581 *bounds = analysis->bounds;
5584 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5586 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5588 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5590 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5591 SetRectEmpty(bounds);
5592 return E_INVALIDARG;
5595 if (type != This->texture_type) {
5596 SetRectEmpty(bounds);
5597 return S_OK;
5600 glyphrunanalysis_get_texturebounds(This, bounds);
5601 return S_OK;
5604 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5606 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5607 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5608 (runbounds->left - bounds->left) * 3;
5609 else
5610 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5611 runbounds->left - bounds->left;
5614 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5616 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5617 struct dwrite_glyphbitmap glyph_bitmap;
5618 IDWriteFontFace4 *fontface;
5619 D2D_POINT_2F origin;
5620 UINT32 i, size;
5621 HRESULT hr;
5622 RECT *bbox;
5624 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5625 if (FAILED(hr)) {
5626 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5627 return hr;
5630 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5631 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5632 size *= 3;
5633 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5634 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5635 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5636 IDWriteFontFace4_Release(fontface);
5637 return E_OUTOFMEMORY;
5640 origin.x = origin.y = 0.0f;
5642 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5643 glyph_bitmap.fontface = fontface;
5644 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5645 glyph_bitmap.emsize = analysis->run.fontEmSize;
5646 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5647 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5648 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5649 glyph_bitmap.m = &analysis->m;
5650 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5651 IDWriteFontFace4_Release(fontface);
5652 return E_OUTOFMEMORY;
5655 bbox = &glyph_bitmap.bbox;
5657 for (i = 0; i < analysis->run.glyphCount; i++) {
5658 BYTE *src = glyph_bitmap.buf, *dst;
5659 int x, y, width, height;
5660 BOOL is_1bpp;
5662 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5663 freetype_get_glyph_bbox(&glyph_bitmap);
5665 if (IsRectEmpty(bbox))
5666 continue;
5668 width = bbox->right - bbox->left;
5669 height = bbox->bottom - bbox->top;
5671 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5672 memset(src, 0, height * glyph_bitmap.pitch);
5673 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5675 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5677 /* blit to analysis bitmap */
5678 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5680 if (is_1bpp) {
5681 /* convert 1bpp to 8bpp/24bpp */
5682 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5683 for (y = 0; y < height; y++) {
5684 for (x = 0; x < width; x++)
5685 if (src[x / 8] & masks[x % 8])
5686 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5687 src += glyph_bitmap.pitch;
5688 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5691 else {
5692 for (y = 0; y < height; y++) {
5693 for (x = 0; x < width; x++)
5694 if (src[x / 8] & masks[x % 8])
5695 dst[x] = DWRITE_ALPHA_MAX;
5696 src += glyph_bitmap.pitch;
5697 dst += analysis->bounds.right - analysis->bounds.left;
5701 else {
5702 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5703 for (y = 0; y < height; y++) {
5704 for (x = 0; x < width; x++)
5705 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5706 src += glyph_bitmap.pitch;
5707 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5710 else {
5711 for (y = 0; y < height; y++) {
5712 for (x = 0; x < width; x++)
5713 dst[x] |= src[x];
5714 src += glyph_bitmap.pitch;
5715 dst += analysis->bounds.right - analysis->bounds.left;
5720 heap_free(glyph_bitmap.buf);
5722 IDWriteFontFace4_Release(fontface);
5724 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5726 /* we don't need this anymore */
5727 heap_free(analysis->glyphs);
5728 heap_free(analysis->origins);
5729 IDWriteFontFace_Release(analysis->run.fontFace);
5731 analysis->glyphs = NULL;
5732 analysis->origins = NULL;
5733 analysis->run.glyphIndices = NULL;
5734 analysis->run.fontFace = NULL;
5736 return S_OK;
5739 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5740 RECT const *bounds, BYTE *bitmap, UINT32 size)
5742 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5743 UINT32 required;
5744 RECT runbounds;
5746 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5748 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5749 return E_INVALIDARG;
5751 /* make sure buffer is large enough for requested texture type */
5752 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5753 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5754 required *= 3;
5756 if (size < required)
5757 return E_NOT_SUFFICIENT_BUFFER;
5759 /* validate requested texture type */
5760 if (This->texture_type != type)
5761 return DWRITE_E_UNSUPPORTEDOPERATION;
5763 memset(bitmap, 0, size);
5764 glyphrunanalysis_get_texturebounds(This, &runbounds);
5765 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5766 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5767 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5768 int dst_width = (bounds->right - bounds->left) * pixel_size;
5769 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5770 BYTE *src, *dst;
5771 int y;
5773 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5774 HRESULT hr;
5776 if (FAILED(hr = glyphrunanalysis_render(This)))
5777 return hr;
5780 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5781 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5783 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5784 memcpy(dst, src, draw_width);
5785 src += src_width;
5786 dst += dst_width;
5790 return S_OK;
5793 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5794 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5796 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5798 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5800 if (!params)
5801 return E_INVALIDARG;
5803 switch (This->rendering_mode)
5805 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5806 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5808 UINT value = 0;
5809 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5810 *gamma = (FLOAT)value / 1000.0f;
5811 *contrast = 0.0f;
5812 *cleartypelevel = 1.0f;
5813 break;
5815 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5816 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5817 /* fallthrough */
5818 case DWRITE_RENDERING_MODE1_ALIASED:
5819 case DWRITE_RENDERING_MODE1_NATURAL:
5820 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5821 *gamma = IDWriteRenderingParams_GetGamma(params);
5822 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5823 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5824 break;
5825 default:
5829 return S_OK;
5832 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5833 glyphrunanalysis_QueryInterface,
5834 glyphrunanalysis_AddRef,
5835 glyphrunanalysis_Release,
5836 glyphrunanalysis_GetAlphaTextureBounds,
5837 glyphrunanalysis_CreateAlphaTexture,
5838 glyphrunanalysis_GetAlphaBlendParams
5841 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5843 D2D_POINT_2F ret;
5844 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5845 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5846 *point = ret;
5849 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5850 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5852 unsigned int upem = fontface->metrics.designUnitsPerEm;
5853 int advance;
5855 if (is_sideways)
5856 FIXME("Sideways mode is not supported.\n");
5858 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5860 switch (measuring_mode)
5862 case DWRITE_MEASURING_MODE_NATURAL:
5863 return (float)advance * emsize / (float)upem;
5864 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5865 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5866 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5867 default:
5868 WARN("Unknown measuring mode %u.\n", measuring_mode);
5869 return 0.0f;
5873 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5875 struct dwrite_glyphrunanalysis *analysis;
5876 struct dwrite_fontface *fontface;
5877 D2D_POINT_2F origin;
5878 FLOAT rtl_factor;
5879 UINT32 i;
5881 *ret = NULL;
5883 /* Check rendering, antialiasing, measuring, and grid fitting modes. */
5884 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5885 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5886 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5887 return E_INVALIDARG;
5889 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5890 return E_INVALIDARG;
5892 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5893 return E_INVALIDARG;
5895 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5896 return E_INVALIDARG;
5898 analysis = heap_alloc(sizeof(*analysis));
5899 if (!analysis)
5900 return E_OUTOFMEMORY;
5902 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5903 analysis->ref = 1;
5904 analysis->rendering_mode = desc->rendering_mode;
5906 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5907 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5908 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5909 else
5910 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5912 analysis->flags = 0;
5913 analysis->bitmap = NULL;
5914 analysis->max_glyph_bitmap_size = 0;
5915 SetRectEmpty(&analysis->bounds);
5916 analysis->run = *desc->run;
5917 IDWriteFontFace_AddRef(analysis->run.fontFace);
5918 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5919 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5921 if (!analysis->glyphs || !analysis->origins) {
5922 heap_free(analysis->glyphs);
5923 heap_free(analysis->origins);
5925 analysis->glyphs = NULL;
5926 analysis->origins = NULL;
5928 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5929 return E_OUTOFMEMORY;
5932 /* check if transform is usable */
5933 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5934 analysis->m = *desc->transform;
5935 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5937 else
5938 memset(&analysis->m, 0, sizeof(analysis->m));
5940 analysis->run.glyphIndices = analysis->glyphs;
5941 analysis->run.glyphAdvances = NULL;
5942 analysis->run.glyphOffsets = NULL;
5944 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5946 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5948 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5950 origin.x = desc->origin.x;
5951 origin.y = desc->origin.y;
5952 for (i = 0; i < desc->run->glyphCount; ++i)
5954 float advance;
5956 /* Use nominal advances if not provided by caller. */
5957 if (desc->run->glyphAdvances)
5958 advance = rtl_factor * desc->run->glyphAdvances[i];
5959 else
5960 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5961 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5963 analysis->origins[i] = origin;
5964 if (desc->run->bidiLevel & 1)
5966 if (desc->run->isSideways)
5967 analysis->origins[i].y += advance;
5968 else
5969 analysis->origins[i].x += advance;
5972 /* Offsets are optional, appled to pre-transformed origin. */
5973 if (desc->run->glyphOffsets) {
5974 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5975 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5977 if (desc->run->isSideways) {
5978 analysis->origins[i].x += ascenderoffset;
5979 analysis->origins[i].y += advanceoffset;
5981 else {
5982 analysis->origins[i].x += advanceoffset;
5983 analysis->origins[i].y += ascenderoffset;
5987 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5988 transform_point(analysis->origins + i, &analysis->m);
5990 if (desc->run->isSideways)
5991 origin.y += advance;
5992 else
5993 origin.x += advance;
5996 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5997 return S_OK;
6000 /* IDWriteColorGlyphRunEnumerator1 */
6001 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator1 *iface, REFIID riid, void **ppv)
6003 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), ppv);
6005 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator1) ||
6006 IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
6007 IsEqualIID(riid, &IID_IUnknown))
6009 *ppv = iface;
6010 IDWriteColorGlyphRunEnumerator1_AddRef(iface);
6011 return S_OK;
6014 WARN("%s not implemented.\n", debugstr_guid(riid));
6016 *ppv = NULL;
6017 return E_NOINTERFACE;
6020 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator1 *iface)
6022 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6023 ULONG refcount = InterlockedIncrement(&glyphenum->refcount);
6025 TRACE("%p, refcount %u.\n", iface, refcount);
6027 return refcount;
6030 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator1 *iface)
6032 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6033 ULONG refcount = InterlockedDecrement(&glyphenum->refcount);
6035 TRACE("%p, refcount %u.\n", iface, refcount);
6037 if (!refcount)
6039 heap_free(glyphenum->advances);
6040 heap_free(glyphenum->color_advances);
6041 heap_free(glyphenum->offsets);
6042 heap_free(glyphenum->color_offsets);
6043 heap_free(glyphenum->glyphindices);
6044 heap_free(glyphenum->glyphs);
6045 if (glyphenum->colr.context)
6046 IDWriteFontFace5_ReleaseFontTable(glyphenum->fontface, glyphenum->colr.context);
6047 IDWriteFontFace5_Release(glyphenum->fontface);
6048 heap_free(glyphenum);
6051 return refcount;
6054 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
6056 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
6057 FLOAT origin = 0.0f;
6059 if (g == 0)
6060 return 0.0f;
6062 while (g--)
6063 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
6064 return origin;
6067 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
6069 DWRITE_COLOR_GLYPH_RUN1 *colorrun = &glyphenum->colorrun;
6070 FLOAT advance_adj = 0.0f;
6071 BOOL got_palette_index;
6072 UINT32 g;
6074 /* start with regular glyphs */
6075 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
6076 UINT32 first_glyph = 0;
6078 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6079 if (glyphenum->glyphs[g].num_layers == 0) {
6080 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
6081 first_glyph = min(first_glyph, g);
6083 else
6084 glyphenum->glyphindices[g] = 1;
6085 glyphenum->color_advances[g] = glyphenum->advances[g];
6086 if (glyphenum->color_offsets)
6087 glyphenum->color_offsets[g] = glyphenum->offsets[g];
6090 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
6091 colorrun->baselineOriginY = glyphenum->origin_y;
6092 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
6093 colorrun->paletteIndex = 0xffff;
6094 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6095 glyphenum->has_regular_glyphs = FALSE;
6096 return TRUE;
6098 else {
6099 colorrun->glyphRun.glyphCount = 0;
6100 got_palette_index = FALSE;
6103 advance_adj = 0.0f;
6104 for (g = 0; g < glyphenum->run.glyphCount; g++) {
6106 glyphenum->glyphindices[g] = 1;
6108 /* all glyph layers were returned */
6109 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
6110 advance_adj += glyphenum->advances[g];
6111 continue;
6114 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
6115 UINT32 index = colorrun->glyphRun.glyphCount;
6116 if (!got_palette_index) {
6117 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
6118 /* use foreground color or request one from the font */
6119 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
6120 if (colorrun->paletteIndex != 0xffff)
6122 HRESULT hr = IDWriteFontFace5_GetPaletteEntries(glyphenum->fontface, glyphenum->palette,
6123 colorrun->paletteIndex, 1, &colorrun->runColor);
6124 if (FAILED(hr))
6125 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
6126 glyphenum->palette, colorrun->paletteIndex, hr);
6128 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
6129 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
6130 colorrun->baselineOriginY = glyphenum->origin_y;
6131 glyphenum->color_advances[index] = glyphenum->advances[g];
6132 got_palette_index = TRUE;
6135 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
6136 /* offsets are relative to glyph origin, nothing to fix up */
6137 if (glyphenum->color_offsets)
6138 glyphenum->color_offsets[index] = glyphenum->offsets[g];
6139 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
6140 if (index)
6141 glyphenum->color_advances[index-1] += advance_adj;
6142 colorrun->glyphRun.glyphCount++;
6143 advance_adj = 0.0f;
6145 else
6146 advance_adj += glyphenum->advances[g];
6149 /* reset last advance */
6150 if (colorrun->glyphRun.glyphCount)
6151 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
6153 return colorrun->glyphRun.glyphCount > 0;
6156 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator1 *iface, BOOL *has_run)
6158 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6160 TRACE("%p, %p.\n", iface, has_run);
6162 *has_run = FALSE;
6164 glyphenum->colorrun.glyphRun.glyphCount = 0;
6165 while (glyphenum->current_layer < glyphenum->max_layer_num)
6167 if (colorglyphenum_build_color_run(glyphenum))
6168 break;
6169 else
6170 glyphenum->current_layer++;
6173 *has_run = glyphenum->colorrun.glyphRun.glyphCount > 0;
6175 return S_OK;
6178 static HRESULT colorglyphenum_get_current_run(const struct dwrite_colorglyphenum *glyphenum,
6179 DWRITE_COLOR_GLYPH_RUN1 const **run)
6181 if (glyphenum->colorrun.glyphRun.glyphCount == 0)
6183 *run = NULL;
6184 return E_NOT_VALID_STATE;
6187 *run = &glyphenum->colorrun;
6188 return S_OK;
6191 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6192 DWRITE_COLOR_GLYPH_RUN const **run)
6194 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6196 TRACE("%p, %p.\n", iface, run);
6198 return colorglyphenum_get_current_run(glyphenum, (DWRITE_COLOR_GLYPH_RUN1 const **)run);
6201 static HRESULT WINAPI colorglyphenum1_GetCurrentRun(IDWriteColorGlyphRunEnumerator1 *iface,
6202 DWRITE_COLOR_GLYPH_RUN1 const **run)
6204 struct dwrite_colorglyphenum *glyphenum = impl_from_IDWriteColorGlyphRunEnumerator1(iface);
6206 TRACE("%p, %p.\n", iface, run);
6208 return colorglyphenum_get_current_run(glyphenum, run);
6211 static const IDWriteColorGlyphRunEnumerator1Vtbl colorglyphenumvtbl =
6213 colorglyphenum_QueryInterface,
6214 colorglyphenum_AddRef,
6215 colorglyphenum_Release,
6216 colorglyphenum_MoveNext,
6217 colorglyphenum_GetCurrentRun,
6218 colorglyphenum1_GetCurrentRun,
6221 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
6222 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
6223 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
6225 struct dwrite_colorglyphenum *colorglyphenum;
6226 BOOL colorfont, has_colored_glyph;
6227 struct dwrite_fontface *fontface;
6228 unsigned int i;
6230 *ret = NULL;
6232 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
6234 colorfont = IDWriteFontFace5_IsColorFont(&fontface->IDWriteFontFace5_iface) &&
6235 IDWriteFontFace5_GetColorPaletteCount(&fontface->IDWriteFontFace5_iface) > palette;
6236 if (!colorfont)
6237 return DWRITE_E_NOCOLOR;
6239 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
6240 if (!colorglyphenum)
6241 return E_OUTOFMEMORY;
6243 colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface.lpVtbl = &colorglyphenumvtbl;
6244 colorglyphenum->refcount = 1;
6245 colorglyphenum->origin_x = originX;
6246 colorglyphenum->origin_y = originY;
6247 colorglyphenum->fontface = &fontface->IDWriteFontFace5_iface;
6248 IDWriteFontFace5_AddRef(colorglyphenum->fontface);
6249 colorglyphenum->glyphs = NULL;
6250 colorglyphenum->run = *run;
6251 colorglyphenum->run.glyphIndices = NULL;
6252 colorglyphenum->run.glyphAdvances = NULL;
6253 colorglyphenum->run.glyphOffsets = NULL;
6254 colorglyphenum->palette = palette;
6255 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
6256 colorglyphenum->colr.exists = TRUE;
6257 get_fontface_table(&fontface->IDWriteFontFace5_iface, MS_COLR_TAG, &colorglyphenum->colr);
6258 colorglyphenum->current_layer = 0;
6259 colorglyphenum->max_layer_num = 0;
6261 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
6263 has_colored_glyph = FALSE;
6264 colorglyphenum->has_regular_glyphs = FALSE;
6265 for (i = 0; i < run->glyphCount; i++) {
6266 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
6267 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
6268 has_colored_glyph = TRUE;
6270 if (colorglyphenum->glyphs[i].num_layers == 0)
6271 colorglyphenum->has_regular_glyphs = TRUE;
6274 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
6275 is supposed to proceed normally, like if font had no color info at all. */
6276 if (!has_colored_glyph) {
6277 IDWriteColorGlyphRunEnumerator1_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface);
6278 return DWRITE_E_NOCOLOR;
6281 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
6282 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
6283 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
6284 if (run->glyphOffsets) {
6285 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
6286 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
6287 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
6290 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
6291 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
6292 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
6293 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
6294 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
6295 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
6296 colorglyphenum->colorrun.measuringMode = measuring_mode;
6297 colorglyphenum->colorrun.glyphImageFormat = DWRITE_GLYPH_IMAGE_FORMATS_NONE; /* FIXME */
6299 if (run->glyphAdvances)
6300 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
6301 else
6303 for (i = 0; i < run->glyphCount; ++i)
6304 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
6305 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
6308 *ret = (IDWriteColorGlyphRunEnumerator *)&colorglyphenum->IDWriteColorGlyphRunEnumerator1_iface;
6310 return S_OK;
6313 /* IDWriteFontFaceReference */
6314 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference1 *iface, REFIID riid, void **obj)
6316 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6318 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference1) ||
6319 IsEqualIID(riid, &IID_IDWriteFontFaceReference) ||
6320 IsEqualIID(riid, &IID_IUnknown))
6322 *obj = iface;
6323 IDWriteFontFaceReference1_AddRef(iface);
6324 return S_OK;
6327 WARN("%s not implemented.\n", debugstr_guid(riid));
6329 *obj = NULL;
6331 return E_NOINTERFACE;
6334 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference1 *iface)
6336 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6337 ULONG refcount = InterlockedIncrement(&reference->refcount);
6339 TRACE("%p, refcount %u.\n", iface, refcount);
6341 return refcount;
6344 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference1 *iface)
6346 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6347 ULONG refcount = InterlockedDecrement(&reference->refcount);
6349 TRACE("%p, refcount %u.\n", iface, refcount);
6351 if (!refcount)
6353 IDWriteFontFile_Release(reference->file);
6354 IDWriteFactory7_Release(reference->factory);
6355 heap_free(reference->axis_values);
6356 heap_free(reference);
6359 return refcount;
6362 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace3 **fontface)
6364 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6366 TRACE("%p, %p.\n", iface, fontface);
6368 return IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations, fontface);
6371 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference1 *iface,
6372 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
6374 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6375 DWRITE_FONT_FILE_TYPE file_type;
6376 DWRITE_FONT_FACE_TYPE face_type;
6377 IDWriteFontFace *fontface;
6378 BOOL is_supported;
6379 UINT32 face_num;
6380 HRESULT hr;
6382 TRACE("%p, %#x, %p.\n", iface, simulations, ret);
6384 hr = IDWriteFontFile_Analyze(reference->file, &is_supported, &file_type, &face_type, &face_num);
6385 if (FAILED(hr))
6386 return hr;
6388 hr = IDWriteFactory7_CreateFontFace(reference->factory, face_type, 1, &reference->file, reference->index,
6389 simulations, &fontface);
6390 if (SUCCEEDED(hr))
6392 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
6393 IDWriteFontFace_Release(fontface);
6396 return hr;
6399 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference1 *iface, IDWriteFontFaceReference *ref)
6401 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6402 struct dwrite_fontfacereference *other = unsafe_impl_from_IDWriteFontFaceReference(ref);
6403 BOOL ret;
6405 TRACE("%p, %p.\n", iface, ref);
6407 ret = is_same_fontfile(reference->file, other->file) && reference->index == other->index &&
6408 reference->simulations == other->simulations;
6409 if (reference->axis_values_count)
6411 ret &= reference->axis_values_count == other->axis_values_count &&
6412 !memcmp(reference->axis_values, other->axis_values, reference->axis_values_count * sizeof(*reference->axis_values));
6415 return ret;
6418 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference1 *iface)
6420 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6422 TRACE("%p.\n", iface);
6424 return reference->index;
6427 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference1 *iface)
6429 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6431 TRACE("%p.\n", iface);
6433 return reference->simulations;
6436 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference1 *iface, IDWriteFontFile **file)
6438 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6439 IDWriteFontFileLoader *loader;
6440 const void *key;
6441 UINT32 key_size;
6442 HRESULT hr;
6444 TRACE("%p, %p.\n", iface, file);
6446 hr = IDWriteFontFile_GetReferenceKey(reference->file, &key, &key_size);
6447 if (FAILED(hr))
6448 return hr;
6450 hr = IDWriteFontFile_GetLoader(reference->file, &loader);
6451 if (FAILED(hr))
6452 return hr;
6454 hr = IDWriteFactory7_CreateCustomFontFileReference(reference->factory, key, key_size, loader, file);
6455 IDWriteFontFileLoader_Release(loader);
6457 return hr;
6460 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference1 *iface)
6462 FIXME("%p.\n", iface);
6464 return 0;
6467 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference1 *iface)
6469 FIXME("%p.\n", iface);
6471 return 0;
6474 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference1 *iface, FILETIME *writetime)
6476 FIXME("%p, %p.\n", iface, writetime);
6478 return E_NOTIMPL;
6481 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference1 *iface)
6483 FIXME("%p.\n", iface);
6485 return DWRITE_LOCALITY_LOCAL;
6488 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference1 *iface)
6490 FIXME("%p.\n", iface);
6492 return E_NOTIMPL;
6495 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference1 *iface,
6496 WCHAR const *chars, UINT32 count)
6498 FIXME("%p, %s, %u.\n", iface, debugstr_wn(chars, count), count);
6500 return E_NOTIMPL;
6503 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference1 *iface,
6504 UINT16 const *glyphs, UINT32 count)
6506 FIXME("%p, %p, %u.\n", iface, glyphs, count);
6508 return E_NOTIMPL;
6511 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference1 *iface,
6512 UINT64 offset, UINT64 size)
6514 FIXME("%p, 0x%s, 0x%s.\n", iface, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6516 return E_NOTIMPL;
6519 static HRESULT WINAPI fontfacereference1_CreateFontFace(IDWriteFontFaceReference1 *iface, IDWriteFontFace5 **fontface)
6521 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6522 IDWriteFontFace3 *fontface3;
6523 HRESULT hr;
6525 TRACE("%p, %p.\n", iface, fontface);
6527 /* FIXME: created instance should likely respect given axis. */
6528 if (SUCCEEDED(hr = IDWriteFontFaceReference1_CreateFontFaceWithSimulations(iface, reference->simulations,
6529 &fontface3)))
6531 hr = IDWriteFontFace3_QueryInterface(fontface3, &IID_IDWriteFontFace5, (void **)fontface);
6532 IDWriteFontFace3_Release(fontface3);
6535 return hr;
6538 static UINT32 WINAPI fontfacereference1_GetFontAxisValueCount(IDWriteFontFaceReference1 *iface)
6540 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6542 TRACE("%p.\n", iface);
6544 return reference->axis_values_count;
6547 static HRESULT WINAPI fontfacereference1_GetFontAxisValues(IDWriteFontFaceReference1 *iface,
6548 DWRITE_FONT_AXIS_VALUE *axis_values, UINT32 value_count)
6550 struct dwrite_fontfacereference *reference = impl_from_IDWriteFontFaceReference1(iface);
6552 TRACE("%p, %p, %u.\n", iface, axis_values, value_count);
6554 if (value_count < reference->axis_values_count)
6555 return E_NOT_SUFFICIENT_BUFFER;
6557 memcpy(axis_values, reference->axis_values, value_count * sizeof(*axis_values));
6559 return S_OK;
6562 static const IDWriteFontFaceReference1Vtbl fontfacereferencevtbl =
6564 fontfacereference_QueryInterface,
6565 fontfacereference_AddRef,
6566 fontfacereference_Release,
6567 fontfacereference_CreateFontFace,
6568 fontfacereference_CreateFontFaceWithSimulations,
6569 fontfacereference_Equals,
6570 fontfacereference_GetFontFaceIndex,
6571 fontfacereference_GetSimulations,
6572 fontfacereference_GetFontFile,
6573 fontfacereference_GetLocalFileSize,
6574 fontfacereference_GetFileSize,
6575 fontfacereference_GetFileTime,
6576 fontfacereference_GetLocality,
6577 fontfacereference_EnqueueFontDownloadRequest,
6578 fontfacereference_EnqueueCharacterDownloadRequest,
6579 fontfacereference_EnqueueGlyphDownloadRequest,
6580 fontfacereference_EnqueueFileFragmentDownloadRequest,
6581 fontfacereference1_CreateFontFace,
6582 fontfacereference1_GetFontAxisValueCount,
6583 fontfacereference1_GetFontAxisValues,
6586 HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 index,
6587 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count,
6588 IDWriteFontFaceReference1 **ret)
6590 struct dwrite_fontfacereference *object;
6592 *ret = NULL;
6594 if (!is_simulation_valid(simulations))
6595 return E_INVALIDARG;
6597 object = heap_alloc_zero(sizeof(*object));
6598 if (!object)
6599 return E_OUTOFMEMORY;
6601 object->IDWriteFontFaceReference1_iface.lpVtbl = &fontfacereferencevtbl;
6602 object->refcount = 1;
6604 object->factory = factory;
6605 IDWriteFactory7_AddRef(object->factory);
6606 object->file = file;
6607 IDWriteFontFile_AddRef(object->file);
6608 object->index = index;
6609 object->simulations = simulations;
6610 if (axis_values_count)
6612 if (!(object->axis_values = heap_alloc(axis_values_count * sizeof(*axis_values))))
6614 IDWriteFontFaceReference1_Release(&object->IDWriteFontFaceReference1_iface);
6615 return E_OUTOFMEMORY;
6617 memcpy(object->axis_values, axis_values, axis_values_count * sizeof(*axis_values));
6618 object->axis_values_count = axis_values_count;
6621 *ret = &object->IDWriteFontFaceReference1_iface;
6623 return S_OK;
6626 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6628 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6630 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6632 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6633 *obj = iface;
6634 IDWriteFontFileStream_AddRef(iface);
6635 return S_OK;
6638 *obj = NULL;
6640 WARN("%s not implemented.\n", debugstr_guid(riid));
6641 return E_NOINTERFACE;
6644 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6646 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6647 ULONG ref = InterlockedIncrement(&stream->ref);
6648 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6649 return ref;
6652 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6654 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6655 ULONG ref = InterlockedDecrement(&stream->ref);
6657 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6659 if (!ref) {
6660 release_inmemory_stream(stream->data);
6661 heap_free(stream);
6664 return ref;
6667 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6668 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6670 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6672 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6673 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6675 *fragment_context = NULL;
6677 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6678 *fragment_start = NULL;
6679 return E_FAIL;
6682 *fragment_start = (char *)stream->data->data + offset;
6683 return S_OK;
6686 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6688 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6690 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6693 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6695 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6697 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6699 *size = stream->data->size;
6701 return S_OK;
6704 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6706 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6708 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6710 *last_writetime = 0;
6712 return E_NOTIMPL;
6715 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6716 inmemoryfilestream_QueryInterface,
6717 inmemoryfilestream_AddRef,
6718 inmemoryfilestream_Release,
6719 inmemoryfilestream_ReadFileFragment,
6720 inmemoryfilestream_ReleaseFileFragment,
6721 inmemoryfilestream_GetFileSize,
6722 inmemoryfilestream_GetLastWriteTime,
6725 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6726 REFIID riid, void **obj)
6728 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6730 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6732 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6733 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6734 IsEqualIID(riid, &IID_IUnknown))
6736 *obj = iface;
6737 IDWriteInMemoryFontFileLoader_AddRef(iface);
6738 return S_OK;
6741 WARN("%s not implemented.\n", debugstr_guid(riid));
6743 *obj = NULL;
6745 return E_NOINTERFACE;
6748 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6750 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6751 ULONG ref = InterlockedIncrement(&loader->ref);
6752 TRACE("(%p)->(%u)\n", loader, ref);
6753 return ref;
6756 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6758 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6759 ULONG ref = InterlockedDecrement(&loader->ref);
6760 size_t i;
6762 TRACE("(%p)->(%u)\n", loader, ref);
6764 if (!ref) {
6765 for (i = 0; i < loader->count; ++i)
6766 release_inmemory_stream(loader->streams[i]);
6767 heap_free(loader->streams);
6768 heap_free(loader);
6771 return ref;
6774 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6775 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6777 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6778 struct dwrite_inmemory_filestream *stream;
6779 DWORD index;
6781 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6783 *ret = NULL;
6785 if (key_size != sizeof(DWORD))
6786 return E_INVALIDARG;
6788 index = *(DWORD *)key;
6790 if (index >= loader->count)
6791 return E_INVALIDARG;
6793 if (!(stream = heap_alloc(sizeof(*stream))))
6794 return E_OUTOFMEMORY;
6796 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6797 stream->ref = 1;
6798 stream->data = loader->streams[index];
6799 InterlockedIncrement(&stream->data->ref);
6801 *ret = &stream->IDWriteFontFileStream_iface;
6803 return S_OK;
6806 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6807 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6809 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6810 struct dwrite_inmemory_stream_data *stream;
6811 DWORD key;
6813 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6815 *fontfile = NULL;
6817 if (!dwrite_array_reserve((void **)&loader->streams, &loader->size, loader->count + 1, sizeof(*loader->streams)))
6818 return E_OUTOFMEMORY;
6820 if (!(stream = heap_alloc(sizeof(*stream))))
6821 return E_OUTOFMEMORY;
6823 stream->ref = 1;
6824 stream->size = data_size;
6825 stream->owner = owner;
6826 if (stream->owner) {
6827 IUnknown_AddRef(stream->owner);
6828 stream->data = (void *)data;
6830 else {
6831 if (!(stream->data = heap_alloc(data_size))) {
6832 heap_free(stream);
6833 return E_OUTOFMEMORY;
6835 memcpy(stream->data, data, data_size);
6838 key = loader->count;
6839 loader->streams[loader->count++] = stream;
6841 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6842 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6845 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6847 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6849 TRACE("%p.\n", iface);
6851 return loader->count;
6854 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6856 inmemoryfontfileloader_QueryInterface,
6857 inmemoryfontfileloader_AddRef,
6858 inmemoryfontfileloader_Release,
6859 inmemoryfontfileloader_CreateStreamFromKey,
6860 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6861 inmemoryfontfileloader_GetFileCount,
6864 HRESULT create_inmemory_fileloader(IDWriteInMemoryFontFileLoader **ret)
6866 struct dwrite_inmemory_fileloader *loader;
6868 *ret = NULL;
6870 loader = heap_alloc_zero(sizeof(*loader));
6871 if (!loader)
6872 return E_OUTOFMEMORY;
6874 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6875 loader->ref = 1;
6877 *ret = &loader->IDWriteInMemoryFontFileLoader_iface;
6879 return S_OK;
6882 static HRESULT WINAPI dwritefontresource_QueryInterface(IDWriteFontResource *iface, REFIID riid, void **obj)
6884 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
6886 if (IsEqualIID(riid, &IID_IDWriteFontResource) ||
6887 IsEqualIID(riid, &IID_IUnknown))
6889 *obj = iface;
6890 IDWriteFontResource_AddRef(iface);
6891 return S_OK;
6894 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
6896 return E_NOINTERFACE;
6899 static ULONG WINAPI dwritefontresource_AddRef(IDWriteFontResource *iface)
6901 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6902 ULONG refcount = InterlockedIncrement(&resource->refcount);
6904 TRACE("%p, refcount %u.\n", iface, refcount);
6906 return refcount;
6909 static ULONG WINAPI dwritefontresource_Release(IDWriteFontResource *iface)
6911 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6912 ULONG refcount = InterlockedDecrement(&resource->refcount);
6914 TRACE("%p, refcount %u.\n", iface, refcount);
6916 if (!refcount)
6918 IDWriteFactory7_Release(resource->factory);
6919 IDWriteFontFile_Release(resource->file);
6920 heap_free(resource);
6923 return refcount;
6926 static HRESULT WINAPI dwritefontresource_GetFontFile(IDWriteFontResource *iface, IDWriteFontFile **fontfile)
6928 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6930 TRACE("%p, %p.\n", iface, fontfile);
6932 *fontfile = resource->file;
6933 IDWriteFontFile_AddRef(*fontfile);
6935 return S_OK;
6938 static UINT32 WINAPI dwritefontresource_GetFontFaceIndex(IDWriteFontResource *iface)
6940 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
6942 TRACE("%p.\n", iface);
6944 return resource->face_index;
6947 static UINT32 WINAPI dwritefontresource_GetFontAxisCount(IDWriteFontResource *iface)
6949 FIXME("%p.\n", iface);
6951 return 0;
6954 static HRESULT WINAPI dwritefontresource_GetDefaultFontAxisValues(IDWriteFontResource *iface,
6955 DWRITE_FONT_AXIS_VALUE const *values, UINT32 num_values)
6957 FIXME("%p, %p, %u.\n", iface, values, num_values);
6959 return E_NOTIMPL;
6962 static HRESULT WINAPI dwritefontresource_GetFontAxisRanges(IDWriteFontResource *iface,
6963 DWRITE_FONT_AXIS_RANGE const *ranges, UINT32 num_ranges)
6965 FIXME("%p, %p, %u.\n", iface, ranges, num_ranges);
6967 return E_NOTIMPL;
6970 static DWRITE_FONT_AXIS_ATTRIBUTES WINAPI dwritefontresource_GetFontAxisAttributes(IDWriteFontResource *iface,
6971 UINT32 axis)
6973 FIXME("%p, %u.\n", iface, axis);
6975 return DWRITE_FONT_AXIS_ATTRIBUTES_NONE;
6978 static HRESULT WINAPI dwritefontresource_GetAxisNames(IDWriteFontResource *iface, UINT32 axis,
6979 IDWriteLocalizedStrings **names)
6981 FIXME("%p, %u, %p.\n", iface, axis, names);
6983 return E_NOTIMPL;
6986 static UINT32 WINAPI dwritefontresource_GetAxisValueNameCount(IDWriteFontResource *iface, UINT32 axis)
6988 FIXME("%p, %u.\n", iface, axis);
6990 return 0;
6993 static HRESULT WINAPI dwritefontresource_GetAxisValueNames(IDWriteFontResource *iface, UINT32 axis,
6994 UINT32 axis_value, DWRITE_FONT_AXIS_RANGE *axis_range, IDWriteLocalizedStrings **names)
6996 FIXME("%p, %u, %u, %p, %p.\n", iface, axis, axis_value, axis_range, names);
6998 return E_NOTIMPL;
7001 static BOOL WINAPI dwritefontresource_HasVariations(IDWriteFontResource *iface)
7003 FIXME("%p.\n", iface);
7005 return FALSE;
7008 static HRESULT WINAPI dwritefontresource_CreateFontFace(IDWriteFontResource *iface,
7009 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7010 IDWriteFontFace5 **fontface)
7012 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7013 IDWriteFontFaceReference1 *reference;
7014 HRESULT hr;
7016 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, fontface);
7018 hr = IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7019 simulations, axis_values, num_values, &reference);
7020 if (SUCCEEDED(hr))
7022 hr = IDWriteFontFaceReference1_CreateFontFace(reference, fontface);
7023 IDWriteFontFaceReference1_Release(reference);
7026 return hr;
7029 static HRESULT WINAPI dwritefontresource_CreateFontFaceReference(IDWriteFontResource *iface,
7030 DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 num_values,
7031 IDWriteFontFaceReference1 **reference)
7033 struct dwrite_fontresource *resource = impl_from_IDWriteFontResource(iface);
7035 TRACE("%p, %#x, %p, %u, %p.\n", iface, simulations, axis_values, num_values, reference);
7037 return IDWriteFactory7_CreateFontFaceReference(resource->factory, resource->file, resource->face_index,
7038 simulations, axis_values, num_values, reference);
7041 static const IDWriteFontResourceVtbl fontresourcevtbl =
7043 dwritefontresource_QueryInterface,
7044 dwritefontresource_AddRef,
7045 dwritefontresource_Release,
7046 dwritefontresource_GetFontFile,
7047 dwritefontresource_GetFontFaceIndex,
7048 dwritefontresource_GetFontAxisCount,
7049 dwritefontresource_GetDefaultFontAxisValues,
7050 dwritefontresource_GetFontAxisRanges,
7051 dwritefontresource_GetFontAxisAttributes,
7052 dwritefontresource_GetAxisNames,
7053 dwritefontresource_GetAxisValueNameCount,
7054 dwritefontresource_GetAxisValueNames,
7055 dwritefontresource_HasVariations,
7056 dwritefontresource_CreateFontFace,
7057 dwritefontresource_CreateFontFaceReference,
7060 HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index,
7061 IDWriteFontResource **ret)
7063 struct dwrite_fontresource *resource;
7065 *ret = NULL;
7067 resource = heap_alloc_zero(sizeof(*resource));
7068 if (!resource)
7069 return E_OUTOFMEMORY;
7071 resource->IDWriteFontResource_iface.lpVtbl = &fontresourcevtbl;
7072 resource->refcount = 1;
7073 resource->face_index = face_index;
7074 resource->file = file;
7075 IDWriteFontFile_AddRef(resource->file);
7076 resource->factory = factory;
7077 IDWriteFactory7_AddRef(resource->factory);
7079 *ret = &resource->IDWriteFontResource_iface;
7081 return S_OK;