winmm: Restrict some MCI actions to the creating thread.
[wine.git] / dlls / dwrite / font.c
bloba8902502f7e5e013f6e809529b3cbe6ecbb1e23a
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2016 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
22 #include <math.h>
24 #define COBJMACROS
26 #include "wine/list.h"
27 #include "dwrite_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
30 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
32 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
33 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
34 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
35 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
36 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
37 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
38 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
39 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
41 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
43 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
44 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
45 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
47 static const WCHAR extraW[] = {'e','x','t','r','a',0};
48 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
49 static const WCHAR semiW[] = {'s','e','m','i',0};
50 static const WCHAR extW[] = {'e','x','t',0};
51 static const WCHAR thinW[] = {'t','h','i','n',0};
52 static const WCHAR lightW[] = {'l','i','g','h','t',0};
53 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
54 static const WCHAR blackW[] = {'b','l','a','c','k',0};
55 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
56 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
57 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
58 static const WCHAR boldW[] = {'B','o','l','d',0};
59 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
60 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
61 static const WCHAR demiW[] = {'d','e','m','i',0};
62 static const WCHAR spaceW[] = {' ',0};
63 static const WCHAR enusW[] = {'e','n','-','u','s',0};
65 struct dwrite_font_propvec {
66 FLOAT stretch;
67 FLOAT style;
68 FLOAT weight;
71 struct dwrite_font_data {
72 LONG ref;
74 DWRITE_FONT_STYLE style;
75 DWRITE_FONT_STRETCH stretch;
76 DWRITE_FONT_WEIGHT weight;
77 DWRITE_PANOSE panose;
78 struct dwrite_font_propvec propvec;
80 DWRITE_FONT_METRICS1 metrics;
81 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
82 IDWriteLocalizedStrings *names;
84 /* data needed to create fontface instance */
85 IDWriteFactory3 *factory;
86 DWRITE_FONT_FACE_TYPE face_type;
87 IDWriteFontFile *file;
88 UINT32 face_index;
90 WCHAR *facename;
92 USHORT simulations;
94 /* used to mark font as tested when scanning for simulation candidate */
95 BOOL bold_sim_tested : 1;
96 BOOL oblique_sim_tested : 1;
99 struct dwrite_fontlist {
100 IDWriteFontList1 IDWriteFontList1_iface;
101 LONG ref;
103 IDWriteFontFamily1 *family;
104 struct dwrite_font_data **fonts;
105 UINT32 font_count;
108 struct dwrite_fontfamily_data {
109 LONG ref;
111 IDWriteLocalizedStrings *familyname;
113 struct dwrite_font_data **fonts;
114 UINT32 font_count;
115 UINT32 font_alloc;
116 BOOL has_normal_face : 1;
117 BOOL has_oblique_face : 1;
118 BOOL has_italic_face : 1;
121 struct dwrite_fontcollection {
122 IDWriteFontCollection1 IDWriteFontCollection1_iface;
123 LONG ref;
125 struct dwrite_fontfamily_data **family_data;
126 UINT32 family_count;
127 UINT32 family_alloc;
130 struct dwrite_fontfamily {
131 IDWriteFontFamily1 IDWriteFontFamily1_iface;
132 LONG ref;
134 struct dwrite_fontfamily_data *data;
136 IDWriteFontCollection1 *collection;
139 struct dwrite_font {
140 IDWriteFont3 IDWriteFont3_iface;
141 LONG ref;
143 IDWriteFontFamily1 *family;
145 DWRITE_FONT_STYLE style;
146 struct dwrite_font_data *data;
149 struct dwrite_fonttable {
150 void *data;
151 void *context;
152 UINT32 size;
153 BOOL exists;
156 enum runanalysis_flags {
157 RUNANALYSIS_BOUNDS_READY = 1 << 0,
158 RUNANALYSIS_BITMAP_READY = 1 << 1,
159 RUNANALYSIS_USE_TRANSFORM = 1 << 2
162 struct dwrite_glyphrunanalysis {
163 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
164 LONG ref;
166 DWRITE_RENDERING_MODE rendering_mode;
167 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
168 DWRITE_MATRIX m;
169 FLOAT ppdip;
170 UINT16 *glyphs;
171 D2D_POINT_2F origin;
172 D2D_POINT_2F *advances;
173 D2D_POINT_2F *advanceoffsets;
174 D2D_POINT_2F *ascenderoffsets;
176 UINT8 flags;
177 RECT bounds;
178 BYTE *bitmap;
181 struct dwrite_colorglyphenum {
182 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
183 LONG ref;
185 FLOAT origin_x; /* original run origin */
186 FLOAT origin_y;
188 IDWriteFontFace3 *fontface; /* for convenience */
189 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
190 DWRITE_GLYPH_RUN run; /* base run */
191 UINT32 palette; /* palette index to get layer color from */
192 FLOAT *advances; /* original or measured advances for base glyphs */
193 FLOAT *color_advances; /* returned color run points to this */
194 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
195 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
196 UINT16 *glyphindices; /* returned color run points to this */
197 struct dwrite_colorglyph *glyphs; /* current glyph color info */
198 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
199 UINT16 current_layer; /* enumerator position, updated with MoveNext */
200 UINT16 max_layer_num; /* max number of layers for this run */
201 struct dwrite_fonttable colr; /* used to access layers */
204 #define GLYPH_BLOCK_SHIFT 8
205 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
206 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
207 #define GLYPH_MAX 65536
209 struct dwrite_fontface {
210 IDWriteFontFace3 IDWriteFontFace3_iface;
211 LONG ref;
213 IDWriteFontFileStream **streams;
214 IDWriteFontFile **files;
215 UINT32 file_count;
216 UINT32 index;
218 USHORT simulations;
219 DWRITE_FONT_FACE_TYPE type;
220 DWRITE_FONT_METRICS1 metrics;
221 DWRITE_CARET_METRICS caret;
222 INT charmap;
223 BOOL is_symbol;
224 BOOL has_kerning_pairs : 1;
225 BOOL is_monospaced : 1;
227 struct dwrite_fonttable cmap;
228 struct dwrite_fonttable vdmx;
229 struct dwrite_fonttable gasp;
230 struct dwrite_fonttable cpal;
231 struct dwrite_fonttable colr;
232 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
235 struct dwrite_fontfile {
236 IDWriteFontFile IDWriteFontFile_iface;
237 LONG ref;
239 IDWriteFontFileLoader *loader;
240 void *reference_key;
241 UINT32 key_size;
242 IDWriteFontFileStream *stream;
245 struct dwrite_fontfacereference {
246 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
247 LONG ref;
249 IDWriteFontFile *file;
250 UINT32 index;
251 USHORT simulations;
252 IDWriteFactory3 *factory;
255 static inline struct dwrite_fontface *impl_from_IDWriteFontFace3(IDWriteFontFace3 *iface)
257 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace3_iface);
260 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
262 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
265 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
267 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
270 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
272 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
275 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
277 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
280 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
282 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
285 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
287 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
290 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
292 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
295 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
297 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
300 static inline const char *debugstr_tag(UINT32 tag)
302 return debugstr_an((char*)&tag, 4);
305 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
307 static const DWRITE_GLYPH_METRICS nil;
308 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
310 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
311 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
312 return S_OK;
315 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
317 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
319 if (!*block) {
320 /* start new block */
321 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
322 if (!*block)
323 return E_OUTOFMEMORY;
326 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
327 return S_OK;
330 static void* get_fontface_table(IDWriteFontFace3 *fontface, UINT32 tag, struct dwrite_fonttable *table)
332 HRESULT hr;
334 if (table->data || !table->exists)
335 return table->data;
337 table->exists = FALSE;
338 hr = IDWriteFontFace3_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
339 &table->exists);
340 if (FAILED(hr) || !table->exists) {
341 WARN("Font does not have a %s table\n", debugstr_tag(tag));
342 return NULL;
345 return table->data;
348 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
349 struct dwrite_font_propvec *vec)
351 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
352 vec->style = style * 7.0f;
353 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
356 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
358 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
361 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
363 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
366 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
368 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CMAP_TAG, &fontface->cmap);
371 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
373 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_VDMX_TAG, &fontface->vdmx);
376 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
378 void *ptr = get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_GASP_TAG, &fontface->gasp);
379 *size = fontface->gasp.size;
380 return ptr;
383 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
385 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CPAL_TAG, &fontface->cpal);
388 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
390 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_COLR_TAG, &fontface->colr);
393 static void release_font_data(struct dwrite_font_data *data)
395 int i;
397 if (InterlockedDecrement(&data->ref) > 0)
398 return;
400 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
401 if (data->info_strings[i])
402 IDWriteLocalizedStrings_Release(data->info_strings[i]);
404 if (data->names)
405 IDWriteLocalizedStrings_Release(data->names);
407 IDWriteFontFile_Release(data->file);
408 IDWriteFactory3_Release(data->factory);
409 heap_free(data->facename);
410 heap_free(data);
413 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
415 int i;
417 if (InterlockedDecrement(&data->ref) > 0)
418 return;
420 for (i = 0; i < data->font_count; i++)
421 release_font_data(data->fonts[i]);
422 heap_free(data->fonts);
423 IDWriteLocalizedStrings_Release(data->familyname);
424 heap_free(data);
427 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace3 *iface, REFIID riid, void **obj)
429 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
431 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
433 if (IsEqualIID(riid, &IID_IDWriteFontFace3) ||
434 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
435 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
436 IsEqualIID(riid, &IID_IDWriteFontFace) ||
437 IsEqualIID(riid, &IID_IUnknown))
439 *obj = iface;
440 IDWriteFontFace3_AddRef(iface);
441 return S_OK;
444 *obj = NULL;
445 return E_NOINTERFACE;
448 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace3 *iface)
450 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
451 ULONG ref = InterlockedIncrement(&This->ref);
452 TRACE("(%p)->(%d)\n", This, ref);
453 return ref;
456 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace3 *iface)
458 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
459 ULONG ref = InterlockedDecrement(&This->ref);
461 TRACE("(%p)->(%d)\n", This, ref);
463 if (!ref) {
464 UINT32 i;
466 if (This->cmap.context)
467 IDWriteFontFace3_ReleaseFontTable(iface, This->cmap.context);
468 if (This->vdmx.context)
469 IDWriteFontFace3_ReleaseFontTable(iface, This->vdmx.context);
470 if (This->gasp.context)
471 IDWriteFontFace3_ReleaseFontTable(iface, This->gasp.context);
472 if (This->cpal.context)
473 IDWriteFontFace3_ReleaseFontTable(iface, This->cpal.context);
474 if (This->colr.context)
475 IDWriteFontFace3_ReleaseFontTable(iface, This->colr.context);
476 for (i = 0; i < This->file_count; i++) {
477 if (This->streams[i])
478 IDWriteFontFileStream_Release(This->streams[i]);
479 if (This->files[i])
480 IDWriteFontFile_Release(This->files[i]);
482 heap_free(This->streams);
483 heap_free(This->files);
485 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
486 heap_free(This->glyphs[i]);
488 freetype_notify_cacheremove(iface);
489 heap_free(This);
492 return ref;
495 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace3 *iface)
497 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
498 TRACE("(%p)\n", This);
499 return This->type;
502 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace3 *iface, UINT32 *number_of_files,
503 IDWriteFontFile **fontfiles)
505 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
506 int i;
508 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
509 if (fontfiles == NULL)
511 *number_of_files = This->file_count;
512 return S_OK;
514 if (*number_of_files < This->file_count)
515 return E_INVALIDARG;
517 for (i = 0; i < This->file_count; i++)
519 IDWriteFontFile_AddRef(This->files[i]);
520 fontfiles[i] = This->files[i];
523 return S_OK;
526 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace3 *iface)
528 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
529 TRACE("(%p)\n", This);
530 return This->index;
533 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace3 *iface)
535 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
536 TRACE("(%p)\n", This);
537 return This->simulations;
540 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace3 *iface)
542 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
543 TRACE("(%p)\n", This);
544 return This->is_symbol;
547 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS *metrics)
549 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
550 TRACE("(%p)->(%p)\n", This, metrics);
551 memcpy(metrics, &This->metrics, sizeof(*metrics));
554 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace3 *iface)
556 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
557 TRACE("(%p)\n", This);
558 return freetype_get_glyphcount(iface);
561 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace3 *iface,
562 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
564 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
565 HRESULT hr;
566 UINT32 i;
568 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
570 if (!glyphs)
571 return E_INVALIDARG;
573 if (is_sideways)
574 FIXME("sideways metrics are not supported.\n");
576 for (i = 0; i < glyph_count; i++) {
577 DWRITE_GLYPH_METRICS metrics;
579 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
580 if (hr != S_OK) {
581 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
582 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
583 if (FAILED(hr))
584 return hr;
586 ret[i] = metrics;
589 return S_OK;
592 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace3 *iface, UINT32 const *codepoints,
593 UINT32 count, UINT16 *glyph_indices)
595 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
597 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
599 if (!glyph_indices)
600 return E_INVALIDARG;
602 if (!codepoints) {
603 memset(glyph_indices, 0, count*sizeof(UINT16));
604 return E_INVALIDARG;
607 freetype_get_glyphs(iface, This->charmap, codepoints, count, glyph_indices);
608 return S_OK;
611 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace3 *iface, UINT32 table_tag,
612 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
614 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
615 struct file_stream_desc stream_desc;
617 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
619 stream_desc.stream = This->streams[0];
620 stream_desc.face_type = This->type;
621 stream_desc.face_index = This->index;
622 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
625 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace3 *iface, void *table_context)
627 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
629 TRACE("(%p)->(%p)\n", This, table_context);
631 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
634 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace3 *iface, FLOAT emSize,
635 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
636 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
638 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
640 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
641 count, is_sideways, is_rtl, sink);
643 if (!glyphs || !sink)
644 return E_INVALIDARG;
646 if (is_sideways)
647 FIXME("sideways mode is not supported.\n");
649 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
652 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
653 FLOAT ppem, WORD gasp)
655 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
657 switch (measuring)
659 case DWRITE_MEASURING_MODE_NATURAL:
661 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
662 mode = DWRITE_RENDERING_MODE_NATURAL;
663 else
664 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
665 break;
667 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
668 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
669 break;
670 case DWRITE_MEASURING_MODE_GDI_NATURAL:
671 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
672 break;
673 default:
677 return mode;
680 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
681 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
683 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
684 WORD gasp, *ptr;
685 UINT32 size;
686 FLOAT ppem;
688 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
690 if (!params) {
691 *mode = DWRITE_RENDERING_MODE_DEFAULT;
692 return E_INVALIDARG;
695 *mode = IDWriteRenderingParams_GetRenderingMode(params);
696 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
697 return S_OK;
699 ppem = emSize * ppdip;
701 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
702 *mode = DWRITE_RENDERING_MODE_OUTLINE;
703 return S_OK;
706 ptr = get_fontface_gasp(This, &size);
707 gasp = opentype_get_gasp_flags(ptr, size, ppem);
708 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
709 return S_OK;
712 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT pixels_per_dip,
713 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
715 DWRITE_FONT_METRICS1 metrics1;
716 HRESULT hr = IDWriteFontFace3_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
717 memcpy(metrics, &metrics1, sizeof(*metrics));
718 return hr;
721 static inline int round_metric(FLOAT metric)
723 return (int)floorf(metric + 0.5f);
726 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT ppdip,
727 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
728 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
730 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
731 DWRITE_MEASURING_MODE mode;
732 FLOAT scale, size;
733 HRESULT hr;
734 UINT32 i;
736 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
737 glyph_count, metrics, is_sideways);
739 if (m && memcmp(m, &identity, sizeof(*m)))
740 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
742 size = emSize * ppdip;
743 scale = size / This->metrics.designUnitsPerEm;
744 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
746 for (i = 0; i < glyph_count; i++) {
747 DWRITE_GLYPH_METRICS *ret = metrics + i;
748 DWRITE_GLYPH_METRICS design;
750 hr = IDWriteFontFace3_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
751 if (FAILED(hr))
752 return hr;
754 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
755 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
757 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
758 SCALE_METRIC(leftSideBearing);
759 SCALE_METRIC(rightSideBearing);
760 SCALE_METRIC(topSideBearing);
761 SCALE_METRIC(advanceHeight);
762 SCALE_METRIC(bottomSideBearing);
763 SCALE_METRIC(verticalOriginY);
764 #undef SCALE_METRIC
767 return S_OK;
770 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS1 *metrics)
772 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
773 TRACE("(%p)->(%p)\n", This, metrics);
774 *metrics = This->metrics;
777 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT em_size, FLOAT pixels_per_dip,
778 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
780 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
781 const DWRITE_FONT_METRICS1 *design = &This->metrics;
782 UINT16 ascent, descent;
783 FLOAT scale;
785 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
787 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
788 memset(metrics, 0, sizeof(*metrics));
789 return E_INVALIDARG;
792 em_size *= pixels_per_dip;
793 if (m && m->m22 != 0.0f)
794 em_size *= fabs(m->m22);
796 scale = em_size / design->designUnitsPerEm;
797 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
798 ascent = round_metric(design->ascent * scale);
799 descent = round_metric(design->descent * scale);
802 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
803 metrics->designUnitsPerEm = design->designUnitsPerEm;
804 metrics->ascent = round_metric(ascent / scale);
805 metrics->descent = round_metric(descent / scale);
807 SCALE_METRIC(lineGap);
808 SCALE_METRIC(capHeight);
809 SCALE_METRIC(xHeight);
810 SCALE_METRIC(underlinePosition);
811 SCALE_METRIC(underlineThickness);
812 SCALE_METRIC(strikethroughPosition);
813 SCALE_METRIC(strikethroughThickness);
814 SCALE_METRIC(glyphBoxLeft);
815 SCALE_METRIC(glyphBoxTop);
816 SCALE_METRIC(glyphBoxRight);
817 SCALE_METRIC(glyphBoxBottom);
818 SCALE_METRIC(subscriptPositionX);
819 SCALE_METRIC(subscriptPositionY);
820 SCALE_METRIC(subscriptSizeX);
821 SCALE_METRIC(subscriptSizeY);
822 SCALE_METRIC(superscriptPositionX);
823 SCALE_METRIC(superscriptPositionY);
824 SCALE_METRIC(superscriptSizeX);
825 SCALE_METRIC(superscriptSizeY);
827 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
828 #undef SCALE_METRIC
830 return S_OK;
833 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace3 *iface, DWRITE_CARET_METRICS *metrics)
835 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
836 TRACE("(%p)->(%p)\n", This, metrics);
837 *metrics = This->caret;
840 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace3 *iface, UINT32 max_count,
841 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
843 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
845 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
847 *count = 0;
848 if (max_count && !ranges)
849 return E_INVALIDARG;
851 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
854 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
856 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
857 TRACE("(%p)\n", This);
858 return This->is_monospaced;
861 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
862 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
864 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
865 UINT32 i;
867 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
869 if (is_sideways)
870 FIXME("sideways mode not supported\n");
872 for (i = 0; i < glyph_count; i++)
873 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
875 return S_OK;
878 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3 *iface,
879 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
880 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
882 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
883 DWRITE_MEASURING_MODE mode;
884 UINT32 i;
886 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
887 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
889 if (em_size < 0.0f || ppdip <= 0.0f) {
890 memset(advances, 0, sizeof(*advances) * glyph_count);
891 return E_INVALIDARG;
894 em_size *= ppdip;
895 if (em_size == 0.0f) {
896 memset(advances, 0, sizeof(*advances) * glyph_count);
897 return S_OK;
900 if (m && memcmp(m, &identity, sizeof(*m)))
901 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
903 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
904 for (i = 0; i < glyph_count; i++) {
905 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
906 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
909 return S_OK;
912 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3 *iface, UINT32 count,
913 const UINT16 *indices, INT32 *adjustments)
915 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
916 UINT32 i;
918 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
920 if (!(indices || adjustments) || !count)
921 return E_INVALIDARG;
923 if (!indices || count == 1) {
924 memset(adjustments, 0, count*sizeof(INT32));
925 return E_INVALIDARG;
928 if (!This->has_kerning_pairs) {
929 memset(adjustments, 0, count*sizeof(INT32));
930 return S_OK;
933 for (i = 0; i < count-1; i++)
934 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
935 adjustments[count-1] = 0;
937 return S_OK;
940 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
942 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
943 TRACE("(%p)\n", This);
944 return This->has_kerning_pairs;
947 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
948 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
949 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
951 DWRITE_GRID_FIT_MODE gridfitmode;
952 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
953 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
956 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3 *iface, UINT32 glyph_count,
957 const UINT16 *nominal_indices, UINT16 *vertical_indices)
959 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
960 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
961 return E_NOTIMPL;
964 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
966 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
967 FIXME("(%p): stub\n", This);
968 return FALSE;
971 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
973 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
974 TRACE("(%p)\n", This);
975 return get_fontface_cpal(This) && get_fontface_colr(This);
978 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace3 *iface)
980 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
981 TRACE("(%p)\n", This);
982 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
985 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3 *iface)
987 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
988 TRACE("(%p)\n", This);
989 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
992 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace3 *iface, UINT32 palette_index,
993 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
995 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
996 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
997 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1000 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
1001 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1002 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1003 DWRITE_GRID_FIT_MODE *gridfitmode)
1005 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1006 FLOAT emthreshold;
1007 WORD gasp, *ptr;
1008 UINT32 size;
1010 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1011 measuringmode, params, renderingmode, gridfitmode);
1013 if (m)
1014 FIXME("transform not supported %s\n", debugstr_matrix(m));
1016 if (is_sideways)
1017 FIXME("sideways mode not supported\n");
1019 emSize *= max(dpiX, dpiY) / 96.0f;
1021 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1022 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1023 if (params) {
1024 IDWriteRenderingParams2 *params2;
1025 HRESULT hr;
1027 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1028 if (hr == S_OK) {
1029 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1030 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1031 IDWriteRenderingParams2_Release(params2);
1033 else
1034 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1037 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1039 ptr = get_fontface_gasp(This, &size);
1040 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1042 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1043 if (emSize >= emthreshold)
1044 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1045 else
1046 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1049 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1050 if (emSize >= emthreshold)
1051 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1052 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1053 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1054 else
1055 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1058 return S_OK;
1061 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace3 *iface, IDWriteFontFaceReference **ref)
1063 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1064 FIXME("(%p)->(%p): stub\n", This, ref);
1065 return E_NOTIMPL;
1068 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace3 *iface, DWRITE_PANOSE *panose)
1070 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1071 FIXME("(%p)->(%p): stub\n", This, panose);
1074 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace3 *iface)
1076 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1077 FIXME("(%p): stub\n", This);
1078 return DWRITE_FONT_WEIGHT_NORMAL;
1081 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace3 *iface)
1083 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1084 FIXME("(%p): stub\n", This);
1085 return DWRITE_FONT_STRETCH_NORMAL;
1088 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace3 *iface)
1090 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1091 FIXME("(%p): stub\n", This);
1092 return DWRITE_FONT_STYLE_NORMAL;
1095 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1097 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1098 FIXME("(%p)->(%p): stub\n", This, names);
1099 return E_NOTIMPL;
1102 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1104 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1105 FIXME("(%p)->(%p): stub\n", This, names);
1106 return E_NOTIMPL;
1109 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace3 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1110 IDWriteLocalizedStrings **strings, BOOL *exists)
1112 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1113 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1114 return E_NOTIMPL;
1117 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace3 *iface, UINT32 ch)
1119 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1120 UINT16 index;
1121 HRESULT hr;
1123 TRACE("(%p)->(0x%08x)\n", This, ch);
1125 index = 0;
1126 hr = IDWriteFontFace3_GetGlyphIndices(iface, &ch, 1, &index);
1127 if (FAILED(hr))
1128 return FALSE;
1130 return index != 0;
1133 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emsize, FLOAT dpi_x, FLOAT dpi_y,
1134 DWRITE_MATRIX const *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1135 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1137 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1138 FIXME("(%p)->(%f %f %f %p %d %u %u %p %p %p): stub\n", This, emsize, dpi_x, dpi_y, transform, is_sideways, threshold,
1139 measuring_mode, params, rendering_mode, gridfit_mode);
1140 return E_NOTIMPL;
1143 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace3 *iface, UINT32 ch)
1145 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1146 FIXME("(%p)->(0x%x): stub\n", This, ch);
1147 return FALSE;
1150 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace3 *iface, UINT16 glyph)
1152 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1153 FIXME("(%p)->(%u): stub\n", This, glyph);
1154 return FALSE;
1157 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace3 *iface, WCHAR const *text,
1158 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1160 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1161 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1162 return E_NOTIMPL;
1165 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace3 *iface, UINT16 const *glyphs,
1166 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1168 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1169 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1170 return E_NOTIMPL;
1173 static const IDWriteFontFace3Vtbl dwritefontfacevtbl = {
1174 dwritefontface_QueryInterface,
1175 dwritefontface_AddRef,
1176 dwritefontface_Release,
1177 dwritefontface_GetType,
1178 dwritefontface_GetFiles,
1179 dwritefontface_GetIndex,
1180 dwritefontface_GetSimulations,
1181 dwritefontface_IsSymbolFont,
1182 dwritefontface_GetMetrics,
1183 dwritefontface_GetGlyphCount,
1184 dwritefontface_GetDesignGlyphMetrics,
1185 dwritefontface_GetGlyphIndices,
1186 dwritefontface_TryGetFontTable,
1187 dwritefontface_ReleaseFontTable,
1188 dwritefontface_GetGlyphRunOutline,
1189 dwritefontface_GetRecommendedRenderingMode,
1190 dwritefontface_GetGdiCompatibleMetrics,
1191 dwritefontface_GetGdiCompatibleGlyphMetrics,
1192 dwritefontface1_GetMetrics,
1193 dwritefontface1_GetGdiCompatibleMetrics,
1194 dwritefontface1_GetCaretMetrics,
1195 dwritefontface1_GetUnicodeRanges,
1196 dwritefontface1_IsMonospacedFont,
1197 dwritefontface1_GetDesignGlyphAdvances,
1198 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1199 dwritefontface1_GetKerningPairAdjustments,
1200 dwritefontface1_HasKerningPairs,
1201 dwritefontface1_GetRecommendedRenderingMode,
1202 dwritefontface1_GetVerticalGlyphVariants,
1203 dwritefontface1_HasVerticalGlyphVariants,
1204 dwritefontface2_IsColorFont,
1205 dwritefontface2_GetColorPaletteCount,
1206 dwritefontface2_GetPaletteEntryCount,
1207 dwritefontface2_GetPaletteEntries,
1208 dwritefontface2_GetRecommendedRenderingMode,
1209 dwritefontface3_GetFontFaceReference,
1210 dwritefontface3_GetPanose,
1211 dwritefontface3_GetWeight,
1212 dwritefontface3_GetStretch,
1213 dwritefontface3_GetStyle,
1214 dwritefontface3_GetFamilyNames,
1215 dwritefontface3_GetFaceNames,
1216 dwritefontface3_GetInformationalStrings,
1217 dwritefontface3_HasCharacter,
1218 dwritefontface3_GetRecommendedRenderingMode,
1219 dwritefontface3_IsCharacterLocal,
1220 dwritefontface3_IsGlyphLocal,
1221 dwritefontface3_AreCharactersLocal,
1222 dwritefontface3_AreGlyphsLocal
1225 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace3 **fontface)
1227 struct dwrite_font_data *data = font->data;
1228 IDWriteFontFace *face;
1229 HRESULT hr;
1231 *fontface = NULL;
1233 hr = IDWriteFactory3_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1234 data->face_index, font->data->simulations, &face);
1235 if (FAILED(hr))
1236 return hr;
1238 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void**)fontface);
1239 IDWriteFontFace_Release(face);
1241 return hr;
1244 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1246 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1248 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1250 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1251 IsEqualIID(riid, &IID_IDWriteFont2) ||
1252 IsEqualIID(riid, &IID_IDWriteFont1) ||
1253 IsEqualIID(riid, &IID_IDWriteFont) ||
1254 IsEqualIID(riid, &IID_IUnknown))
1256 *obj = iface;
1257 IDWriteFont3_AddRef(iface);
1258 return S_OK;
1261 *obj = NULL;
1262 return E_NOINTERFACE;
1265 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1267 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1268 ULONG ref = InterlockedIncrement(&This->ref);
1269 TRACE("(%p)->(%d)\n", This, ref);
1270 return ref;
1273 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1275 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1276 ULONG ref = InterlockedDecrement(&This->ref);
1278 TRACE("(%p)->(%d)\n", This, ref);
1280 if (!ref) {
1281 IDWriteFontFamily1_Release(This->family);
1282 release_font_data(This->data);
1283 heap_free(This);
1286 return ref;
1289 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1291 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1292 TRACE("(%p)->(%p)\n", This, family);
1294 *family = (IDWriteFontFamily*)This->family;
1295 IDWriteFontFamily_AddRef(*family);
1296 return S_OK;
1299 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1301 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1302 TRACE("(%p)\n", This);
1303 return This->data->weight;
1306 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1308 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1309 TRACE("(%p)\n", This);
1310 return This->data->stretch;
1313 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1315 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1316 TRACE("(%p)\n", This);
1317 return This->style;
1320 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1322 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1323 IDWriteFontFace3 *fontface;
1324 HRESULT hr;
1326 TRACE("(%p)\n", This);
1328 hr = get_fontface_from_font(This, &fontface);
1329 if (FAILED(hr))
1330 return FALSE;
1332 return IDWriteFontFace3_IsSymbolFont(fontface);
1335 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1337 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1338 TRACE("(%p)->(%p)\n", This, names);
1339 return clone_localizedstring(This->data->names, names);
1342 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1343 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1345 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1346 struct dwrite_font_data *data = This->data;
1347 HRESULT hr;
1349 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1351 *exists = FALSE;
1352 *strings = NULL;
1354 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1355 return S_OK;
1357 if (!data->info_strings[stringid]) {
1358 IDWriteFontFace3 *fontface;
1359 const void *table_data;
1360 BOOL table_exists;
1361 void *context;
1362 UINT32 size;
1364 hr = get_fontface_from_font(This, &fontface);
1365 if (FAILED(hr))
1366 return hr;
1368 table_exists = FALSE;
1369 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1370 if (FAILED(hr) || !table_exists)
1371 WARN("no NAME table found.\n");
1373 if (table_exists) {
1374 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1375 if (FAILED(hr) || !data->info_strings[stringid])
1376 return hr;
1377 IDWriteFontFace3_ReleaseFontTable(fontface, context);
1381 hr = clone_localizedstring(data->info_strings[stringid], strings);
1382 if (FAILED(hr))
1383 return hr;
1385 *exists = TRUE;
1386 return S_OK;
1389 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1391 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1392 TRACE("(%p)\n", This);
1393 return This->data->simulations;
1396 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1398 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1400 TRACE("(%p)->(%p)\n", This, metrics);
1401 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1404 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1406 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1407 IDWriteFontFace3 *fontface;
1408 UINT16 index;
1409 HRESULT hr;
1411 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1413 *exists = FALSE;
1415 hr = get_fontface_from_font(This, &fontface);
1416 if (FAILED(hr))
1417 return hr;
1419 index = 0;
1420 hr = IDWriteFontFace3_GetGlyphIndices(fontface, &value, 1, &index);
1421 if (FAILED(hr))
1422 return hr;
1424 *exists = index != 0;
1425 return S_OK;
1428 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **face)
1430 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1431 HRESULT hr;
1433 TRACE("(%p)->(%p)\n", This, face);
1435 hr = get_fontface_from_font(This, (IDWriteFontFace3**)face);
1436 if (hr == S_OK)
1437 IDWriteFontFace_AddRef(*face);
1439 return hr;
1442 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1444 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1445 TRACE("(%p)->(%p)\n", This, metrics);
1446 *metrics = This->data->metrics;
1449 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1451 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1452 TRACE("(%p)->(%p)\n", This, panose);
1453 *panose = This->data->panose;
1456 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1458 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1459 IDWriteFontFace3 *fontface;
1460 HRESULT hr;
1462 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1464 hr = get_fontface_from_font(This, &fontface);
1465 if (FAILED(hr))
1466 return hr;
1468 return IDWriteFontFace3_GetUnicodeRanges(fontface, max_count, ranges, count);
1471 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1473 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1474 IDWriteFontFace3 *fontface;
1475 HRESULT hr;
1477 TRACE("(%p)\n", This);
1479 hr = get_fontface_from_font(This, &fontface);
1480 if (FAILED(hr))
1481 return FALSE;
1483 return IDWriteFontFace3_IsMonospacedFont(fontface);
1486 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1488 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1489 IDWriteFontFace3 *fontface;
1490 HRESULT hr;
1492 TRACE("(%p)\n", This);
1494 hr = get_fontface_from_font(This, &fontface);
1495 if (FAILED(hr))
1496 return FALSE;
1498 return IDWriteFontFace3_IsColorFont(fontface);
1501 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1503 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1504 FIXME("(%p)->(%p): stub\n", This, fontface);
1505 return E_NOTIMPL;
1508 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1510 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1511 FIXME("(%p)->(%p): stub\n", This, font);
1512 return FALSE;
1515 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1517 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1519 TRACE("(%p)->(%p)\n", This, reference);
1521 return IDWriteFactory3_CreateFontFaceReference_(This->data->factory, This->data->file, This->data->face_index,
1522 This->data->simulations, reference);
1525 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1527 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1528 BOOL ret;
1530 TRACE("(%p)->(0x%x)\n", This, ch);
1532 IDWriteFont_HasCharacter((IDWriteFont*)iface, ch, &ret);
1533 return ret;
1536 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1538 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1539 FIXME("(%p): stub\n", This);
1540 return DWRITE_LOCALITY_LOCAL;
1543 static const IDWriteFont3Vtbl dwritefontvtbl = {
1544 dwritefont_QueryInterface,
1545 dwritefont_AddRef,
1546 dwritefont_Release,
1547 dwritefont_GetFontFamily,
1548 dwritefont_GetWeight,
1549 dwritefont_GetStretch,
1550 dwritefont_GetStyle,
1551 dwritefont_IsSymbolFont,
1552 dwritefont_GetFaceNames,
1553 dwritefont_GetInformationalStrings,
1554 dwritefont_GetSimulations,
1555 dwritefont_GetMetrics,
1556 dwritefont_HasCharacter,
1557 dwritefont_CreateFontFace,
1558 dwritefont1_GetMetrics,
1559 dwritefont1_GetPanose,
1560 dwritefont1_GetUnicodeRanges,
1561 dwritefont1_IsMonospacedFont,
1562 dwritefont2_IsColorFont,
1563 dwritefont3_CreateFontFace,
1564 dwritefont3_Equals,
1565 dwritefont3_GetFontFaceReference,
1566 dwritefont3_HasCharacter,
1567 dwritefont3_GetLocality
1570 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily1 *family, IDWriteFont3 **font)
1572 struct dwrite_font *This;
1573 *font = NULL;
1575 This = heap_alloc(sizeof(struct dwrite_font));
1576 if (!This) return E_OUTOFMEMORY;
1578 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1579 This->ref = 1;
1580 This->family = family;
1581 IDWriteFontFamily1_AddRef(family);
1582 This->style = data->style;
1583 This->data = data;
1584 InterlockedIncrement(&This->data->ref);
1586 *font = &This->IDWriteFont3_iface;
1588 return S_OK;
1591 /* IDWriteFontList1 */
1592 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1594 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1596 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1598 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1599 IsEqualIID(riid, &IID_IDWriteFontList) ||
1600 IsEqualIID(riid, &IID_IUnknown))
1602 *obj = iface;
1603 IDWriteFontList1_AddRef(iface);
1604 return S_OK;
1607 *obj = NULL;
1608 return E_NOINTERFACE;
1611 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1613 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1614 ULONG ref = InterlockedIncrement(&This->ref);
1615 TRACE("(%p)->(%d)\n", This, ref);
1616 return ref;
1619 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1621 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1622 ULONG ref = InterlockedDecrement(&This->ref);
1624 TRACE("(%p)->(%d)\n", This, ref);
1626 if (!ref) {
1627 UINT32 i;
1629 for (i = 0; i < This->font_count; i++)
1630 release_font_data(This->fonts[i]);
1631 IDWriteFontFamily1_Release(This->family);
1632 heap_free(This);
1635 return ref;
1638 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1640 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1641 return IDWriteFontFamily1_GetFontCollection(This->family, collection);
1644 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1646 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1647 TRACE("(%p)\n", This);
1648 return This->font_count;
1651 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1653 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1655 TRACE("(%p)->(%u %p)\n", This, index, font);
1657 *font = NULL;
1659 if (This->font_count == 0)
1660 return S_FALSE;
1662 if (index >= This->font_count)
1663 return E_INVALIDARG;
1665 return create_font(This->fonts[index], This->family, (IDWriteFont3**)font);
1668 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1670 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1672 FIXME("(%p)->(%u): stub\n", This, index);
1674 return DWRITE_LOCALITY_LOCAL;
1677 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1679 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1681 FIXME("(%p)->(%u %p): stub\n", This, index, font);
1683 return E_NOTIMPL;
1686 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1687 IDWriteFontFaceReference **reference)
1689 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1691 FIXME("(%p)->(%u %p): stub\n", This, index, reference);
1693 return E_NOTIMPL;
1696 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1697 dwritefontlist_QueryInterface,
1698 dwritefontlist_AddRef,
1699 dwritefontlist_Release,
1700 dwritefontlist_GetFontCollection,
1701 dwritefontlist_GetFontCount,
1702 dwritefontlist_GetFont,
1703 dwritefontlist1_GetFontLocality,
1704 dwritefontlist1_GetFont,
1705 dwritefontlist1_GetFontFaceReference
1708 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1710 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1712 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1714 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1715 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1716 IsEqualIID(riid, &IID_IDWriteFontList) ||
1717 IsEqualIID(riid, &IID_IUnknown))
1719 *obj = iface;
1720 IDWriteFontFamily1_AddRef(iface);
1721 return S_OK;
1724 *obj = NULL;
1725 return E_NOINTERFACE;
1728 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1730 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1731 ULONG ref = InterlockedIncrement(&This->ref);
1732 TRACE("(%p)->(%d)\n", This, ref);
1733 return ref;
1736 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1738 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1739 ULONG ref = InterlockedDecrement(&This->ref);
1741 TRACE("(%p)->(%d)\n", This, ref);
1743 if (!ref)
1745 IDWriteFontCollection1_Release(This->collection);
1746 release_fontfamily_data(This->data);
1747 heap_free(This);
1750 return ref;
1753 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1755 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1757 TRACE("(%p)->(%p)\n", This, collection);
1759 *collection = (IDWriteFontCollection*)This->collection;
1760 IDWriteFontCollection_AddRef(*collection);
1761 return S_OK;
1764 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1766 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1767 TRACE("(%p)\n", This);
1768 return This->data->font_count;
1771 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1773 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1775 TRACE("(%p)->(%u %p)\n", This, index, font);
1777 *font = NULL;
1779 if (This->data->font_count == 0)
1780 return S_FALSE;
1782 if (index >= This->data->font_count)
1783 return E_INVALIDARG;
1785 return create_font(This->data->fonts[index], iface, (IDWriteFont3**)font);
1788 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1790 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1791 return clone_localizedstring(This->data->familyname, names);
1794 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1795 const struct dwrite_font_propvec *req)
1797 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1798 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1799 FLOAT cur_req_prod, next_req_prod;
1801 if (next_to_req < cur_to_req)
1802 return TRUE;
1804 if (next_to_req > cur_to_req)
1805 return FALSE;
1807 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1808 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1810 if (next_req_prod > cur_req_prod)
1811 return TRUE;
1813 if (next_req_prod < cur_req_prod)
1814 return FALSE;
1816 if (next->stretch > cur->stretch)
1817 return TRUE;
1818 if (next->stretch < cur->stretch)
1819 return FALSE;
1821 if (next->style > cur->style)
1822 return TRUE;
1823 if (next->style < cur->style)
1824 return FALSE;
1826 if (next->weight > cur->weight)
1827 return TRUE;
1828 if (next->weight < cur->weight)
1829 return FALSE;
1831 /* full match, no reason to prefer new variant */
1832 return FALSE;
1835 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1836 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1838 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1839 struct dwrite_font_propvec req;
1840 struct dwrite_font_data *match;
1841 UINT32 i;
1843 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1845 if (This->data->font_count == 0) {
1846 *font = NULL;
1847 return DWRITE_E_NOFONT;
1850 init_font_prop_vec(weight, stretch, style, &req);
1851 match = This->data->fonts[0];
1853 for (i = 1; i < This->data->font_count; i++) {
1854 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1855 match = This->data->fonts[i];
1858 return create_font(match, iface, (IDWriteFont3**)font);
1861 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1863 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1865 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1868 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1870 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1873 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1875 UINT32 b = fonts->font_count - 1, j, t;
1877 while (1) {
1878 t = b;
1880 for (j = 0; j < b; j++) {
1881 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1882 struct dwrite_font_data *s = fonts->fonts[j];
1883 fonts->fonts[j] = fonts->fonts[j+1];
1884 fonts->fonts[j+1] = s;
1885 t = j;
1889 if (t == b)
1890 break;
1891 b = t;
1895 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1896 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1898 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1899 matching_filter_func func = NULL;
1900 struct dwrite_font_propvec req;
1901 struct dwrite_fontlist *fonts;
1902 UINT32 i;
1904 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1906 *ret = NULL;
1908 fonts = heap_alloc(sizeof(*fonts));
1909 if (!fonts)
1910 return E_OUTOFMEMORY;
1912 /* Allocate as many as family has, not all of them will be necessary used. */
1913 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1914 if (!fonts->fonts) {
1915 heap_free(fonts);
1916 return E_OUTOFMEMORY;
1919 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
1920 fonts->ref = 1;
1921 fonts->family = iface;
1922 IDWriteFontFamily1_AddRef(fonts->family);
1923 fonts->font_count = 0;
1925 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1926 if (style == DWRITE_FONT_STYLE_NORMAL) {
1927 if (This->data->has_normal_face || This->data->has_italic_face)
1928 func = is_font_acceptable_for_normal;
1930 else /* requested oblique or italic */ {
1931 if (This->data->has_oblique_face || This->data->has_italic_face)
1932 func = is_font_acceptable_for_oblique_italic;
1935 for (i = 0; i < This->data->font_count; i++) {
1936 if (!func || func(This->data->fonts[i])) {
1937 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1938 InterlockedIncrement(&This->data->fonts[i]->ref);
1939 fonts->font_count++;
1943 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1944 init_font_prop_vec(weight, stretch, style, &req);
1945 matchingfonts_sort(fonts, &req);
1947 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
1948 return S_OK;
1951 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
1953 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1955 FIXME("(%p)->(%u): stub\n", This, index);
1957 return DWRITE_LOCALITY_LOCAL;
1960 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
1962 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1964 TRACE("(%p)->(%u %p)\n", This, index, font);
1966 *font = NULL;
1968 if (This->data->font_count == 0)
1969 return S_FALSE;
1971 if (index >= This->data->font_count)
1972 return E_FAIL;
1974 return create_font(This->data->fonts[index], iface, font);
1977 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
1978 IDWriteFontFaceReference **ref)
1980 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1982 FIXME("(%p)->(%u %p): stub\n", This, index, ref);
1984 return E_NOTIMPL;
1987 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
1988 dwritefontfamily_QueryInterface,
1989 dwritefontfamily_AddRef,
1990 dwritefontfamily_Release,
1991 dwritefontfamily_GetFontCollection,
1992 dwritefontfamily_GetFontCount,
1993 dwritefontfamily_GetFont,
1994 dwritefontfamily_GetFamilyNames,
1995 dwritefontfamily_GetFirstMatchingFont,
1996 dwritefontfamily_GetMatchingFonts,
1997 dwritefontfamily1_GetFontLocality,
1998 dwritefontfamily1_GetFont,
1999 dwritefontfamily1_GetFontFaceReference
2002 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection1 *collection, IDWriteFontFamily1 **family)
2004 struct dwrite_fontfamily *This;
2006 *family = NULL;
2008 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2009 if (!This) return E_OUTOFMEMORY;
2011 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2012 This->ref = 1;
2013 This->collection = collection;
2014 IDWriteFontCollection1_AddRef(collection);
2015 This->data = data;
2016 InterlockedIncrement(&This->data->ref);
2018 *family = &This->IDWriteFontFamily1_iface;
2020 return S_OK;
2023 BOOL is_system_collection(IDWriteFontCollection *collection)
2025 void *obj;
2026 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2029 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2031 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2032 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2034 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2035 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2036 IsEqualIID(riid, &IID_IUnknown))
2038 *obj = iface;
2039 IDWriteFontCollection1_AddRef(iface);
2040 return S_OK;
2043 *obj = NULL;
2045 if (IsEqualIID(riid, &IID_issystemcollection))
2046 return S_OK;
2048 return E_NOINTERFACE;
2051 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2053 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2054 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2056 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2057 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2058 IsEqualIID(riid, &IID_IUnknown))
2060 *obj = iface;
2061 IDWriteFontCollection1_AddRef(iface);
2062 return S_OK;
2065 *obj = NULL;
2067 return E_NOINTERFACE;
2070 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2072 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2073 ULONG ref = InterlockedIncrement(&This->ref);
2074 TRACE("(%p)->(%d)\n", This, ref);
2075 return ref;
2078 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2080 unsigned int i;
2081 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2082 ULONG ref = InterlockedDecrement(&This->ref);
2083 TRACE("(%p)->(%d)\n", This, ref);
2085 if (!ref) {
2086 for (i = 0; i < This->family_count; i++)
2087 release_fontfamily_data(This->family_data[i]);
2088 heap_free(This->family_data);
2089 heap_free(This);
2092 return ref;
2095 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2097 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2098 TRACE("(%p)\n", This);
2099 return This->family_count;
2102 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2104 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2106 TRACE("(%p)->(%u %p)\n", This, index, family);
2108 if (index >= This->family_count) {
2109 *family = NULL;
2110 return E_FAIL;
2113 return create_fontfamily(This->family_data[index], iface, (IDWriteFontFamily1**)family);
2116 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2118 UINT32 i;
2120 for (i = 0; i < collection->family_count; i++) {
2121 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2122 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2123 HRESULT hr;
2125 for (j = 0; j < count; j++) {
2126 WCHAR buffer[255];
2127 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2128 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2129 return i;
2133 return ~0u;
2136 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2138 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2139 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2140 *index = collection_find_family(This, name);
2141 *exists = *index != ~0u;
2142 return S_OK;
2145 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2147 UINT32 left_key_size, right_key_size;
2148 const void *left_key, *right_key;
2149 HRESULT hr;
2151 if (left == right)
2152 return TRUE;
2154 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2155 if (FAILED(hr))
2156 return FALSE;
2158 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2159 if (FAILED(hr))
2160 return FALSE;
2162 if (left_key_size != right_key_size)
2163 return FALSE;
2165 return !memcmp(left_key, right_key, left_key_size);
2168 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2170 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2171 struct dwrite_fontfamily_data *found_family = NULL;
2172 struct dwrite_font_data *found_font = NULL;
2173 IDWriteFontFamily1 *family;
2174 UINT32 i, j, face_index;
2175 IDWriteFontFile *file;
2176 HRESULT hr;
2178 TRACE("(%p)->(%p %p)\n", This, face, font);
2180 *font = NULL;
2182 if (!face)
2183 return E_INVALIDARG;
2185 i = 1;
2186 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2187 if (FAILED(hr))
2188 return hr;
2189 face_index = IDWriteFontFace_GetIndex(face);
2191 for (i = 0; i < This->family_count; i++) {
2192 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2193 for (j = 0; j < family_data->font_count; j++) {
2194 struct dwrite_font_data *font_data = family_data->fonts[j];
2196 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2197 found_font = font_data;
2198 found_family = family_data;
2199 break;
2204 if (!found_font)
2205 return DWRITE_E_NOFONT;
2207 hr = create_fontfamily(found_family, iface, &family);
2208 if (FAILED(hr))
2209 return hr;
2211 hr = create_font(found_font, family, (IDWriteFont3**)font);
2212 IDWriteFontFamily1_Release(family);
2213 return hr;
2216 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2218 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2220 FIXME("(%p)->(%p): stub\n", This, fontset);
2222 return E_NOTIMPL;
2225 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2227 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2229 TRACE("(%p)->(%u %p)\n", This, index, family);
2231 if (index >= This->family_count) {
2232 *family = NULL;
2233 return E_FAIL;
2236 return create_fontfamily(This->family_data[index], iface, family);
2239 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2240 dwritefontcollection_QueryInterface,
2241 dwritefontcollection_AddRef,
2242 dwritefontcollection_Release,
2243 dwritefontcollection_GetFontFamilyCount,
2244 dwritefontcollection_GetFontFamily,
2245 dwritefontcollection_FindFamilyName,
2246 dwritefontcollection_GetFontFromFontFace,
2247 dwritefontcollection1_GetFontSet,
2248 dwritefontcollection1_GetFontFamily
2251 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2252 dwritesystemfontcollection_QueryInterface,
2253 dwritefontcollection_AddRef,
2254 dwritefontcollection_Release,
2255 dwritefontcollection_GetFontFamilyCount,
2256 dwritefontcollection_GetFontFamily,
2257 dwritefontcollection_FindFamilyName,
2258 dwritefontcollection_GetFontFromFontFace,
2259 dwritefontcollection1_GetFontSet,
2260 dwritefontcollection1_GetFontFamily
2263 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2265 if (family_data->font_count + 1 >= family_data->font_alloc) {
2266 struct dwrite_font_data **new_list;
2267 UINT32 new_alloc;
2269 new_alloc = family_data->font_alloc * 2;
2270 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2271 if (!new_list)
2272 return E_OUTOFMEMORY;
2273 family_data->fonts = new_list;
2274 family_data->font_alloc = new_alloc;
2277 family_data->fonts[family_data->font_count] = font_data;
2278 family_data->font_count++;
2279 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2280 family_data->has_normal_face = 1;
2281 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2282 family_data->has_oblique_face = 1;
2283 else
2284 family_data->has_italic_face = 1;
2285 return S_OK;
2288 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2290 if (collection->family_alloc < collection->family_count + 1) {
2291 struct dwrite_fontfamily_data **new_list;
2292 UINT32 new_alloc;
2294 new_alloc = collection->family_alloc * 2;
2295 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2296 if (!new_list)
2297 return E_OUTOFMEMORY;
2299 collection->family_alloc = new_alloc;
2300 collection->family_data = new_list;
2303 collection->family_data[collection->family_count] = family;
2304 collection->family_count++;
2306 return S_OK;
2309 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2311 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2312 collection->ref = 1;
2313 collection->family_count = 0;
2314 collection->family_alloc = is_system ? 30 : 5;
2315 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2316 if (!collection->family_data)
2317 return E_OUTOFMEMORY;
2319 return S_OK;
2322 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2324 IDWriteFontFileLoader *loader;
2325 const void *key;
2326 UINT32 key_size;
2327 HRESULT hr;
2329 *stream = NULL;
2331 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2332 if (FAILED(hr))
2333 return hr;
2335 hr = IDWriteFontFile_GetLoader(file, &loader);
2336 if (FAILED(hr))
2337 return hr;
2339 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2340 IDWriteFontFileLoader_Release(loader);
2341 if (FAILED(hr))
2342 return hr;
2344 return hr;
2347 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2349 BOOL exists = FALSE;
2350 UINT32 index;
2351 HRESULT hr;
2353 buffer[0] = 0;
2354 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2355 if (FAILED(hr) || !exists)
2356 return;
2358 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2361 static int trim_spaces(WCHAR *in, WCHAR *ret)
2363 int len;
2365 while (isspaceW(*in))
2366 in++;
2368 ret[0] = 0;
2369 if (!(len = strlenW(in)))
2370 return 0;
2372 while (isspaceW(in[len-1]))
2373 len--;
2375 memcpy(ret, in, len*sizeof(WCHAR));
2376 ret[len] = 0;
2378 return len;
2381 struct name_token {
2382 struct list entry;
2383 const WCHAR *ptr;
2384 INT len; /* token length */
2385 INT fulllen; /* full length including following separators */
2388 static inline BOOL is_name_separator_char(WCHAR ch)
2390 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2393 struct name_pattern {
2394 const WCHAR *part1; /* NULL indicates end of list */
2395 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2398 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2400 const struct name_pattern *pattern;
2401 struct name_token *token;
2402 int i = 0;
2404 while ((pattern = &patterns[i++])->part1) {
2405 int len_part1 = strlenW(pattern->part1);
2406 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2408 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2409 if (len_part2 == 0) {
2410 /* simple case with single part pattern */
2411 if (token->len != len_part1)
2412 continue;
2414 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2415 if (match) *match = *token;
2416 list_remove(&token->entry);
2417 heap_free(token);
2418 return TRUE;
2421 else {
2422 struct name_token *next_token;
2423 struct list *next_entry;
2425 /* pattern parts are stored in reading order, tokens list is reversed */
2426 if (token->len < len_part2)
2427 continue;
2429 /* it's possible to have combined string as a token, like ExtraCondensed */
2430 if (token->len == len_part1 + len_part2) {
2431 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2432 continue;
2434 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2435 continue;
2437 /* combined string match */
2438 if (match) *match = *token;
2439 list_remove(&token->entry);
2440 heap_free(token);
2441 return TRUE;
2444 /* now it's only possible to have two tokens matched to respective pattern parts */
2445 if (token->len != len_part2)
2446 continue;
2448 next_entry = list_next(tokens, &token->entry);
2449 if (next_entry) {
2450 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2451 if (next_token->len != len_part1)
2452 continue;
2454 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2455 continue;
2457 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2458 continue;
2460 /* both parts matched, remove tokens */
2461 if (match) {
2462 match->ptr = next_token->ptr;
2463 match->len = (token->ptr - next_token->ptr) + token->len;
2465 list_remove(&token->entry);
2466 list_remove(&next_token->entry);
2467 heap_free(next_token);
2468 heap_free(token);
2469 return TRUE;
2475 if (match) {
2476 match->ptr = NULL;
2477 match->len = 0;
2479 return FALSE;
2482 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2484 static const WCHAR itaW[] = {'i','t','a',0};
2485 static const WCHAR italW[] = {'i','t','a','l',0};
2486 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2487 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2489 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2490 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2491 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2492 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2494 static const struct name_pattern italic_patterns[] = {
2495 { itaW },
2496 { italW },
2497 { italicW },
2498 { cursiveW },
2499 { kursivW },
2500 { NULL }
2503 static const struct name_pattern oblique_patterns[] = {
2504 { inclinedW },
2505 { obliqueW },
2506 { backslantedW },
2507 { backslantW },
2508 { slantedW },
2509 { NULL }
2512 /* italic patterns first */
2513 if (match_pattern_list(tokens, italic_patterns, match))
2514 return DWRITE_FONT_STYLE_ITALIC;
2516 /* oblique patterns */
2517 if (match_pattern_list(tokens, oblique_patterns, match))
2518 return DWRITE_FONT_STYLE_OBLIQUE;
2520 return style;
2523 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2524 struct name_token *match)
2526 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2527 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2528 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2529 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2530 static const WCHAR wideW[] = {'w','i','d','e',0};
2531 static const WCHAR condW[] = {'c','o','n','d',0};
2533 static const struct name_pattern ultracondensed_patterns[] = {
2534 { extraW, compressedW },
2535 { extW, compressedW },
2536 { ultraW, compressedW },
2537 { ultraW, condensedW },
2538 { ultraW, condW },
2539 { NULL }
2542 static const struct name_pattern extracondensed_patterns[] = {
2543 { compressedW },
2544 { extraW, condensedW },
2545 { extW, condensedW },
2546 { extraW, condW },
2547 { extW, condW },
2548 { NULL }
2551 static const struct name_pattern semicondensed_patterns[] = {
2552 { narrowW },
2553 { compactW },
2554 { semiW, condensedW },
2555 { semiW, condW },
2556 { NULL }
2559 static const struct name_pattern semiexpanded_patterns[] = {
2560 { wideW },
2561 { semiW, expandedW },
2562 { semiW, extendedW },
2563 { NULL }
2566 static const struct name_pattern extraexpanded_patterns[] = {
2567 { extraW, expandedW },
2568 { extW, expandedW },
2569 { extraW, extendedW },
2570 { extW, extendedW },
2571 { NULL }
2574 static const struct name_pattern ultraexpanded_patterns[] = {
2575 { ultraW, expandedW },
2576 { ultraW, extendedW },
2577 { NULL }
2580 static const struct name_pattern condensed_patterns[] = {
2581 { condensedW },
2582 { condW },
2583 { NULL }
2586 static const struct name_pattern expanded_patterns[] = {
2587 { expandedW },
2588 { extendedW },
2589 { NULL }
2592 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2593 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2595 if (match_pattern_list(tokens, extracondensed_patterns, match))
2596 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2598 if (match_pattern_list(tokens, semicondensed_patterns, match))
2599 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2601 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2602 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2604 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2605 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2607 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2608 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2610 if (match_pattern_list(tokens, condensed_patterns, match))
2611 return DWRITE_FONT_STRETCH_CONDENSED;
2613 if (match_pattern_list(tokens, expanded_patterns, match))
2614 return DWRITE_FONT_STRETCH_EXPANDED;
2616 return stretch;
2619 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2620 struct name_token *match)
2622 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2623 static const WCHAR nordW[] = {'n','o','r','d',0};
2625 static const struct name_pattern thin_patterns[] = {
2626 { extraW, thinW },
2627 { extW, thinW },
2628 { ultraW, thinW },
2629 { NULL }
2632 static const struct name_pattern extralight_patterns[] = {
2633 { extraW, lightW },
2634 { extW, lightW },
2635 { ultraW, lightW },
2636 { NULL }
2639 static const struct name_pattern semilight_patterns[] = {
2640 { semiW, lightW },
2641 { NULL }
2644 static const struct name_pattern demibold_patterns[] = {
2645 { semiW, boldW },
2646 { demiW, boldW },
2647 { NULL }
2650 static const struct name_pattern extrabold_patterns[] = {
2651 { extraW, boldW },
2652 { extW, boldW },
2653 { ultraW, boldW },
2654 { NULL }
2657 static const struct name_pattern extrablack_patterns[] = {
2658 { extraW, blackW },
2659 { extW, blackW },
2660 { ultraW, blackW },
2661 { NULL }
2664 static const struct name_pattern bold_patterns[] = {
2665 { boldW },
2666 { NULL }
2669 static const struct name_pattern thin2_patterns[] = {
2670 { thinW },
2671 { NULL }
2674 static const struct name_pattern light_patterns[] = {
2675 { lightW },
2676 { NULL }
2679 static const struct name_pattern medium_patterns[] = {
2680 { mediumW },
2681 { NULL }
2684 static const struct name_pattern black_patterns[] = {
2685 { blackW },
2686 { heavyW },
2687 { nordW },
2688 { NULL }
2691 static const struct name_pattern demibold2_patterns[] = {
2692 { demiW },
2693 { NULL }
2696 static const struct name_pattern extrabold2_patterns[] = {
2697 { ultraW },
2698 { NULL }
2701 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2702 matching pattern. */
2704 if (match_pattern_list(tokens, thin_patterns, match))
2705 return DWRITE_FONT_WEIGHT_THIN;
2707 if (match_pattern_list(tokens, extralight_patterns, match))
2708 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2710 if (match_pattern_list(tokens, semilight_patterns, match))
2711 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2713 if (match_pattern_list(tokens, demibold_patterns, match))
2714 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2716 if (match_pattern_list(tokens, extrabold_patterns, match))
2717 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2719 if (match_pattern_list(tokens, extrablack_patterns, match))
2720 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2722 if (match_pattern_list(tokens, bold_patterns, match))
2723 return DWRITE_FONT_WEIGHT_BOLD;
2725 if (match_pattern_list(tokens, thin2_patterns, match))
2726 return DWRITE_FONT_WEIGHT_THIN;
2728 if (match_pattern_list(tokens, light_patterns, match))
2729 return DWRITE_FONT_WEIGHT_LIGHT;
2731 if (match_pattern_list(tokens, medium_patterns, match))
2732 return DWRITE_FONT_WEIGHT_MEDIUM;
2734 if (match_pattern_list(tokens, black_patterns, match))
2735 return DWRITE_FONT_WEIGHT_BLACK;
2737 if (match_pattern_list(tokens, black_patterns, match))
2738 return DWRITE_FONT_WEIGHT_BLACK;
2740 if (match_pattern_list(tokens, demibold2_patterns, match))
2741 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2743 if (match_pattern_list(tokens, extrabold2_patterns, match))
2744 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2746 /* FIXME: use abbreviated names to extract weight */
2748 return weight;
2751 struct knownweight_entry {
2752 const WCHAR *nameW;
2753 DWRITE_FONT_WEIGHT weight;
2756 static int compare_knownweights(const void *a, const void* b)
2758 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2759 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2760 int ret = 0;
2762 if (target > entry->weight)
2763 ret = 1;
2764 else if (target < entry->weight)
2765 ret = -1;
2767 return ret;
2770 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2772 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2773 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2774 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2775 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2776 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2777 const struct knownweight_entry *ptr;
2779 static const struct knownweight_entry knownweights[] = {
2780 { thinW, DWRITE_FONT_WEIGHT_THIN },
2781 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2782 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2783 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2784 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2785 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2786 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2787 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2788 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2789 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2792 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2793 compare_knownweights);
2794 if (!ptr) {
2795 nameW[0] = 0;
2796 return FALSE;
2799 strcpyW(nameW, ptr->nameW);
2800 return TRUE;
2803 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2805 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2806 strW[name->len] = 0;
2809 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2810 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2812 static const WCHAR bookW[] = {'B','o','o','k',0};
2813 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2814 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2815 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2816 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2818 static const WCHAR *regular_patterns[] = {
2819 bookW,
2820 normalW,
2821 regularW,
2822 romanW,
2823 uprightW,
2824 NULL
2827 const WCHAR *regular_ptr = NULL, *ptr;
2828 int i = 0;
2830 if (len == -1)
2831 len = strlenW(facenameW);
2833 /* remove rightmost regular variant from face name */
2834 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2835 int pattern_len = strlenW(ptr);
2836 WCHAR *src;
2838 if (pattern_len > len)
2839 continue;
2841 src = facenameW + len - pattern_len;
2842 while (src >= facenameW) {
2843 if (!strncmpiW(src, ptr, pattern_len)) {
2844 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2845 len = strlenW(facenameW);
2846 regular_ptr = ptr;
2847 break;
2849 else
2850 src--;
2854 return regular_ptr;
2857 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2859 const WCHAR *ptr;
2861 list_init(tokens);
2862 ptr = nameW;
2864 while (*ptr) {
2865 struct name_token *token = heap_alloc(sizeof(*token));
2866 token->ptr = ptr;
2867 token->len = 0;
2868 token->fulllen = 0;
2870 while (*ptr && !is_name_separator_char(*ptr)) {
2871 token->len++;
2872 token->fulllen++;
2873 ptr++;
2876 /* skip separators */
2877 while (is_name_separator_char(*ptr)) {
2878 token->fulllen++;
2879 ptr++;
2882 list_add_head(tokens, &token->entry);
2886 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2888 struct name_token *token, *token2;
2889 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2890 int len;
2892 list_remove(&token->entry);
2894 /* don't include last separator */
2895 len = list_empty(tokens) ? token->len : token->fulllen;
2896 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2897 nameW += len;
2899 heap_free(token);
2901 *nameW = 0;
2904 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2906 struct name_token stretch_name, weight_name, style_name;
2907 WCHAR familynameW[255], facenameW[255], finalW[255];
2908 WCHAR weightW[32], stretchW[32], styleW[32];
2909 const WCHAR *regular_ptr = NULL;
2910 DWRITE_FONT_STRETCH stretch;
2911 DWRITE_FONT_WEIGHT weight;
2912 struct list tokens;
2913 int len;
2915 /* remove leading and trailing spaces from family and face name */
2916 trim_spaces(familyW, familynameW);
2917 len = trim_spaces(faceW, facenameW);
2919 /* remove rightmost regular variant from face name */
2920 regular_ptr = facename_remove_regular_term(facenameW, len);
2922 /* append face name to family name, FIXME check if face name is a substring of family name */
2923 if (*facenameW) {
2924 strcatW(familynameW, spaceW);
2925 strcatW(familynameW, facenameW);
2928 /* tokenize with " .-_" */
2929 fontname_tokenize(&tokens, familynameW);
2931 /* extract and resolve style */
2932 font->style = font_extract_style(&tokens, font->style, &style_name);
2934 /* extract stretch */
2935 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2937 /* extract weight */
2938 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2940 /* resolve weight */
2941 if (weight != font->weight) {
2942 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2943 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2944 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2945 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2946 !(abs(weight - font->weight) <= 150 &&
2947 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2948 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2949 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2951 font->weight = weight;
2955 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2956 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2957 stretch itself is normal (extracted stretch is never normal). */
2958 if (stretch != font->stretch) {
2959 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2960 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2961 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2963 font->stretch = stretch;
2967 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2969 /* get final combined string from what's left in token list, list is released */
2970 fontname_tokens_to_str(&tokens, finalW);
2972 if (!strcmpW(familyW, finalW))
2973 return FALSE;
2975 /* construct face name */
2976 strcpyW(familyW, finalW);
2978 /* resolved weight name */
2979 if (weight_name.ptr)
2980 font_name_token_to_str(&weight_name, weightW);
2981 /* ignore normal weight */
2982 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2983 weightW[0] = 0;
2984 /* for known weight values use appropriate names */
2985 else if (is_known_weight_value(font->weight, weightW)) {
2987 /* use Wnnn format as a fallback in case weight is not one of known values */
2988 else {
2989 static const WCHAR fmtW[] = {'W','%','d',0};
2990 sprintfW(weightW, fmtW, font->weight);
2993 /* resolved stretch name */
2994 if (stretch_name.ptr)
2995 font_name_token_to_str(&stretch_name, stretchW);
2996 /* ignore normal stretch */
2997 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2998 stretchW[0] = 0;
2999 /* use predefined stretch names */
3000 else {
3001 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3002 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3003 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3004 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3005 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3006 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3008 static const WCHAR *stretchnamesW[] = {
3009 ultracondensedW,
3010 extracondensedW,
3011 condensedW,
3012 semicondensedW,
3013 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3014 semiexpandedW,
3015 expandedW,
3016 extraexpandedW,
3017 ultraexpandedW
3019 strcpyW(stretchW, stretchnamesW[font->stretch]);
3022 /* resolved style name */
3023 if (style_name.ptr)
3024 font_name_token_to_str(&style_name, styleW);
3025 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3026 styleW[0] = 0;
3027 /* use predefined names */
3028 else {
3029 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3030 strcpyW(styleW, italicW);
3031 else
3032 strcpyW(styleW, obliqueW);
3035 /* use Regular match if it was found initially */
3036 if (!*weightW && !*stretchW && !*styleW)
3037 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3038 else {
3039 faceW[0] = 0;
3040 if (*stretchW)
3041 strcpyW(faceW, stretchW);
3042 if (*weightW) {
3043 if (*faceW)
3044 strcatW(faceW, spaceW);
3045 strcatW(faceW, weightW);
3047 if (*styleW) {
3048 if (*faceW)
3049 strcatW(faceW, spaceW);
3050 strcatW(faceW, styleW);
3054 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3055 return TRUE;
3058 static HRESULT init_font_data(IDWriteFactory3 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
3059 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
3061 struct file_stream_desc stream_desc;
3062 struct dwrite_font_props props;
3063 struct dwrite_font_data *data;
3064 IDWriteFontFileStream *stream;
3065 WCHAR familyW[255], faceW[255];
3066 HRESULT hr;
3068 *ret = NULL;
3069 data = heap_alloc_zero(sizeof(*data));
3070 if (!data)
3071 return E_OUTOFMEMORY;
3073 hr = get_filestream_from_file(file, &stream);
3074 if (FAILED(hr)) {
3075 heap_free(data);
3076 return hr;
3079 data->ref = 1;
3080 data->factory = factory;
3081 data->file = file;
3082 data->face_index = face_index;
3083 data->face_type = face_type;
3084 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3085 data->bold_sim_tested = 0;
3086 data->oblique_sim_tested = 0;
3087 IDWriteFontFile_AddRef(file);
3088 IDWriteFactory3_AddRef(factory);
3090 stream_desc.stream = stream;
3091 stream_desc.face_type = face_type;
3092 stream_desc.face_index = face_index;
3093 opentype_get_font_properties(&stream_desc, &props);
3094 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3095 opentype_get_font_facename(&stream_desc, &data->names);
3097 /* get family name from font file */
3098 hr = opentype_get_font_familyname(&stream_desc, family_name);
3099 IDWriteFontFileStream_Release(stream);
3100 if (FAILED(hr)) {
3101 WARN("unable to get family name from font\n");
3102 release_font_data(data);
3103 return hr;
3106 data->style = props.style;
3107 data->stretch = props.stretch;
3108 data->weight = props.weight;
3109 data->panose = props.panose;
3111 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3112 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3113 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3114 set_en_localizedstring(*family_name, familyW);
3115 set_en_localizedstring(data->names, faceW);
3118 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3120 *ret = data;
3121 return S_OK;
3124 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
3125 struct dwrite_font_data **ret)
3127 struct dwrite_font_data *data;
3129 *ret = NULL;
3130 data = heap_alloc_zero(sizeof(*data));
3131 if (!data)
3132 return E_OUTOFMEMORY;
3134 *data = *src;
3135 data->ref = 1;
3136 data->simulations |= sim;
3137 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3138 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3139 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3140 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3141 memset(data->info_strings, 0, sizeof(data->info_strings));
3142 data->names = NULL;
3143 IDWriteFactory3_AddRef(data->factory);
3144 IDWriteFontFile_AddRef(data->file);
3146 create_localizedstrings(&data->names);
3147 add_localizedstring(data->names, enusW, facenameW);
3149 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3151 *ret = data;
3152 return S_OK;
3155 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3157 struct dwrite_fontfamily_data *data;
3159 data = heap_alloc(sizeof(*data));
3160 if (!data)
3161 return E_OUTOFMEMORY;
3163 data->ref = 1;
3164 data->font_count = 0;
3165 data->font_alloc = 2;
3166 data->has_normal_face = 0;
3167 data->has_oblique_face = 0;
3168 data->has_italic_face = 0;
3170 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3171 if (!data->fonts) {
3172 heap_free(data);
3173 return E_OUTOFMEMORY;
3176 data->familyname = familyname;
3177 IDWriteLocalizedStrings_AddRef(familyname);
3179 *ret = data;
3180 return S_OK;
3183 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3185 UINT32 i, j, heaviest;
3187 for (i = 0; i < family->font_count; i++) {
3188 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3189 heaviest = i;
3191 if (family->fonts[i]->bold_sim_tested)
3192 continue;
3194 family->fonts[i]->bold_sim_tested = 1;
3195 for (j = i; j < family->font_count; j++) {
3196 if (family->fonts[j]->bold_sim_tested)
3197 continue;
3199 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3200 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3201 if (family->fonts[j]->weight > weight) {
3202 weight = family->fonts[j]->weight;
3203 heaviest = j;
3205 family->fonts[j]->bold_sim_tested = 1;
3209 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3210 static const struct name_pattern weightsim_patterns[] = {
3211 { extraW, lightW },
3212 { extW, lightW },
3213 { ultraW, lightW },
3214 { semiW, lightW },
3215 { semiW, boldW },
3216 { demiW, boldW },
3217 { boldW },
3218 { thinW },
3219 { lightW },
3220 { mediumW },
3221 { demiW },
3222 { NULL }
3225 WCHAR facenameW[255], initialW[255];
3226 struct dwrite_font_data *boldface;
3227 struct list tokens;
3229 /* add Bold simulation based on heaviest face data */
3231 /* Simulated face name should only contain Bold as weight term,
3232 so remove existing regular and weight terms. */
3233 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3234 facename_remove_regular_term(initialW, -1);
3236 /* remove current weight pattern */
3237 fontname_tokenize(&tokens, initialW);
3238 match_pattern_list(&tokens, weightsim_patterns, NULL);
3239 fontname_tokens_to_str(&tokens, facenameW);
3241 /* Bold suffix for new name */
3242 if (*facenameW)
3243 strcatW(facenameW, spaceW);
3244 strcatW(facenameW, boldW);
3246 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3247 boldface->bold_sim_tested = 1;
3248 fontfamily_add_font(family, boldface);
3254 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3256 UINT32 i, j;
3258 for (i = 0; i < family->font_count; i++) {
3259 UINT32 regular = ~0u, oblique = ~0u;
3260 struct dwrite_font_data *obliqueface;
3261 WCHAR facenameW[255];
3263 if (family->fonts[i]->oblique_sim_tested)
3264 continue;
3266 family->fonts[i]->oblique_sim_tested = 1;
3267 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3268 regular = i;
3269 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3270 oblique = i;
3272 /* find regular style with same weight/stretch values */
3273 for (j = i; j < family->font_count; j++) {
3274 if (family->fonts[j]->oblique_sim_tested)
3275 continue;
3277 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3278 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3280 family->fonts[j]->oblique_sim_tested = 1;
3281 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3282 regular = j;
3284 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3285 oblique = j;
3288 if (regular != ~0u && oblique != ~0u)
3289 break;
3292 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3293 if (regular == ~0u)
3294 continue;
3296 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3297 if (oblique != ~0u)
3298 continue;
3300 /* add oblique simulation based on this regular face */
3302 /* remove regular term if any, append 'Oblique' */
3303 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3304 facename_remove_regular_term(facenameW, -1);
3306 if (*facenameW)
3307 strcatW(facenameW, spaceW);
3308 strcatW(facenameW, obliqueW);
3310 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3311 obliqueface->oblique_sim_tested = 1;
3312 fontfamily_add_font(family, obliqueface);
3317 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3318 const WCHAR *replacement_name)
3320 UINT32 i = collection_find_family(collection, replacement_name);
3321 struct dwrite_fontfamily_data *target;
3322 IDWriteLocalizedStrings *strings;
3323 HRESULT hr;
3325 /* replacement does not exist */
3326 if (i == ~0u)
3327 return FALSE;
3329 hr = create_localizedstrings(&strings);
3330 if (FAILED(hr))
3331 return FALSE;
3333 /* add a new family with target name, reuse font data from replacement */
3334 add_localizedstring(strings, enusW, target_name);
3335 hr = init_fontfamily_data(strings, &target);
3336 if (hr == S_OK) {
3337 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3338 WCHAR nameW[255];
3340 for (i = 0; i < replacement->font_count; i++)
3341 fontfamily_add_font(target, replacement->fonts[i]);
3343 fontcollection_add_family(collection, target);
3344 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3345 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3347 IDWriteLocalizedStrings_Release(strings);
3348 return TRUE;
3351 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3352 system font collections. */
3353 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3355 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3356 WCHAR *name;
3357 void *data;
3358 HKEY hkey;
3360 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3361 return;
3363 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3364 RegCloseKey(hkey);
3365 return;
3368 max_namelen++; /* returned value doesn't include room for '\0' */
3369 name = heap_alloc(max_namelen * sizeof(WCHAR));
3370 data = heap_alloc(max_datalen);
3372 datalen = max_datalen;
3373 namelen = max_namelen;
3374 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3375 if (collection_find_family(collection, name) == ~0u) {
3376 if (type == REG_MULTI_SZ) {
3377 WCHAR *replacement = data;
3378 while (*replacement) {
3379 if (fontcollection_add_replacement(collection, name, replacement))
3380 break;
3381 replacement += strlenW(replacement) + 1;
3384 else if (type == REG_SZ)
3385 fontcollection_add_replacement(collection, name, data);
3387 else
3388 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3390 datalen = max_datalen;
3391 namelen = max_namelen;
3394 heap_free(data);
3395 heap_free(name);
3396 RegCloseKey(hkey);
3399 HRESULT create_font_collection(IDWriteFactory3 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3401 struct fontfile_enum {
3402 struct list entry;
3403 IDWriteFontFile *file;
3405 struct fontfile_enum *fileenum, *fileenum2;
3406 struct dwrite_fontcollection *collection;
3407 struct list scannedfiles;
3408 BOOL current = FALSE;
3409 HRESULT hr = S_OK;
3410 UINT32 i;
3412 *ret = NULL;
3414 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3415 if (!collection) return E_OUTOFMEMORY;
3417 hr = init_font_collection(collection, is_system);
3418 if (FAILED(hr)) {
3419 heap_free(collection);
3420 return hr;
3423 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3425 TRACE("building font collection:\n");
3427 list_init(&scannedfiles);
3428 while (hr == S_OK) {
3429 DWRITE_FONT_FACE_TYPE face_type;
3430 DWRITE_FONT_FILE_TYPE file_type;
3431 BOOL supported, same = FALSE;
3432 IDWriteFontFile *file;
3433 UINT32 face_count;
3435 current = FALSE;
3436 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3437 if (FAILED(hr) || !current)
3438 break;
3440 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3441 if (FAILED(hr))
3442 break;
3444 /* check if we've scanned this file already */
3445 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3446 if ((same = is_same_fontfile(fileenum->file, file)))
3447 break;
3450 if (same) {
3451 IDWriteFontFile_Release(file);
3452 continue;
3455 /* failed font files are skipped */
3456 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3457 if (FAILED(hr) || !supported || face_count == 0) {
3458 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3459 IDWriteFontFile_Release(file);
3460 hr = S_OK;
3461 continue;
3464 /* add to scanned list */
3465 fileenum = heap_alloc(sizeof(*fileenum));
3466 fileenum->file = file;
3467 list_add_tail(&scannedfiles, &fileenum->entry);
3469 for (i = 0; i < face_count; i++) {
3470 IDWriteLocalizedStrings *family_name = NULL;
3471 struct dwrite_font_data *font_data;
3472 WCHAR familyW[255];
3473 UINT32 index;
3475 /* alloc and init new font data structure */
3476 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3477 if (FAILED(hr)) {
3478 /* move to next one */
3479 hr = S_OK;
3480 continue;
3483 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3485 index = collection_find_family(collection, familyW);
3486 if (index != ~0u)
3487 hr = fontfamily_add_font(collection->family_data[index], font_data);
3488 else {
3489 struct dwrite_fontfamily_data *family_data;
3491 /* create and init new family */
3492 hr = init_fontfamily_data(family_name, &family_data);
3493 if (hr == S_OK) {
3494 /* add font to family, family - to collection */
3495 hr = fontfamily_add_font(family_data, font_data);
3496 if (hr == S_OK)
3497 hr = fontcollection_add_family(collection, family_data);
3499 if (FAILED(hr))
3500 release_fontfamily_data(family_data);
3504 IDWriteLocalizedStrings_Release(family_name);
3506 if (FAILED(hr))
3507 break;
3511 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3512 IDWriteFontFile_Release(fileenum->file);
3513 list_remove(&fileenum->entry);
3514 heap_free(fileenum);
3517 for (i = 0; i < collection->family_count; i++) {
3518 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3519 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3522 if (is_system)
3523 fontcollection_add_replacements(collection);
3525 return hr;
3528 struct system_fontfile_enumerator
3530 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3531 LONG ref;
3533 IDWriteFactory3 *factory;
3534 HKEY hkey;
3535 int index;
3538 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3540 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3543 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3545 *obj = NULL;
3547 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3548 IDWriteFontFileEnumerator_AddRef(iface);
3549 *obj = iface;
3550 return S_OK;
3553 return E_NOINTERFACE;
3556 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3558 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3559 return InterlockedIncrement(&enumerator->ref);
3562 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3564 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3565 ULONG ref = InterlockedDecrement(&enumerator->ref);
3567 if (!ref) {
3568 IDWriteFactory3_Release(enumerator->factory);
3569 RegCloseKey(enumerator->hkey);
3570 heap_free(enumerator);
3573 return ref;
3576 static HRESULT create_local_file_reference(IDWriteFactory3 *factory, const WCHAR *filename, IDWriteFontFile **file)
3578 HRESULT hr;
3580 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3581 if (!strchrW(filename, '\\')) {
3582 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3583 WCHAR fullpathW[MAX_PATH];
3585 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3586 strcatW(fullpathW, fontsW);
3587 strcatW(fullpathW, filename);
3589 hr = IDWriteFactory3_CreateFontFileReference(factory, fullpathW, NULL, file);
3591 else
3592 hr = IDWriteFactory3_CreateFontFileReference(factory, filename, NULL, file);
3594 return hr;
3597 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3599 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3600 DWORD ret, type, val_count, count;
3601 WCHAR *value, *filename;
3602 HRESULT hr;
3604 *file = NULL;
3606 if (enumerator->index < 0)
3607 return E_FAIL;
3609 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3610 if (ret != ERROR_SUCCESS)
3611 return E_FAIL;
3613 val_count++;
3614 value = heap_alloc( val_count * sizeof(value[0]) );
3615 filename = heap_alloc(count);
3616 if (!value || !filename) {
3617 heap_free(value);
3618 heap_free(filename);
3619 return E_OUTOFMEMORY;
3622 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3623 if (ret) {
3624 heap_free(value);
3625 heap_free(filename);
3626 return E_FAIL;
3629 hr = create_local_file_reference(enumerator->factory, filename, file);
3631 heap_free(value);
3632 heap_free(filename);
3633 return hr;
3636 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3638 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3639 DWORD ret, max_val_count;
3640 WCHAR *value;
3642 *current = FALSE;
3643 enumerator->index++;
3645 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3646 if (ret != ERROR_SUCCESS)
3647 return E_FAIL;
3649 max_val_count++;
3650 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3651 return E_OUTOFMEMORY;
3653 /* iterate until we find next string value */
3654 while (1) {
3655 DWORD type = 0, count, val_count;
3656 val_count = max_val_count;
3657 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3658 break;
3659 if (type == REG_SZ) {
3660 *current = TRUE;
3661 break;
3663 enumerator->index++;
3666 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3667 heap_free(value);
3668 return S_OK;
3671 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3673 systemfontfileenumerator_QueryInterface,
3674 systemfontfileenumerator_AddRef,
3675 systemfontfileenumerator_Release,
3676 systemfontfileenumerator_MoveNext,
3677 systemfontfileenumerator_GetCurrentFontFile
3680 static HRESULT create_system_fontfile_enumerator(IDWriteFactory3 *factory, IDWriteFontFileEnumerator **ret)
3682 struct system_fontfile_enumerator *enumerator;
3683 static const WCHAR fontslistW[] = {
3684 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3685 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3686 'F','o','n','t','s',0
3689 *ret = NULL;
3691 enumerator = heap_alloc(sizeof(*enumerator));
3692 if (!enumerator)
3693 return E_OUTOFMEMORY;
3695 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3696 enumerator->ref = 1;
3697 enumerator->factory = factory;
3698 enumerator->index = -1;
3699 IDWriteFactory3_AddRef(factory);
3701 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3702 ERR("failed to open fonts list key\n");
3703 IDWriteFactory3_Release(factory);
3704 heap_free(enumerator);
3705 return E_FAIL;
3708 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3710 return S_OK;
3713 HRESULT get_system_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection **collection)
3715 IDWriteFontFileEnumerator *enumerator;
3716 HRESULT hr;
3718 *collection = NULL;
3720 hr = create_system_fontfile_enumerator(factory, &enumerator);
3721 if (FAILED(hr))
3722 return hr;
3724 TRACE("building system font collection for factory %p\n", factory);
3725 hr = create_font_collection(factory, enumerator, TRUE, collection);
3726 IDWriteFontFileEnumerator_Release(enumerator);
3727 return hr;
3730 static HRESULT eudc_collection_add_family(IDWriteFactory3 *factory, struct dwrite_fontcollection *collection,
3731 const WCHAR *keynameW, const WCHAR *pathW)
3733 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};
3734 static const WCHAR emptyW[] = {0};
3735 IDWriteLocalizedStrings *names;
3736 DWRITE_FONT_FACE_TYPE face_type;
3737 DWRITE_FONT_FILE_TYPE file_type;
3738 BOOL supported;
3739 UINT32 face_count, i;
3740 IDWriteFontFile *file;
3741 HRESULT hr;
3742 struct dwrite_fontfamily_data *family_data;
3744 /* create font file from this path */
3745 hr = create_local_file_reference(factory, pathW, &file);
3746 if (FAILED(hr))
3747 return S_FALSE;
3749 /* failed font files are skipped */
3750 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3751 if (FAILED(hr) || !supported || face_count == 0) {
3752 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3753 IDWriteFontFile_Release(file);
3754 return S_FALSE;
3757 /* create and init new family */
3759 /* Family names are added for non-specific locale, represented with empty string.
3760 Default family appears with empty family name. */
3761 create_localizedstrings(&names);
3762 if (!strcmpiW(keynameW, defaultfontW))
3763 add_localizedstring(names, emptyW, emptyW);
3764 else
3765 add_localizedstring(names, emptyW, keynameW);
3767 hr = init_fontfamily_data(names, &family_data);
3768 IDWriteLocalizedStrings_Release(names);
3769 if (hr != S_OK) {
3770 IDWriteFontFile_Release(file);
3771 return hr;
3774 /* fill with faces */
3775 for (i = 0; i < face_count; i++) {
3776 struct dwrite_font_data *font_data;
3778 /* alloc and init new font data structure */
3779 hr = init_font_data(factory, file, face_type, i, &names, &font_data);
3780 if (FAILED(hr))
3781 continue;
3783 IDWriteLocalizedStrings_Release(names);
3785 /* add font to family */
3786 hr = fontfamily_add_font(family_data, font_data);
3787 if (hr != S_OK)
3788 release_font_data(font_data);
3791 /* add family to collection */
3792 hr = fontcollection_add_family(collection, family_data);
3793 if (FAILED(hr))
3794 release_fontfamily_data(family_data);
3795 IDWriteFontFile_Release(file);
3797 return hr;
3800 HRESULT get_eudc_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection **ret)
3802 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3803 struct dwrite_fontcollection *collection;
3804 static const WCHAR emptyW[] = {0};
3805 WCHAR eudckeypathW[16];
3806 HKEY eudckey;
3807 DWORD index;
3808 BOOL exists;
3809 LONG retval;
3810 HRESULT hr;
3811 UINT32 i;
3813 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3815 *ret = NULL;
3817 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3818 if (!collection) return E_OUTOFMEMORY;
3820 hr = init_font_collection(collection, FALSE);
3821 if (FAILED(hr)) {
3822 heap_free(collection);
3823 return hr;
3826 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3828 /* return empty collection if EUDC fonts are not configured */
3829 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3830 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3831 return S_OK;
3833 retval = ERROR_SUCCESS;
3834 index = 0;
3835 while (retval != ERROR_NO_MORE_ITEMS) {
3836 WCHAR keynameW[64], pathW[MAX_PATH];
3837 DWORD type, path_len, name_len;
3839 path_len = sizeof(pathW)/sizeof(*pathW);
3840 name_len = sizeof(keynameW)/sizeof(*keynameW);
3841 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3842 if (retval || type != REG_SZ)
3843 continue;
3845 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3846 if (hr != S_OK)
3847 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3849 RegCloseKey(eudckey);
3851 /* try to add global default if not defined for specific codepage */
3852 exists = FALSE;
3853 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
3854 &index, &exists);
3855 if (FAILED(hr) || !exists) {
3856 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3857 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3858 if (hr != S_OK)
3859 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3862 /* EUDC collection offers simulated faces too */
3863 for (i = 0; i < collection->family_count; i++) {
3864 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3865 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3868 return S_OK;
3871 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3873 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3875 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3877 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3879 *obj = iface;
3880 IDWriteFontFile_AddRef(iface);
3881 return S_OK;
3884 *obj = NULL;
3885 return E_NOINTERFACE;
3888 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3890 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3891 ULONG ref = InterlockedIncrement(&This->ref);
3892 TRACE("(%p)->(%d)\n", This, ref);
3893 return ref;
3896 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3898 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3899 ULONG ref = InterlockedDecrement(&This->ref);
3901 TRACE("(%p)->(%d)\n", This, ref);
3903 if (!ref)
3905 IDWriteFontFileLoader_Release(This->loader);
3906 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3907 heap_free(This->reference_key);
3908 heap_free(This);
3911 return ref;
3914 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3916 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3917 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3918 *fontFileReferenceKey = This->reference_key;
3919 *fontFileReferenceKeySize = This->key_size;
3921 return S_OK;
3924 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3926 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3927 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3928 *fontFileLoader = This->loader;
3929 IDWriteFontFileLoader_AddRef(This->loader);
3931 return S_OK;
3934 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
3935 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3937 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3938 IDWriteFontFileStream *stream;
3939 HRESULT hr;
3941 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3943 *isSupportedFontType = FALSE;
3944 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3945 if (fontFaceType)
3946 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3947 *numberOfFaces = 0;
3949 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3950 if (FAILED(hr))
3951 return hr;
3953 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3955 /* TODO: Further Analysis */
3956 IDWriteFontFileStream_Release(stream);
3957 return S_OK;
3960 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3961 dwritefontfile_QueryInterface,
3962 dwritefontfile_AddRef,
3963 dwritefontfile_Release,
3964 dwritefontfile_GetReferenceKey,
3965 dwritefontfile_GetLoader,
3966 dwritefontfile_Analyze,
3969 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3971 struct dwrite_fontfile *This;
3973 This = heap_alloc(sizeof(struct dwrite_fontfile));
3974 if (!This) return E_OUTOFMEMORY;
3976 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3977 This->ref = 1;
3978 IDWriteFontFileLoader_AddRef(loader);
3979 This->loader = loader;
3980 This->stream = NULL;
3981 This->reference_key = heap_alloc(key_size);
3982 memcpy(This->reference_key, reference_key, key_size);
3983 This->key_size = key_size;
3985 *font_file = &This->IDWriteFontFile_iface;
3987 return S_OK;
3990 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3992 IDWriteFontFileLoader *loader;
3993 UINT32 key_size;
3994 const void *key;
3995 HRESULT hr;
3997 *stream = NULL;
3998 hr = IDWriteFontFile_GetLoader(file, &loader);
3999 if (FAILED(hr))
4000 return hr;
4002 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
4003 if (FAILED(hr)) {
4004 IDWriteFontFileLoader_Release(loader);
4005 return hr;
4008 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
4009 IDWriteFontFileLoader_Release(loader);
4011 return hr;
4014 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
4015 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
4017 struct file_stream_desc stream_desc;
4018 struct dwrite_fontface *fontface;
4019 HRESULT hr = S_OK;
4020 int i;
4022 *ret = NULL;
4024 fontface = heap_alloc(sizeof(struct dwrite_fontface));
4025 if (!fontface)
4026 return E_OUTOFMEMORY;
4028 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
4029 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
4031 if (!fontface->files || !fontface->streams) {
4032 heap_free(fontface->files);
4033 heap_free(fontface->streams);
4034 heap_free(fontface);
4035 return E_OUTOFMEMORY;
4038 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
4039 fontface->ref = 1;
4040 fontface->type = facetype;
4041 fontface->file_count = files_number;
4042 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
4043 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
4044 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
4045 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
4046 memset(&fontface->colr, 0, sizeof(fontface->colr));
4047 fontface->cmap.exists = TRUE;
4048 fontface->vdmx.exists = TRUE;
4049 fontface->gasp.exists = TRUE;
4050 fontface->cpal.exists = TRUE;
4051 fontface->colr.exists = TRUE;
4052 fontface->index = index;
4053 fontface->simulations = simulations;
4054 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
4056 for (i = 0; i < fontface->file_count; i++) {
4057 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
4058 if (FAILED(hr)) {
4059 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
4060 return hr;
4063 fontface->files[i] = font_files[i];
4064 IDWriteFontFile_AddRef(font_files[i]);
4067 stream_desc.stream = fontface->streams[0];
4068 stream_desc.face_type = facetype;
4069 stream_desc.face_index = index;
4070 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4071 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4072 /* TODO: test what happens if caret is already slanted */
4073 if (fontface->caret.slopeRise == 1) {
4074 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4075 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4078 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
4079 fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
4080 fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
4082 *ret = &fontface->IDWriteFontFace3_iface;
4083 return S_OK;
4086 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4087 struct local_refkey
4089 FILETIME writetime;
4090 WCHAR name[1];
4093 struct local_cached_stream
4095 struct list entry;
4096 IDWriteFontFileStream *stream;
4097 struct local_refkey *key;
4098 UINT32 key_size;
4101 struct dwrite_localfontfilestream
4103 IDWriteFontFileStream IDWriteFontFileStream_iface;
4104 LONG ref;
4106 struct local_cached_stream *entry;
4107 const void *file_ptr;
4108 UINT64 size;
4111 struct dwrite_localfontfileloader {
4112 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4113 LONG ref;
4115 struct list streams;
4118 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4120 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4123 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4125 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4128 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4130 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4131 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4132 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4134 *obj = iface;
4135 IDWriteFontFileStream_AddRef(iface);
4136 return S_OK;
4139 *obj = NULL;
4140 return E_NOINTERFACE;
4143 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4145 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4146 ULONG ref = InterlockedIncrement(&This->ref);
4147 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4148 return ref;
4151 static inline void release_cached_stream(struct local_cached_stream *stream)
4153 list_remove(&stream->entry);
4154 heap_free(stream->key);
4155 heap_free(stream);
4158 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4160 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4161 ULONG ref = InterlockedDecrement(&This->ref);
4163 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4165 if (!ref) {
4166 UnmapViewOfFile(This->file_ptr);
4167 release_cached_stream(This->entry);
4168 heap_free(This);
4171 return ref;
4174 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
4176 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4178 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
4179 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4181 *fragment_context = NULL;
4183 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4184 *fragment_start = NULL;
4185 return E_FAIL;
4188 *fragment_start = (char*)This->file_ptr + offset;
4189 return S_OK;
4192 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4194 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4195 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4198 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4200 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4201 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4202 *size = This->size;
4203 return S_OK;
4206 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4208 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4209 ULARGE_INTEGER li;
4211 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4213 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4214 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4215 *last_writetime = li.QuadPart;
4217 return S_OK;
4220 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4222 localfontfilestream_QueryInterface,
4223 localfontfilestream_AddRef,
4224 localfontfilestream_Release,
4225 localfontfilestream_ReadFileFragment,
4226 localfontfilestream_ReleaseFileFragment,
4227 localfontfilestream_GetFileSize,
4228 localfontfilestream_GetLastWriteTime
4231 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4233 struct dwrite_localfontfilestream *This;
4235 *ret = NULL;
4237 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4238 if (!This)
4239 return E_OUTOFMEMORY;
4241 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4242 This->ref = 1;
4244 This->file_ptr = file_ptr;
4245 This->size = size;
4246 This->entry = entry;
4248 *ret = &This->IDWriteFontFileStream_iface;
4249 return S_OK;
4252 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4254 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4256 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4258 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4260 *obj = iface;
4261 IDWriteLocalFontFileLoader_AddRef(iface);
4262 return S_OK;
4265 *obj = NULL;
4266 return E_NOINTERFACE;
4269 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4271 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4272 ULONG ref = InterlockedIncrement(&This->ref);
4273 TRACE("(%p)->(%d)\n", This, ref);
4274 return ref;
4277 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4279 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4280 ULONG ref = InterlockedDecrement(&This->ref);
4282 TRACE("(%p)->(%d)\n", This, ref);
4284 if (!ref) {
4285 struct local_cached_stream *stream, *stream2;
4287 /* This will detach all entries from cache. Entries are released together with streams,
4288 so stream controls cache entry lifetime. */
4289 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4290 list_init(&stream->entry);
4292 heap_free(This);
4295 return ref;
4298 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4300 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4301 const struct local_refkey *refkey = key;
4302 struct local_cached_stream *stream;
4303 IDWriteFontFileStream *filestream;
4304 HANDLE file, mapping;
4305 LARGE_INTEGER size;
4306 void *file_ptr;
4307 HRESULT hr;
4309 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4310 TRACE("name: %s\n", debugstr_w(refkey->name));
4312 /* search cache first */
4313 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4314 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4315 *ret = stream->stream;
4316 IDWriteFontFileStream_AddRef(*ret);
4317 return S_OK;
4321 *ret = NULL;
4323 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4324 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4325 if (file == INVALID_HANDLE_VALUE)
4326 return E_FAIL;
4328 GetFileSizeEx(file, &size);
4329 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4330 CloseHandle(file);
4331 if (!mapping)
4332 return E_FAIL;
4334 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4335 CloseHandle(mapping);
4337 stream = heap_alloc(sizeof(*stream));
4338 if (!stream) {
4339 UnmapViewOfFile(file_ptr);
4340 return E_OUTOFMEMORY;
4343 stream->key = heap_alloc(key_size);
4344 if (!stream->key) {
4345 UnmapViewOfFile(file_ptr);
4346 heap_free(stream);
4347 return E_OUTOFMEMORY;
4350 stream->key_size = key_size;
4351 memcpy(stream->key, key, key_size);
4353 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4354 if (FAILED(hr)) {
4355 UnmapViewOfFile(file_ptr);
4356 heap_free(stream->key);
4357 heap_free(stream);
4358 return hr;
4361 stream->stream = filestream;
4362 list_add_head(&This->streams, &stream->entry);
4364 *ret = stream->stream;
4366 return S_OK;
4369 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4371 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4372 const struct local_refkey *refkey = key;
4374 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4376 *length = strlenW(refkey->name);
4377 return S_OK;
4380 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4382 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4383 const struct local_refkey *refkey = key;
4385 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4387 if (length < strlenW(refkey->name))
4388 return E_INVALIDARG;
4390 strcpyW(path, refkey->name);
4391 return S_OK;
4394 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4396 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4397 const struct local_refkey *refkey = key;
4399 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4401 *writetime = refkey->writetime;
4402 return S_OK;
4405 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4406 localfontfileloader_QueryInterface,
4407 localfontfileloader_AddRef,
4408 localfontfileloader_Release,
4409 localfontfileloader_CreateStreamFromKey,
4410 localfontfileloader_GetFilePathLengthFromKey,
4411 localfontfileloader_GetFilePathFromKey,
4412 localfontfileloader_GetLastWriteTimeFromKey
4415 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4417 struct dwrite_localfontfileloader *This;
4419 *ret = NULL;
4421 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4422 if (!This)
4423 return E_OUTOFMEMORY;
4425 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4426 This->ref = 1;
4427 list_init(&This->streams);
4429 *ret = &This->IDWriteLocalFontFileLoader_iface;
4430 return S_OK;
4433 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4435 struct local_refkey *refkey;
4437 if (!path)
4438 return E_INVALIDARG;
4440 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4441 *key = NULL;
4443 refkey = heap_alloc(*size);
4444 if (!refkey)
4445 return E_OUTOFMEMORY;
4447 if (writetime)
4448 refkey->writetime = *writetime;
4449 else {
4450 WIN32_FILE_ATTRIBUTE_DATA info;
4452 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4453 refkey->writetime = info.ftLastWriteTime;
4454 else
4455 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4457 strcpyW(refkey->name, path);
4459 *key = refkey;
4461 return S_OK;
4464 /* IDWriteGlyphRunAnalysis */
4465 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4467 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4469 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4471 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4472 IsEqualIID(riid, &IID_IUnknown))
4474 *ppv = iface;
4475 IDWriteGlyphRunAnalysis_AddRef(iface);
4476 return S_OK;
4479 *ppv = NULL;
4480 return E_NOINTERFACE;
4483 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4485 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4486 ULONG ref = InterlockedIncrement(&This->ref);
4487 TRACE("(%p)->(%u)\n", This, ref);
4488 return ref;
4491 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4493 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4494 ULONG ref = InterlockedDecrement(&This->ref);
4496 TRACE("(%p)->(%u)\n", This, ref);
4498 if (!ref) {
4499 if (This->run.fontFace)
4500 IDWriteFontFace_Release(This->run.fontFace);
4501 heap_free(This->glyphs);
4502 heap_free(This->advances);
4503 heap_free(This->advanceoffsets);
4504 heap_free(This->ascenderoffsets);
4505 heap_free(This->bitmap);
4506 heap_free(This);
4509 return ref;
4512 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4514 struct dwrite_glyphbitmap glyph_bitmap;
4515 IDWriteFontFace3 *fontface3;
4516 D2D_POINT_2F origin;
4517 BOOL is_rtl;
4518 HRESULT hr;
4519 UINT32 i;
4521 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4522 *bounds = analysis->bounds;
4523 return;
4526 if (analysis->run.isSideways)
4527 FIXME("sideways runs are not supported.\n");
4529 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4530 if (FAILED(hr))
4531 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4533 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4534 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4535 for any non-zero glyph ascender */
4536 origin.x = origin.y = 0.0f;
4537 is_rtl = analysis->run.bidiLevel & 1;
4539 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4540 glyph_bitmap.fontface = fontface3;
4541 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4542 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4543 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4544 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4545 glyph_bitmap.m = &analysis->m;
4547 for (i = 0; i < analysis->run.glyphCount; i++) {
4548 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4549 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4550 const D2D_POINT_2F *advance = analysis->advances + i;
4551 RECT *bbox = &glyph_bitmap.bbox;
4553 glyph_bitmap.index = analysis->run.glyphIndices[i];
4554 freetype_get_glyph_bbox(&glyph_bitmap);
4556 if (is_rtl)
4557 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4558 else
4559 OffsetRect(bbox, origin.x, origin.y);
4561 if (advanceoffset)
4562 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4564 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4565 origin.x += advance->x;
4566 origin.y += advance->y;
4569 IDWriteFontFace3_Release(fontface3);
4571 /* translate to given run origin */
4572 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4573 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4574 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4576 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4577 *bounds = analysis->bounds;
4580 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4582 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4584 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4586 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4587 memset(bounds, 0, sizeof(*bounds));
4588 return E_INVALIDARG;
4591 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4592 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4593 memset(bounds, 0, sizeof(*bounds));
4594 return S_OK;
4597 glyphrunanalysis_get_texturebounds(This, bounds);
4598 return S_OK;
4601 static inline int get_dib_stride( int width, int bpp )
4603 return ((width * bpp + 31) >> 3) & ~3;
4606 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4608 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4609 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4610 (runbounds->left - bounds->left) * 3;
4611 else
4612 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4613 runbounds->left - bounds->left;
4616 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4618 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4619 struct dwrite_glyphbitmap glyph_bitmap;
4620 IDWriteFontFace3 *fontface2;
4621 D2D_POINT_2F origin;
4622 UINT32 i, size;
4623 BOOL is_rtl;
4624 HRESULT hr;
4625 RECT *bbox;
4627 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4628 if (FAILED(hr)) {
4629 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4630 return;
4633 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4634 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4635 size *= 3;
4636 analysis->bitmap = heap_alloc_zero(size);
4638 origin.x = origin.y = 0.0f;
4639 is_rtl = analysis->run.bidiLevel & 1;
4641 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4642 glyph_bitmap.fontface = fontface2;
4643 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4644 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4645 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4646 glyph_bitmap.type = type;
4647 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4648 glyph_bitmap.m = &analysis->m;
4649 bbox = &glyph_bitmap.bbox;
4651 for (i = 0; i < analysis->run.glyphCount; i++) {
4652 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4653 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4654 const D2D_POINT_2F *advance = analysis->advances + i;
4655 int x, y, width, height;
4656 BYTE *src, *dst;
4657 BOOL is_1bpp;
4659 glyph_bitmap.index = analysis->run.glyphIndices[i];
4660 freetype_get_glyph_bbox(&glyph_bitmap);
4662 if (IsRectEmpty(bbox)) {
4663 origin.x += advance->x;
4664 origin.y += advance->y;
4665 continue;
4668 width = bbox->right - bbox->left;
4669 height = bbox->bottom - bbox->top;
4671 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4672 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4673 else
4674 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4676 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4677 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4679 if (is_rtl)
4680 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4681 else
4682 OffsetRect(bbox, origin.x, origin.y);
4684 if (advanceoffset)
4685 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4687 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4688 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4689 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4691 /* blit to analysis bitmap */
4692 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4694 if (is_1bpp) {
4695 /* convert 1bpp to 8bpp/24bpp */
4696 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4697 for (y = 0; y < height; y++) {
4698 for (x = 0; x < width; x++)
4699 if (src[x / 8] & masks[x % 8])
4700 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4701 src += glyph_bitmap.pitch;
4702 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4705 else {
4706 for (y = 0; y < height; y++) {
4707 for (x = 0; x < width; x++)
4708 if (src[x / 8] & masks[x % 8])
4709 dst[x] = DWRITE_ALPHA_MAX;
4710 src += get_dib_stride(width, 1);
4711 dst += analysis->bounds.right - analysis->bounds.left;
4715 else {
4716 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4717 for (y = 0; y < height; y++) {
4718 for (x = 0; x < width; x++)
4719 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4720 src += glyph_bitmap.pitch;
4721 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4725 heap_free(glyph_bitmap.buf);
4727 origin.x += advance->x;
4728 origin.y += advance->y;
4731 IDWriteFontFace3_Release(fontface2);
4733 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4735 /* we don't need this anymore */
4736 heap_free(analysis->glyphs);
4737 heap_free(analysis->advances);
4738 heap_free(analysis->advanceoffsets);
4739 heap_free(analysis->ascenderoffsets);
4740 IDWriteFontFace_Release(analysis->run.fontFace);
4742 analysis->glyphs = NULL;
4743 analysis->advances = NULL;
4744 analysis->advanceoffsets = NULL;
4745 analysis->ascenderoffsets = NULL;
4746 analysis->run.glyphIndices = NULL;
4747 analysis->run.fontFace = NULL;
4750 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4751 RECT const *bounds, BYTE *bitmap, UINT32 size)
4753 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4754 UINT32 required;
4755 RECT runbounds;
4757 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4759 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4760 return E_INVALIDARG;
4762 /* make sure buffer is large enough for requested texture type */
4763 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4764 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4765 required *= 3;
4767 if (size < required)
4768 return E_NOT_SUFFICIENT_BUFFER;
4770 /* validate requested texture type with rendering mode */
4771 switch (This->rendering_mode)
4773 case DWRITE_RENDERING_MODE_ALIASED:
4774 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4775 return DWRITE_E_UNSUPPORTEDOPERATION;
4776 break;
4777 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4778 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4779 case DWRITE_RENDERING_MODE_NATURAL:
4780 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4781 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4782 return DWRITE_E_UNSUPPORTEDOPERATION;
4783 break;
4784 default:
4788 memset(bitmap, 0, size);
4789 glyphrunanalysis_get_texturebounds(This, &runbounds);
4790 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4791 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4792 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4793 int dst_width = (bounds->right - bounds->left) * pixel_size;
4794 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4795 BYTE *src, *dst;
4796 int y;
4798 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4799 glyphrunanalysis_render(This, type);
4801 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4802 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4804 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4805 memcpy(dst, src, draw_width);
4806 src += src_width;
4807 dst += dst_width;
4811 return S_OK;
4814 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4815 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4817 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4819 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4821 if (!params)
4822 return E_INVALIDARG;
4824 switch (This->rendering_mode)
4826 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4827 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4829 UINT value = 0;
4830 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4831 *gamma = (FLOAT)value / 1000.0f;
4832 *contrast = 0.0f;
4833 *cleartypelevel = 1.0f;
4834 break;
4836 case DWRITE_RENDERING_MODE_ALIASED:
4837 case DWRITE_RENDERING_MODE_NATURAL:
4838 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4839 *gamma = IDWriteRenderingParams_GetGamma(params);
4840 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4841 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4842 break;
4843 default:
4847 return S_OK;
4850 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4851 glyphrunanalysis_QueryInterface,
4852 glyphrunanalysis_AddRef,
4853 glyphrunanalysis_Release,
4854 glyphrunanalysis_GetAlphaTextureBounds,
4855 glyphrunanalysis_CreateAlphaTexture,
4856 glyphrunanalysis_GetAlphaBlendParams
4859 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4861 if (is_vertical) {
4862 vec->x = 0.0f;
4863 vec->y = length;
4865 else {
4866 vec->x = length;
4867 vec->y = 0.0f;
4871 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4873 D2D_POINT_2F ret;
4874 ret.x = vec->x * m->m11 + vec->y * m->m21;
4875 ret.y = vec->x * m->m12 + vec->y * m->m22;
4876 *vec = ret;
4879 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
4881 struct dwrite_glyphrunanalysis *analysis;
4882 FLOAT rtl_factor;
4883 UINT32 i;
4885 *ret = NULL;
4887 /* check for valid rendering mode */
4888 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || desc->rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4889 return E_INVALIDARG;
4891 analysis = heap_alloc(sizeof(*analysis));
4892 if (!analysis)
4893 return E_OUTOFMEMORY;
4895 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4896 analysis->ref = 1;
4897 analysis->rendering_mode = desc->rendering_mode;
4898 analysis->flags = 0;
4899 analysis->bitmap = NULL;
4900 analysis->ppdip = desc->ppdip;
4901 analysis->origin.x = desc->origin_x * desc->ppdip;
4902 analysis->origin.y = desc->origin_y * desc->ppdip;
4903 SetRectEmpty(&analysis->bounds);
4904 analysis->run = *desc->run;
4905 IDWriteFontFace_AddRef(analysis->run.fontFace);
4906 analysis->glyphs = heap_alloc(desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
4907 analysis->advances = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advances));
4908 if (desc->run->glyphOffsets) {
4909 analysis->advanceoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advanceoffsets));
4910 analysis->ascenderoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->ascenderoffsets));
4912 else {
4913 analysis->advanceoffsets = NULL;
4914 analysis->ascenderoffsets = NULL;
4917 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && desc->run->glyphOffsets)) {
4918 heap_free(analysis->glyphs);
4919 heap_free(analysis->advances);
4920 heap_free(analysis->advanceoffsets);
4921 heap_free(analysis->ascenderoffsets);
4923 analysis->glyphs = NULL;
4924 analysis->advances = NULL;
4925 analysis->advanceoffsets = NULL;
4926 analysis->ascenderoffsets = NULL;
4928 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4929 return E_OUTOFMEMORY;
4932 /* check if transform is usable */
4933 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
4934 analysis->m = *desc->transform;
4935 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4937 else
4938 memset(&analysis->m, 0, sizeof(analysis->m));
4940 analysis->run.glyphIndices = analysis->glyphs;
4941 analysis->run.glyphAdvances = NULL;
4942 analysis->run.glyphOffsets = NULL;
4944 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
4946 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4947 transform_2d_vec(&analysis->origin, &analysis->m);
4949 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
4951 if (desc->run->glyphAdvances) {
4952 for (i = 0; i < desc->run->glyphCount; i++) {
4953 init_2d_vec(analysis->advances + i, rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip, desc->run->isSideways);
4954 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4955 transform_2d_vec(analysis->advances + i, &analysis->m);
4958 else {
4959 DWRITE_FONT_METRICS metrics;
4960 IDWriteFontFace1 *fontface1;
4962 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
4963 IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4965 for (i = 0; i < desc->run->glyphCount; i++) {
4966 HRESULT hr;
4967 INT32 a;
4969 switch (desc->measuring_mode)
4971 case DWRITE_MEASURING_MODE_NATURAL:
4972 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a, desc->run->isSideways);
4973 if (FAILED(hr))
4974 a = 0;
4975 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip,
4976 desc->run->isSideways);
4977 break;
4978 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4979 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4980 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize, desc->ppdip, desc->transform,
4981 desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, desc->run->isSideways, 1, desc->run->glyphIndices + i, &a);
4982 if (FAILED(hr))
4983 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4984 else
4985 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f),
4986 desc->run->isSideways);
4987 break;
4988 default:
4992 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4993 transform_2d_vec(analysis->advances + i, &analysis->m);
4996 IDWriteFontFace1_Release(fontface1);
4999 if (desc->run->glyphOffsets) {
5000 for (i = 0; i < desc->run->glyphCount; i++) {
5001 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip, desc->run->isSideways);
5002 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
5003 init_2d_vec(analysis->ascenderoffsets + i, -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip, !desc->run->isSideways);
5004 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
5005 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
5006 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
5011 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5012 return S_OK;
5015 /* IDWriteColorGlyphRunEnumerator */
5016 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5018 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5020 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5022 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5023 IsEqualIID(riid, &IID_IUnknown))
5025 *ppv = iface;
5026 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5027 return S_OK;
5030 *ppv = NULL;
5031 return E_NOINTERFACE;
5034 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5036 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5037 ULONG ref = InterlockedIncrement(&This->ref);
5038 TRACE("(%p)->(%u)\n", This, ref);
5039 return ref;
5042 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5044 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5045 ULONG ref = InterlockedDecrement(&This->ref);
5047 TRACE("(%p)->(%u)\n", This, ref);
5049 if (!ref) {
5050 heap_free(This->advances);
5051 heap_free(This->color_advances);
5052 heap_free(This->offsets);
5053 heap_free(This->color_offsets);
5054 heap_free(This->glyphindices);
5055 heap_free(This->glyphs);
5056 if (This->colr.context)
5057 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
5058 IDWriteFontFace3_Release(This->fontface);
5059 heap_free(This);
5062 return ref;
5065 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5067 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5068 FLOAT origin = 0.0f;
5070 if (g == 0)
5071 return 0.0f;
5073 while (g--)
5074 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5075 return origin;
5078 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5080 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5081 FLOAT advance_adj = 0.0f;
5082 BOOL got_palette_index;
5083 UINT32 g;
5085 /* start with regular glyphs */
5086 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5087 UINT32 first_glyph = 0;
5089 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5090 if (glyphenum->glyphs[g].num_layers == 0) {
5091 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5092 first_glyph = min(first_glyph, g);
5094 else
5095 glyphenum->glyphindices[g] = 1;
5096 glyphenum->color_advances[g] = glyphenum->advances[g];
5097 if (glyphenum->color_offsets)
5098 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5101 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5102 colorrun->baselineOriginY = glyphenum->origin_y;
5103 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5104 colorrun->paletteIndex = 0xffff;
5105 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5106 glyphenum->has_regular_glyphs = FALSE;
5107 return TRUE;
5109 else {
5110 colorrun->glyphRun.glyphCount = 0;
5111 got_palette_index = FALSE;
5114 advance_adj = 0.0f;
5115 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5117 glyphenum->glyphindices[g] = 1;
5119 /* all glyph layers were returned */
5120 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5121 advance_adj += glyphenum->advances[g];
5122 continue;
5125 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5126 UINT32 index = colorrun->glyphRun.glyphCount;
5127 if (!got_palette_index) {
5128 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5129 /* use foreground color or request one from the font */
5130 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5131 if (colorrun->paletteIndex != 0xffff) {
5132 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5133 1, &colorrun->runColor);
5134 if (FAILED(hr))
5135 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5136 glyphenum->palette, colorrun->paletteIndex, hr);
5138 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5139 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5140 colorrun->baselineOriginY = glyphenum->origin_y;
5141 glyphenum->color_advances[index] = glyphenum->advances[g];
5142 got_palette_index = TRUE;
5145 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5146 /* offsets are relative to glyph origin, nothing to fix up */
5147 if (glyphenum->color_offsets)
5148 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5149 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5150 if (index)
5151 glyphenum->color_advances[index-1] += advance_adj;
5152 colorrun->glyphRun.glyphCount++;
5153 advance_adj = 0.0f;
5155 else
5156 advance_adj += glyphenum->advances[g];
5159 /* reset last advance */
5160 if (colorrun->glyphRun.glyphCount)
5161 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5163 return colorrun->glyphRun.glyphCount > 0;
5166 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5168 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5170 TRACE("(%p)->(%p)\n", This, has_run);
5172 *has_run = FALSE;
5174 This->colorrun.glyphRun.glyphCount = 0;
5175 while (This->current_layer < This->max_layer_num) {
5176 if (colorglyphenum_build_color_run(This))
5177 break;
5178 else
5179 This->current_layer++;
5182 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5184 return S_OK;
5187 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5189 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5191 TRACE("(%p)->(%p)\n", This, run);
5193 if (This->colorrun.glyphRun.glyphCount == 0) {
5194 *run = NULL;
5195 return E_NOT_VALID_STATE;
5198 *run = &This->colorrun;
5199 return S_OK;
5202 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5203 colorglyphenum_QueryInterface,
5204 colorglyphenum_AddRef,
5205 colorglyphenum_Release,
5206 colorglyphenum_MoveNext,
5207 colorglyphenum_GetCurrentRun
5210 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5211 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5213 struct dwrite_colorglyphenum *colorglyphenum;
5214 BOOL colorfont, has_colored_glyph;
5215 IDWriteFontFace3 *fontface3;
5216 HRESULT hr;
5217 UINT32 i;
5219 *ret = NULL;
5221 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5222 if (FAILED(hr)) {
5223 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5224 return hr;
5227 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5228 if (!colorfont) {
5229 hr = DWRITE_E_NOCOLOR;
5230 goto failed;
5233 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5234 if (!colorglyphenum) {
5235 hr = E_OUTOFMEMORY;
5236 goto failed;
5239 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5240 colorglyphenum->ref = 1;
5241 colorglyphenum->origin_x = originX;
5242 colorglyphenum->origin_y = originY;
5243 colorglyphenum->fontface = fontface3;
5244 colorglyphenum->glyphs = NULL;
5245 colorglyphenum->run = *run;
5246 colorglyphenum->run.glyphIndices = NULL;
5247 colorglyphenum->run.glyphAdvances = NULL;
5248 colorglyphenum->run.glyphOffsets = NULL;
5249 colorglyphenum->palette = palette;
5250 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5251 colorglyphenum->colr.exists = TRUE;
5252 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5253 colorglyphenum->current_layer = 0;
5254 colorglyphenum->max_layer_num = 0;
5256 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5258 has_colored_glyph = FALSE;
5259 colorglyphenum->has_regular_glyphs = FALSE;
5260 for (i = 0; i < run->glyphCount; i++) {
5261 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5262 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5263 has_colored_glyph = TRUE;
5265 if (colorglyphenum->glyphs[i].num_layers == 0)
5266 colorglyphenum->has_regular_glyphs = TRUE;
5269 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5270 is supposed to proceed normally, like if font had no color info at all. */
5271 if (!has_colored_glyph) {
5272 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5273 return DWRITE_E_NOCOLOR;
5276 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5277 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5278 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5279 if (run->glyphOffsets) {
5280 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5281 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5282 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5285 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5286 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5287 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5288 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5290 if (run->glyphAdvances)
5291 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5292 else {
5293 DWRITE_FONT_METRICS metrics;
5295 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5296 for (i = 0; i < run->glyphCount; i++) {
5297 HRESULT hr;
5298 INT32 a;
5300 switch (measuring_mode)
5302 case DWRITE_MEASURING_MODE_NATURAL:
5303 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5304 if (FAILED(hr))
5305 a = 0;
5306 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5307 break;
5308 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5309 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5310 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5311 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5312 if (FAILED(hr))
5313 colorglyphenum->advances[i] = 0.0f;
5314 else
5315 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5316 break;
5317 default:
5323 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5324 return S_OK;
5326 failed:
5327 IDWriteFontFace3_Release(fontface3);
5328 return hr;
5331 /* IDWriteFontFaceReference */
5332 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5334 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5336 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5338 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5339 *obj = iface;
5340 IDWriteFontFaceReference_AddRef(iface);
5341 return S_OK;
5344 *obj = NULL;
5346 return E_NOINTERFACE;
5349 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5351 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5352 ULONG ref = InterlockedIncrement(&This->ref);
5353 TRACE("(%p)->(%u)\n", This, ref);
5354 return ref;
5357 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5359 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5360 ULONG ref = InterlockedDecrement(&This->ref);
5362 TRACE("(%p)->(%u)\n", This, ref);
5364 if (!ref) {
5365 IDWriteFontFile_Release(This->file);
5366 IDWriteFactory3_Release(This->factory);
5367 heap_free(This);
5370 return ref;
5373 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5375 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5377 TRACE("(%p)->(%p)\n", This, fontface);
5379 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5382 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5383 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5385 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5386 DWRITE_FONT_FILE_TYPE file_type;
5387 DWRITE_FONT_FACE_TYPE face_type;
5388 IDWriteFontFace *fontface;
5389 BOOL is_supported;
5390 UINT32 face_num;
5391 HRESULT hr;
5393 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5395 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5396 if (FAILED(hr))
5397 return hr;
5399 hr = IDWriteFactory3_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5400 if (SUCCEEDED(hr)) {
5401 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)ret);
5402 IDWriteFontFace_Release(fontface);
5405 return hr;
5408 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5410 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5411 IDWriteFontFile *file;
5412 BOOL ret;
5414 TRACE("(%p)->(%p)\n", This, ref);
5416 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5417 return FALSE;
5419 ret = is_same_fontfile(This->file, file);
5420 IDWriteFontFile_Release(file);
5422 return ret;
5425 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5427 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5429 TRACE("(%p)\n", This);
5431 return This->index;
5434 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5436 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5438 TRACE("(%p)\n", This);
5440 return This->simulations;
5443 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5445 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5446 IDWriteFontFileLoader *loader;
5447 const void *key;
5448 UINT32 key_size;
5449 HRESULT hr;
5451 TRACE("(%p)->(%p)\n", This, file);
5453 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5454 if (FAILED(hr))
5455 return hr;
5457 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5458 if (FAILED(hr))
5459 return hr;
5461 hr = IDWriteFactory3_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5462 IDWriteFontFileLoader_Release(loader);
5464 return hr;
5467 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5469 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5471 FIXME("(%p): stub\n", This);
5473 return 0;
5476 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5478 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5480 FIXME("(%p): stub\n", This);
5482 return 0;
5485 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5487 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5489 FIXME("(%p)->(%p): stub\n", This, writetime);
5491 return E_NOTIMPL;
5494 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5496 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5498 FIXME("(%p): stub\n", This);
5500 return DWRITE_LOCALITY_LOCAL;
5503 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5505 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5507 FIXME("(%p): stub\n", This);
5509 return E_NOTIMPL;
5512 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5513 UINT32 count)
5515 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5517 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5519 return E_NOTIMPL;
5522 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5523 UINT32 count)
5525 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5527 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5529 return E_NOTIMPL;
5532 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5533 UINT64 offset, UINT64 size)
5535 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5537 FIXME("(%p)->(%s %s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5539 return E_NOTIMPL;
5542 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5543 fontfacereference_QueryInterface,
5544 fontfacereference_AddRef,
5545 fontfacereference_Release,
5546 fontfacereference_CreateFontFace,
5547 fontfacereference_CreateFontFaceWithSimulations,
5548 fontfacereference_Equals,
5549 fontfacereference_GetFontFaceIndex,
5550 fontfacereference_GetSimulations,
5551 fontfacereference_GetFontFile,
5552 fontfacereference_GetLocalFileSize,
5553 fontfacereference_GetFileSize,
5554 fontfacereference_GetFileTime,
5555 fontfacereference_GetLocality,
5556 fontfacereference_EnqueueFontDownloadRequest,
5557 fontfacereference_EnqueueCharacterDownloadRequest,
5558 fontfacereference_EnqueueGlyphDownloadRequest,
5559 fontfacereference_EnqueueFileFragmentDownloadRequest
5562 HRESULT create_fontfacereference(IDWriteFactory3 *factory, IDWriteFontFile *file, UINT32 index,
5563 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5565 struct dwrite_fontfacereference *ref;
5567 *ret = NULL;
5569 ref = heap_alloc(sizeof(*ref));
5570 if (!ref)
5571 return E_OUTOFMEMORY;
5573 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
5574 ref->ref = 1;
5576 ref->factory = factory;
5577 IDWriteFactory3_AddRef(ref->factory);
5578 ref->file = file;
5579 IDWriteFontFile_AddRef(ref->file);
5580 ref->index = index;
5581 ref->simulations = simulations;
5582 *ret = &ref->IDWriteFontFaceReference_iface;
5584 return S_OK;