mshtml/tests: A spelling fix for a dom ok() message.
[wine.git] / dlls / dwrite / font.c
blob2a2f39fffbe0287d9460a26db4a85ae7f28b30a6
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);
616 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
618 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
621 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace3 *iface, void *table_context)
623 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
625 TRACE("(%p)->(%p)\n", This, table_context);
627 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
630 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace3 *iface, FLOAT emSize,
631 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
632 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
634 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
636 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
637 count, is_sideways, is_rtl, sink);
639 if (!glyphs || !sink)
640 return E_INVALIDARG;
642 if (is_sideways)
643 FIXME("sideways mode is not supported.\n");
645 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
648 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
649 FLOAT ppem, WORD gasp)
651 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
653 switch (measuring)
655 case DWRITE_MEASURING_MODE_NATURAL:
657 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
658 mode = DWRITE_RENDERING_MODE_NATURAL;
659 else
660 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
661 break;
663 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
664 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
665 break;
666 case DWRITE_MEASURING_MODE_GDI_NATURAL:
667 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
668 break;
669 default:
673 return mode;
676 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
677 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
679 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
680 WORD gasp, *ptr;
681 UINT32 size;
682 FLOAT ppem;
684 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
686 if (!params) {
687 *mode = DWRITE_RENDERING_MODE_DEFAULT;
688 return E_INVALIDARG;
691 *mode = IDWriteRenderingParams_GetRenderingMode(params);
692 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
693 return S_OK;
695 ppem = emSize * ppdip;
697 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
698 *mode = DWRITE_RENDERING_MODE_OUTLINE;
699 return S_OK;
702 ptr = get_fontface_gasp(This, &size);
703 gasp = opentype_get_gasp_flags(ptr, size, ppem);
704 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
705 return S_OK;
708 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT pixels_per_dip,
709 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
711 DWRITE_FONT_METRICS1 metrics1;
712 HRESULT hr = IDWriteFontFace3_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
713 memcpy(metrics, &metrics1, sizeof(*metrics));
714 return hr;
717 static inline int round_metric(FLOAT metric)
719 return (int)floorf(metric + 0.5f);
722 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT ppdip,
723 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
724 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
726 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
727 DWRITE_MEASURING_MODE mode;
728 FLOAT scale, size;
729 HRESULT hr;
730 UINT32 i;
732 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
733 glyph_count, metrics, is_sideways);
735 if (m && memcmp(m, &identity, sizeof(*m)))
736 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
738 size = emSize * ppdip;
739 scale = size / This->metrics.designUnitsPerEm;
740 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
742 for (i = 0; i < glyph_count; i++) {
743 DWRITE_GLYPH_METRICS *ret = metrics + i;
744 DWRITE_GLYPH_METRICS design;
746 hr = IDWriteFontFace3_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
747 if (FAILED(hr))
748 return hr;
750 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
751 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
753 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
754 SCALE_METRIC(leftSideBearing);
755 SCALE_METRIC(rightSideBearing);
756 SCALE_METRIC(topSideBearing);
757 SCALE_METRIC(advanceHeight);
758 SCALE_METRIC(bottomSideBearing);
759 SCALE_METRIC(verticalOriginY);
760 #undef SCALE_METRIC
763 return S_OK;
766 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS1 *metrics)
768 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
769 TRACE("(%p)->(%p)\n", This, metrics);
770 *metrics = This->metrics;
773 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT em_size, FLOAT pixels_per_dip,
774 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
776 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
777 const DWRITE_FONT_METRICS1 *design = &This->metrics;
778 UINT16 ascent, descent;
779 FLOAT scale;
781 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
783 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
784 memset(metrics, 0, sizeof(*metrics));
785 return E_INVALIDARG;
788 em_size *= pixels_per_dip;
789 if (m && m->m22 != 0.0f)
790 em_size *= fabs(m->m22);
792 scale = em_size / design->designUnitsPerEm;
793 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
794 ascent = round_metric(design->ascent * scale);
795 descent = round_metric(design->descent * scale);
798 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
799 metrics->designUnitsPerEm = design->designUnitsPerEm;
800 metrics->ascent = round_metric(ascent / scale);
801 metrics->descent = round_metric(descent / scale);
803 SCALE_METRIC(lineGap);
804 SCALE_METRIC(capHeight);
805 SCALE_METRIC(xHeight);
806 SCALE_METRIC(underlinePosition);
807 SCALE_METRIC(underlineThickness);
808 SCALE_METRIC(strikethroughPosition);
809 SCALE_METRIC(strikethroughThickness);
810 SCALE_METRIC(glyphBoxLeft);
811 SCALE_METRIC(glyphBoxTop);
812 SCALE_METRIC(glyphBoxRight);
813 SCALE_METRIC(glyphBoxBottom);
814 SCALE_METRIC(subscriptPositionX);
815 SCALE_METRIC(subscriptPositionY);
816 SCALE_METRIC(subscriptSizeX);
817 SCALE_METRIC(subscriptSizeY);
818 SCALE_METRIC(superscriptPositionX);
819 SCALE_METRIC(superscriptPositionY);
820 SCALE_METRIC(superscriptSizeX);
821 SCALE_METRIC(superscriptSizeY);
823 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
824 #undef SCALE_METRIC
826 return S_OK;
829 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace3 *iface, DWRITE_CARET_METRICS *metrics)
831 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
832 TRACE("(%p)->(%p)\n", This, metrics);
833 *metrics = This->caret;
836 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace3 *iface, UINT32 max_count,
837 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
839 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
841 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
843 *count = 0;
844 if (max_count && !ranges)
845 return E_INVALIDARG;
847 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
850 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
852 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
853 TRACE("(%p)\n", This);
854 return This->is_monospaced;
857 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
858 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
860 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
861 UINT32 i;
863 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
865 if (is_sideways)
866 FIXME("sideways mode not supported\n");
868 for (i = 0; i < glyph_count; i++)
869 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
871 return S_OK;
874 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3 *iface,
875 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
876 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
878 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
879 DWRITE_MEASURING_MODE mode;
880 UINT32 i;
882 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
883 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
885 if (em_size < 0.0f || ppdip <= 0.0f) {
886 memset(advances, 0, sizeof(*advances) * glyph_count);
887 return E_INVALIDARG;
890 em_size *= ppdip;
891 if (em_size == 0.0f) {
892 memset(advances, 0, sizeof(*advances) * glyph_count);
893 return S_OK;
896 if (m && memcmp(m, &identity, sizeof(*m)))
897 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
899 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
900 for (i = 0; i < glyph_count; i++) {
901 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
902 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
905 return S_OK;
908 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3 *iface, UINT32 count,
909 const UINT16 *indices, INT32 *adjustments)
911 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
912 UINT32 i;
914 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
916 if (!(indices || adjustments) || !count)
917 return E_INVALIDARG;
919 if (!indices || count == 1) {
920 memset(adjustments, 0, count*sizeof(INT32));
921 return E_INVALIDARG;
924 if (!This->has_kerning_pairs) {
925 memset(adjustments, 0, count*sizeof(INT32));
926 return S_OK;
929 for (i = 0; i < count-1; i++)
930 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
931 adjustments[count-1] = 0;
933 return S_OK;
936 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
938 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
939 TRACE("(%p)\n", This);
940 return This->has_kerning_pairs;
943 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
944 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
945 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
947 DWRITE_GRID_FIT_MODE gridfitmode;
948 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
949 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
952 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3 *iface, UINT32 glyph_count,
953 const UINT16 *nominal_indices, UINT16 *vertical_indices)
955 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
956 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
957 return E_NOTIMPL;
960 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
962 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
963 FIXME("(%p): stub\n", This);
964 return FALSE;
967 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
969 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
970 TRACE("(%p)\n", This);
971 return get_fontface_cpal(This) && get_fontface_colr(This);
974 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace3 *iface)
976 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
977 TRACE("(%p)\n", This);
978 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
981 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3 *iface)
983 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
984 TRACE("(%p)\n", This);
985 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
988 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace3 *iface, UINT32 palette_index,
989 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
991 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
992 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
993 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
996 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
997 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
998 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
999 DWRITE_GRID_FIT_MODE *gridfitmode)
1001 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1002 FLOAT emthreshold;
1003 WORD gasp, *ptr;
1004 UINT32 size;
1006 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1007 measuringmode, params, renderingmode, gridfitmode);
1009 if (m)
1010 FIXME("transform not supported %s\n", debugstr_matrix(m));
1012 if (is_sideways)
1013 FIXME("sideways mode not supported\n");
1015 emSize *= max(dpiX, dpiY) / 96.0f;
1017 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1018 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1019 if (params) {
1020 IDWriteRenderingParams2 *params2;
1021 HRESULT hr;
1023 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1024 if (hr == S_OK) {
1025 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1026 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1027 IDWriteRenderingParams2_Release(params2);
1029 else
1030 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1033 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1035 ptr = get_fontface_gasp(This, &size);
1036 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1038 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1039 if (emSize >= emthreshold)
1040 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1041 else
1042 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1045 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1046 if (emSize >= emthreshold)
1047 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1048 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1049 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1050 else
1051 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1054 return S_OK;
1057 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace3 *iface, IDWriteFontFaceReference **ref)
1059 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1060 FIXME("(%p)->(%p): stub\n", This, ref);
1061 return E_NOTIMPL;
1064 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace3 *iface, DWRITE_PANOSE *panose)
1066 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1067 FIXME("(%p)->(%p): stub\n", This, panose);
1070 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace3 *iface)
1072 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1073 FIXME("(%p): stub\n", This);
1074 return DWRITE_FONT_WEIGHT_NORMAL;
1077 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace3 *iface)
1079 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1080 FIXME("(%p): stub\n", This);
1081 return DWRITE_FONT_STRETCH_NORMAL;
1084 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace3 *iface)
1086 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1087 FIXME("(%p): stub\n", This);
1088 return DWRITE_FONT_STYLE_NORMAL;
1091 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1093 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1094 FIXME("(%p)->(%p): stub\n", This, names);
1095 return E_NOTIMPL;
1098 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1100 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1101 FIXME("(%p)->(%p): stub\n", This, names);
1102 return E_NOTIMPL;
1105 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace3 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1106 IDWriteLocalizedStrings **strings, BOOL *exists)
1108 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1109 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1110 return E_NOTIMPL;
1113 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace3 *iface, UINT32 ch)
1115 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1116 UINT16 index;
1117 HRESULT hr;
1119 TRACE("(%p)->(0x%08x)\n", This, ch);
1121 index = 0;
1122 hr = IDWriteFontFace3_GetGlyphIndices(iface, &ch, 1, &index);
1123 if (FAILED(hr))
1124 return FALSE;
1126 return index != 0;
1129 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emsize, FLOAT dpi_x, FLOAT dpi_y,
1130 DWRITE_MATRIX const *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1131 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1133 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1134 FIXME("(%p)->(%f %f %f %p %d %u %u %p %p %p): stub\n", This, emsize, dpi_x, dpi_y, transform, is_sideways, threshold,
1135 measuring_mode, params, rendering_mode, gridfit_mode);
1136 return E_NOTIMPL;
1139 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace3 *iface, UINT32 ch)
1141 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1142 FIXME("(%p)->(0x%x): stub\n", This, ch);
1143 return FALSE;
1146 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace3 *iface, UINT16 glyph)
1148 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1149 FIXME("(%p)->(%u): stub\n", This, glyph);
1150 return FALSE;
1153 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace3 *iface, WCHAR const *text,
1154 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1156 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1157 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1158 return E_NOTIMPL;
1161 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace3 *iface, UINT16 const *glyphs,
1162 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1164 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1165 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1166 return E_NOTIMPL;
1169 static const IDWriteFontFace3Vtbl dwritefontfacevtbl = {
1170 dwritefontface_QueryInterface,
1171 dwritefontface_AddRef,
1172 dwritefontface_Release,
1173 dwritefontface_GetType,
1174 dwritefontface_GetFiles,
1175 dwritefontface_GetIndex,
1176 dwritefontface_GetSimulations,
1177 dwritefontface_IsSymbolFont,
1178 dwritefontface_GetMetrics,
1179 dwritefontface_GetGlyphCount,
1180 dwritefontface_GetDesignGlyphMetrics,
1181 dwritefontface_GetGlyphIndices,
1182 dwritefontface_TryGetFontTable,
1183 dwritefontface_ReleaseFontTable,
1184 dwritefontface_GetGlyphRunOutline,
1185 dwritefontface_GetRecommendedRenderingMode,
1186 dwritefontface_GetGdiCompatibleMetrics,
1187 dwritefontface_GetGdiCompatibleGlyphMetrics,
1188 dwritefontface1_GetMetrics,
1189 dwritefontface1_GetGdiCompatibleMetrics,
1190 dwritefontface1_GetCaretMetrics,
1191 dwritefontface1_GetUnicodeRanges,
1192 dwritefontface1_IsMonospacedFont,
1193 dwritefontface1_GetDesignGlyphAdvances,
1194 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1195 dwritefontface1_GetKerningPairAdjustments,
1196 dwritefontface1_HasKerningPairs,
1197 dwritefontface1_GetRecommendedRenderingMode,
1198 dwritefontface1_GetVerticalGlyphVariants,
1199 dwritefontface1_HasVerticalGlyphVariants,
1200 dwritefontface2_IsColorFont,
1201 dwritefontface2_GetColorPaletteCount,
1202 dwritefontface2_GetPaletteEntryCount,
1203 dwritefontface2_GetPaletteEntries,
1204 dwritefontface2_GetRecommendedRenderingMode,
1205 dwritefontface3_GetFontFaceReference,
1206 dwritefontface3_GetPanose,
1207 dwritefontface3_GetWeight,
1208 dwritefontface3_GetStretch,
1209 dwritefontface3_GetStyle,
1210 dwritefontface3_GetFamilyNames,
1211 dwritefontface3_GetFaceNames,
1212 dwritefontface3_GetInformationalStrings,
1213 dwritefontface3_HasCharacter,
1214 dwritefontface3_GetRecommendedRenderingMode,
1215 dwritefontface3_IsCharacterLocal,
1216 dwritefontface3_IsGlyphLocal,
1217 dwritefontface3_AreCharactersLocal,
1218 dwritefontface3_AreGlyphsLocal
1221 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace3 **fontface)
1223 struct dwrite_font_data *data = font->data;
1224 IDWriteFontFace *face;
1225 HRESULT hr;
1227 *fontface = NULL;
1229 hr = IDWriteFactory3_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1230 data->face_index, font->data->simulations, &face);
1231 if (FAILED(hr))
1232 return hr;
1234 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void**)fontface);
1235 IDWriteFontFace_Release(face);
1237 return hr;
1240 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1242 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1244 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1246 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1247 IsEqualIID(riid, &IID_IDWriteFont2) ||
1248 IsEqualIID(riid, &IID_IDWriteFont1) ||
1249 IsEqualIID(riid, &IID_IDWriteFont) ||
1250 IsEqualIID(riid, &IID_IUnknown))
1252 *obj = iface;
1253 IDWriteFont3_AddRef(iface);
1254 return S_OK;
1257 *obj = NULL;
1258 return E_NOINTERFACE;
1261 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1263 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1264 ULONG ref = InterlockedIncrement(&This->ref);
1265 TRACE("(%p)->(%d)\n", This, ref);
1266 return ref;
1269 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1271 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1272 ULONG ref = InterlockedDecrement(&This->ref);
1274 TRACE("(%p)->(%d)\n", This, ref);
1276 if (!ref) {
1277 IDWriteFontFamily1_Release(This->family);
1278 release_font_data(This->data);
1279 heap_free(This);
1282 return ref;
1285 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1287 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1288 TRACE("(%p)->(%p)\n", This, family);
1290 *family = (IDWriteFontFamily*)This->family;
1291 IDWriteFontFamily_AddRef(*family);
1292 return S_OK;
1295 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1297 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1298 TRACE("(%p)\n", This);
1299 return This->data->weight;
1302 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1304 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1305 TRACE("(%p)\n", This);
1306 return This->data->stretch;
1309 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1311 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1312 TRACE("(%p)\n", This);
1313 return This->style;
1316 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1318 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1319 IDWriteFontFace3 *fontface;
1320 HRESULT hr;
1322 TRACE("(%p)\n", This);
1324 hr = get_fontface_from_font(This, &fontface);
1325 if (FAILED(hr))
1326 return FALSE;
1328 return IDWriteFontFace3_IsSymbolFont(fontface);
1331 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1333 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1334 TRACE("(%p)->(%p)\n", This, names);
1335 return clone_localizedstring(This->data->names, names);
1338 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1339 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1341 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1342 struct dwrite_font_data *data = This->data;
1343 HRESULT hr;
1345 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1347 *exists = FALSE;
1348 *strings = NULL;
1350 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1351 return S_OK;
1353 if (!data->info_strings[stringid]) {
1354 IDWriteFontFace3 *fontface;
1355 const void *table_data;
1356 BOOL table_exists;
1357 void *context;
1358 UINT32 size;
1360 hr = get_fontface_from_font(This, &fontface);
1361 if (FAILED(hr))
1362 return hr;
1364 table_exists = FALSE;
1365 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1366 if (FAILED(hr) || !table_exists)
1367 WARN("no NAME table found.\n");
1369 if (table_exists) {
1370 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1371 if (FAILED(hr) || !data->info_strings[stringid])
1372 return hr;
1373 IDWriteFontFace3_ReleaseFontTable(fontface, context);
1377 hr = clone_localizedstring(data->info_strings[stringid], strings);
1378 if (FAILED(hr))
1379 return hr;
1381 *exists = TRUE;
1382 return S_OK;
1385 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1387 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1388 TRACE("(%p)\n", This);
1389 return This->data->simulations;
1392 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1394 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1396 TRACE("(%p)->(%p)\n", This, metrics);
1397 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1400 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1402 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1403 IDWriteFontFace3 *fontface;
1404 UINT16 index;
1405 HRESULT hr;
1407 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1409 *exists = FALSE;
1411 hr = get_fontface_from_font(This, &fontface);
1412 if (FAILED(hr))
1413 return hr;
1415 index = 0;
1416 hr = IDWriteFontFace3_GetGlyphIndices(fontface, &value, 1, &index);
1417 if (FAILED(hr))
1418 return hr;
1420 *exists = index != 0;
1421 return S_OK;
1424 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **face)
1426 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1427 HRESULT hr;
1429 TRACE("(%p)->(%p)\n", This, face);
1431 hr = get_fontface_from_font(This, (IDWriteFontFace3**)face);
1432 if (hr == S_OK)
1433 IDWriteFontFace_AddRef(*face);
1435 return hr;
1438 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1440 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1441 TRACE("(%p)->(%p)\n", This, metrics);
1442 *metrics = This->data->metrics;
1445 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1447 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1448 TRACE("(%p)->(%p)\n", This, panose);
1449 *panose = This->data->panose;
1452 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1454 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1455 IDWriteFontFace3 *fontface;
1456 HRESULT hr;
1458 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1460 hr = get_fontface_from_font(This, &fontface);
1461 if (FAILED(hr))
1462 return hr;
1464 return IDWriteFontFace3_GetUnicodeRanges(fontface, max_count, ranges, count);
1467 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1469 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1470 IDWriteFontFace3 *fontface;
1471 HRESULT hr;
1473 TRACE("(%p)\n", This);
1475 hr = get_fontface_from_font(This, &fontface);
1476 if (FAILED(hr))
1477 return FALSE;
1479 return IDWriteFontFace3_IsMonospacedFont(fontface);
1482 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1484 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1485 IDWriteFontFace3 *fontface;
1486 HRESULT hr;
1488 TRACE("(%p)\n", This);
1490 hr = get_fontface_from_font(This, &fontface);
1491 if (FAILED(hr))
1492 return FALSE;
1494 return IDWriteFontFace3_IsColorFont(fontface);
1497 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1499 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1500 FIXME("(%p)->(%p): stub\n", This, fontface);
1501 return E_NOTIMPL;
1504 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1506 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1507 FIXME("(%p)->(%p): stub\n", This, font);
1508 return FALSE;
1511 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1513 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1515 TRACE("(%p)->(%p)\n", This, reference);
1517 return IDWriteFactory3_CreateFontFaceReference_(This->data->factory, This->data->file, This->data->face_index,
1518 This->data->simulations, reference);
1521 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1523 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1524 BOOL ret;
1526 TRACE("(%p)->(0x%x)\n", This, ch);
1528 IDWriteFont_HasCharacter((IDWriteFont*)iface, ch, &ret);
1529 return ret;
1532 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1534 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1535 FIXME("(%p): stub\n", This);
1536 return DWRITE_LOCALITY_LOCAL;
1539 static const IDWriteFont3Vtbl dwritefontvtbl = {
1540 dwritefont_QueryInterface,
1541 dwritefont_AddRef,
1542 dwritefont_Release,
1543 dwritefont_GetFontFamily,
1544 dwritefont_GetWeight,
1545 dwritefont_GetStretch,
1546 dwritefont_GetStyle,
1547 dwritefont_IsSymbolFont,
1548 dwritefont_GetFaceNames,
1549 dwritefont_GetInformationalStrings,
1550 dwritefont_GetSimulations,
1551 dwritefont_GetMetrics,
1552 dwritefont_HasCharacter,
1553 dwritefont_CreateFontFace,
1554 dwritefont1_GetMetrics,
1555 dwritefont1_GetPanose,
1556 dwritefont1_GetUnicodeRanges,
1557 dwritefont1_IsMonospacedFont,
1558 dwritefont2_IsColorFont,
1559 dwritefont3_CreateFontFace,
1560 dwritefont3_Equals,
1561 dwritefont3_GetFontFaceReference,
1562 dwritefont3_HasCharacter,
1563 dwritefont3_GetLocality
1566 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily1 *family, IDWriteFont3 **font)
1568 struct dwrite_font *This;
1569 *font = NULL;
1571 This = heap_alloc(sizeof(struct dwrite_font));
1572 if (!This) return E_OUTOFMEMORY;
1574 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1575 This->ref = 1;
1576 This->family = family;
1577 IDWriteFontFamily1_AddRef(family);
1578 This->style = data->style;
1579 This->data = data;
1580 InterlockedIncrement(&This->data->ref);
1582 *font = &This->IDWriteFont3_iface;
1584 return S_OK;
1587 /* IDWriteFontList1 */
1588 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1590 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1592 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1594 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1595 IsEqualIID(riid, &IID_IDWriteFontList) ||
1596 IsEqualIID(riid, &IID_IUnknown))
1598 *obj = iface;
1599 IDWriteFontList1_AddRef(iface);
1600 return S_OK;
1603 *obj = NULL;
1604 return E_NOINTERFACE;
1607 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1609 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1610 ULONG ref = InterlockedIncrement(&This->ref);
1611 TRACE("(%p)->(%d)\n", This, ref);
1612 return ref;
1615 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1617 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1618 ULONG ref = InterlockedDecrement(&This->ref);
1620 TRACE("(%p)->(%d)\n", This, ref);
1622 if (!ref) {
1623 UINT32 i;
1625 for (i = 0; i < This->font_count; i++)
1626 release_font_data(This->fonts[i]);
1627 IDWriteFontFamily1_Release(This->family);
1628 heap_free(This);
1631 return ref;
1634 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1636 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1637 return IDWriteFontFamily1_GetFontCollection(This->family, collection);
1640 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1642 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1643 TRACE("(%p)\n", This);
1644 return This->font_count;
1647 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1649 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1651 TRACE("(%p)->(%u %p)\n", This, index, font);
1653 *font = NULL;
1655 if (This->font_count == 0)
1656 return S_FALSE;
1658 if (index >= This->font_count)
1659 return E_INVALIDARG;
1661 return create_font(This->fonts[index], This->family, (IDWriteFont3**)font);
1664 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1666 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1668 FIXME("(%p)->(%u): stub\n", This, index);
1670 return DWRITE_LOCALITY_LOCAL;
1673 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1675 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1677 FIXME("(%p)->(%u %p): stub\n", This, index, font);
1679 return E_NOTIMPL;
1682 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1683 IDWriteFontFaceReference **reference)
1685 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1687 FIXME("(%p)->(%u %p): stub\n", This, index, reference);
1689 return E_NOTIMPL;
1692 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1693 dwritefontlist_QueryInterface,
1694 dwritefontlist_AddRef,
1695 dwritefontlist_Release,
1696 dwritefontlist_GetFontCollection,
1697 dwritefontlist_GetFontCount,
1698 dwritefontlist_GetFont,
1699 dwritefontlist1_GetFontLocality,
1700 dwritefontlist1_GetFont,
1701 dwritefontlist1_GetFontFaceReference
1704 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1706 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1708 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1710 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1711 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1712 IsEqualIID(riid, &IID_IDWriteFontList) ||
1713 IsEqualIID(riid, &IID_IUnknown))
1715 *obj = iface;
1716 IDWriteFontFamily1_AddRef(iface);
1717 return S_OK;
1720 *obj = NULL;
1721 return E_NOINTERFACE;
1724 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1726 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1727 ULONG ref = InterlockedIncrement(&This->ref);
1728 TRACE("(%p)->(%d)\n", This, ref);
1729 return ref;
1732 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1734 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1735 ULONG ref = InterlockedDecrement(&This->ref);
1737 TRACE("(%p)->(%d)\n", This, ref);
1739 if (!ref)
1741 IDWriteFontCollection1_Release(This->collection);
1742 release_fontfamily_data(This->data);
1743 heap_free(This);
1746 return ref;
1749 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1751 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1753 TRACE("(%p)->(%p)\n", This, collection);
1755 *collection = (IDWriteFontCollection*)This->collection;
1756 IDWriteFontCollection_AddRef(*collection);
1757 return S_OK;
1760 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1762 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1763 TRACE("(%p)\n", This);
1764 return This->data->font_count;
1767 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1769 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1771 TRACE("(%p)->(%u %p)\n", This, index, font);
1773 *font = NULL;
1775 if (This->data->font_count == 0)
1776 return S_FALSE;
1778 if (index >= This->data->font_count)
1779 return E_INVALIDARG;
1781 return create_font(This->data->fonts[index], iface, (IDWriteFont3**)font);
1784 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1786 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1787 return clone_localizedstring(This->data->familyname, names);
1790 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1791 const struct dwrite_font_propvec *req)
1793 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1794 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1795 FLOAT cur_req_prod, next_req_prod;
1797 if (next_to_req < cur_to_req)
1798 return TRUE;
1800 if (next_to_req > cur_to_req)
1801 return FALSE;
1803 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1804 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1806 if (next_req_prod > cur_req_prod)
1807 return TRUE;
1809 if (next_req_prod < cur_req_prod)
1810 return FALSE;
1812 if (next->stretch > cur->stretch)
1813 return TRUE;
1814 if (next->stretch < cur->stretch)
1815 return FALSE;
1817 if (next->style > cur->style)
1818 return TRUE;
1819 if (next->style < cur->style)
1820 return FALSE;
1822 if (next->weight > cur->weight)
1823 return TRUE;
1824 if (next->weight < cur->weight)
1825 return FALSE;
1827 /* full match, no reason to prefer new variant */
1828 return FALSE;
1831 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1832 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1834 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1835 struct dwrite_font_propvec req;
1836 struct dwrite_font_data *match;
1837 UINT32 i;
1839 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1841 if (This->data->font_count == 0) {
1842 *font = NULL;
1843 return DWRITE_E_NOFONT;
1846 init_font_prop_vec(weight, stretch, style, &req);
1847 match = This->data->fonts[0];
1849 for (i = 1; i < This->data->font_count; i++) {
1850 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1851 match = This->data->fonts[i];
1854 return create_font(match, iface, (IDWriteFont3**)font);
1857 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1859 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1861 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1864 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1866 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1869 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1871 UINT32 b = fonts->font_count - 1, j, t;
1873 while (1) {
1874 t = b;
1876 for (j = 0; j < b; j++) {
1877 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1878 struct dwrite_font_data *s = fonts->fonts[j];
1879 fonts->fonts[j] = fonts->fonts[j+1];
1880 fonts->fonts[j+1] = s;
1881 t = j;
1885 if (t == b)
1886 break;
1887 b = t;
1891 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1892 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1894 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1895 matching_filter_func func = NULL;
1896 struct dwrite_font_propvec req;
1897 struct dwrite_fontlist *fonts;
1898 UINT32 i;
1900 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1902 *ret = NULL;
1904 fonts = heap_alloc(sizeof(*fonts));
1905 if (!fonts)
1906 return E_OUTOFMEMORY;
1908 /* Allocate as many as family has, not all of them will be necessary used. */
1909 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1910 if (!fonts->fonts) {
1911 heap_free(fonts);
1912 return E_OUTOFMEMORY;
1915 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
1916 fonts->ref = 1;
1917 fonts->family = iface;
1918 IDWriteFontFamily1_AddRef(fonts->family);
1919 fonts->font_count = 0;
1921 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1922 if (style == DWRITE_FONT_STYLE_NORMAL) {
1923 if (This->data->has_normal_face || This->data->has_italic_face)
1924 func = is_font_acceptable_for_normal;
1926 else /* requested oblique or italic */ {
1927 if (This->data->has_oblique_face || This->data->has_italic_face)
1928 func = is_font_acceptable_for_oblique_italic;
1931 for (i = 0; i < This->data->font_count; i++) {
1932 if (!func || func(This->data->fonts[i])) {
1933 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1934 InterlockedIncrement(&This->data->fonts[i]->ref);
1935 fonts->font_count++;
1939 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1940 init_font_prop_vec(weight, stretch, style, &req);
1941 matchingfonts_sort(fonts, &req);
1943 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
1944 return S_OK;
1947 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
1949 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1951 FIXME("(%p)->(%u): stub\n", This, index);
1953 return DWRITE_LOCALITY_LOCAL;
1956 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
1958 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1960 TRACE("(%p)->(%u %p)\n", This, index, font);
1962 *font = NULL;
1964 if (This->data->font_count == 0)
1965 return S_FALSE;
1967 if (index >= This->data->font_count)
1968 return E_FAIL;
1970 return create_font(This->data->fonts[index], iface, font);
1973 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
1974 IDWriteFontFaceReference **ref)
1976 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1978 FIXME("(%p)->(%u %p): stub\n", This, index, ref);
1980 return E_NOTIMPL;
1983 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
1984 dwritefontfamily_QueryInterface,
1985 dwritefontfamily_AddRef,
1986 dwritefontfamily_Release,
1987 dwritefontfamily_GetFontCollection,
1988 dwritefontfamily_GetFontCount,
1989 dwritefontfamily_GetFont,
1990 dwritefontfamily_GetFamilyNames,
1991 dwritefontfamily_GetFirstMatchingFont,
1992 dwritefontfamily_GetMatchingFonts,
1993 dwritefontfamily1_GetFontLocality,
1994 dwritefontfamily1_GetFont,
1995 dwritefontfamily1_GetFontFaceReference
1998 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection1 *collection, IDWriteFontFamily1 **family)
2000 struct dwrite_fontfamily *This;
2002 *family = NULL;
2004 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2005 if (!This) return E_OUTOFMEMORY;
2007 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2008 This->ref = 1;
2009 This->collection = collection;
2010 IDWriteFontCollection1_AddRef(collection);
2011 This->data = data;
2012 InterlockedIncrement(&This->data->ref);
2014 *family = &This->IDWriteFontFamily1_iface;
2016 return S_OK;
2019 BOOL is_system_collection(IDWriteFontCollection *collection)
2021 void *obj;
2022 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2025 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2027 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2028 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2030 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2031 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2032 IsEqualIID(riid, &IID_IUnknown))
2034 *obj = iface;
2035 IDWriteFontCollection1_AddRef(iface);
2036 return S_OK;
2039 *obj = NULL;
2041 if (IsEqualIID(riid, &IID_issystemcollection))
2042 return S_OK;
2044 return E_NOINTERFACE;
2047 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2049 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2050 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2052 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2053 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2054 IsEqualIID(riid, &IID_IUnknown))
2056 *obj = iface;
2057 IDWriteFontCollection1_AddRef(iface);
2058 return S_OK;
2061 *obj = NULL;
2063 return E_NOINTERFACE;
2066 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2068 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2069 ULONG ref = InterlockedIncrement(&This->ref);
2070 TRACE("(%p)->(%d)\n", This, ref);
2071 return ref;
2074 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2076 unsigned int i;
2077 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2078 ULONG ref = InterlockedDecrement(&This->ref);
2079 TRACE("(%p)->(%d)\n", This, ref);
2081 if (!ref) {
2082 for (i = 0; i < This->family_count; i++)
2083 release_fontfamily_data(This->family_data[i]);
2084 heap_free(This->family_data);
2085 heap_free(This);
2088 return ref;
2091 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2093 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2094 TRACE("(%p)\n", This);
2095 return This->family_count;
2098 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2100 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2102 TRACE("(%p)->(%u %p)\n", This, index, family);
2104 if (index >= This->family_count) {
2105 *family = NULL;
2106 return E_FAIL;
2109 return create_fontfamily(This->family_data[index], iface, (IDWriteFontFamily1**)family);
2112 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2114 UINT32 i;
2116 for (i = 0; i < collection->family_count; i++) {
2117 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2118 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2119 HRESULT hr;
2121 for (j = 0; j < count; j++) {
2122 WCHAR buffer[255];
2123 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2124 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2125 return i;
2129 return ~0u;
2132 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2134 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2135 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2136 *index = collection_find_family(This, name);
2137 *exists = *index != ~0u;
2138 return S_OK;
2141 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2143 UINT32 left_key_size, right_key_size;
2144 const void *left_key, *right_key;
2145 HRESULT hr;
2147 if (left == right)
2148 return TRUE;
2150 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2151 if (FAILED(hr))
2152 return FALSE;
2154 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2155 if (FAILED(hr))
2156 return FALSE;
2158 if (left_key_size != right_key_size)
2159 return FALSE;
2161 return !memcmp(left_key, right_key, left_key_size);
2164 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2166 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2167 struct dwrite_fontfamily_data *found_family = NULL;
2168 struct dwrite_font_data *found_font = NULL;
2169 IDWriteFontFamily1 *family;
2170 UINT32 i, j, face_index;
2171 IDWriteFontFile *file;
2172 HRESULT hr;
2174 TRACE("(%p)->(%p %p)\n", This, face, font);
2176 *font = NULL;
2178 if (!face)
2179 return E_INVALIDARG;
2181 i = 1;
2182 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2183 if (FAILED(hr))
2184 return hr;
2185 face_index = IDWriteFontFace_GetIndex(face);
2187 for (i = 0; i < This->family_count; i++) {
2188 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2189 for (j = 0; j < family_data->font_count; j++) {
2190 struct dwrite_font_data *font_data = family_data->fonts[j];
2192 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2193 found_font = font_data;
2194 found_family = family_data;
2195 break;
2200 if (!found_font)
2201 return DWRITE_E_NOFONT;
2203 hr = create_fontfamily(found_family, iface, &family);
2204 if (FAILED(hr))
2205 return hr;
2207 hr = create_font(found_font, family, (IDWriteFont3**)font);
2208 IDWriteFontFamily1_Release(family);
2209 return hr;
2212 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2214 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2216 FIXME("(%p)->(%p): stub\n", This, fontset);
2218 return E_NOTIMPL;
2221 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2223 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2225 TRACE("(%p)->(%u %p)\n", This, index, family);
2227 if (index >= This->family_count) {
2228 *family = NULL;
2229 return E_FAIL;
2232 return create_fontfamily(This->family_data[index], iface, family);
2235 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2236 dwritefontcollection_QueryInterface,
2237 dwritefontcollection_AddRef,
2238 dwritefontcollection_Release,
2239 dwritefontcollection_GetFontFamilyCount,
2240 dwritefontcollection_GetFontFamily,
2241 dwritefontcollection_FindFamilyName,
2242 dwritefontcollection_GetFontFromFontFace,
2243 dwritefontcollection1_GetFontSet,
2244 dwritefontcollection1_GetFontFamily
2247 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2248 dwritesystemfontcollection_QueryInterface,
2249 dwritefontcollection_AddRef,
2250 dwritefontcollection_Release,
2251 dwritefontcollection_GetFontFamilyCount,
2252 dwritefontcollection_GetFontFamily,
2253 dwritefontcollection_FindFamilyName,
2254 dwritefontcollection_GetFontFromFontFace,
2255 dwritefontcollection1_GetFontSet,
2256 dwritefontcollection1_GetFontFamily
2259 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2261 if (family_data->font_count + 1 >= family_data->font_alloc) {
2262 struct dwrite_font_data **new_list;
2263 UINT32 new_alloc;
2265 new_alloc = family_data->font_alloc * 2;
2266 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2267 if (!new_list)
2268 return E_OUTOFMEMORY;
2269 family_data->fonts = new_list;
2270 family_data->font_alloc = new_alloc;
2273 family_data->fonts[family_data->font_count] = font_data;
2274 family_data->font_count++;
2275 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2276 family_data->has_normal_face = 1;
2277 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2278 family_data->has_oblique_face = 1;
2279 else
2280 family_data->has_italic_face = 1;
2281 return S_OK;
2284 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2286 if (collection->family_alloc < collection->family_count + 1) {
2287 struct dwrite_fontfamily_data **new_list;
2288 UINT32 new_alloc;
2290 new_alloc = collection->family_alloc * 2;
2291 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2292 if (!new_list)
2293 return E_OUTOFMEMORY;
2295 collection->family_alloc = new_alloc;
2296 collection->family_data = new_list;
2299 collection->family_data[collection->family_count] = family;
2300 collection->family_count++;
2302 return S_OK;
2305 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2307 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2308 collection->ref = 1;
2309 collection->family_count = 0;
2310 collection->family_alloc = is_system ? 30 : 5;
2311 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2312 if (!collection->family_data)
2313 return E_OUTOFMEMORY;
2315 return S_OK;
2318 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2320 IDWriteFontFileLoader *loader;
2321 const void *key;
2322 UINT32 key_size;
2323 HRESULT hr;
2325 *stream = NULL;
2327 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2328 if (FAILED(hr))
2329 return hr;
2331 hr = IDWriteFontFile_GetLoader(file, &loader);
2332 if (FAILED(hr))
2333 return hr;
2335 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2336 IDWriteFontFileLoader_Release(loader);
2337 if (FAILED(hr))
2338 return hr;
2340 return hr;
2343 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2345 BOOL exists = FALSE;
2346 UINT32 index;
2347 HRESULT hr;
2349 buffer[0] = 0;
2350 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2351 if (FAILED(hr) || !exists)
2352 return;
2354 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2357 static int trim_spaces(WCHAR *in, WCHAR *ret)
2359 int len;
2361 while (isspaceW(*in))
2362 in++;
2364 ret[0] = 0;
2365 if (!(len = strlenW(in)))
2366 return 0;
2368 while (isspaceW(in[len-1]))
2369 len--;
2371 memcpy(ret, in, len*sizeof(WCHAR));
2372 ret[len] = 0;
2374 return len;
2377 struct name_token {
2378 struct list entry;
2379 const WCHAR *ptr;
2380 INT len; /* token length */
2381 INT fulllen; /* full length including following separators */
2384 static inline BOOL is_name_separator_char(WCHAR ch)
2386 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2389 struct name_pattern {
2390 const WCHAR *part1; /* NULL indicates end of list */
2391 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2394 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2396 const struct name_pattern *pattern;
2397 struct name_token *token;
2398 int i = 0;
2400 while ((pattern = &patterns[i++])->part1) {
2401 int len_part1 = strlenW(pattern->part1);
2402 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2404 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2405 if (len_part2 == 0) {
2406 /* simple case with single part pattern */
2407 if (token->len != len_part1)
2408 continue;
2410 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2411 if (match) *match = *token;
2412 list_remove(&token->entry);
2413 heap_free(token);
2414 return TRUE;
2417 else {
2418 struct name_token *next_token;
2419 struct list *next_entry;
2421 /* pattern parts are stored in reading order, tokens list is reversed */
2422 if (token->len < len_part2)
2423 continue;
2425 /* it's possible to have combined string as a token, like ExtraCondensed */
2426 if (token->len == len_part1 + len_part2) {
2427 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2428 continue;
2430 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2431 continue;
2433 /* combined string match */
2434 if (match) *match = *token;
2435 list_remove(&token->entry);
2436 heap_free(token);
2437 return TRUE;
2440 /* now it's only possible to have two tokens matched to respective pattern parts */
2441 if (token->len != len_part2)
2442 continue;
2444 next_entry = list_next(tokens, &token->entry);
2445 if (next_entry) {
2446 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2447 if (next_token->len != len_part1)
2448 continue;
2450 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2451 continue;
2453 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2454 continue;
2456 /* both parts matched, remove tokens */
2457 if (match) {
2458 match->ptr = next_token->ptr;
2459 match->len = (token->ptr - next_token->ptr) + token->len;
2461 list_remove(&token->entry);
2462 list_remove(&next_token->entry);
2463 heap_free(next_token);
2464 heap_free(token);
2465 return TRUE;
2471 if (match) {
2472 match->ptr = NULL;
2473 match->len = 0;
2475 return FALSE;
2478 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2480 static const WCHAR itaW[] = {'i','t','a',0};
2481 static const WCHAR italW[] = {'i','t','a','l',0};
2482 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2483 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2485 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2486 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2487 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2488 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2490 static const struct name_pattern italic_patterns[] = {
2491 { itaW },
2492 { italW },
2493 { italicW },
2494 { cursiveW },
2495 { kursivW },
2496 { NULL }
2499 static const struct name_pattern oblique_patterns[] = {
2500 { inclinedW },
2501 { obliqueW },
2502 { backslantedW },
2503 { backslantW },
2504 { slantedW },
2505 { NULL }
2508 /* italic patterns first */
2509 if (match_pattern_list(tokens, italic_patterns, match))
2510 return DWRITE_FONT_STYLE_ITALIC;
2512 /* oblique patterns */
2513 if (match_pattern_list(tokens, oblique_patterns, match))
2514 return DWRITE_FONT_STYLE_OBLIQUE;
2516 return style;
2519 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2520 struct name_token *match)
2522 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2523 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2524 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2525 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2526 static const WCHAR wideW[] = {'w','i','d','e',0};
2527 static const WCHAR condW[] = {'c','o','n','d',0};
2529 static const struct name_pattern ultracondensed_patterns[] = {
2530 { extraW, compressedW },
2531 { extW, compressedW },
2532 { ultraW, compressedW },
2533 { ultraW, condensedW },
2534 { ultraW, condW },
2535 { NULL }
2538 static const struct name_pattern extracondensed_patterns[] = {
2539 { compressedW },
2540 { extraW, condensedW },
2541 { extW, condensedW },
2542 { extraW, condW },
2543 { extW, condW },
2544 { NULL }
2547 static const struct name_pattern semicondensed_patterns[] = {
2548 { narrowW },
2549 { compactW },
2550 { semiW, condensedW },
2551 { semiW, condW },
2552 { NULL }
2555 static const struct name_pattern semiexpanded_patterns[] = {
2556 { wideW },
2557 { semiW, expandedW },
2558 { semiW, extendedW },
2559 { NULL }
2562 static const struct name_pattern extraexpanded_patterns[] = {
2563 { extraW, expandedW },
2564 { extW, expandedW },
2565 { extraW, extendedW },
2566 { extW, extendedW },
2567 { NULL }
2570 static const struct name_pattern ultraexpanded_patterns[] = {
2571 { ultraW, expandedW },
2572 { ultraW, extendedW },
2573 { NULL }
2576 static const struct name_pattern condensed_patterns[] = {
2577 { condensedW },
2578 { condW },
2579 { NULL }
2582 static const struct name_pattern expanded_patterns[] = {
2583 { expandedW },
2584 { extendedW },
2585 { NULL }
2588 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2589 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2591 if (match_pattern_list(tokens, extracondensed_patterns, match))
2592 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2594 if (match_pattern_list(tokens, semicondensed_patterns, match))
2595 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2597 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2598 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2600 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2601 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2603 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2604 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2606 if (match_pattern_list(tokens, condensed_patterns, match))
2607 return DWRITE_FONT_STRETCH_CONDENSED;
2609 if (match_pattern_list(tokens, expanded_patterns, match))
2610 return DWRITE_FONT_STRETCH_EXPANDED;
2612 return stretch;
2615 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2616 struct name_token *match)
2618 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2619 static const WCHAR nordW[] = {'n','o','r','d',0};
2621 static const struct name_pattern thin_patterns[] = {
2622 { extraW, thinW },
2623 { extW, thinW },
2624 { ultraW, thinW },
2625 { NULL }
2628 static const struct name_pattern extralight_patterns[] = {
2629 { extraW, lightW },
2630 { extW, lightW },
2631 { ultraW, lightW },
2632 { NULL }
2635 static const struct name_pattern semilight_patterns[] = {
2636 { semiW, lightW },
2637 { NULL }
2640 static const struct name_pattern demibold_patterns[] = {
2641 { semiW, boldW },
2642 { demiW, boldW },
2643 { NULL }
2646 static const struct name_pattern extrabold_patterns[] = {
2647 { extraW, boldW },
2648 { extW, boldW },
2649 { ultraW, boldW },
2650 { NULL }
2653 static const struct name_pattern extrablack_patterns[] = {
2654 { extraW, blackW },
2655 { extW, blackW },
2656 { ultraW, blackW },
2657 { NULL }
2660 static const struct name_pattern bold_patterns[] = {
2661 { boldW },
2662 { NULL }
2665 static const struct name_pattern thin2_patterns[] = {
2666 { thinW },
2667 { NULL }
2670 static const struct name_pattern light_patterns[] = {
2671 { lightW },
2672 { NULL }
2675 static const struct name_pattern medium_patterns[] = {
2676 { mediumW },
2677 { NULL }
2680 static const struct name_pattern black_patterns[] = {
2681 { blackW },
2682 { heavyW },
2683 { nordW },
2684 { NULL }
2687 static const struct name_pattern demibold2_patterns[] = {
2688 { demiW },
2689 { NULL }
2692 static const struct name_pattern extrabold2_patterns[] = {
2693 { ultraW },
2694 { NULL }
2697 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2698 matching pattern. */
2700 if (match_pattern_list(tokens, thin_patterns, match))
2701 return DWRITE_FONT_WEIGHT_THIN;
2703 if (match_pattern_list(tokens, extralight_patterns, match))
2704 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2706 if (match_pattern_list(tokens, semilight_patterns, match))
2707 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2709 if (match_pattern_list(tokens, demibold_patterns, match))
2710 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2712 if (match_pattern_list(tokens, extrabold_patterns, match))
2713 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2715 if (match_pattern_list(tokens, extrablack_patterns, match))
2716 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2718 if (match_pattern_list(tokens, bold_patterns, match))
2719 return DWRITE_FONT_WEIGHT_BOLD;
2721 if (match_pattern_list(tokens, thin2_patterns, match))
2722 return DWRITE_FONT_WEIGHT_THIN;
2724 if (match_pattern_list(tokens, light_patterns, match))
2725 return DWRITE_FONT_WEIGHT_LIGHT;
2727 if (match_pattern_list(tokens, medium_patterns, match))
2728 return DWRITE_FONT_WEIGHT_MEDIUM;
2730 if (match_pattern_list(tokens, black_patterns, match))
2731 return DWRITE_FONT_WEIGHT_BLACK;
2733 if (match_pattern_list(tokens, black_patterns, match))
2734 return DWRITE_FONT_WEIGHT_BLACK;
2736 if (match_pattern_list(tokens, demibold2_patterns, match))
2737 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2739 if (match_pattern_list(tokens, extrabold2_patterns, match))
2740 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2742 /* FIXME: use abbreviated names to extract weight */
2744 return weight;
2747 struct knownweight_entry {
2748 const WCHAR *nameW;
2749 DWRITE_FONT_WEIGHT weight;
2752 static int compare_knownweights(const void *a, const void* b)
2754 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2755 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2756 int ret = 0;
2758 if (target > entry->weight)
2759 ret = 1;
2760 else if (target < entry->weight)
2761 ret = -1;
2763 return ret;
2766 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2768 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2769 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2770 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2771 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2772 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2773 const struct knownweight_entry *ptr;
2775 static const struct knownweight_entry knownweights[] = {
2776 { thinW, DWRITE_FONT_WEIGHT_THIN },
2777 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2778 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2779 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2780 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2781 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2782 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2783 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2784 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2785 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2788 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2789 compare_knownweights);
2790 if (!ptr) {
2791 nameW[0] = 0;
2792 return FALSE;
2795 strcpyW(nameW, ptr->nameW);
2796 return TRUE;
2799 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2801 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2802 strW[name->len] = 0;
2805 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2806 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2808 static const WCHAR bookW[] = {'B','o','o','k',0};
2809 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2810 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2811 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2812 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2814 static const WCHAR *regular_patterns[] = {
2815 bookW,
2816 normalW,
2817 regularW,
2818 romanW,
2819 uprightW,
2820 NULL
2823 const WCHAR *regular_ptr = NULL, *ptr;
2824 int i = 0;
2826 if (len == -1)
2827 len = strlenW(facenameW);
2829 /* remove rightmost regular variant from face name */
2830 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2831 int pattern_len = strlenW(ptr);
2832 WCHAR *src;
2834 if (pattern_len > len)
2835 continue;
2837 src = facenameW + len - pattern_len;
2838 while (src >= facenameW) {
2839 if (!strncmpiW(src, ptr, pattern_len)) {
2840 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2841 len = strlenW(facenameW);
2842 regular_ptr = ptr;
2843 break;
2845 else
2846 src--;
2850 return regular_ptr;
2853 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2855 const WCHAR *ptr;
2857 list_init(tokens);
2858 ptr = nameW;
2860 while (*ptr) {
2861 struct name_token *token = heap_alloc(sizeof(*token));
2862 token->ptr = ptr;
2863 token->len = 0;
2864 token->fulllen = 0;
2866 while (*ptr && !is_name_separator_char(*ptr)) {
2867 token->len++;
2868 token->fulllen++;
2869 ptr++;
2872 /* skip separators */
2873 while (is_name_separator_char(*ptr)) {
2874 token->fulllen++;
2875 ptr++;
2878 list_add_head(tokens, &token->entry);
2882 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2884 struct name_token *token, *token2;
2885 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2886 int len;
2888 list_remove(&token->entry);
2890 /* don't include last separator */
2891 len = list_empty(tokens) ? token->len : token->fulllen;
2892 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2893 nameW += len;
2895 heap_free(token);
2897 *nameW = 0;
2900 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2902 struct name_token stretch_name, weight_name, style_name;
2903 WCHAR familynameW[255], facenameW[255], finalW[255];
2904 WCHAR weightW[32], stretchW[32], styleW[32];
2905 const WCHAR *regular_ptr = NULL;
2906 DWRITE_FONT_STRETCH stretch;
2907 DWRITE_FONT_WEIGHT weight;
2908 struct list tokens;
2909 int len;
2911 /* remove leading and trailing spaces from family and face name */
2912 trim_spaces(familyW, familynameW);
2913 len = trim_spaces(faceW, facenameW);
2915 /* remove rightmost regular variant from face name */
2916 regular_ptr = facename_remove_regular_term(facenameW, len);
2918 /* append face name to family name, FIXME check if face name is a substring of family name */
2919 if (*facenameW) {
2920 strcatW(familynameW, spaceW);
2921 strcatW(familynameW, facenameW);
2924 /* tokenize with " .-_" */
2925 fontname_tokenize(&tokens, familynameW);
2927 /* extract and resolve style */
2928 font->style = font_extract_style(&tokens, font->style, &style_name);
2930 /* extract stretch */
2931 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2933 /* extract weight */
2934 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2936 /* resolve weight */
2937 if (weight != font->weight) {
2938 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2939 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2940 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2941 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2942 !(abs(weight - font->weight) <= 150 &&
2943 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2944 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2945 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2947 font->weight = weight;
2951 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2952 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2953 stretch itself is normal (extracted stretch is never normal). */
2954 if (stretch != font->stretch) {
2955 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2956 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2957 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2959 font->stretch = stretch;
2963 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2965 /* get final combined string from what's left in token list, list is released */
2966 fontname_tokens_to_str(&tokens, finalW);
2968 if (!strcmpW(familyW, finalW))
2969 return FALSE;
2971 /* construct face name */
2972 strcpyW(familyW, finalW);
2974 /* resolved weight name */
2975 if (weight_name.ptr)
2976 font_name_token_to_str(&weight_name, weightW);
2977 /* ignore normal weight */
2978 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2979 weightW[0] = 0;
2980 /* for known weight values use appropriate names */
2981 else if (is_known_weight_value(font->weight, weightW)) {
2983 /* use Wnnn format as a fallback in case weight is not one of known values */
2984 else {
2985 static const WCHAR fmtW[] = {'W','%','d',0};
2986 sprintfW(weightW, fmtW, font->weight);
2989 /* resolved stretch name */
2990 if (stretch_name.ptr)
2991 font_name_token_to_str(&stretch_name, stretchW);
2992 /* ignore normal stretch */
2993 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2994 stretchW[0] = 0;
2995 /* use predefined stretch names */
2996 else {
2997 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2998 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2999 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3000 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3001 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3002 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3004 static const WCHAR *stretchnamesW[] = {
3005 ultracondensedW,
3006 extracondensedW,
3007 condensedW,
3008 semicondensedW,
3009 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3010 semiexpandedW,
3011 expandedW,
3012 extraexpandedW,
3013 ultraexpandedW
3015 strcpyW(stretchW, stretchnamesW[font->stretch]);
3018 /* resolved style name */
3019 if (style_name.ptr)
3020 font_name_token_to_str(&style_name, styleW);
3021 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3022 styleW[0] = 0;
3023 /* use predefined names */
3024 else {
3025 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3026 strcpyW(styleW, italicW);
3027 else
3028 strcpyW(styleW, obliqueW);
3031 /* use Regular match if it was found initially */
3032 if (!*weightW && !*stretchW && !*styleW)
3033 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3034 else {
3035 faceW[0] = 0;
3036 if (*stretchW)
3037 strcpyW(faceW, stretchW);
3038 if (*weightW) {
3039 if (*faceW)
3040 strcatW(faceW, spaceW);
3041 strcatW(faceW, weightW);
3043 if (*styleW) {
3044 if (*faceW)
3045 strcatW(faceW, spaceW);
3046 strcatW(faceW, styleW);
3050 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3051 return TRUE;
3054 static HRESULT init_font_data(IDWriteFactory3 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
3055 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
3057 struct dwrite_font_props props;
3058 struct dwrite_font_data *data;
3059 IDWriteFontFileStream *stream;
3060 WCHAR familyW[255], faceW[255];
3061 HRESULT hr;
3063 *ret = NULL;
3064 data = heap_alloc_zero(sizeof(*data));
3065 if (!data)
3066 return E_OUTOFMEMORY;
3068 hr = get_filestream_from_file(file, &stream);
3069 if (FAILED(hr)) {
3070 heap_free(data);
3071 return hr;
3074 data->ref = 1;
3075 data->factory = factory;
3076 data->file = file;
3077 data->face_index = face_index;
3078 data->face_type = face_type;
3079 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3080 data->bold_sim_tested = 0;
3081 data->oblique_sim_tested = 0;
3082 IDWriteFontFile_AddRef(file);
3083 IDWriteFactory3_AddRef(factory);
3085 opentype_get_font_properties(stream, face_type, face_index, &props);
3086 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
3087 opentype_get_font_facename(stream, face_type, face_index, &data->names);
3089 /* get family name from font file */
3090 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
3091 IDWriteFontFileStream_Release(stream);
3092 if (FAILED(hr)) {
3093 WARN("unable to get family name from font\n");
3094 release_font_data(data);
3095 return hr;
3098 data->style = props.style;
3099 data->stretch = props.stretch;
3100 data->weight = props.weight;
3101 data->panose = props.panose;
3103 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3104 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3105 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3106 set_en_localizedstring(*family_name, familyW);
3107 set_en_localizedstring(data->names, faceW);
3110 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3112 *ret = data;
3113 return S_OK;
3116 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
3117 struct dwrite_font_data **ret)
3119 struct dwrite_font_data *data;
3121 *ret = NULL;
3122 data = heap_alloc_zero(sizeof(*data));
3123 if (!data)
3124 return E_OUTOFMEMORY;
3126 *data = *src;
3127 data->ref = 1;
3128 data->simulations |= sim;
3129 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3130 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3131 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3132 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3133 memset(data->info_strings, 0, sizeof(data->info_strings));
3134 data->names = NULL;
3135 IDWriteFactory3_AddRef(data->factory);
3136 IDWriteFontFile_AddRef(data->file);
3138 create_localizedstrings(&data->names);
3139 add_localizedstring(data->names, enusW, facenameW);
3141 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3143 *ret = data;
3144 return S_OK;
3147 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3149 struct dwrite_fontfamily_data *data;
3151 data = heap_alloc(sizeof(*data));
3152 if (!data)
3153 return E_OUTOFMEMORY;
3155 data->ref = 1;
3156 data->font_count = 0;
3157 data->font_alloc = 2;
3158 data->has_normal_face = 0;
3159 data->has_oblique_face = 0;
3160 data->has_italic_face = 0;
3162 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3163 if (!data->fonts) {
3164 heap_free(data);
3165 return E_OUTOFMEMORY;
3168 data->familyname = familyname;
3169 IDWriteLocalizedStrings_AddRef(familyname);
3171 *ret = data;
3172 return S_OK;
3175 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3177 UINT32 i, j, heaviest;
3179 for (i = 0; i < family->font_count; i++) {
3180 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3181 heaviest = i;
3183 if (family->fonts[i]->bold_sim_tested)
3184 continue;
3186 family->fonts[i]->bold_sim_tested = 1;
3187 for (j = i; j < family->font_count; j++) {
3188 if (family->fonts[j]->bold_sim_tested)
3189 continue;
3191 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3192 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3193 if (family->fonts[j]->weight > weight) {
3194 weight = family->fonts[j]->weight;
3195 heaviest = j;
3197 family->fonts[j]->bold_sim_tested = 1;
3201 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3202 static const struct name_pattern weightsim_patterns[] = {
3203 { extraW, lightW },
3204 { extW, lightW },
3205 { ultraW, lightW },
3206 { semiW, lightW },
3207 { semiW, boldW },
3208 { demiW, boldW },
3209 { boldW },
3210 { thinW },
3211 { lightW },
3212 { mediumW },
3213 { demiW },
3214 { NULL }
3217 WCHAR facenameW[255], initialW[255];
3218 struct dwrite_font_data *boldface;
3219 struct list tokens;
3221 /* add Bold simulation based on heaviest face data */
3223 /* Simulated face name should only contain Bold as weight term,
3224 so remove existing regular and weight terms. */
3225 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3226 facename_remove_regular_term(initialW, -1);
3228 /* remove current weight pattern */
3229 fontname_tokenize(&tokens, initialW);
3230 match_pattern_list(&tokens, weightsim_patterns, NULL);
3231 fontname_tokens_to_str(&tokens, facenameW);
3233 /* Bold suffix for new name */
3234 if (*facenameW)
3235 strcatW(facenameW, spaceW);
3236 strcatW(facenameW, boldW);
3238 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3239 boldface->bold_sim_tested = 1;
3240 fontfamily_add_font(family, boldface);
3246 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3248 UINT32 i, j;
3250 for (i = 0; i < family->font_count; i++) {
3251 UINT32 regular = ~0u, oblique = ~0u;
3252 struct dwrite_font_data *obliqueface;
3253 WCHAR facenameW[255];
3255 if (family->fonts[i]->oblique_sim_tested)
3256 continue;
3258 family->fonts[i]->oblique_sim_tested = 1;
3259 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3260 regular = i;
3261 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3262 oblique = i;
3264 /* find regular style with same weight/stretch values */
3265 for (j = i; j < family->font_count; j++) {
3266 if (family->fonts[j]->oblique_sim_tested)
3267 continue;
3269 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3270 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3272 family->fonts[j]->oblique_sim_tested = 1;
3273 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3274 regular = j;
3276 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3277 oblique = j;
3280 if (regular != ~0u && oblique != ~0u)
3281 break;
3284 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3285 if (regular == ~0u)
3286 continue;
3288 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3289 if (oblique != ~0u)
3290 continue;
3292 /* add oblique simulation based on this regular face */
3294 /* remove regular term if any, append 'Oblique' */
3295 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3296 facename_remove_regular_term(facenameW, -1);
3298 if (*facenameW)
3299 strcatW(facenameW, spaceW);
3300 strcatW(facenameW, obliqueW);
3302 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3303 obliqueface->oblique_sim_tested = 1;
3304 fontfamily_add_font(family, obliqueface);
3309 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3310 const WCHAR *replacement_name)
3312 UINT32 i = collection_find_family(collection, replacement_name);
3313 struct dwrite_fontfamily_data *target;
3314 IDWriteLocalizedStrings *strings;
3315 HRESULT hr;
3317 /* replacement does not exist */
3318 if (i == ~0u)
3319 return FALSE;
3321 hr = create_localizedstrings(&strings);
3322 if (FAILED(hr))
3323 return FALSE;
3325 /* add a new family with target name, reuse font data from replacement */
3326 add_localizedstring(strings, enusW, target_name);
3327 hr = init_fontfamily_data(strings, &target);
3328 if (hr == S_OK) {
3329 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3330 WCHAR nameW[255];
3332 for (i = 0; i < replacement->font_count; i++)
3333 fontfamily_add_font(target, replacement->fonts[i]);
3335 fontcollection_add_family(collection, target);
3336 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3337 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3339 IDWriteLocalizedStrings_Release(strings);
3340 return TRUE;
3343 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3344 system font collections. */
3345 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3347 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3348 WCHAR *name;
3349 void *data;
3350 HKEY hkey;
3352 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3353 return;
3355 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3356 RegCloseKey(hkey);
3357 return;
3360 max_namelen++; /* returned value doesn't include room for '\0' */
3361 name = heap_alloc(max_namelen * sizeof(WCHAR));
3362 data = heap_alloc(max_datalen);
3364 datalen = max_datalen;
3365 namelen = max_namelen;
3366 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3367 if (collection_find_family(collection, name) == ~0u) {
3368 if (type == REG_MULTI_SZ) {
3369 WCHAR *replacement = data;
3370 while (*replacement) {
3371 if (fontcollection_add_replacement(collection, name, replacement))
3372 break;
3373 replacement += strlenW(replacement) + 1;
3376 else if (type == REG_SZ)
3377 fontcollection_add_replacement(collection, name, data);
3379 else
3380 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3382 datalen = max_datalen;
3383 namelen = max_namelen;
3386 heap_free(data);
3387 heap_free(name);
3388 RegCloseKey(hkey);
3391 HRESULT create_font_collection(IDWriteFactory3 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3393 struct fontfile_enum {
3394 struct list entry;
3395 IDWriteFontFile *file;
3397 struct fontfile_enum *fileenum, *fileenum2;
3398 struct dwrite_fontcollection *collection;
3399 struct list scannedfiles;
3400 BOOL current = FALSE;
3401 HRESULT hr = S_OK;
3402 UINT32 i;
3404 *ret = NULL;
3406 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3407 if (!collection) return E_OUTOFMEMORY;
3409 hr = init_font_collection(collection, is_system);
3410 if (FAILED(hr)) {
3411 heap_free(collection);
3412 return hr;
3415 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3417 TRACE("building font collection:\n");
3419 list_init(&scannedfiles);
3420 while (hr == S_OK) {
3421 DWRITE_FONT_FACE_TYPE face_type;
3422 DWRITE_FONT_FILE_TYPE file_type;
3423 BOOL supported, same = FALSE;
3424 IDWriteFontFile *file;
3425 UINT32 face_count;
3427 current = FALSE;
3428 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3429 if (FAILED(hr) || !current)
3430 break;
3432 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3433 if (FAILED(hr))
3434 break;
3436 /* check if we've scanned this file already */
3437 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3438 if ((same = is_same_fontfile(fileenum->file, file)))
3439 break;
3442 if (same) {
3443 IDWriteFontFile_Release(file);
3444 continue;
3447 /* failed font files are skipped */
3448 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3449 if (FAILED(hr) || !supported || face_count == 0) {
3450 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3451 IDWriteFontFile_Release(file);
3452 hr = S_OK;
3453 continue;
3456 /* add to scanned list */
3457 fileenum = heap_alloc(sizeof(*fileenum));
3458 fileenum->file = file;
3459 list_add_tail(&scannedfiles, &fileenum->entry);
3461 for (i = 0; i < face_count; i++) {
3462 IDWriteLocalizedStrings *family_name = NULL;
3463 struct dwrite_font_data *font_data;
3464 WCHAR familyW[255];
3465 UINT32 index;
3467 /* alloc and init new font data structure */
3468 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3469 if (FAILED(hr)) {
3470 /* move to next one */
3471 hr = S_OK;
3472 continue;
3475 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3477 index = collection_find_family(collection, familyW);
3478 if (index != ~0u)
3479 hr = fontfamily_add_font(collection->family_data[index], font_data);
3480 else {
3481 struct dwrite_fontfamily_data *family_data;
3483 /* create and init new family */
3484 hr = init_fontfamily_data(family_name, &family_data);
3485 if (hr == S_OK) {
3486 /* add font to family, family - to collection */
3487 hr = fontfamily_add_font(family_data, font_data);
3488 if (hr == S_OK)
3489 hr = fontcollection_add_family(collection, family_data);
3491 if (FAILED(hr))
3492 release_fontfamily_data(family_data);
3496 IDWriteLocalizedStrings_Release(family_name);
3498 if (FAILED(hr))
3499 break;
3503 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3504 IDWriteFontFile_Release(fileenum->file);
3505 list_remove(&fileenum->entry);
3506 heap_free(fileenum);
3509 for (i = 0; i < collection->family_count; i++) {
3510 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3511 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3514 if (is_system)
3515 fontcollection_add_replacements(collection);
3517 return hr;
3520 struct system_fontfile_enumerator
3522 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3523 LONG ref;
3525 IDWriteFactory3 *factory;
3526 HKEY hkey;
3527 int index;
3530 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3532 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3535 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3537 *obj = NULL;
3539 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3540 IDWriteFontFileEnumerator_AddRef(iface);
3541 *obj = iface;
3542 return S_OK;
3545 return E_NOINTERFACE;
3548 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3550 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3551 return InterlockedIncrement(&enumerator->ref);
3554 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3556 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3557 ULONG ref = InterlockedDecrement(&enumerator->ref);
3559 if (!ref) {
3560 IDWriteFactory3_Release(enumerator->factory);
3561 RegCloseKey(enumerator->hkey);
3562 heap_free(enumerator);
3565 return ref;
3568 static HRESULT create_local_file_reference(IDWriteFactory3 *factory, const WCHAR *filename, IDWriteFontFile **file)
3570 HRESULT hr;
3572 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3573 if (!strchrW(filename, '\\')) {
3574 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3575 WCHAR fullpathW[MAX_PATH];
3577 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3578 strcatW(fullpathW, fontsW);
3579 strcatW(fullpathW, filename);
3581 hr = IDWriteFactory3_CreateFontFileReference(factory, fullpathW, NULL, file);
3583 else
3584 hr = IDWriteFactory3_CreateFontFileReference(factory, filename, NULL, file);
3586 return hr;
3589 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3591 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3592 DWORD ret, type, val_count, count;
3593 WCHAR *value, *filename;
3594 HRESULT hr;
3596 *file = NULL;
3598 if (enumerator->index < 0)
3599 return E_FAIL;
3601 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3602 if (ret != ERROR_SUCCESS)
3603 return E_FAIL;
3605 val_count++;
3606 value = heap_alloc( val_count * sizeof(value[0]) );
3607 filename = heap_alloc(count);
3608 if (!value || !filename) {
3609 heap_free(value);
3610 heap_free(filename);
3611 return E_OUTOFMEMORY;
3614 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3615 if (ret) {
3616 heap_free(value);
3617 heap_free(filename);
3618 return E_FAIL;
3621 hr = create_local_file_reference(enumerator->factory, filename, file);
3623 heap_free(value);
3624 heap_free(filename);
3625 return hr;
3628 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3630 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3631 DWORD ret, max_val_count;
3632 WCHAR *value;
3634 *current = FALSE;
3635 enumerator->index++;
3637 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3638 if (ret != ERROR_SUCCESS)
3639 return E_FAIL;
3641 max_val_count++;
3642 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3643 return E_OUTOFMEMORY;
3645 /* iterate until we find next string value */
3646 while (1) {
3647 DWORD type = 0, count, val_count;
3648 val_count = max_val_count;
3649 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3650 break;
3651 if (type == REG_SZ) {
3652 *current = TRUE;
3653 break;
3655 enumerator->index++;
3658 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3659 heap_free(value);
3660 return S_OK;
3663 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3665 systemfontfileenumerator_QueryInterface,
3666 systemfontfileenumerator_AddRef,
3667 systemfontfileenumerator_Release,
3668 systemfontfileenumerator_MoveNext,
3669 systemfontfileenumerator_GetCurrentFontFile
3672 static HRESULT create_system_fontfile_enumerator(IDWriteFactory3 *factory, IDWriteFontFileEnumerator **ret)
3674 struct system_fontfile_enumerator *enumerator;
3675 static const WCHAR fontslistW[] = {
3676 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3677 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3678 'F','o','n','t','s',0
3681 *ret = NULL;
3683 enumerator = heap_alloc(sizeof(*enumerator));
3684 if (!enumerator)
3685 return E_OUTOFMEMORY;
3687 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3688 enumerator->ref = 1;
3689 enumerator->factory = factory;
3690 enumerator->index = -1;
3691 IDWriteFactory3_AddRef(factory);
3693 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3694 ERR("failed to open fonts list key\n");
3695 IDWriteFactory3_Release(factory);
3696 heap_free(enumerator);
3697 return E_FAIL;
3700 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3702 return S_OK;
3705 HRESULT get_system_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection **collection)
3707 IDWriteFontFileEnumerator *enumerator;
3708 HRESULT hr;
3710 *collection = NULL;
3712 hr = create_system_fontfile_enumerator(factory, &enumerator);
3713 if (FAILED(hr))
3714 return hr;
3716 TRACE("building system font collection for factory %p\n", factory);
3717 hr = create_font_collection(factory, enumerator, TRUE, collection);
3718 IDWriteFontFileEnumerator_Release(enumerator);
3719 return hr;
3722 static HRESULT eudc_collection_add_family(IDWriteFactory3 *factory, struct dwrite_fontcollection *collection,
3723 const WCHAR *keynameW, const WCHAR *pathW)
3725 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};
3726 static const WCHAR emptyW[] = {0};
3727 IDWriteLocalizedStrings *names;
3728 DWRITE_FONT_FACE_TYPE face_type;
3729 DWRITE_FONT_FILE_TYPE file_type;
3730 BOOL supported;
3731 UINT32 face_count, i;
3732 IDWriteFontFile *file;
3733 HRESULT hr;
3734 struct dwrite_fontfamily_data *family_data;
3736 /* create font file from this path */
3737 hr = create_local_file_reference(factory, pathW, &file);
3738 if (FAILED(hr))
3739 return S_FALSE;
3741 /* failed font files are skipped */
3742 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3743 if (FAILED(hr) || !supported || face_count == 0) {
3744 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3745 IDWriteFontFile_Release(file);
3746 return S_FALSE;
3749 /* create and init new family */
3751 /* Family names are added for non-specific locale, represented with empty string.
3752 Default family appears with empty family name. */
3753 create_localizedstrings(&names);
3754 if (!strcmpiW(keynameW, defaultfontW))
3755 add_localizedstring(names, emptyW, emptyW);
3756 else
3757 add_localizedstring(names, emptyW, keynameW);
3759 hr = init_fontfamily_data(names, &family_data);
3760 IDWriteLocalizedStrings_Release(names);
3761 if (hr != S_OK) {
3762 IDWriteFontFile_Release(file);
3763 return hr;
3766 /* fill with faces */
3767 for (i = 0; i < face_count; i++) {
3768 struct dwrite_font_data *font_data;
3770 /* alloc and init new font data structure */
3771 hr = init_font_data(factory, file, face_type, i, &names, &font_data);
3772 if (FAILED(hr))
3773 continue;
3775 IDWriteLocalizedStrings_Release(names);
3777 /* add font to family */
3778 hr = fontfamily_add_font(family_data, font_data);
3779 if (hr != S_OK)
3780 release_font_data(font_data);
3783 /* add family to collection */
3784 hr = fontcollection_add_family(collection, family_data);
3785 if (FAILED(hr))
3786 release_fontfamily_data(family_data);
3787 IDWriteFontFile_Release(file);
3789 return hr;
3792 HRESULT get_eudc_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection **ret)
3794 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3795 struct dwrite_fontcollection *collection;
3796 static const WCHAR emptyW[] = {0};
3797 WCHAR eudckeypathW[16];
3798 HKEY eudckey;
3799 DWORD index;
3800 BOOL exists;
3801 LONG retval;
3802 HRESULT hr;
3803 UINT32 i;
3805 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3807 *ret = NULL;
3809 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3810 if (!collection) return E_OUTOFMEMORY;
3812 hr = init_font_collection(collection, FALSE);
3813 if (FAILED(hr)) {
3814 heap_free(collection);
3815 return hr;
3818 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3820 /* return empty collection if EUDC fonts are not configured */
3821 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3822 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3823 return S_OK;
3825 retval = ERROR_SUCCESS;
3826 index = 0;
3827 while (retval != ERROR_NO_MORE_ITEMS) {
3828 WCHAR keynameW[64], pathW[MAX_PATH];
3829 DWORD type, path_len, name_len;
3831 path_len = sizeof(pathW)/sizeof(*pathW);
3832 name_len = sizeof(keynameW)/sizeof(*keynameW);
3833 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3834 if (retval || type != REG_SZ)
3835 continue;
3837 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3838 if (hr != S_OK)
3839 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3841 RegCloseKey(eudckey);
3843 /* try to add global default if not defined for specific codepage */
3844 exists = FALSE;
3845 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
3846 &index, &exists);
3847 if (FAILED(hr) || !exists) {
3848 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3849 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3850 if (hr != S_OK)
3851 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3854 /* EUDC collection offers simulated faces too */
3855 for (i = 0; i < collection->family_count; i++) {
3856 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3857 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3860 return S_OK;
3863 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3865 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3867 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3869 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3871 *obj = iface;
3872 IDWriteFontFile_AddRef(iface);
3873 return S_OK;
3876 *obj = NULL;
3877 return E_NOINTERFACE;
3880 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3882 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3883 ULONG ref = InterlockedIncrement(&This->ref);
3884 TRACE("(%p)->(%d)\n", This, ref);
3885 return ref;
3888 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3890 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3891 ULONG ref = InterlockedDecrement(&This->ref);
3893 TRACE("(%p)->(%d)\n", This, ref);
3895 if (!ref)
3897 IDWriteFontFileLoader_Release(This->loader);
3898 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3899 heap_free(This->reference_key);
3900 heap_free(This);
3903 return ref;
3906 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3908 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3909 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3910 *fontFileReferenceKey = This->reference_key;
3911 *fontFileReferenceKeySize = This->key_size;
3913 return S_OK;
3916 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3918 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3919 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3920 *fontFileLoader = This->loader;
3921 IDWriteFontFileLoader_AddRef(This->loader);
3923 return S_OK;
3926 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
3927 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3929 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3930 IDWriteFontFileStream *stream;
3931 HRESULT hr;
3933 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3935 *isSupportedFontType = FALSE;
3936 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3937 if (fontFaceType)
3938 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3939 *numberOfFaces = 0;
3941 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3942 if (FAILED(hr))
3943 return hr;
3945 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3947 /* TODO: Further Analysis */
3948 IDWriteFontFileStream_Release(stream);
3949 return S_OK;
3952 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3953 dwritefontfile_QueryInterface,
3954 dwritefontfile_AddRef,
3955 dwritefontfile_Release,
3956 dwritefontfile_GetReferenceKey,
3957 dwritefontfile_GetLoader,
3958 dwritefontfile_Analyze,
3961 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3963 struct dwrite_fontfile *This;
3965 This = heap_alloc(sizeof(struct dwrite_fontfile));
3966 if (!This) return E_OUTOFMEMORY;
3968 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3969 This->ref = 1;
3970 IDWriteFontFileLoader_AddRef(loader);
3971 This->loader = loader;
3972 This->stream = NULL;
3973 This->reference_key = heap_alloc(key_size);
3974 memcpy(This->reference_key, reference_key, key_size);
3975 This->key_size = key_size;
3977 *font_file = &This->IDWriteFontFile_iface;
3979 return S_OK;
3982 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3984 IDWriteFontFileLoader *loader;
3985 UINT32 key_size;
3986 const void *key;
3987 HRESULT hr;
3989 *stream = NULL;
3990 hr = IDWriteFontFile_GetLoader(file, &loader);
3991 if (FAILED(hr))
3992 return hr;
3994 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3995 if (FAILED(hr)) {
3996 IDWriteFontFileLoader_Release(loader);
3997 return hr;
4000 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
4001 IDWriteFontFileLoader_Release(loader);
4003 return hr;
4006 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
4007 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
4009 struct dwrite_fontface *fontface;
4010 HRESULT hr = S_OK;
4011 int i;
4013 *ret = NULL;
4015 fontface = heap_alloc(sizeof(struct dwrite_fontface));
4016 if (!fontface)
4017 return E_OUTOFMEMORY;
4019 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
4020 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
4022 if (!fontface->files || !fontface->streams) {
4023 heap_free(fontface->files);
4024 heap_free(fontface->streams);
4025 heap_free(fontface);
4026 return E_OUTOFMEMORY;
4029 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
4030 fontface->ref = 1;
4031 fontface->type = facetype;
4032 fontface->file_count = files_number;
4033 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
4034 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
4035 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
4036 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
4037 memset(&fontface->colr, 0, sizeof(fontface->colr));
4038 fontface->cmap.exists = TRUE;
4039 fontface->vdmx.exists = TRUE;
4040 fontface->gasp.exists = TRUE;
4041 fontface->cpal.exists = TRUE;
4042 fontface->colr.exists = TRUE;
4043 fontface->index = index;
4044 fontface->simulations = simulations;
4045 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
4047 for (i = 0; i < fontface->file_count; i++) {
4048 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
4049 if (FAILED(hr)) {
4050 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
4051 return hr;
4054 fontface->files[i] = font_files[i];
4055 IDWriteFontFile_AddRef(font_files[i]);
4058 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
4059 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4060 /* TODO: test what happens if caret is already slanted */
4061 if (fontface->caret.slopeRise == 1) {
4062 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4063 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4066 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
4067 fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
4068 fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
4070 *ret = &fontface->IDWriteFontFace3_iface;
4071 return S_OK;
4074 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4075 struct local_refkey
4077 FILETIME writetime;
4078 WCHAR name[1];
4081 struct local_cached_stream
4083 struct list entry;
4084 IDWriteFontFileStream *stream;
4085 struct local_refkey *key;
4086 UINT32 key_size;
4089 struct dwrite_localfontfilestream
4091 IDWriteFontFileStream IDWriteFontFileStream_iface;
4092 LONG ref;
4094 struct local_cached_stream *entry;
4095 const void *file_ptr;
4096 UINT64 size;
4099 struct dwrite_localfontfileloader {
4100 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4101 LONG ref;
4103 struct list streams;
4106 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4108 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4111 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4113 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4116 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4118 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4119 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4120 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4122 *obj = iface;
4123 IDWriteFontFileStream_AddRef(iface);
4124 return S_OK;
4127 *obj = NULL;
4128 return E_NOINTERFACE;
4131 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4133 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4134 ULONG ref = InterlockedIncrement(&This->ref);
4135 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4136 return ref;
4139 static inline void release_cached_stream(struct local_cached_stream *stream)
4141 list_remove(&stream->entry);
4142 heap_free(stream->key);
4143 heap_free(stream);
4146 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4148 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4149 ULONG ref = InterlockedDecrement(&This->ref);
4151 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4153 if (!ref) {
4154 UnmapViewOfFile(This->file_ptr);
4155 release_cached_stream(This->entry);
4156 heap_free(This);
4159 return ref;
4162 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
4164 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4166 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
4167 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4169 *fragment_context = NULL;
4171 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4172 *fragment_start = NULL;
4173 return E_FAIL;
4176 *fragment_start = (char*)This->file_ptr + offset;
4177 return S_OK;
4180 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4182 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4183 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4186 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4188 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4189 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4190 *size = This->size;
4191 return S_OK;
4194 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4196 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4197 ULARGE_INTEGER li;
4199 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4201 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4202 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4203 *last_writetime = li.QuadPart;
4205 return S_OK;
4208 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4210 localfontfilestream_QueryInterface,
4211 localfontfilestream_AddRef,
4212 localfontfilestream_Release,
4213 localfontfilestream_ReadFileFragment,
4214 localfontfilestream_ReleaseFileFragment,
4215 localfontfilestream_GetFileSize,
4216 localfontfilestream_GetLastWriteTime
4219 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4221 struct dwrite_localfontfilestream *This;
4223 *ret = NULL;
4225 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4226 if (!This)
4227 return E_OUTOFMEMORY;
4229 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4230 This->ref = 1;
4232 This->file_ptr = file_ptr;
4233 This->size = size;
4234 This->entry = entry;
4236 *ret = &This->IDWriteFontFileStream_iface;
4237 return S_OK;
4240 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4242 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4244 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4246 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4248 *obj = iface;
4249 IDWriteLocalFontFileLoader_AddRef(iface);
4250 return S_OK;
4253 *obj = NULL;
4254 return E_NOINTERFACE;
4257 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4259 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4260 ULONG ref = InterlockedIncrement(&This->ref);
4261 TRACE("(%p)->(%d)\n", This, ref);
4262 return ref;
4265 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4267 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4268 ULONG ref = InterlockedDecrement(&This->ref);
4270 TRACE("(%p)->(%d)\n", This, ref);
4272 if (!ref) {
4273 struct local_cached_stream *stream, *stream2;
4275 /* This will detach all entries from cache. Entries are released together with streams,
4276 so stream controls cache entry lifetime. */
4277 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4278 list_init(&stream->entry);
4280 heap_free(This);
4283 return ref;
4286 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4288 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4289 const struct local_refkey *refkey = key;
4290 struct local_cached_stream *stream;
4291 IDWriteFontFileStream *filestream;
4292 HANDLE file, mapping;
4293 LARGE_INTEGER size;
4294 void *file_ptr;
4295 HRESULT hr;
4297 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4298 TRACE("name: %s\n", debugstr_w(refkey->name));
4300 /* search cache first */
4301 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4302 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4303 *ret = stream->stream;
4304 IDWriteFontFileStream_AddRef(*ret);
4305 return S_OK;
4309 *ret = NULL;
4311 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4312 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4313 if (file == INVALID_HANDLE_VALUE)
4314 return E_FAIL;
4316 GetFileSizeEx(file, &size);
4317 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4318 CloseHandle(file);
4319 if (!mapping)
4320 return E_FAIL;
4322 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4323 CloseHandle(mapping);
4325 stream = heap_alloc(sizeof(*stream));
4326 if (!stream) {
4327 UnmapViewOfFile(file_ptr);
4328 return E_OUTOFMEMORY;
4331 stream->key = heap_alloc(key_size);
4332 if (!stream->key) {
4333 UnmapViewOfFile(file_ptr);
4334 heap_free(stream);
4335 return E_OUTOFMEMORY;
4338 stream->key_size = key_size;
4339 memcpy(stream->key, key, key_size);
4341 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4342 if (FAILED(hr)) {
4343 UnmapViewOfFile(file_ptr);
4344 heap_free(stream->key);
4345 heap_free(stream);
4346 return hr;
4349 stream->stream = filestream;
4350 list_add_head(&This->streams, &stream->entry);
4352 *ret = stream->stream;
4354 return S_OK;
4357 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4359 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4360 const struct local_refkey *refkey = key;
4362 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4364 *length = strlenW(refkey->name);
4365 return S_OK;
4368 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4370 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4371 const struct local_refkey *refkey = key;
4373 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4375 if (length < strlenW(refkey->name))
4376 return E_INVALIDARG;
4378 strcpyW(path, refkey->name);
4379 return S_OK;
4382 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4384 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4385 const struct local_refkey *refkey = key;
4387 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4389 *writetime = refkey->writetime;
4390 return S_OK;
4393 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4394 localfontfileloader_QueryInterface,
4395 localfontfileloader_AddRef,
4396 localfontfileloader_Release,
4397 localfontfileloader_CreateStreamFromKey,
4398 localfontfileloader_GetFilePathLengthFromKey,
4399 localfontfileloader_GetFilePathFromKey,
4400 localfontfileloader_GetLastWriteTimeFromKey
4403 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4405 struct dwrite_localfontfileloader *This;
4407 *ret = NULL;
4409 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4410 if (!This)
4411 return E_OUTOFMEMORY;
4413 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4414 This->ref = 1;
4415 list_init(&This->streams);
4417 *ret = &This->IDWriteLocalFontFileLoader_iface;
4418 return S_OK;
4421 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4423 struct local_refkey *refkey;
4425 if (!path)
4426 return E_INVALIDARG;
4428 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4429 *key = NULL;
4431 refkey = heap_alloc(*size);
4432 if (!refkey)
4433 return E_OUTOFMEMORY;
4435 if (writetime)
4436 refkey->writetime = *writetime;
4437 else {
4438 WIN32_FILE_ATTRIBUTE_DATA info;
4440 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4441 refkey->writetime = info.ftLastWriteTime;
4442 else
4443 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4445 strcpyW(refkey->name, path);
4447 *key = refkey;
4449 return S_OK;
4452 /* IDWriteGlyphRunAnalysis */
4453 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4455 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4457 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4459 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4460 IsEqualIID(riid, &IID_IUnknown))
4462 *ppv = iface;
4463 IDWriteGlyphRunAnalysis_AddRef(iface);
4464 return S_OK;
4467 *ppv = NULL;
4468 return E_NOINTERFACE;
4471 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4473 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4474 ULONG ref = InterlockedIncrement(&This->ref);
4475 TRACE("(%p)->(%u)\n", This, ref);
4476 return ref;
4479 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4481 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4482 ULONG ref = InterlockedDecrement(&This->ref);
4484 TRACE("(%p)->(%u)\n", This, ref);
4486 if (!ref) {
4487 if (This->run.fontFace)
4488 IDWriteFontFace_Release(This->run.fontFace);
4489 heap_free(This->glyphs);
4490 heap_free(This->advances);
4491 heap_free(This->advanceoffsets);
4492 heap_free(This->ascenderoffsets);
4493 heap_free(This->bitmap);
4494 heap_free(This);
4497 return ref;
4500 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4502 struct dwrite_glyphbitmap glyph_bitmap;
4503 IDWriteFontFace3 *fontface3;
4504 D2D_POINT_2F origin;
4505 BOOL is_rtl;
4506 HRESULT hr;
4507 UINT32 i;
4509 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4510 *bounds = analysis->bounds;
4511 return;
4514 if (analysis->run.isSideways)
4515 FIXME("sideways runs are not supported.\n");
4517 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4518 if (FAILED(hr))
4519 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4521 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4522 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4523 for any non-zero glyph ascender */
4524 origin.x = origin.y = 0.0f;
4525 is_rtl = analysis->run.bidiLevel & 1;
4527 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4528 glyph_bitmap.fontface = fontface3;
4529 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4530 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4531 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4532 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4533 glyph_bitmap.m = &analysis->m;
4535 for (i = 0; i < analysis->run.glyphCount; i++) {
4536 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4537 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4538 const D2D_POINT_2F *advance = analysis->advances + i;
4539 RECT *bbox = &glyph_bitmap.bbox;
4541 glyph_bitmap.index = analysis->run.glyphIndices[i];
4542 freetype_get_glyph_bbox(&glyph_bitmap);
4544 if (is_rtl)
4545 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4546 else
4547 OffsetRect(bbox, origin.x, origin.y);
4549 if (advanceoffset)
4550 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4552 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4553 origin.x += advance->x;
4554 origin.y += advance->y;
4557 IDWriteFontFace3_Release(fontface3);
4559 /* translate to given run origin */
4560 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4561 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4562 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4564 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4565 *bounds = analysis->bounds;
4568 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4570 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4572 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4574 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4575 memset(bounds, 0, sizeof(*bounds));
4576 return E_INVALIDARG;
4579 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4580 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4581 memset(bounds, 0, sizeof(*bounds));
4582 return S_OK;
4585 glyphrunanalysis_get_texturebounds(This, bounds);
4586 return S_OK;
4589 static inline int get_dib_stride( int width, int bpp )
4591 return ((width * bpp + 31) >> 3) & ~3;
4594 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4596 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4597 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4598 (runbounds->left - bounds->left) * 3;
4599 else
4600 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4601 runbounds->left - bounds->left;
4604 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4606 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4607 struct dwrite_glyphbitmap glyph_bitmap;
4608 IDWriteFontFace3 *fontface2;
4609 D2D_POINT_2F origin;
4610 UINT32 i, size;
4611 BOOL is_rtl;
4612 HRESULT hr;
4613 RECT *bbox;
4615 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4616 if (FAILED(hr)) {
4617 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4618 return;
4621 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4622 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4623 size *= 3;
4624 analysis->bitmap = heap_alloc_zero(size);
4626 origin.x = origin.y = 0.0f;
4627 is_rtl = analysis->run.bidiLevel & 1;
4629 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4630 glyph_bitmap.fontface = fontface2;
4631 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4632 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4633 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4634 glyph_bitmap.type = type;
4635 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4636 glyph_bitmap.m = &analysis->m;
4637 bbox = &glyph_bitmap.bbox;
4639 for (i = 0; i < analysis->run.glyphCount; i++) {
4640 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4641 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4642 const D2D_POINT_2F *advance = analysis->advances + i;
4643 int x, y, width, height;
4644 BYTE *src, *dst;
4645 BOOL is_1bpp;
4647 glyph_bitmap.index = analysis->run.glyphIndices[i];
4648 freetype_get_glyph_bbox(&glyph_bitmap);
4650 if (IsRectEmpty(bbox)) {
4651 origin.x += advance->x;
4652 origin.y += advance->y;
4653 continue;
4656 width = bbox->right - bbox->left;
4657 height = bbox->bottom - bbox->top;
4659 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4660 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4661 else
4662 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4664 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4665 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4667 if (is_rtl)
4668 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4669 else
4670 OffsetRect(bbox, origin.x, origin.y);
4672 if (advanceoffset)
4673 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4675 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4676 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4677 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4679 /* blit to analysis bitmap */
4680 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4682 if (is_1bpp) {
4683 /* convert 1bpp to 8bpp/24bpp */
4684 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4685 for (y = 0; y < height; y++) {
4686 for (x = 0; x < width; x++)
4687 if (src[x / 8] & masks[x % 8])
4688 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4689 src += glyph_bitmap.pitch;
4690 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4693 else {
4694 for (y = 0; y < height; y++) {
4695 for (x = 0; x < width; x++)
4696 if (src[x / 8] & masks[x % 8])
4697 dst[x] = DWRITE_ALPHA_MAX;
4698 src += get_dib_stride(width, 1);
4699 dst += analysis->bounds.right - analysis->bounds.left;
4703 else {
4704 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4705 for (y = 0; y < height; y++) {
4706 for (x = 0; x < width; x++)
4707 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4708 src += glyph_bitmap.pitch;
4709 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4713 heap_free(glyph_bitmap.buf);
4715 origin.x += advance->x;
4716 origin.y += advance->y;
4719 IDWriteFontFace3_Release(fontface2);
4721 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4723 /* we don't need this anymore */
4724 heap_free(analysis->glyphs);
4725 heap_free(analysis->advances);
4726 heap_free(analysis->advanceoffsets);
4727 heap_free(analysis->ascenderoffsets);
4728 IDWriteFontFace_Release(analysis->run.fontFace);
4730 analysis->glyphs = NULL;
4731 analysis->advances = NULL;
4732 analysis->advanceoffsets = NULL;
4733 analysis->ascenderoffsets = NULL;
4734 analysis->run.glyphIndices = NULL;
4735 analysis->run.fontFace = NULL;
4738 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4739 RECT const *bounds, BYTE *bitmap, UINT32 size)
4741 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4742 UINT32 required;
4743 RECT runbounds;
4745 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4747 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4748 return E_INVALIDARG;
4750 /* make sure buffer is large enough for requested texture type */
4751 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4752 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4753 required *= 3;
4755 if (size < required)
4756 return E_NOT_SUFFICIENT_BUFFER;
4758 /* validate requested texture type with rendering mode */
4759 switch (This->rendering_mode)
4761 case DWRITE_RENDERING_MODE_ALIASED:
4762 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4763 return DWRITE_E_UNSUPPORTEDOPERATION;
4764 break;
4765 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4766 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4767 case DWRITE_RENDERING_MODE_NATURAL:
4768 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4769 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4770 return DWRITE_E_UNSUPPORTEDOPERATION;
4771 break;
4772 default:
4776 memset(bitmap, 0, size);
4777 glyphrunanalysis_get_texturebounds(This, &runbounds);
4778 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4779 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4780 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4781 int dst_width = (bounds->right - bounds->left) * pixel_size;
4782 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4783 BYTE *src, *dst;
4784 int y;
4786 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4787 glyphrunanalysis_render(This, type);
4789 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4790 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4792 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4793 memcpy(dst, src, draw_width);
4794 src += src_width;
4795 dst += dst_width;
4799 return S_OK;
4802 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4803 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4805 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4807 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4809 if (!params)
4810 return E_INVALIDARG;
4812 switch (This->rendering_mode)
4814 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4815 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4817 UINT value = 0;
4818 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4819 *gamma = (FLOAT)value / 1000.0f;
4820 *contrast = 0.0f;
4821 *cleartypelevel = 1.0f;
4822 break;
4824 case DWRITE_RENDERING_MODE_ALIASED:
4825 case DWRITE_RENDERING_MODE_NATURAL:
4826 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4827 *gamma = IDWriteRenderingParams_GetGamma(params);
4828 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4829 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4830 break;
4831 default:
4835 return S_OK;
4838 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4839 glyphrunanalysis_QueryInterface,
4840 glyphrunanalysis_AddRef,
4841 glyphrunanalysis_Release,
4842 glyphrunanalysis_GetAlphaTextureBounds,
4843 glyphrunanalysis_CreateAlphaTexture,
4844 glyphrunanalysis_GetAlphaBlendParams
4847 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4849 if (is_vertical) {
4850 vec->x = 0.0f;
4851 vec->y = length;
4853 else {
4854 vec->x = length;
4855 vec->y = 0.0f;
4859 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4861 D2D_POINT_2F ret;
4862 ret.x = vec->x * m->m11 + vec->y * m->m21;
4863 ret.y = vec->x * m->m12 + vec->y * m->m22;
4864 *vec = ret;
4867 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4868 FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
4869 FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4871 struct dwrite_glyphrunanalysis *analysis;
4872 FLOAT rtl_factor;
4873 UINT32 i;
4875 *ret = NULL;
4877 /* check for valid rendering mode */
4878 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4879 return E_INVALIDARG;
4881 analysis = heap_alloc(sizeof(*analysis));
4882 if (!analysis)
4883 return E_OUTOFMEMORY;
4885 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4886 analysis->ref = 1;
4887 analysis->rendering_mode = rendering_mode;
4888 analysis->flags = 0;
4889 analysis->bitmap = NULL;
4890 analysis->ppdip = ppdip;
4891 analysis->origin.x = originX * ppdip;
4892 analysis->origin.y = originY * ppdip;
4893 SetRectEmpty(&analysis->bounds);
4894 analysis->run = *run;
4895 IDWriteFontFace_AddRef(analysis->run.fontFace);
4896 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4897 analysis->advances = heap_alloc(run->glyphCount*sizeof(*analysis->advances));
4898 if (run->glyphOffsets) {
4899 analysis->advanceoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->advanceoffsets));
4900 analysis->ascenderoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->ascenderoffsets));
4902 else {
4903 analysis->advanceoffsets = NULL;
4904 analysis->ascenderoffsets = NULL;
4907 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && run->glyphOffsets)) {
4908 heap_free(analysis->glyphs);
4909 heap_free(analysis->advances);
4910 heap_free(analysis->advanceoffsets);
4911 heap_free(analysis->ascenderoffsets);
4913 analysis->glyphs = NULL;
4914 analysis->advances = NULL;
4915 analysis->advanceoffsets = NULL;
4916 analysis->ascenderoffsets = NULL;
4918 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4919 return E_OUTOFMEMORY;
4922 /* check if transform is usable */
4923 if (transform && memcmp(transform, &identity, sizeof(*transform))) {
4924 analysis->m = *transform;
4925 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4927 else
4928 memset(&analysis->m, 0, sizeof(analysis->m));
4930 analysis->run.glyphIndices = analysis->glyphs;
4931 analysis->run.glyphAdvances = NULL;
4932 analysis->run.glyphOffsets = NULL;
4934 rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f;
4936 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4937 transform_2d_vec(&analysis->origin, &analysis->m);
4939 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4941 if (run->glyphAdvances) {
4942 for (i = 0; i < run->glyphCount; i++) {
4943 init_2d_vec(analysis->advances + i, rtl_factor * run->glyphAdvances[i] * ppdip, run->isSideways);
4944 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4945 transform_2d_vec(analysis->advances + i, &analysis->m);
4948 else {
4949 DWRITE_FONT_METRICS metrics;
4950 IDWriteFontFace1 *fontface1;
4952 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4953 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4955 for (i = 0; i < run->glyphCount; i++) {
4956 HRESULT hr;
4957 INT32 a;
4959 switch (measuring_mode)
4961 case DWRITE_MEASURING_MODE_NATURAL:
4962 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4963 if (FAILED(hr))
4964 a = 0;
4965 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics) * ppdip,
4966 run->isSideways);
4967 break;
4968 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4969 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4970 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, transform,
4971 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4972 if (FAILED(hr))
4973 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4974 else
4975 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f),
4976 run->isSideways);
4977 break;
4978 default:
4982 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4983 transform_2d_vec(analysis->advances + i, &analysis->m);
4986 IDWriteFontFace1_Release(fontface1);
4989 if (run->glyphOffsets) {
4990 for (i = 0; i < run->glyphCount; i++) {
4991 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
4992 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4993 init_2d_vec(analysis->ascenderoffsets + i, -run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
4994 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
4995 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
4996 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
5001 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5002 return S_OK;
5005 /* IDWriteColorGlyphRunEnumerator */
5006 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5008 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5010 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5012 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5013 IsEqualIID(riid, &IID_IUnknown))
5015 *ppv = iface;
5016 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5017 return S_OK;
5020 *ppv = NULL;
5021 return E_NOINTERFACE;
5024 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5026 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5027 ULONG ref = InterlockedIncrement(&This->ref);
5028 TRACE("(%p)->(%u)\n", This, ref);
5029 return ref;
5032 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5034 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5035 ULONG ref = InterlockedDecrement(&This->ref);
5037 TRACE("(%p)->(%u)\n", This, ref);
5039 if (!ref) {
5040 heap_free(This->advances);
5041 heap_free(This->color_advances);
5042 heap_free(This->offsets);
5043 heap_free(This->color_offsets);
5044 heap_free(This->glyphindices);
5045 heap_free(This->glyphs);
5046 if (This->colr.context)
5047 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
5048 IDWriteFontFace3_Release(This->fontface);
5049 heap_free(This);
5052 return ref;
5055 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5057 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5058 FLOAT origin = 0.0f;
5060 if (g == 0)
5061 return 0.0f;
5063 while (g--)
5064 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5065 return origin;
5068 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5070 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5071 FLOAT advance_adj = 0.0f;
5072 BOOL got_palette_index;
5073 UINT32 g;
5075 /* start with regular glyphs */
5076 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5077 UINT32 first_glyph = 0;
5079 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5080 if (glyphenum->glyphs[g].num_layers == 0) {
5081 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5082 first_glyph = min(first_glyph, g);
5084 else
5085 glyphenum->glyphindices[g] = 1;
5086 glyphenum->color_advances[g] = glyphenum->advances[g];
5087 if (glyphenum->color_offsets)
5088 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5091 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5092 colorrun->baselineOriginY = glyphenum->origin_y;
5093 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5094 colorrun->paletteIndex = 0xffff;
5095 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5096 glyphenum->has_regular_glyphs = FALSE;
5097 return TRUE;
5099 else {
5100 colorrun->glyphRun.glyphCount = 0;
5101 got_palette_index = FALSE;
5104 advance_adj = 0.0f;
5105 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5107 glyphenum->glyphindices[g] = 1;
5109 /* all glyph layers were returned */
5110 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5111 advance_adj += glyphenum->advances[g];
5112 continue;
5115 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5116 UINT32 index = colorrun->glyphRun.glyphCount;
5117 if (!got_palette_index) {
5118 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5119 /* use foreground color or request one from the font */
5120 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5121 if (colorrun->paletteIndex != 0xffff) {
5122 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5123 1, &colorrun->runColor);
5124 if (FAILED(hr))
5125 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5126 glyphenum->palette, colorrun->paletteIndex, hr);
5128 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5129 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5130 colorrun->baselineOriginY = glyphenum->origin_y;
5131 glyphenum->color_advances[index] = glyphenum->advances[g];
5132 got_palette_index = TRUE;
5135 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5136 /* offsets are relative to glyph origin, nothing to fix up */
5137 if (glyphenum->color_offsets)
5138 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5139 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5140 if (index)
5141 glyphenum->color_advances[index-1] += advance_adj;
5142 colorrun->glyphRun.glyphCount++;
5143 advance_adj = 0.0f;
5145 else
5146 advance_adj += glyphenum->advances[g];
5149 /* reset last advance */
5150 if (colorrun->glyphRun.glyphCount)
5151 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5153 return colorrun->glyphRun.glyphCount > 0;
5156 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5158 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5160 TRACE("(%p)->(%p)\n", This, has_run);
5162 *has_run = FALSE;
5164 This->colorrun.glyphRun.glyphCount = 0;
5165 while (This->current_layer < This->max_layer_num) {
5166 if (colorglyphenum_build_color_run(This))
5167 break;
5168 else
5169 This->current_layer++;
5172 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5174 return S_OK;
5177 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5179 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5181 TRACE("(%p)->(%p)\n", This, run);
5183 if (This->colorrun.glyphRun.glyphCount == 0) {
5184 *run = NULL;
5185 return E_NOT_VALID_STATE;
5188 *run = &This->colorrun;
5189 return S_OK;
5192 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5193 colorglyphenum_QueryInterface,
5194 colorglyphenum_AddRef,
5195 colorglyphenum_Release,
5196 colorglyphenum_MoveNext,
5197 colorglyphenum_GetCurrentRun
5200 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5201 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5203 struct dwrite_colorglyphenum *colorglyphenum;
5204 BOOL colorfont, has_colored_glyph;
5205 IDWriteFontFace3 *fontface3;
5206 HRESULT hr;
5207 UINT32 i;
5209 *ret = NULL;
5211 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5212 if (FAILED(hr)) {
5213 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5214 return hr;
5217 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5218 if (!colorfont) {
5219 hr = DWRITE_E_NOCOLOR;
5220 goto failed;
5223 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5224 if (!colorglyphenum) {
5225 hr = E_OUTOFMEMORY;
5226 goto failed;
5229 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5230 colorglyphenum->ref = 1;
5231 colorglyphenum->origin_x = originX;
5232 colorglyphenum->origin_y = originY;
5233 colorglyphenum->fontface = fontface3;
5234 colorglyphenum->glyphs = NULL;
5235 colorglyphenum->run = *run;
5236 colorglyphenum->run.glyphIndices = NULL;
5237 colorglyphenum->run.glyphAdvances = NULL;
5238 colorglyphenum->run.glyphOffsets = NULL;
5239 colorglyphenum->palette = palette;
5240 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5241 colorglyphenum->colr.exists = TRUE;
5242 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5243 colorglyphenum->current_layer = 0;
5244 colorglyphenum->max_layer_num = 0;
5246 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5248 has_colored_glyph = FALSE;
5249 colorglyphenum->has_regular_glyphs = FALSE;
5250 for (i = 0; i < run->glyphCount; i++) {
5251 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5252 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5253 has_colored_glyph = TRUE;
5255 if (colorglyphenum->glyphs[i].num_layers == 0)
5256 colorglyphenum->has_regular_glyphs = TRUE;
5259 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5260 is supposed to proceed normally, like if font had no color info at all. */
5261 if (!has_colored_glyph) {
5262 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5263 return DWRITE_E_NOCOLOR;
5266 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5267 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5268 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5269 if (run->glyphOffsets) {
5270 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5271 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5272 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5275 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5276 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5277 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5278 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5280 if (run->glyphAdvances)
5281 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5282 else {
5283 DWRITE_FONT_METRICS metrics;
5285 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5286 for (i = 0; i < run->glyphCount; i++) {
5287 HRESULT hr;
5288 INT32 a;
5290 switch (measuring_mode)
5292 case DWRITE_MEASURING_MODE_NATURAL:
5293 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5294 if (FAILED(hr))
5295 a = 0;
5296 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5297 break;
5298 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5299 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5300 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5301 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5302 if (FAILED(hr))
5303 colorglyphenum->advances[i] = 0.0f;
5304 else
5305 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5306 break;
5307 default:
5313 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5314 return S_OK;
5316 failed:
5317 IDWriteFontFace3_Release(fontface3);
5318 return hr;
5321 /* IDWriteFontFaceReference */
5322 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5324 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5326 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5328 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5329 *obj = iface;
5330 IDWriteFontFaceReference_AddRef(iface);
5331 return S_OK;
5334 *obj = NULL;
5336 return E_NOINTERFACE;
5339 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5341 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5342 ULONG ref = InterlockedIncrement(&This->ref);
5343 TRACE("(%p)->(%u)\n", This, ref);
5344 return ref;
5347 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5349 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5350 ULONG ref = InterlockedDecrement(&This->ref);
5352 TRACE("(%p)->(%u)\n", This, ref);
5354 if (!ref) {
5355 IDWriteFontFile_Release(This->file);
5356 IDWriteFactory3_Release(This->factory);
5357 heap_free(This);
5360 return ref;
5363 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5365 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5367 TRACE("(%p)->(%p)\n", This, fontface);
5369 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5372 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5373 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5375 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5376 DWRITE_FONT_FILE_TYPE file_type;
5377 DWRITE_FONT_FACE_TYPE face_type;
5378 IDWriteFontFace *fontface;
5379 BOOL is_supported;
5380 UINT32 face_num;
5381 HRESULT hr;
5383 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5385 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5386 if (FAILED(hr))
5387 return hr;
5389 hr = IDWriteFactory3_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5390 if (SUCCEEDED(hr)) {
5391 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)ret);
5392 IDWriteFontFace_Release(fontface);
5395 return hr;
5398 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5400 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5401 IDWriteFontFile *file;
5402 BOOL ret;
5404 TRACE("(%p)->(%p)\n", This, ref);
5406 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5407 return FALSE;
5409 ret = is_same_fontfile(This->file, file);
5410 IDWriteFontFile_Release(file);
5412 return ret;
5415 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5417 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5419 TRACE("(%p)\n", This);
5421 return This->index;
5424 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5426 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5428 TRACE("(%p)\n", This);
5430 return This->simulations;
5433 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5435 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5436 IDWriteFontFileLoader *loader;
5437 const void *key;
5438 UINT32 key_size;
5439 HRESULT hr;
5441 TRACE("(%p)->(%p)\n", This, file);
5443 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5444 if (FAILED(hr))
5445 return hr;
5447 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5448 if (FAILED(hr))
5449 return hr;
5451 hr = IDWriteFactory3_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5452 IDWriteFontFileLoader_Release(loader);
5454 return hr;
5457 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5459 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5461 FIXME("(%p): stub\n", This);
5463 return 0;
5466 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5468 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5470 FIXME("(%p): stub\n", This);
5472 return 0;
5475 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5477 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5479 FIXME("(%p)->(%p): stub\n", This, writetime);
5481 return E_NOTIMPL;
5484 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5486 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5488 FIXME("(%p): stub\n", This);
5490 return DWRITE_LOCALITY_LOCAL;
5493 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5495 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5497 FIXME("(%p): stub\n", This);
5499 return E_NOTIMPL;
5502 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5503 UINT32 count)
5505 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5507 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5509 return E_NOTIMPL;
5512 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5513 UINT32 count)
5515 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5517 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5519 return E_NOTIMPL;
5522 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5523 UINT64 offset, UINT64 size)
5525 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5527 FIXME("(%p)->(%s %s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5529 return E_NOTIMPL;
5532 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5533 fontfacereference_QueryInterface,
5534 fontfacereference_AddRef,
5535 fontfacereference_Release,
5536 fontfacereference_CreateFontFace,
5537 fontfacereference_CreateFontFaceWithSimulations,
5538 fontfacereference_Equals,
5539 fontfacereference_GetFontFaceIndex,
5540 fontfacereference_GetSimulations,
5541 fontfacereference_GetFontFile,
5542 fontfacereference_GetLocalFileSize,
5543 fontfacereference_GetFileSize,
5544 fontfacereference_GetFileTime,
5545 fontfacereference_GetLocality,
5546 fontfacereference_EnqueueFontDownloadRequest,
5547 fontfacereference_EnqueueCharacterDownloadRequest,
5548 fontfacereference_EnqueueGlyphDownloadRequest,
5549 fontfacereference_EnqueueFileFragmentDownloadRequest
5552 HRESULT create_fontfacereference(IDWriteFactory3 *factory, IDWriteFontFile *file, UINT32 index,
5553 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5555 struct dwrite_fontfacereference *ref;
5557 *ret = NULL;
5559 ref = heap_alloc(sizeof(*ref));
5560 if (!ref)
5561 return E_OUTOFMEMORY;
5563 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
5564 ref->ref = 1;
5566 ref->factory = factory;
5567 IDWriteFactory3_AddRef(ref->factory);
5568 ref->file = file;
5569 IDWriteFontFile_AddRef(ref->file);
5570 ref->index = index;
5571 ref->simulations = simulations;
5572 *ret = &ref->IDWriteFontFaceReference_iface;
5574 return S_OK;