Release 4.0.4.
[wine.git] / dlls / dwrite / font.c
blob97b99f9775174638a7f001c653f18a342628b60c
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
31 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
33 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
34 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
44 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
45 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
46 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
48 static const WCHAR extraW[] = {'e','x','t','r','a',0};
49 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
50 static const WCHAR semiW[] = {'s','e','m','i',0};
51 static const WCHAR extW[] = {'e','x','t',0};
52 static const WCHAR thinW[] = {'t','h','i','n',0};
53 static const WCHAR lightW[] = {'l','i','g','h','t',0};
54 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
55 static const WCHAR blackW[] = {'b','l','a','c','k',0};
56 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
57 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
58 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
59 static const WCHAR boldW[] = {'B','o','l','d',0};
60 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
61 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
62 static const WCHAR demiW[] = {'d','e','m','i',0};
63 static const WCHAR spaceW[] = {' ',0};
64 static const WCHAR enusW[] = {'e','n','-','u','s',0};
66 struct dwrite_font_propvec {
67 FLOAT stretch;
68 FLOAT style;
69 FLOAT weight;
72 struct dwrite_font_data {
73 LONG ref;
75 DWRITE_FONT_STYLE style;
76 DWRITE_FONT_STRETCH stretch;
77 DWRITE_FONT_WEIGHT weight;
78 DWRITE_PANOSE panose;
79 FONTSIGNATURE fontsig;
80 struct dwrite_font_propvec propvec;
82 DWRITE_FONT_METRICS1 metrics;
83 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
84 IDWriteLocalizedStrings *names;
86 /* data needed to create fontface instance */
87 DWRITE_FONT_FACE_TYPE face_type;
88 IDWriteFontFile *file;
89 UINT32 face_index;
91 WCHAR *facename;
93 USHORT simulations;
95 LOGFONTW lf;
97 /* used to mark font as tested when scanning for simulation candidate */
98 BOOL bold_sim_tested : 1;
99 BOOL oblique_sim_tested : 1;
102 struct dwrite_fontfamily_data {
103 LONG ref;
105 IDWriteLocalizedStrings *familyname;
107 struct dwrite_font_data **fonts;
108 UINT32 font_count;
109 UINT32 font_alloc;
110 BOOL has_normal_face : 1;
111 BOOL has_oblique_face : 1;
112 BOOL has_italic_face : 1;
115 struct dwrite_fontcollection {
116 IDWriteFontCollection1 IDWriteFontCollection1_iface;
117 LONG ref;
119 IDWriteFactory5 *factory;
120 struct dwrite_fontfamily_data **family_data;
121 UINT32 family_count;
122 UINT32 family_alloc;
125 struct dwrite_fontfamily {
126 IDWriteFontFamily1 IDWriteFontFamily1_iface;
127 IDWriteFontList1 IDWriteFontList1_iface;
128 LONG ref;
130 struct dwrite_fontfamily_data *data;
131 struct dwrite_fontcollection *collection;
134 struct dwrite_fontlist {
135 IDWriteFontList1 IDWriteFontList1_iface;
136 LONG ref;
138 struct dwrite_font_data **fonts;
139 UINT32 font_count;
140 struct dwrite_fontfamily *family;
143 struct dwrite_font {
144 IDWriteFont3 IDWriteFont3_iface;
145 LONG ref;
147 DWRITE_FONT_STYLE style;
148 struct dwrite_font_data *data;
149 struct dwrite_fontfamily *family;
152 struct dwrite_fonttable {
153 void *data;
154 void *context;
155 UINT32 size;
156 BOOL exists;
159 enum runanalysis_flags {
160 RUNANALYSIS_BOUNDS_READY = 1 << 0,
161 RUNANALYSIS_BITMAP_READY = 1 << 1,
162 RUNANALYSIS_USE_TRANSFORM = 1 << 2
165 struct dwrite_glyphrunanalysis {
166 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
167 LONG ref;
169 DWRITE_RENDERING_MODE1 rendering_mode;
170 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
171 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
172 DWRITE_MATRIX m;
173 UINT16 *glyphs;
174 D2D_POINT_2F *origins;
176 UINT8 flags;
177 RECT bounds;
178 BYTE *bitmap;
179 UINT32 max_glyph_bitmap_size;
182 struct dwrite_colorglyphenum {
183 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
184 LONG ref;
186 FLOAT origin_x; /* original run origin */
187 FLOAT origin_y;
189 IDWriteFontFace4 *fontface; /* for convenience */
190 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
191 DWRITE_GLYPH_RUN run; /* base run */
192 UINT32 palette; /* palette index to get layer color from */
193 FLOAT *advances; /* original or measured advances for base glyphs */
194 FLOAT *color_advances; /* returned color run points to this */
195 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
196 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
197 UINT16 *glyphindices; /* returned color run points to this */
198 struct dwrite_colorglyph *glyphs; /* current glyph color info */
199 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
200 UINT16 current_layer; /* enumerator position, updated with MoveNext */
201 UINT16 max_layer_num; /* max number of layers for this run */
202 struct dwrite_fonttable colr; /* used to access layers */
205 #define GLYPH_BLOCK_SHIFT 8
206 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
207 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
208 #define GLYPH_MAX 65536
210 enum fontface_flags {
211 FONTFACE_IS_SYMBOL = 1 << 0,
212 FONTFACE_IS_MONOSPACED = 1 << 1,
213 FONTFACE_HAS_KERNING_PAIRS = 1 << 2,
214 FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
217 struct dwrite_fontface {
218 IDWriteFontFace4 IDWriteFontFace4_iface;
219 LONG ref;
221 IDWriteFontFileStream *stream;
222 IDWriteFontFile **files;
223 UINT32 file_count;
224 UINT32 index;
226 IDWriteFactory5 *factory;
227 struct fontfacecached *cached;
229 USHORT simulations;
230 DWRITE_FONT_FACE_TYPE type;
231 DWRITE_FONT_METRICS1 metrics;
232 DWRITE_CARET_METRICS caret;
233 INT charmap;
234 UINT16 flags;
236 struct dwrite_fonttable cmap;
237 struct dwrite_fonttable vdmx;
238 struct dwrite_fonttable gasp;
239 struct dwrite_fonttable cpal;
240 struct dwrite_fonttable colr;
241 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
243 DWRITE_FONT_STYLE style;
244 DWRITE_FONT_STRETCH stretch;
245 DWRITE_FONT_WEIGHT weight;
246 DWRITE_PANOSE panose;
247 FONTSIGNATURE fontsig;
248 UINT32 glyph_image_formats;
250 LOGFONTW lf;
253 struct dwrite_fontfile {
254 IDWriteFontFile IDWriteFontFile_iface;
255 LONG ref;
257 IDWriteFontFileLoader *loader;
258 void *reference_key;
259 UINT32 key_size;
260 IDWriteFontFileStream *stream;
263 struct dwrite_fontfacereference {
264 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
265 LONG ref;
267 IDWriteFontFile *file;
268 UINT32 index;
269 USHORT simulations;
270 IDWriteFactory5 *factory;
273 static inline struct dwrite_fontface *impl_from_IDWriteFontFace4(IDWriteFontFace4 *iface)
275 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
278 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
280 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
283 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
285 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
288 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
290 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
293 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList1(IDWriteFontList1 *iface)
295 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList1_iface);
298 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
300 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
303 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
305 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
308 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
310 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
313 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
315 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
318 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
320 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
323 static inline const char *debugstr_tag(UINT32 tag)
325 return debugstr_an((char*)&tag, 4);
328 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
330 static const DWRITE_GLYPH_METRICS nil;
331 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
333 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
334 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
335 return S_OK;
338 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
340 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
342 if (!*block) {
343 /* start new block */
344 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
345 if (!*block)
346 return E_OUTOFMEMORY;
349 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
350 return S_OK;
353 static void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table)
355 HRESULT hr;
357 if (table->data || !table->exists)
358 return table->data;
360 table->exists = FALSE;
361 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
362 &table->exists);
363 if (FAILED(hr) || !table->exists) {
364 TRACE("Font does not have %s table\n", debugstr_tag(tag));
365 return NULL;
368 return table->data;
371 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
372 struct dwrite_font_propvec *vec)
374 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
375 vec->style = style * 7.0f;
376 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
379 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
381 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
384 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
386 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
389 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
391 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CMAP_TAG, &fontface->cmap);
394 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
396 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx);
399 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
401 void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp);
402 *size = fontface->gasp.size;
403 return ptr;
406 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
408 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal);
411 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
413 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &fontface->colr);
416 static void addref_font_data(struct dwrite_font_data *data)
418 InterlockedIncrement(&data->ref);
421 static void release_font_data(struct dwrite_font_data *data)
423 int i;
425 if (InterlockedDecrement(&data->ref) > 0)
426 return;
428 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < ARRAY_SIZE(data->info_strings); i++) {
429 if (data->info_strings[i])
430 IDWriteLocalizedStrings_Release(data->info_strings[i]);
432 if (data->names)
433 IDWriteLocalizedStrings_Release(data->names);
435 IDWriteFontFile_Release(data->file);
436 heap_free(data->facename);
437 heap_free(data);
440 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
442 int i;
444 if (InterlockedDecrement(&data->ref) > 0)
445 return;
447 for (i = 0; i < data->font_count; i++)
448 release_font_data(data->fonts[i]);
449 heap_free(data->fonts);
450 IDWriteLocalizedStrings_Release(data->familyname);
451 heap_free(data);
454 void fontface_detach_from_cache(IDWriteFontFace4 *iface)
456 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace4(iface);
457 fontface->cached = NULL;
460 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace4 *iface, REFIID riid, void **obj)
462 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
464 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
466 if (IsEqualIID(riid, &IID_IDWriteFontFace4) ||
467 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
468 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
469 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
470 IsEqualIID(riid, &IID_IDWriteFontFace) ||
471 IsEqualIID(riid, &IID_IUnknown))
473 *obj = iface;
474 if (InterlockedIncrement(&This->ref) == 1) {
475 InterlockedDecrement(&This->ref);
476 *obj = NULL;
477 return E_FAIL;
479 return S_OK;
482 WARN("%s not implemented.\n", debugstr_guid(riid));
484 *obj = NULL;
485 return E_NOINTERFACE;
488 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace4 *iface)
490 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
491 ULONG ref = InterlockedIncrement(&This->ref);
492 TRACE("(%p)->(%d)\n", This, ref);
493 return ref;
496 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
498 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
499 ULONG ref = InterlockedDecrement(&This->ref);
501 TRACE("(%p)->(%d)\n", This, ref);
503 if (!ref) {
504 UINT32 i;
506 if (This->cached) {
507 factory_lock(This->factory);
508 list_remove(&This->cached->entry);
509 factory_unlock(This->factory);
510 heap_free(This->cached);
513 if (This->cmap.context)
514 IDWriteFontFace4_ReleaseFontTable(iface, This->cmap.context);
515 if (This->vdmx.context)
516 IDWriteFontFace4_ReleaseFontTable(iface, This->vdmx.context);
517 if (This->gasp.context)
518 IDWriteFontFace4_ReleaseFontTable(iface, This->gasp.context);
519 if (This->cpal.context)
520 IDWriteFontFace4_ReleaseFontTable(iface, This->cpal.context);
521 if (This->colr.context)
522 IDWriteFontFace4_ReleaseFontTable(iface, This->colr.context);
523 for (i = 0; i < This->file_count; i++) {
524 if (This->files[i])
525 IDWriteFontFile_Release(This->files[i]);
527 if (This->stream)
528 IDWriteFontFileStream_Release(This->stream);
529 heap_free(This->files);
531 for (i = 0; i < ARRAY_SIZE(This->glyphs); i++)
532 heap_free(This->glyphs[i]);
534 freetype_notify_cacheremove(iface);
536 IDWriteFactory5_Release(This->factory);
537 heap_free(This);
540 return ref;
543 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace4 *iface)
545 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
546 TRACE("(%p)\n", This);
547 return This->type;
550 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace4 *iface, UINT32 *number_of_files,
551 IDWriteFontFile **fontfiles)
553 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
554 int i;
556 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
557 if (fontfiles == NULL)
559 *number_of_files = This->file_count;
560 return S_OK;
562 if (*number_of_files < This->file_count)
563 return E_INVALIDARG;
565 for (i = 0; i < This->file_count; i++)
567 IDWriteFontFile_AddRef(This->files[i]);
568 fontfiles[i] = This->files[i];
571 return S_OK;
574 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace4 *iface)
576 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
577 TRACE("(%p)\n", This);
578 return This->index;
581 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace4 *iface)
583 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
584 TRACE("(%p)\n", This);
585 return This->simulations;
588 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace4 *iface)
590 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
591 TRACE("(%p)\n", This);
592 return !!(This->flags & FONTFACE_IS_SYMBOL);
595 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS *metrics)
597 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
598 TRACE("(%p)->(%p)\n", This, metrics);
599 memcpy(metrics, &This->metrics, sizeof(*metrics));
602 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface)
604 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
605 TRACE("(%p)\n", This);
606 return freetype_get_glyphcount(iface);
609 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface,
610 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
612 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
613 HRESULT hr;
614 UINT32 i;
616 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
618 if (!glyphs)
619 return E_INVALIDARG;
621 if (is_sideways)
622 FIXME("sideways metrics are not supported.\n");
624 for (i = 0; i < glyph_count; i++) {
625 DWRITE_GLYPH_METRICS metrics;
627 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
628 if (hr != S_OK) {
629 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
630 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
631 if (FAILED(hr))
632 return hr;
634 ret[i] = metrics;
637 return S_OK;
640 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
641 UINT32 count, UINT16 *glyphs)
643 if (!glyphs)
644 return E_INVALIDARG;
646 if (!codepoints) {
647 memset(glyphs, 0, count * sizeof(*glyphs));
648 return E_INVALIDARG;
651 freetype_get_glyphs(&fontface->IDWriteFontFace4_iface, fontface->charmap, codepoints, count, glyphs);
652 return S_OK;
655 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace4 *iface, UINT32 const *codepoints,
656 UINT32 count, UINT16 *glyphs)
658 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
660 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyphs);
662 return fontface_get_glyphs(This, codepoints, count, glyphs);
665 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace4 *iface, UINT32 table_tag,
666 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
668 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
669 struct file_stream_desc stream_desc;
671 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
673 stream_desc.stream = This->stream;
674 stream_desc.face_type = This->type;
675 stream_desc.face_index = This->index;
676 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
679 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace4 *iface, void *table_context)
681 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
683 TRACE("(%p)->(%p)\n", This, table_context);
685 IDWriteFontFileStream_ReleaseFileFragment(This->stream, table_context);
688 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, FLOAT emSize,
689 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
690 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
692 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
694 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
695 count, is_sideways, is_rtl, sink);
697 if (!glyphs || !sink)
698 return E_INVALIDARG;
700 if (is_sideways)
701 FIXME("sideways mode is not supported.\n");
703 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
706 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
707 FLOAT ppem, WORD gasp)
709 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
711 switch (measuring)
713 case DWRITE_MEASURING_MODE_NATURAL:
715 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
716 mode = DWRITE_RENDERING_MODE_NATURAL;
717 else
718 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
719 break;
721 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
722 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
723 break;
724 case DWRITE_MEASURING_MODE_GDI_NATURAL:
725 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
726 break;
727 default:
731 return mode;
734 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
735 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
737 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
738 WORD gasp, *ptr;
739 UINT32 size;
740 FLOAT ppem;
742 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
744 if (!params) {
745 *mode = DWRITE_RENDERING_MODE_DEFAULT;
746 return E_INVALIDARG;
749 *mode = IDWriteRenderingParams_GetRenderingMode(params);
750 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
751 return S_OK;
753 ppem = emSize * ppdip;
755 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
756 *mode = DWRITE_RENDERING_MODE_OUTLINE;
757 return S_OK;
760 ptr = get_fontface_gasp(This, &size);
761 gasp = opentype_get_gasp_flags(ptr, size, ppem);
762 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
763 return S_OK;
766 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT pixels_per_dip,
767 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
769 DWRITE_FONT_METRICS1 metrics1;
770 HRESULT hr = IDWriteFontFace4_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
771 memcpy(metrics, &metrics1, sizeof(*metrics));
772 return hr;
775 static inline int round_metric(FLOAT metric)
777 return (int)floorf(metric + 0.5f);
780 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
782 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
783 return 0;
785 return (fontface->metrics.designUnitsPerEm + 49) / 50;
788 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip,
789 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
790 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
792 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
793 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
794 DWRITE_MEASURING_MODE mode;
795 FLOAT scale, size;
796 HRESULT hr;
797 UINT32 i;
799 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
800 glyph_count, metrics, is_sideways);
802 if (m && memcmp(m, &identity, sizeof(*m)))
803 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
805 size = emSize * ppdip;
806 scale = size / This->metrics.designUnitsPerEm;
807 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
809 for (i = 0; i < glyph_count; i++) {
810 DWRITE_GLYPH_METRICS *ret = metrics + i;
811 DWRITE_GLYPH_METRICS design;
812 BOOL has_contours;
814 hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
815 if (FAILED(hr))
816 return hr;
818 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
819 if (has_contours)
820 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment);
821 else
822 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
824 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
825 SCALE_METRIC(leftSideBearing);
826 SCALE_METRIC(rightSideBearing);
827 SCALE_METRIC(topSideBearing);
828 SCALE_METRIC(advanceHeight);
829 SCALE_METRIC(bottomSideBearing);
830 SCALE_METRIC(verticalOriginY);
831 #undef SCALE_METRIC
834 return S_OK;
837 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS1 *metrics)
839 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
840 TRACE("(%p)->(%p)\n", This, metrics);
841 *metrics = This->metrics;
844 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT em_size, FLOAT pixels_per_dip,
845 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
847 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
848 const DWRITE_FONT_METRICS1 *design = &This->metrics;
849 UINT16 ascent, descent;
850 FLOAT scale;
852 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
854 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
855 memset(metrics, 0, sizeof(*metrics));
856 return E_INVALIDARG;
859 em_size *= pixels_per_dip;
860 if (m && m->m22 != 0.0f)
861 em_size *= fabs(m->m22);
863 scale = em_size / design->designUnitsPerEm;
864 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
865 ascent = round_metric(design->ascent * scale);
866 descent = round_metric(design->descent * scale);
869 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
870 metrics->designUnitsPerEm = design->designUnitsPerEm;
871 metrics->ascent = round_metric(ascent / scale);
872 metrics->descent = round_metric(descent / scale);
874 SCALE_METRIC(lineGap);
875 SCALE_METRIC(capHeight);
876 SCALE_METRIC(xHeight);
877 SCALE_METRIC(underlinePosition);
878 SCALE_METRIC(underlineThickness);
879 SCALE_METRIC(strikethroughPosition);
880 SCALE_METRIC(strikethroughThickness);
881 SCALE_METRIC(glyphBoxLeft);
882 SCALE_METRIC(glyphBoxTop);
883 SCALE_METRIC(glyphBoxRight);
884 SCALE_METRIC(glyphBoxBottom);
885 SCALE_METRIC(subscriptPositionX);
886 SCALE_METRIC(subscriptPositionY);
887 SCALE_METRIC(subscriptSizeX);
888 SCALE_METRIC(subscriptSizeY);
889 SCALE_METRIC(superscriptPositionX);
890 SCALE_METRIC(superscriptPositionY);
891 SCALE_METRIC(superscriptSizeX);
892 SCALE_METRIC(superscriptSizeY);
894 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
895 #undef SCALE_METRIC
897 return S_OK;
900 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace4 *iface, DWRITE_CARET_METRICS *metrics)
902 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
903 TRACE("(%p)->(%p)\n", This, metrics);
904 *metrics = This->caret;
907 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, UINT32 max_count,
908 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
910 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
912 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
914 *count = 0;
915 if (max_count && !ranges)
916 return E_INVALIDARG;
918 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
921 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface)
923 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
924 TRACE("(%p)\n", This);
925 return !!(This->flags & FONTFACE_IS_MONOSPACED);
928 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *iface,
929 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
931 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
932 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
933 UINT32 i;
935 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
937 if (is_sideways)
938 FIXME("sideways mode not supported\n");
940 for (i = 0; i < glyph_count; i++) {
941 BOOL has_contours;
943 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i],
944 DWRITE_MEASURING_MODE_NATURAL, &has_contours);
945 if (has_contours)
946 advances[i] += adjustment;
949 return S_OK;
952 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4 *iface,
953 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
954 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
956 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
957 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
958 DWRITE_MEASURING_MODE mode;
959 UINT32 i;
961 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
962 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
964 if (em_size < 0.0f || ppdip <= 0.0f) {
965 memset(advances, 0, sizeof(*advances) * glyph_count);
966 return E_INVALIDARG;
969 em_size *= ppdip;
970 if (em_size == 0.0f) {
971 memset(advances, 0, sizeof(*advances) * glyph_count);
972 return S_OK;
975 if (m && memcmp(m, &identity, sizeof(*m)))
976 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
978 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
979 for (i = 0; i < glyph_count; i++) {
980 BOOL has_contours;
982 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode, &has_contours);
983 if (has_contours)
984 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size + adjustment);
985 else
986 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
989 return S_OK;
992 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace4 *iface, UINT32 count,
993 const UINT16 *indices, INT32 *adjustments)
995 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
996 UINT32 i;
998 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
1000 if (!(indices || adjustments) || !count)
1001 return E_INVALIDARG;
1003 if (!indices || count == 1) {
1004 memset(adjustments, 0, count*sizeof(INT32));
1005 return E_INVALIDARG;
1008 if (!(This->flags & FONTFACE_HAS_KERNING_PAIRS)) {
1009 memset(adjustments, 0, count*sizeof(INT32));
1010 return S_OK;
1013 for (i = 0; i < count-1; i++)
1014 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1015 adjustments[count-1] = 0;
1017 return S_OK;
1020 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace4 *iface)
1022 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1023 TRACE("(%p)\n", This);
1024 return !!(This->flags & FONTFACE_HAS_KERNING_PAIRS);
1027 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace4 *iface,
1028 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1029 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1031 DWRITE_GRID_FIT_MODE gridfitmode;
1032 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1033 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1036 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace4 *iface, UINT32 glyph_count,
1037 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1039 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1040 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1041 return E_NOTIMPL;
1044 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace4 *iface)
1046 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1047 TRACE("(%p)\n", This);
1048 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1051 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace4 *iface)
1053 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1054 TRACE("(%p)\n", This);
1055 return get_fontface_cpal(This) && get_fontface_colr(This);
1058 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace4 *iface)
1060 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1061 TRACE("(%p)\n", This);
1062 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1065 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace4 *iface)
1067 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1068 TRACE("(%p)\n", This);
1069 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1072 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace4 *iface, UINT32 palette_index,
1073 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1075 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1076 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1077 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1080 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
1081 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1082 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1083 DWRITE_GRID_FIT_MODE *gridfitmode)
1085 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1086 FLOAT emthreshold;
1087 WORD gasp, *ptr;
1088 UINT32 size;
1090 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1091 measuringmode, params, renderingmode, gridfitmode);
1093 if (m)
1094 FIXME("transform not supported %s\n", debugstr_matrix(m));
1096 if (is_sideways)
1097 FIXME("sideways mode not supported\n");
1099 emSize *= max(dpiX, dpiY) / 96.0f;
1101 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1102 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1103 if (params) {
1104 IDWriteRenderingParams2 *params2;
1105 HRESULT hr;
1107 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1108 if (hr == S_OK) {
1109 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1110 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1111 IDWriteRenderingParams2_Release(params2);
1113 else
1114 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1117 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1119 ptr = get_fontface_gasp(This, &size);
1120 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1122 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1123 if (emSize >= emthreshold)
1124 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1125 else
1126 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1129 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1130 if (emSize >= emthreshold)
1131 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1132 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1133 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1134 else
1135 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1138 return S_OK;
1141 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace4 *iface, IDWriteFontFaceReference **ref)
1143 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1144 FIXME("(%p)->(%p): stub\n", This, ref);
1145 return E_NOTIMPL;
1148 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace4 *iface, DWRITE_PANOSE *panose)
1150 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1151 TRACE("(%p)->(%p)\n", This, panose);
1152 *panose = This->panose;
1155 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace4 *iface)
1157 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1158 TRACE("(%p)\n", This);
1159 return This->weight;
1162 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace4 *iface)
1164 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1165 TRACE("(%p)\n", This);
1166 return This->stretch;
1169 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace4 *iface)
1171 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1172 TRACE("(%p)\n", This);
1173 return This->style;
1176 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1178 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1179 FIXME("(%p)->(%p): stub\n", This, names);
1180 return E_NOTIMPL;
1183 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1185 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1186 FIXME("(%p)->(%p): stub\n", This, names);
1187 return E_NOTIMPL;
1190 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace4 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1191 IDWriteLocalizedStrings **strings, BOOL *exists)
1193 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1194 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1195 return E_NOTIMPL;
1198 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace4 *iface, UINT32 ch)
1200 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1201 UINT16 index;
1203 TRACE("(%p)->(%#x)\n", This, ch);
1205 index = 0;
1206 if (FAILED(fontface_get_glyphs(This, &ch, 1, &index)))
1207 return FALSE;
1209 return index != 0;
1212 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1213 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1214 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1216 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1217 FLOAT emthreshold;
1218 WORD gasp, *ptr;
1219 UINT32 size;
1221 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1222 measuring_mode, params, rendering_mode, gridfit_mode);
1224 if (m)
1225 FIXME("transform not supported %s\n", debugstr_matrix(m));
1227 if (is_sideways)
1228 FIXME("sideways mode not supported\n");
1230 emSize *= max(dpiX, dpiY) / 96.0f;
1232 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1233 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1234 if (params) {
1235 IDWriteRenderingParams3 *params3;
1236 HRESULT hr;
1238 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1239 if (hr == S_OK) {
1240 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1241 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1242 IDWriteRenderingParams3_Release(params3);
1244 else
1245 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1248 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1250 ptr = get_fontface_gasp(This, &size);
1251 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1253 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1254 if (emSize >= emthreshold)
1255 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1256 else
1257 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp);
1260 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1261 if (emSize >= emthreshold)
1262 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1263 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1264 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1265 else
1266 *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1269 return S_OK;
1272 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace4 *iface, UINT32 ch)
1274 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1275 FIXME("(%p)->(0x%x): stub\n", This, ch);
1276 return FALSE;
1279 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace4 *iface, UINT16 glyph)
1281 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1282 FIXME("(%p)->(%u): stub\n", This, glyph);
1283 return FALSE;
1286 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace4 *iface, WCHAR const *text,
1287 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1289 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1290 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1291 return E_NOTIMPL;
1294 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace4 *iface, UINT16 const *glyphs,
1295 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1297 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1298 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1299 return E_NOTIMPL;
1302 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace4 *iface, UINT16 glyph,
1303 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1305 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1306 FIXME("(%p)->(%u %u %u %p): stub\n", This, glyph, ppem_first, ppem_last, formats);
1307 return E_NOTIMPL;
1310 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace4 *iface)
1312 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1314 TRACE("(%p)\n", This);
1316 return This->glyph_image_formats;
1319 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace4 *iface, UINT16 glyph,
1320 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1322 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1323 FIXME("(%p)->(%u %u %d %p %p): stub\n", This, glyph, ppem, format, data, context);
1324 return E_NOTIMPL;
1327 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace4 *iface, void *context)
1329 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1330 FIXME("(%p)->(%p): stub\n", This, context);
1333 static const IDWriteFontFace4Vtbl dwritefontfacevtbl = {
1334 dwritefontface_QueryInterface,
1335 dwritefontface_AddRef,
1336 dwritefontface_Release,
1337 dwritefontface_GetType,
1338 dwritefontface_GetFiles,
1339 dwritefontface_GetIndex,
1340 dwritefontface_GetSimulations,
1341 dwritefontface_IsSymbolFont,
1342 dwritefontface_GetMetrics,
1343 dwritefontface_GetGlyphCount,
1344 dwritefontface_GetDesignGlyphMetrics,
1345 dwritefontface_GetGlyphIndices,
1346 dwritefontface_TryGetFontTable,
1347 dwritefontface_ReleaseFontTable,
1348 dwritefontface_GetGlyphRunOutline,
1349 dwritefontface_GetRecommendedRenderingMode,
1350 dwritefontface_GetGdiCompatibleMetrics,
1351 dwritefontface_GetGdiCompatibleGlyphMetrics,
1352 dwritefontface1_GetMetrics,
1353 dwritefontface1_GetGdiCompatibleMetrics,
1354 dwritefontface1_GetCaretMetrics,
1355 dwritefontface1_GetUnicodeRanges,
1356 dwritefontface1_IsMonospacedFont,
1357 dwritefontface1_GetDesignGlyphAdvances,
1358 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1359 dwritefontface1_GetKerningPairAdjustments,
1360 dwritefontface1_HasKerningPairs,
1361 dwritefontface1_GetRecommendedRenderingMode,
1362 dwritefontface1_GetVerticalGlyphVariants,
1363 dwritefontface1_HasVerticalGlyphVariants,
1364 dwritefontface2_IsColorFont,
1365 dwritefontface2_GetColorPaletteCount,
1366 dwritefontface2_GetPaletteEntryCount,
1367 dwritefontface2_GetPaletteEntries,
1368 dwritefontface2_GetRecommendedRenderingMode,
1369 dwritefontface3_GetFontFaceReference,
1370 dwritefontface3_GetPanose,
1371 dwritefontface3_GetWeight,
1372 dwritefontface3_GetStretch,
1373 dwritefontface3_GetStyle,
1374 dwritefontface3_GetFamilyNames,
1375 dwritefontface3_GetFaceNames,
1376 dwritefontface3_GetInformationalStrings,
1377 dwritefontface3_HasCharacter,
1378 dwritefontface3_GetRecommendedRenderingMode,
1379 dwritefontface3_IsCharacterLocal,
1380 dwritefontface3_IsGlyphLocal,
1381 dwritefontface3_AreCharactersLocal,
1382 dwritefontface3_AreGlyphsLocal,
1383 dwritefontface4_GetGlyphImageFormats_,
1384 dwritefontface4_GetGlyphImageFormats,
1385 dwritefontface4_GetGlyphImageData,
1386 dwritefontface4_ReleaseGlyphImageData
1389 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace4 **fontface)
1391 struct dwrite_font_data *data = font->data;
1392 struct fontface_desc desc;
1393 struct list *cached_list;
1394 HRESULT hr;
1396 *fontface = NULL;
1398 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1399 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1400 if (hr == S_OK)
1401 return hr;
1403 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1404 return hr;
1406 desc.factory = font->family->collection->factory;
1407 desc.face_type = data->face_type;
1408 desc.files = &data->file;
1409 desc.files_number = 1;
1410 desc.index = data->face_index;
1411 desc.simulations = data->simulations;
1412 desc.font_data = data;
1413 hr = create_fontface(&desc, cached_list, fontface);
1415 IDWriteFontFileStream_Release(desc.stream);
1416 return hr;
1419 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1421 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1423 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1425 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1426 IsEqualIID(riid, &IID_IDWriteFont2) ||
1427 IsEqualIID(riid, &IID_IDWriteFont1) ||
1428 IsEqualIID(riid, &IID_IDWriteFont) ||
1429 IsEqualIID(riid, &IID_IUnknown))
1431 *obj = iface;
1432 IDWriteFont3_AddRef(iface);
1433 return S_OK;
1436 WARN("%s not implemented.\n", debugstr_guid(riid));
1438 *obj = NULL;
1439 return E_NOINTERFACE;
1442 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1444 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1445 ULONG ref = InterlockedIncrement(&This->ref);
1446 TRACE("(%p)->(%d)\n", This, ref);
1447 return ref;
1450 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1452 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1453 ULONG ref = InterlockedDecrement(&This->ref);
1455 TRACE("(%p)->(%d)\n", This, ref);
1457 if (!ref) {
1458 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1459 release_font_data(This->data);
1460 heap_free(This);
1463 return ref;
1466 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1468 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1469 TRACE("(%p)->(%p)\n", This, family);
1471 *family = (IDWriteFontFamily*)This->family;
1472 IDWriteFontFamily_AddRef(*family);
1473 return S_OK;
1476 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1478 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1479 TRACE("(%p)\n", This);
1480 return This->data->weight;
1483 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1485 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1486 TRACE("(%p)\n", This);
1487 return This->data->stretch;
1490 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1492 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1493 TRACE("(%p)\n", This);
1494 return This->style;
1497 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1499 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1500 IDWriteFontFace4 *fontface;
1501 HRESULT hr;
1502 BOOL ret;
1504 TRACE("(%p)\n", This);
1506 hr = get_fontface_from_font(This, &fontface);
1507 if (FAILED(hr))
1508 return FALSE;
1510 ret = IDWriteFontFace4_IsSymbolFont(fontface);
1511 IDWriteFontFace4_Release(fontface);
1512 return ret;
1515 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1517 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1518 TRACE("(%p)->(%p)\n", This, names);
1519 return clone_localizedstring(This->data->names, names);
1522 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1523 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1525 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1526 struct dwrite_font_data *data = This->data;
1527 HRESULT hr;
1529 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1531 *exists = FALSE;
1532 *strings = NULL;
1534 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1535 return S_OK;
1537 if (!data->info_strings[stringid]) {
1538 IDWriteFontFace4 *fontface;
1539 const void *table_data;
1540 BOOL table_exists;
1541 void *context;
1542 UINT32 size;
1544 hr = get_fontface_from_font(This, &fontface);
1545 if (FAILED(hr))
1546 return hr;
1548 table_exists = FALSE;
1549 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1550 if (FAILED(hr) || !table_exists)
1551 WARN("no NAME table found.\n");
1553 if (table_exists) {
1554 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1555 IDWriteFontFace4_ReleaseFontTable(fontface, context);
1556 if (FAILED(hr) || !data->info_strings[stringid])
1557 return hr;
1559 IDWriteFontFace4_Release(fontface);
1562 hr = clone_localizedstring(data->info_strings[stringid], strings);
1563 if (FAILED(hr))
1564 return hr;
1566 *exists = TRUE;
1567 return S_OK;
1570 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1572 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1573 TRACE("(%p)\n", This);
1574 return This->data->simulations;
1577 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1579 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1581 TRACE("(%p)->(%p)\n", This, metrics);
1582 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1585 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1587 IDWriteFontFace4 *fontface;
1588 UINT16 index;
1589 HRESULT hr;
1591 *exists = FALSE;
1593 hr = get_fontface_from_font(font, &fontface);
1594 if (FAILED(hr))
1595 return hr;
1597 index = 0;
1598 hr = IDWriteFontFace4_GetGlyphIndices(fontface, &ch, 1, &index);
1599 IDWriteFontFace4_Release(fontface);
1600 if (FAILED(hr))
1601 return hr;
1603 *exists = index != 0;
1604 return S_OK;
1607 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1609 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1611 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1613 return font_has_character(This, ch, exists);
1616 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1618 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1619 TRACE("(%p)->(%p)\n", This, fontface);
1620 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1623 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1625 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1626 TRACE("(%p)->(%p)\n", This, metrics);
1627 *metrics = This->data->metrics;
1630 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1632 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1633 TRACE("(%p)->(%p)\n", This, panose);
1634 *panose = This->data->panose;
1637 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1639 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1640 IDWriteFontFace4 *fontface;
1641 HRESULT hr;
1643 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1645 hr = get_fontface_from_font(This, &fontface);
1646 if (FAILED(hr))
1647 return hr;
1649 hr = IDWriteFontFace4_GetUnicodeRanges(fontface, max_count, ranges, count);
1650 IDWriteFontFace4_Release(fontface);
1651 return hr;
1654 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1656 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1657 IDWriteFontFace4 *fontface;
1658 HRESULT hr;
1659 BOOL ret;
1661 TRACE("(%p)\n", This);
1663 hr = get_fontface_from_font(This, &fontface);
1664 if (FAILED(hr))
1665 return FALSE;
1667 ret = IDWriteFontFace4_IsMonospacedFont(fontface);
1668 IDWriteFontFace4_Release(fontface);
1669 return ret;
1672 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1674 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1675 IDWriteFontFace4 *fontface;
1676 HRESULT hr;
1677 BOOL ret;
1679 TRACE("(%p)\n", This);
1681 hr = get_fontface_from_font(This, &fontface);
1682 if (FAILED(hr))
1683 return FALSE;
1685 ret = IDWriteFontFace4_IsColorFont(fontface);
1686 IDWriteFontFace4_Release(fontface);
1687 return ret;
1690 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1692 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1694 TRACE("(%p)->(%p)\n", This, fontface);
1696 return get_fontface_from_font(This, (IDWriteFontFace4 **)fontface);
1699 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1701 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1702 FIXME("(%p)->(%p): stub\n", This, font);
1703 return FALSE;
1706 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1708 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1710 TRACE("(%p)->(%p)\n", This, reference);
1712 return IDWriteFactory5_CreateFontFaceReference_(This->family->collection->factory, This->data->file,
1713 This->data->face_index, This->data->simulations, reference);
1716 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1718 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1719 BOOL ret;
1721 TRACE("(%p)->(%#x)\n", This, ch);
1723 return font_has_character(This, ch, &ret) == S_OK && ret;
1726 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1728 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1729 FIXME("(%p): stub\n", This);
1730 return DWRITE_LOCALITY_LOCAL;
1733 static const IDWriteFont3Vtbl dwritefontvtbl = {
1734 dwritefont_QueryInterface,
1735 dwritefont_AddRef,
1736 dwritefont_Release,
1737 dwritefont_GetFontFamily,
1738 dwritefont_GetWeight,
1739 dwritefont_GetStretch,
1740 dwritefont_GetStyle,
1741 dwritefont_IsSymbolFont,
1742 dwritefont_GetFaceNames,
1743 dwritefont_GetInformationalStrings,
1744 dwritefont_GetSimulations,
1745 dwritefont_GetMetrics,
1746 dwritefont_HasCharacter,
1747 dwritefont_CreateFontFace,
1748 dwritefont1_GetMetrics,
1749 dwritefont1_GetPanose,
1750 dwritefont1_GetUnicodeRanges,
1751 dwritefont1_IsMonospacedFont,
1752 dwritefont2_IsColorFont,
1753 dwritefont3_CreateFontFace,
1754 dwritefont3_Equals,
1755 dwritefont3_GetFontFaceReference,
1756 dwritefont3_HasCharacter,
1757 dwritefont3_GetLocality
1760 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1762 if (!iface)
1763 return NULL;
1764 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1765 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1768 static struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1770 if (!iface)
1771 return NULL;
1772 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1773 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
1776 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1778 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1779 *lf = font->data->lf;
1782 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1784 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1785 *lf = fontface->lf;
1788 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
1790 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1791 *fontsig = font->data->fontsig;
1792 return S_OK;
1795 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
1797 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1798 *fontsig = fontface->fontsig;
1799 return S_OK;
1802 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1804 struct dwrite_font *This;
1806 *font = NULL;
1808 This = heap_alloc(sizeof(*This));
1809 if (!This)
1810 return E_OUTOFMEMORY;
1812 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1813 This->ref = 1;
1814 This->family = family;
1815 IDWriteFontFamily1_AddRef(&family->IDWriteFontFamily1_iface);
1816 This->data = family->data->fonts[index];
1817 This->style = This->data->style;
1818 addref_font_data(This->data);
1820 *font = &This->IDWriteFont3_iface;
1822 return S_OK;
1825 /* IDWriteFontList1 */
1826 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1828 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1830 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1832 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1833 IsEqualIID(riid, &IID_IDWriteFontList) ||
1834 IsEqualIID(riid, &IID_IUnknown))
1836 *obj = iface;
1837 IDWriteFontList1_AddRef(iface);
1838 return S_OK;
1841 WARN("%s not implemented.\n", debugstr_guid(riid));
1843 *obj = NULL;
1844 return E_NOINTERFACE;
1847 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1849 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1850 ULONG ref = InterlockedIncrement(&This->ref);
1851 TRACE("(%p)->(%d)\n", This, ref);
1852 return ref;
1855 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1857 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1858 ULONG ref = InterlockedDecrement(&This->ref);
1860 TRACE("(%p)->(%d)\n", This, ref);
1862 if (!ref) {
1863 UINT32 i;
1865 for (i = 0; i < This->font_count; i++)
1866 release_font_data(This->fonts[i]);
1867 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1868 heap_free(This->fonts);
1869 heap_free(This);
1872 return ref;
1875 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1877 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1878 return IDWriteFontFamily1_GetFontCollection(&This->family->IDWriteFontFamily1_iface, collection);
1881 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1883 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1884 TRACE("(%p)\n", This);
1885 return This->font_count;
1888 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1890 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1892 TRACE("(%p)->(%u %p)\n", This, index, font);
1894 *font = NULL;
1896 if (This->font_count == 0)
1897 return S_FALSE;
1899 if (index >= This->font_count)
1900 return E_INVALIDARG;
1902 return create_font(This->family, index, (IDWriteFont3 **)font);
1905 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1907 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1909 FIXME("(%p)->(%u): stub\n", This, index);
1911 return DWRITE_LOCALITY_LOCAL;
1914 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1916 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1918 TRACE("(%p)->(%u %p)\n", This, index, font);
1920 *font = NULL;
1922 if (This->font_count == 0)
1923 return S_FALSE;
1925 if (index >= This->font_count)
1926 return E_FAIL;
1928 return create_font(This->family, index, font);
1931 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1932 IDWriteFontFaceReference **reference)
1934 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1935 IDWriteFont3 *font;
1936 HRESULT hr;
1938 TRACE("(%p)->(%u %p)\n", This, index, reference);
1940 *reference = NULL;
1942 hr = IDWriteFontList1_GetFont(iface, index, &font);
1943 if (FAILED(hr))
1944 return hr;
1946 hr = IDWriteFont3_GetFontFaceReference(font, reference);
1947 IDWriteFont3_Release(font);
1949 return hr;
1952 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1953 dwritefontlist_QueryInterface,
1954 dwritefontlist_AddRef,
1955 dwritefontlist_Release,
1956 dwritefontlist_GetFontCollection,
1957 dwritefontlist_GetFontCount,
1958 dwritefontlist_GetFont,
1959 dwritefontlist1_GetFontLocality,
1960 dwritefontlist1_GetFont,
1961 dwritefontlist1_GetFontFaceReference
1964 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1966 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1968 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1970 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1971 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1972 IsEqualIID(riid, &IID_IUnknown))
1974 *obj = iface;
1975 IDWriteFontFamily1_AddRef(iface);
1976 return S_OK;
1979 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1980 IsEqualIID(riid, &IID_IDWriteFontList))
1982 *obj = &This->IDWriteFontList1_iface;
1983 IDWriteFontList1_AddRef(&This->IDWriteFontList1_iface);
1984 return S_OK;
1987 WARN("%s not implemented.\n", debugstr_guid(riid));
1989 *obj = NULL;
1990 return E_NOINTERFACE;
1993 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1995 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1996 ULONG ref = InterlockedIncrement(&This->ref);
1997 TRACE("(%p)->(%d)\n", This, ref);
1998 return ref;
2001 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
2003 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2004 ULONG ref = InterlockedDecrement(&This->ref);
2006 TRACE("(%p)->(%d)\n", This, ref);
2008 if (!ref)
2010 IDWriteFontCollection1_Release(&This->collection->IDWriteFontCollection1_iface);
2011 release_fontfamily_data(This->data);
2012 heap_free(This);
2015 return ref;
2018 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
2020 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2022 TRACE("(%p)->(%p)\n", This, collection);
2024 *collection = (IDWriteFontCollection*)This->collection;
2025 IDWriteFontCollection_AddRef(*collection);
2026 return S_OK;
2029 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
2031 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2032 TRACE("(%p)\n", This);
2033 return This->data->font_count;
2036 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
2038 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2040 TRACE("(%p)->(%u %p)\n", This, index, font);
2042 *font = NULL;
2044 if (This->data->font_count == 0)
2045 return S_FALSE;
2047 if (index >= This->data->font_count)
2048 return E_INVALIDARG;
2050 return create_font(This, index, (IDWriteFont3 **)font);
2053 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
2055 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2056 return clone_localizedstring(This->data->familyname, names);
2059 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2060 const struct dwrite_font_propvec *req)
2062 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2063 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2064 FLOAT cur_req_prod, next_req_prod;
2066 if (next_to_req < cur_to_req)
2067 return TRUE;
2069 if (next_to_req > cur_to_req)
2070 return FALSE;
2072 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2073 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2075 if (next_req_prod > cur_req_prod)
2076 return TRUE;
2078 if (next_req_prod < cur_req_prod)
2079 return FALSE;
2081 if (next->stretch > cur->stretch)
2082 return TRUE;
2083 if (next->stretch < cur->stretch)
2084 return FALSE;
2086 if (next->style > cur->style)
2087 return TRUE;
2088 if (next->style < cur->style)
2089 return FALSE;
2091 if (next->weight > cur->weight)
2092 return TRUE;
2093 if (next->weight < cur->weight)
2094 return FALSE;
2096 /* full match, no reason to prefer new variant */
2097 return FALSE;
2100 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2101 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2103 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2104 struct dwrite_font_propvec req;
2105 UINT32 i, match;
2107 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
2109 if (This->data->font_count == 0) {
2110 *font = NULL;
2111 return DWRITE_E_NOFONT;
2114 init_font_prop_vec(weight, stretch, style, &req);
2115 match = 0;
2117 for (i = 1; i < This->data->font_count; i++) {
2118 if (is_better_font_match(&This->data->fonts[i]->propvec, &This->data->fonts[match]->propvec, &req))
2119 match = i;
2122 return create_font(This, match, (IDWriteFont3 **)font);
2125 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2127 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2129 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2132 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2134 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2137 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2139 UINT32 b = fonts->font_count - 1, j, t;
2141 while (1) {
2142 t = b;
2144 for (j = 0; j < b; j++) {
2145 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2146 struct dwrite_font_data *s = fonts->fonts[j];
2147 fonts->fonts[j] = fonts->fonts[j+1];
2148 fonts->fonts[j+1] = s;
2149 t = j;
2153 if (t == b)
2154 break;
2155 b = t;
2159 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2160 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2162 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2163 matching_filter_func func = NULL;
2164 struct dwrite_font_propvec req;
2165 struct dwrite_fontlist *fonts;
2166 UINT32 i;
2168 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
2170 *ret = NULL;
2172 fonts = heap_alloc(sizeof(*fonts));
2173 if (!fonts)
2174 return E_OUTOFMEMORY;
2176 /* Allocate as many as family has, not all of them will be necessary used. */
2177 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
2178 if (!fonts->fonts) {
2179 heap_free(fonts);
2180 return E_OUTOFMEMORY;
2183 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2184 fonts->ref = 1;
2185 fonts->family = This;
2186 IDWriteFontFamily1_AddRef(&fonts->family->IDWriteFontFamily1_iface);
2187 fonts->font_count = 0;
2189 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2190 if (style == DWRITE_FONT_STYLE_NORMAL) {
2191 if (This->data->has_normal_face || This->data->has_italic_face)
2192 func = is_font_acceptable_for_normal;
2194 else /* requested oblique or italic */ {
2195 if (This->data->has_oblique_face || This->data->has_italic_face)
2196 func = is_font_acceptable_for_oblique_italic;
2199 for (i = 0; i < This->data->font_count; i++) {
2200 if (!func || func(This->data->fonts[i])) {
2201 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2202 addref_font_data(This->data->fonts[i]);
2203 fonts->font_count++;
2207 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2208 init_font_prop_vec(weight, stretch, style, &req);
2209 matchingfonts_sort(fonts, &req);
2211 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2212 return S_OK;
2215 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2217 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2219 FIXME("(%p)->(%u): stub\n", This, index);
2221 return DWRITE_LOCALITY_LOCAL;
2224 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2226 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2228 TRACE("(%p)->(%u %p)\n", This, index, font);
2230 *font = NULL;
2232 if (This->data->font_count == 0)
2233 return S_FALSE;
2235 if (index >= This->data->font_count)
2236 return E_FAIL;
2238 return create_font(This, index, font);
2241 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2242 IDWriteFontFaceReference **reference)
2244 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2245 IDWriteFont3 *font;
2246 HRESULT hr;
2248 TRACE("(%p)->(%u %p)\n", This, index, reference);
2250 *reference = NULL;
2252 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2253 if (FAILED(hr))
2254 return hr;
2256 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2257 IDWriteFont3_Release(font);
2259 return hr;
2262 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2263 dwritefontfamily_QueryInterface,
2264 dwritefontfamily_AddRef,
2265 dwritefontfamily_Release,
2266 dwritefontfamily_GetFontCollection,
2267 dwritefontfamily_GetFontCount,
2268 dwritefontfamily_GetFont,
2269 dwritefontfamily_GetFamilyNames,
2270 dwritefontfamily_GetFirstMatchingFont,
2271 dwritefontfamily_GetMatchingFonts,
2272 dwritefontfamily1_GetFontLocality,
2273 dwritefontfamily1_GetFont,
2274 dwritefontfamily1_GetFontFaceReference
2277 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
2279 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2280 return dwritefontfamily_QueryInterface(&This->IDWriteFontFamily1_iface, riid, obj);
2283 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList1 *iface)
2285 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2286 return dwritefontfamily_AddRef(&This->IDWriteFontFamily1_iface);
2289 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList1 *iface)
2291 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2292 return dwritefontfamily_Release(&This->IDWriteFontFamily1_iface);
2295 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList1 *iface,
2296 IDWriteFontCollection **collection)
2298 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2299 return dwritefontfamily_GetFontCollection(&This->IDWriteFontFamily1_iface, collection);
2302 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList1 *iface)
2304 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2305 return dwritefontfamily_GetFontCount(&This->IDWriteFontFamily1_iface);
2308 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
2310 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2311 return dwritefontfamily_GetFont(&This->IDWriteFontFamily1_iface, index, font);
2314 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
2316 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2317 return dwritefontfamily1_GetFontLocality(&This->IDWriteFontFamily1_iface, index);
2320 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
2322 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2323 return dwritefontfamily1_GetFont(&This->IDWriteFontFamily1_iface, index, font);
2326 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
2327 IDWriteFontFaceReference **reference)
2329 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2330 return dwritefontfamily1_GetFontFaceReference(&This->IDWriteFontFamily1_iface, index, reference);
2333 static const IDWriteFontList1Vtbl fontfamilylistvtbl = {
2334 dwritefontfamilylist_QueryInterface,
2335 dwritefontfamilylist_AddRef,
2336 dwritefontfamilylist_Release,
2337 dwritefontfamilylist_GetFontCollection,
2338 dwritefontfamilylist_GetFontCount,
2339 dwritefontfamilylist_GetFont,
2340 dwritefontfamilylist1_GetFontLocality,
2341 dwritefontfamilylist1_GetFont,
2342 dwritefontfamilylist1_GetFontFaceReference,
2345 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index, IDWriteFontFamily1 **family)
2347 struct dwrite_fontfamily *This;
2349 *family = NULL;
2351 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2352 if (!This) return E_OUTOFMEMORY;
2354 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2355 This->IDWriteFontList1_iface.lpVtbl = &fontfamilylistvtbl;
2356 This->ref = 1;
2357 This->collection = collection;
2358 IDWriteFontCollection1_AddRef(&collection->IDWriteFontCollection1_iface);
2359 This->data = collection->family_data[index];
2360 InterlockedIncrement(&This->data->ref);
2362 *family = &This->IDWriteFontFamily1_iface;
2364 return S_OK;
2367 BOOL is_system_collection(IDWriteFontCollection *collection)
2369 void *obj;
2370 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2373 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2375 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2376 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2378 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2379 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2380 IsEqualIID(riid, &IID_IUnknown))
2382 *obj = iface;
2383 IDWriteFontCollection1_AddRef(iface);
2384 return S_OK;
2387 *obj = NULL;
2389 if (IsEqualIID(riid, &IID_issystemcollection))
2390 return S_OK;
2392 WARN("%s not implemented.\n", debugstr_guid(riid));
2394 return E_NOINTERFACE;
2397 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2399 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2400 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2402 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2403 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2404 IsEqualIID(riid, &IID_IUnknown))
2406 *obj = iface;
2407 IDWriteFontCollection1_AddRef(iface);
2408 return S_OK;
2411 WARN("%s not implemented.\n", debugstr_guid(riid));
2413 *obj = NULL;
2415 return E_NOINTERFACE;
2418 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2420 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2421 ULONG ref = InterlockedIncrement(&This->ref);
2422 TRACE("(%p)->(%d)\n", This, ref);
2423 return ref;
2426 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2428 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2429 ULONG ref = InterlockedDecrement(&This->ref);
2431 TRACE("(%p)->(%d)\n", This, ref);
2433 if (!ref) {
2434 int i;
2436 factory_detach_fontcollection(This->factory, iface);
2437 for (i = 0; i < This->family_count; i++)
2438 release_fontfamily_data(This->family_data[i]);
2439 heap_free(This->family_data);
2440 heap_free(This);
2443 return ref;
2446 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2448 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2449 TRACE("(%p)\n", This);
2450 return This->family_count;
2453 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2455 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2457 TRACE("(%p)->(%u %p)\n", This, index, family);
2459 if (index >= This->family_count) {
2460 *family = NULL;
2461 return E_FAIL;
2464 return create_fontfamily(This, index, (IDWriteFontFamily1 **)family);
2467 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2469 UINT32 i;
2471 for (i = 0; i < collection->family_count; i++) {
2472 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2473 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2474 HRESULT hr;
2476 for (j = 0; j < count; j++) {
2477 WCHAR buffer[255];
2478 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2479 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2480 return i;
2484 return ~0u;
2487 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2489 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2490 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2491 *index = collection_find_family(This, name);
2492 *exists = *index != ~0u;
2493 return S_OK;
2496 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2498 UINT32 left_key_size, right_key_size;
2499 const void *left_key, *right_key;
2500 HRESULT hr;
2502 if (left == right)
2503 return TRUE;
2505 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2506 if (FAILED(hr))
2507 return FALSE;
2509 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2510 if (FAILED(hr))
2511 return FALSE;
2513 if (left_key_size != right_key_size)
2514 return FALSE;
2516 return !memcmp(left_key, right_key, left_key_size);
2519 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2521 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2522 IDWriteFontFamily1 *family;
2523 UINT32 i, j, face_index;
2524 BOOL found_font = FALSE;
2525 IDWriteFontFile *file;
2526 HRESULT hr;
2528 TRACE("(%p)->(%p %p)\n", This, face, font);
2530 *font = NULL;
2532 if (!face)
2533 return E_INVALIDARG;
2535 i = 1;
2536 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2537 if (FAILED(hr))
2538 return hr;
2539 face_index = IDWriteFontFace_GetIndex(face);
2541 found_font = FALSE;
2542 for (i = 0; i < This->family_count; i++) {
2543 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2545 for (j = 0; j < family_data->font_count; j++) {
2546 struct dwrite_font_data *font_data = family_data->fonts[j];
2548 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2549 found_font = TRUE;
2550 break;
2554 if (found_font)
2555 break;
2557 IDWriteFontFile_Release(file);
2559 if (!found_font)
2560 return DWRITE_E_NOFONT;
2562 hr = create_fontfamily(This, i, &family);
2563 if (FAILED(hr))
2564 return hr;
2566 hr = create_font(impl_from_IDWriteFontFamily1(family), j, (IDWriteFont3 **)font);
2567 IDWriteFontFamily1_Release(family);
2568 return hr;
2571 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2573 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2575 FIXME("(%p)->(%p): stub\n", This, fontset);
2577 return E_NOTIMPL;
2580 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2582 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2584 TRACE("(%p)->(%u %p)\n", This, index, family);
2586 if (index >= This->family_count) {
2587 *family = NULL;
2588 return E_FAIL;
2591 return create_fontfamily(This, index, family);
2594 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2595 dwritefontcollection_QueryInterface,
2596 dwritefontcollection_AddRef,
2597 dwritefontcollection_Release,
2598 dwritefontcollection_GetFontFamilyCount,
2599 dwritefontcollection_GetFontFamily,
2600 dwritefontcollection_FindFamilyName,
2601 dwritefontcollection_GetFontFromFontFace,
2602 dwritefontcollection1_GetFontSet,
2603 dwritefontcollection1_GetFontFamily
2606 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2607 dwritesystemfontcollection_QueryInterface,
2608 dwritefontcollection_AddRef,
2609 dwritefontcollection_Release,
2610 dwritefontcollection_GetFontFamilyCount,
2611 dwritefontcollection_GetFontFamily,
2612 dwritefontcollection_FindFamilyName,
2613 dwritefontcollection_GetFontFromFontFace,
2614 dwritefontcollection1_GetFontSet,
2615 dwritefontcollection1_GetFontFamily
2618 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2620 if (family_data->font_count + 1 >= family_data->font_alloc) {
2621 struct dwrite_font_data **new_list;
2622 UINT32 new_alloc;
2624 new_alloc = family_data->font_alloc * 2;
2625 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2626 if (!new_list)
2627 return E_OUTOFMEMORY;
2628 family_data->fonts = new_list;
2629 family_data->font_alloc = new_alloc;
2632 family_data->fonts[family_data->font_count] = font_data;
2633 family_data->font_count++;
2634 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2635 family_data->has_normal_face = 1;
2636 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2637 family_data->has_oblique_face = 1;
2638 else
2639 family_data->has_italic_face = 1;
2640 return S_OK;
2643 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2645 if (collection->family_alloc < collection->family_count + 1) {
2646 struct dwrite_fontfamily_data **new_list;
2647 UINT32 new_alloc;
2649 new_alloc = collection->family_alloc * 2;
2650 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2651 if (!new_list)
2652 return E_OUTOFMEMORY;
2654 collection->family_alloc = new_alloc;
2655 collection->family_data = new_list;
2658 collection->family_data[collection->family_count++] = family;
2659 return S_OK;
2662 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2664 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2665 collection->ref = 1;
2666 collection->family_count = 0;
2667 collection->family_alloc = is_system ? 30 : 5;
2668 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2669 if (!collection->family_data)
2670 return E_OUTOFMEMORY;
2672 return S_OK;
2675 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2677 IDWriteFontFileLoader *loader;
2678 const void *key;
2679 UINT32 key_size;
2680 HRESULT hr;
2682 *stream = NULL;
2684 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2685 if (FAILED(hr))
2686 return hr;
2688 hr = IDWriteFontFile_GetLoader(file, &loader);
2689 if (FAILED(hr))
2690 return hr;
2692 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2693 IDWriteFontFileLoader_Release(loader);
2694 if (FAILED(hr))
2695 return hr;
2697 return hr;
2700 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2702 BOOL exists = FALSE;
2703 UINT32 index;
2704 HRESULT hr;
2706 buffer[0] = 0;
2707 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2708 if (FAILED(hr) || !exists)
2709 return;
2711 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2714 static int trim_spaces(WCHAR *in, WCHAR *ret)
2716 int len;
2718 while (isspaceW(*in))
2719 in++;
2721 ret[0] = 0;
2722 if (!(len = strlenW(in)))
2723 return 0;
2725 while (isspaceW(in[len-1]))
2726 len--;
2728 memcpy(ret, in, len*sizeof(WCHAR));
2729 ret[len] = 0;
2731 return len;
2734 struct name_token {
2735 struct list entry;
2736 const WCHAR *ptr;
2737 INT len; /* token length */
2738 INT fulllen; /* full length including following separators */
2741 static inline BOOL is_name_separator_char(WCHAR ch)
2743 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2746 struct name_pattern {
2747 const WCHAR *part1; /* NULL indicates end of list */
2748 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2751 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2753 const struct name_pattern *pattern;
2754 struct name_token *token;
2755 int i = 0;
2757 while ((pattern = &patterns[i++])->part1) {
2758 int len_part1 = strlenW(pattern->part1);
2759 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2761 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2762 if (len_part2 == 0) {
2763 /* simple case with single part pattern */
2764 if (token->len != len_part1)
2765 continue;
2767 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2768 if (match) *match = *token;
2769 list_remove(&token->entry);
2770 heap_free(token);
2771 return TRUE;
2774 else {
2775 struct name_token *next_token;
2776 struct list *next_entry;
2778 /* pattern parts are stored in reading order, tokens list is reversed */
2779 if (token->len < len_part2)
2780 continue;
2782 /* it's possible to have combined string as a token, like ExtraCondensed */
2783 if (token->len == len_part1 + len_part2) {
2784 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2785 continue;
2787 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2788 continue;
2790 /* combined string match */
2791 if (match) *match = *token;
2792 list_remove(&token->entry);
2793 heap_free(token);
2794 return TRUE;
2797 /* now it's only possible to have two tokens matched to respective pattern parts */
2798 if (token->len != len_part2)
2799 continue;
2801 next_entry = list_next(tokens, &token->entry);
2802 if (next_entry) {
2803 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2804 if (next_token->len != len_part1)
2805 continue;
2807 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2808 continue;
2810 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2811 continue;
2813 /* both parts matched, remove tokens */
2814 if (match) {
2815 match->ptr = next_token->ptr;
2816 match->len = (token->ptr - next_token->ptr) + token->len;
2818 list_remove(&token->entry);
2819 list_remove(&next_token->entry);
2820 heap_free(next_token);
2821 heap_free(token);
2822 return TRUE;
2828 if (match) {
2829 match->ptr = NULL;
2830 match->len = 0;
2832 return FALSE;
2835 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2837 static const WCHAR itaW[] = {'i','t','a',0};
2838 static const WCHAR italW[] = {'i','t','a','l',0};
2839 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2840 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2842 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2843 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2844 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2845 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2847 static const struct name_pattern italic_patterns[] = {
2848 { itaW },
2849 { italW },
2850 { italicW },
2851 { cursiveW },
2852 { kursivW },
2853 { NULL }
2856 static const struct name_pattern oblique_patterns[] = {
2857 { inclinedW },
2858 { obliqueW },
2859 { backslantedW },
2860 { backslantW },
2861 { slantedW },
2862 { NULL }
2865 /* italic patterns first */
2866 if (match_pattern_list(tokens, italic_patterns, match))
2867 return DWRITE_FONT_STYLE_ITALIC;
2869 /* oblique patterns */
2870 if (match_pattern_list(tokens, oblique_patterns, match))
2871 return DWRITE_FONT_STYLE_OBLIQUE;
2873 return style;
2876 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2877 struct name_token *match)
2879 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2880 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2881 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2882 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2883 static const WCHAR wideW[] = {'w','i','d','e',0};
2884 static const WCHAR condW[] = {'c','o','n','d',0};
2886 static const struct name_pattern ultracondensed_patterns[] = {
2887 { extraW, compressedW },
2888 { extW, compressedW },
2889 { ultraW, compressedW },
2890 { ultraW, condensedW },
2891 { ultraW, condW },
2892 { NULL }
2895 static const struct name_pattern extracondensed_patterns[] = {
2896 { compressedW },
2897 { extraW, condensedW },
2898 { extW, condensedW },
2899 { extraW, condW },
2900 { extW, condW },
2901 { NULL }
2904 static const struct name_pattern semicondensed_patterns[] = {
2905 { narrowW },
2906 { compactW },
2907 { semiW, condensedW },
2908 { semiW, condW },
2909 { NULL }
2912 static const struct name_pattern semiexpanded_patterns[] = {
2913 { wideW },
2914 { semiW, expandedW },
2915 { semiW, extendedW },
2916 { NULL }
2919 static const struct name_pattern extraexpanded_patterns[] = {
2920 { extraW, expandedW },
2921 { extW, expandedW },
2922 { extraW, extendedW },
2923 { extW, extendedW },
2924 { NULL }
2927 static const struct name_pattern ultraexpanded_patterns[] = {
2928 { ultraW, expandedW },
2929 { ultraW, extendedW },
2930 { NULL }
2933 static const struct name_pattern condensed_patterns[] = {
2934 { condensedW },
2935 { condW },
2936 { NULL }
2939 static const struct name_pattern expanded_patterns[] = {
2940 { expandedW },
2941 { extendedW },
2942 { NULL }
2945 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2946 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2948 if (match_pattern_list(tokens, extracondensed_patterns, match))
2949 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2951 if (match_pattern_list(tokens, semicondensed_patterns, match))
2952 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2954 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2955 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2957 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2958 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2960 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2961 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2963 if (match_pattern_list(tokens, condensed_patterns, match))
2964 return DWRITE_FONT_STRETCH_CONDENSED;
2966 if (match_pattern_list(tokens, expanded_patterns, match))
2967 return DWRITE_FONT_STRETCH_EXPANDED;
2969 return stretch;
2972 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2973 struct name_token *match)
2975 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2976 static const WCHAR nordW[] = {'n','o','r','d',0};
2978 static const struct name_pattern thin_patterns[] = {
2979 { extraW, thinW },
2980 { extW, thinW },
2981 { ultraW, thinW },
2982 { NULL }
2985 static const struct name_pattern extralight_patterns[] = {
2986 { extraW, lightW },
2987 { extW, lightW },
2988 { ultraW, lightW },
2989 { NULL }
2992 static const struct name_pattern semilight_patterns[] = {
2993 { semiW, lightW },
2994 { NULL }
2997 static const struct name_pattern demibold_patterns[] = {
2998 { semiW, boldW },
2999 { demiW, boldW },
3000 { NULL }
3003 static const struct name_pattern extrabold_patterns[] = {
3004 { extraW, boldW },
3005 { extW, boldW },
3006 { ultraW, boldW },
3007 { NULL }
3010 static const struct name_pattern extrablack_patterns[] = {
3011 { extraW, blackW },
3012 { extW, blackW },
3013 { ultraW, blackW },
3014 { NULL }
3017 static const struct name_pattern bold_patterns[] = {
3018 { boldW },
3019 { NULL }
3022 static const struct name_pattern thin2_patterns[] = {
3023 { thinW },
3024 { NULL }
3027 static const struct name_pattern light_patterns[] = {
3028 { lightW },
3029 { NULL }
3032 static const struct name_pattern medium_patterns[] = {
3033 { mediumW },
3034 { NULL }
3037 static const struct name_pattern black_patterns[] = {
3038 { blackW },
3039 { heavyW },
3040 { nordW },
3041 { NULL }
3044 static const struct name_pattern demibold2_patterns[] = {
3045 { demiW },
3046 { NULL }
3049 static const struct name_pattern extrabold2_patterns[] = {
3050 { ultraW },
3051 { NULL }
3054 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3055 matching pattern. */
3057 if (match_pattern_list(tokens, thin_patterns, match))
3058 return DWRITE_FONT_WEIGHT_THIN;
3060 if (match_pattern_list(tokens, extralight_patterns, match))
3061 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3063 if (match_pattern_list(tokens, semilight_patterns, match))
3064 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3066 if (match_pattern_list(tokens, demibold_patterns, match))
3067 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3069 if (match_pattern_list(tokens, extrabold_patterns, match))
3070 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3072 if (match_pattern_list(tokens, extrablack_patterns, match))
3073 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3075 if (match_pattern_list(tokens, bold_patterns, match))
3076 return DWRITE_FONT_WEIGHT_BOLD;
3078 if (match_pattern_list(tokens, thin2_patterns, match))
3079 return DWRITE_FONT_WEIGHT_THIN;
3081 if (match_pattern_list(tokens, light_patterns, match))
3082 return DWRITE_FONT_WEIGHT_LIGHT;
3084 if (match_pattern_list(tokens, medium_patterns, match))
3085 return DWRITE_FONT_WEIGHT_MEDIUM;
3087 if (match_pattern_list(tokens, black_patterns, match))
3088 return DWRITE_FONT_WEIGHT_BLACK;
3090 if (match_pattern_list(tokens, black_patterns, match))
3091 return DWRITE_FONT_WEIGHT_BLACK;
3093 if (match_pattern_list(tokens, demibold2_patterns, match))
3094 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3096 if (match_pattern_list(tokens, extrabold2_patterns, match))
3097 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3099 /* FIXME: use abbreviated names to extract weight */
3101 return weight;
3104 struct knownweight_entry {
3105 const WCHAR *nameW;
3106 DWRITE_FONT_WEIGHT weight;
3109 static int compare_knownweights(const void *a, const void* b)
3111 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3112 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3113 int ret = 0;
3115 if (target > entry->weight)
3116 ret = 1;
3117 else if (target < entry->weight)
3118 ret = -1;
3120 return ret;
3123 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3125 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3126 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3127 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3128 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3129 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3130 const struct knownweight_entry *ptr;
3132 static const struct knownweight_entry knownweights[] = {
3133 { thinW, DWRITE_FONT_WEIGHT_THIN },
3134 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3135 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3136 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3137 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3138 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3139 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3140 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3141 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3142 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3145 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3146 compare_knownweights);
3147 if (!ptr) {
3148 nameW[0] = 0;
3149 return FALSE;
3152 strcpyW(nameW, ptr->nameW);
3153 return TRUE;
3156 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3158 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3159 strW[name->len] = 0;
3162 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3163 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3165 static const WCHAR bookW[] = {'B','o','o','k',0};
3166 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3167 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3168 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3169 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3171 static const WCHAR *regular_patterns[] = {
3172 bookW,
3173 normalW,
3174 regularW,
3175 romanW,
3176 uprightW,
3177 NULL
3180 const WCHAR *regular_ptr = NULL, *ptr;
3181 int i = 0;
3183 if (len == -1)
3184 len = strlenW(facenameW);
3186 /* remove rightmost regular variant from face name */
3187 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3188 int pattern_len = strlenW(ptr);
3189 WCHAR *src;
3191 if (pattern_len > len)
3192 continue;
3194 src = facenameW + len - pattern_len;
3195 while (src >= facenameW) {
3196 if (!strncmpiW(src, ptr, pattern_len)) {
3197 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3198 len = strlenW(facenameW);
3199 regular_ptr = ptr;
3200 break;
3202 else
3203 src--;
3207 return regular_ptr;
3210 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3212 const WCHAR *ptr;
3214 list_init(tokens);
3215 ptr = nameW;
3217 while (*ptr) {
3218 struct name_token *token = heap_alloc(sizeof(*token));
3219 token->ptr = ptr;
3220 token->len = 0;
3221 token->fulllen = 0;
3223 while (*ptr && !is_name_separator_char(*ptr)) {
3224 token->len++;
3225 token->fulllen++;
3226 ptr++;
3229 /* skip separators */
3230 while (is_name_separator_char(*ptr)) {
3231 token->fulllen++;
3232 ptr++;
3235 list_add_head(tokens, &token->entry);
3239 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3241 struct name_token *token, *token2;
3242 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3243 int len;
3245 list_remove(&token->entry);
3247 /* don't include last separator */
3248 len = list_empty(tokens) ? token->len : token->fulllen;
3249 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3250 nameW += len;
3252 heap_free(token);
3254 *nameW = 0;
3257 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3259 struct name_token stretch_name, weight_name, style_name;
3260 WCHAR familynameW[255], facenameW[255], finalW[255];
3261 WCHAR weightW[32], stretchW[32], styleW[32];
3262 const WCHAR *regular_ptr = NULL;
3263 DWRITE_FONT_STRETCH stretch;
3264 DWRITE_FONT_WEIGHT weight;
3265 struct list tokens;
3266 int len;
3268 /* remove leading and trailing spaces from family and face name */
3269 trim_spaces(familyW, familynameW);
3270 len = trim_spaces(faceW, facenameW);
3272 /* remove rightmost regular variant from face name */
3273 regular_ptr = facename_remove_regular_term(facenameW, len);
3275 /* append face name to family name, FIXME check if face name is a substring of family name */
3276 if (*facenameW) {
3277 strcatW(familynameW, spaceW);
3278 strcatW(familynameW, facenameW);
3281 /* tokenize with " .-_" */
3282 fontname_tokenize(&tokens, familynameW);
3284 /* extract and resolve style */
3285 font->style = font_extract_style(&tokens, font->style, &style_name);
3287 /* extract stretch */
3288 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3290 /* extract weight */
3291 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3293 /* resolve weight */
3294 if (weight != font->weight) {
3295 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3296 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3297 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3298 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3299 !(abs(weight - font->weight) <= 150 &&
3300 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3301 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3302 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3304 font->weight = weight;
3308 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3309 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3310 stretch itself is normal (extracted stretch is never normal). */
3311 if (stretch != font->stretch) {
3312 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3313 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3314 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3316 font->stretch = stretch;
3320 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3322 /* get final combined string from what's left in token list, list is released */
3323 fontname_tokens_to_str(&tokens, finalW);
3325 if (!strcmpW(familyW, finalW))
3326 return FALSE;
3328 /* construct face name */
3329 strcpyW(familyW, finalW);
3331 /* resolved weight name */
3332 if (weight_name.ptr)
3333 font_name_token_to_str(&weight_name, weightW);
3334 /* ignore normal weight */
3335 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3336 weightW[0] = 0;
3337 /* for known weight values use appropriate names */
3338 else if (is_known_weight_value(font->weight, weightW)) {
3340 /* use Wnnn format as a fallback in case weight is not one of known values */
3341 else {
3342 static const WCHAR fmtW[] = {'W','%','d',0};
3343 sprintfW(weightW, fmtW, font->weight);
3346 /* resolved stretch name */
3347 if (stretch_name.ptr)
3348 font_name_token_to_str(&stretch_name, stretchW);
3349 /* ignore normal stretch */
3350 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3351 stretchW[0] = 0;
3352 /* use predefined stretch names */
3353 else {
3354 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3355 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3356 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3357 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3358 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3359 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3361 static const WCHAR *stretchnamesW[] = {
3362 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3363 ultracondensedW,
3364 extracondensedW,
3365 condensedW,
3366 semicondensedW,
3367 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3368 semiexpandedW,
3369 expandedW,
3370 extraexpandedW,
3371 ultraexpandedW
3373 strcpyW(stretchW, stretchnamesW[font->stretch]);
3376 /* resolved style name */
3377 if (style_name.ptr)
3378 font_name_token_to_str(&style_name, styleW);
3379 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3380 styleW[0] = 0;
3381 /* use predefined names */
3382 else {
3383 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3384 strcpyW(styleW, italicW);
3385 else
3386 strcpyW(styleW, obliqueW);
3389 /* use Regular match if it was found initially */
3390 if (!*weightW && !*stretchW && !*styleW)
3391 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3392 else {
3393 faceW[0] = 0;
3394 if (*stretchW)
3395 strcpyW(faceW, stretchW);
3396 if (*weightW) {
3397 if (*faceW)
3398 strcatW(faceW, spaceW);
3399 strcatW(faceW, weightW);
3401 if (*styleW) {
3402 if (*faceW)
3403 strcatW(faceW, spaceW);
3404 strcatW(faceW, styleW);
3408 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3409 return TRUE;
3412 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name,
3413 struct dwrite_font_data **ret)
3415 struct file_stream_desc stream_desc;
3416 struct dwrite_font_props props;
3417 struct dwrite_font_data *data;
3418 WCHAR familyW[255], faceW[255];
3419 HRESULT hr;
3421 *ret = NULL;
3423 data = heap_alloc_zero(sizeof(*data));
3424 if (!data)
3425 return E_OUTOFMEMORY;
3427 data->ref = 1;
3428 data->file = desc->files[0];
3429 data->face_index = desc->index;
3430 data->face_type = desc->face_type;
3431 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3432 data->bold_sim_tested = 0;
3433 data->oblique_sim_tested = 0;
3434 IDWriteFontFile_AddRef(data->file);
3436 stream_desc.stream = desc->stream;
3437 stream_desc.face_type = desc->face_type;
3438 stream_desc.face_index = desc->index;
3439 opentype_get_font_properties(&stream_desc, &props);
3440 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3441 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3443 /* get family name from font file */
3444 hr = opentype_get_font_familyname(&stream_desc, family_name);
3445 if (FAILED(hr)) {
3446 WARN("unable to get family name from font\n");
3447 release_font_data(data);
3448 return hr;
3451 data->style = props.style;
3452 data->stretch = props.stretch;
3453 data->weight = props.weight;
3454 data->panose = props.panose;
3455 data->fontsig = props.fontsig;
3456 data->lf = props.lf;
3458 fontstrings_get_en_string(*family_name, familyW, ARRAY_SIZE(familyW));
3459 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3460 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3461 set_en_localizedstring(*family_name, familyW);
3462 set_en_localizedstring(data->names, faceW);
3465 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3467 *ret = data;
3468 return S_OK;
3471 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3472 const WCHAR *facenameW, struct dwrite_font_data **ret)
3474 struct dwrite_font_data *data;
3476 *ret = NULL;
3478 data = heap_alloc_zero(sizeof(*data));
3479 if (!data)
3480 return E_OUTOFMEMORY;
3482 *data = *src;
3483 data->ref = 1;
3484 data->simulations |= sim;
3485 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3486 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3487 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3488 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3489 memset(data->info_strings, 0, sizeof(data->info_strings));
3490 data->names = NULL;
3491 IDWriteFontFile_AddRef(data->file);
3493 create_localizedstrings(&data->names);
3494 add_localizedstring(data->names, enusW, facenameW);
3496 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3498 *ret = data;
3499 return S_OK;
3502 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3504 struct dwrite_fontfamily_data *data;
3506 data = heap_alloc(sizeof(*data));
3507 if (!data)
3508 return E_OUTOFMEMORY;
3510 data->ref = 1;
3511 data->font_count = 0;
3512 data->font_alloc = 2;
3513 data->has_normal_face = 0;
3514 data->has_oblique_face = 0;
3515 data->has_italic_face = 0;
3517 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3518 if (!data->fonts) {
3519 heap_free(data);
3520 return E_OUTOFMEMORY;
3523 data->familyname = familyname;
3524 IDWriteLocalizedStrings_AddRef(familyname);
3526 *ret = data;
3527 return S_OK;
3530 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3532 UINT32 i, j, heaviest;
3534 for (i = 0; i < family->font_count; i++) {
3535 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3536 heaviest = i;
3538 if (family->fonts[i]->bold_sim_tested)
3539 continue;
3541 family->fonts[i]->bold_sim_tested = 1;
3542 for (j = i; j < family->font_count; j++) {
3543 if (family->fonts[j]->bold_sim_tested)
3544 continue;
3546 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3547 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3548 if (family->fonts[j]->weight > weight) {
3549 weight = family->fonts[j]->weight;
3550 heaviest = j;
3552 family->fonts[j]->bold_sim_tested = 1;
3556 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3557 static const struct name_pattern weightsim_patterns[] = {
3558 { extraW, lightW },
3559 { extW, lightW },
3560 { ultraW, lightW },
3561 { semiW, lightW },
3562 { semiW, boldW },
3563 { demiW, boldW },
3564 { boldW },
3565 { thinW },
3566 { lightW },
3567 { mediumW },
3568 { demiW },
3569 { NULL }
3572 WCHAR facenameW[255], initialW[255];
3573 struct dwrite_font_data *boldface;
3574 struct list tokens;
3576 /* add Bold simulation based on heaviest face data */
3578 /* Simulated face name should only contain Bold as weight term,
3579 so remove existing regular and weight terms. */
3580 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
3581 facename_remove_regular_term(initialW, -1);
3583 /* remove current weight pattern */
3584 fontname_tokenize(&tokens, initialW);
3585 match_pattern_list(&tokens, weightsim_patterns, NULL);
3586 fontname_tokens_to_str(&tokens, facenameW);
3588 /* Bold suffix for new name */
3589 if (*facenameW)
3590 strcatW(facenameW, spaceW);
3591 strcatW(facenameW, boldW);
3593 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3594 boldface->bold_sim_tested = 1;
3595 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3596 fontfamily_add_font(family, boldface);
3602 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3604 UINT32 i, j;
3606 for (i = 0; i < family->font_count; i++) {
3607 UINT32 regular = ~0u, oblique = ~0u;
3608 struct dwrite_font_data *obliqueface;
3609 WCHAR facenameW[255];
3611 if (family->fonts[i]->oblique_sim_tested)
3612 continue;
3614 family->fonts[i]->oblique_sim_tested = 1;
3615 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3616 regular = i;
3617 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3618 oblique = i;
3620 /* find regular style with same weight/stretch values */
3621 for (j = i; j < family->font_count; j++) {
3622 if (family->fonts[j]->oblique_sim_tested)
3623 continue;
3625 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3626 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3628 family->fonts[j]->oblique_sim_tested = 1;
3629 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3630 regular = j;
3632 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3633 oblique = j;
3636 if (regular != ~0u && oblique != ~0u)
3637 break;
3640 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3641 if (regular == ~0u)
3642 continue;
3644 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3645 if (oblique != ~0u)
3646 continue;
3648 /* add oblique simulation based on this regular face */
3650 /* remove regular term if any, append 'Oblique' */
3651 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
3652 facename_remove_regular_term(facenameW, -1);
3654 if (*facenameW)
3655 strcatW(facenameW, spaceW);
3656 strcatW(facenameW, obliqueW);
3658 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3659 obliqueface->oblique_sim_tested = 1;
3660 obliqueface->lf.lfItalic = 1;
3661 fontfamily_add_font(family, obliqueface);
3666 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3667 const WCHAR *replacement_name)
3669 UINT32 i = collection_find_family(collection, replacement_name);
3670 struct dwrite_fontfamily_data *target;
3671 IDWriteLocalizedStrings *strings;
3672 HRESULT hr;
3674 /* replacement does not exist */
3675 if (i == ~0u)
3676 return FALSE;
3678 hr = create_localizedstrings(&strings);
3679 if (FAILED(hr))
3680 return FALSE;
3682 /* add a new family with target name, reuse font data from replacement */
3683 add_localizedstring(strings, enusW, target_name);
3684 hr = init_fontfamily_data(strings, &target);
3685 if (hr == S_OK) {
3686 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3687 WCHAR nameW[255];
3689 for (i = 0; i < replacement->font_count; i++) {
3690 fontfamily_add_font(target, replacement->fonts[i]);
3691 addref_font_data(replacement->fonts[i]);
3694 fontcollection_add_family(collection, target);
3695 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
3696 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3698 IDWriteLocalizedStrings_Release(strings);
3699 return TRUE;
3702 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3703 system font collections. */
3704 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3706 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3707 WCHAR *name;
3708 void *data;
3709 HKEY hkey;
3711 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3712 return;
3714 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3715 RegCloseKey(hkey);
3716 return;
3719 max_namelen++; /* returned value doesn't include room for '\0' */
3720 name = heap_alloc(max_namelen * sizeof(WCHAR));
3721 data = heap_alloc(max_datalen);
3723 datalen = max_datalen;
3724 namelen = max_namelen;
3725 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3726 if (collection_find_family(collection, name) == ~0u) {
3727 if (type == REG_MULTI_SZ) {
3728 WCHAR *replacement = data;
3729 while (*replacement) {
3730 if (fontcollection_add_replacement(collection, name, replacement))
3731 break;
3732 replacement += strlenW(replacement) + 1;
3735 else if (type == REG_SZ)
3736 fontcollection_add_replacement(collection, name, data);
3738 else
3739 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3741 datalen = max_datalen;
3742 namelen = max_namelen;
3745 heap_free(data);
3746 heap_free(name);
3747 RegCloseKey(hkey);
3750 HRESULT create_font_collection(IDWriteFactory5 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3751 IDWriteFontCollection1 **ret)
3753 struct fontfile_enum {
3754 struct list entry;
3755 IDWriteFontFile *file;
3757 struct fontfile_enum *fileenum, *fileenum2;
3758 struct dwrite_fontcollection *collection;
3759 struct list scannedfiles;
3760 BOOL current = FALSE;
3761 HRESULT hr = S_OK;
3762 UINT32 i;
3764 *ret = NULL;
3766 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3767 if (!collection) return E_OUTOFMEMORY;
3769 hr = init_font_collection(collection, is_system);
3770 if (FAILED(hr)) {
3771 heap_free(collection);
3772 return hr;
3775 *ret = &collection->IDWriteFontCollection1_iface;
3777 TRACE("building font collection:\n");
3779 list_init(&scannedfiles);
3780 while (hr == S_OK) {
3781 DWRITE_FONT_FACE_TYPE face_type;
3782 DWRITE_FONT_FILE_TYPE file_type;
3783 BOOL supported, same = FALSE;
3784 IDWriteFontFileStream *stream;
3785 IDWriteFontFile *file;
3786 UINT32 face_count;
3788 current = FALSE;
3789 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3790 if (FAILED(hr) || !current)
3791 break;
3793 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3794 if (FAILED(hr))
3795 break;
3797 /* check if we've scanned this file already */
3798 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3799 if ((same = is_same_fontfile(fileenum->file, file)))
3800 break;
3803 if (same) {
3804 IDWriteFontFile_Release(file);
3805 continue;
3808 if (FAILED(get_filestream_from_file(file, &stream))) {
3809 IDWriteFontFile_Release(file);
3810 continue;
3813 /* Unsupported formats are skipped. */
3814 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
3815 if (FAILED(hr) || !supported || face_count == 0) {
3816 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3817 IDWriteFontFileStream_Release(stream);
3818 IDWriteFontFile_Release(file);
3819 hr = S_OK;
3820 continue;
3823 /* add to scanned list */
3824 fileenum = heap_alloc(sizeof(*fileenum));
3825 fileenum->file = file;
3826 list_add_tail(&scannedfiles, &fileenum->entry);
3828 for (i = 0; i < face_count; i++) {
3829 IDWriteLocalizedStrings *family_name = NULL;
3830 struct dwrite_font_data *font_data;
3831 struct fontface_desc desc;
3832 WCHAR familyW[255];
3833 UINT32 index;
3835 desc.factory = factory;
3836 desc.face_type = face_type;
3837 desc.files = &file;
3838 desc.stream = stream;
3839 desc.files_number = 1;
3840 desc.index = i;
3841 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3842 desc.font_data = NULL;
3844 /* alloc and init new font data structure */
3845 hr = init_font_data(&desc, &family_name, &font_data);
3846 if (FAILED(hr)) {
3847 /* move to next one */
3848 hr = S_OK;
3849 continue;
3852 fontstrings_get_en_string(family_name, familyW, ARRAY_SIZE(familyW));
3854 /* ignore dot named faces */
3855 if (familyW[0] == '.') {
3856 WARN("Ignoring face %s\n", debugstr_w(familyW));
3857 IDWriteLocalizedStrings_Release(family_name);
3858 release_font_data(font_data);
3859 continue;
3862 index = collection_find_family(collection, familyW);
3863 if (index != ~0u)
3864 hr = fontfamily_add_font(collection->family_data[index], font_data);
3865 else {
3866 struct dwrite_fontfamily_data *family_data;
3868 /* create and init new family */
3869 hr = init_fontfamily_data(family_name, &family_data);
3870 if (hr == S_OK) {
3871 /* add font to family, family - to collection */
3872 hr = fontfamily_add_font(family_data, font_data);
3873 if (hr == S_OK)
3874 hr = fontcollection_add_family(collection, family_data);
3876 if (FAILED(hr))
3877 release_fontfamily_data(family_data);
3881 IDWriteLocalizedStrings_Release(family_name);
3883 if (FAILED(hr))
3884 break;
3887 IDWriteFontFileStream_Release(stream);
3890 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3891 IDWriteFontFile_Release(fileenum->file);
3892 list_remove(&fileenum->entry);
3893 heap_free(fileenum);
3896 for (i = 0; i < collection->family_count; i++) {
3897 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3898 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3901 if (is_system)
3902 fontcollection_add_replacements(collection);
3904 collection->factory = factory;
3905 IDWriteFactory5_AddRef(factory);
3907 return hr;
3910 struct system_fontfile_enumerator
3912 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3913 LONG ref;
3915 IDWriteFactory5 *factory;
3916 HKEY hkey;
3917 int index;
3919 WCHAR *filename;
3920 DWORD filename_size;
3923 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3925 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3928 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3930 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3931 IDWriteFontFileEnumerator_AddRef(iface);
3932 *obj = iface;
3933 return S_OK;
3936 WARN("%s not implemented.\n", debugstr_guid(riid));
3938 *obj = NULL;
3940 return E_NOINTERFACE;
3943 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3945 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3946 return InterlockedIncrement(&enumerator->ref);
3949 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3951 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3952 ULONG ref = InterlockedDecrement(&enumerator->ref);
3954 if (!ref) {
3955 IDWriteFactory5_Release(enumerator->factory);
3956 RegCloseKey(enumerator->hkey);
3957 heap_free(enumerator->filename);
3958 heap_free(enumerator);
3961 return ref;
3964 static HRESULT create_local_file_reference(IDWriteFactory5 *factory, const WCHAR *filename, IDWriteFontFile **file)
3966 HRESULT hr;
3968 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3969 if (!strchrW(filename, '\\')) {
3970 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3971 WCHAR fullpathW[MAX_PATH];
3973 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
3974 strcatW(fullpathW, fontsW);
3975 strcatW(fullpathW, filename);
3977 hr = IDWriteFactory5_CreateFontFileReference(factory, fullpathW, NULL, file);
3979 else
3980 hr = IDWriteFactory5_CreateFontFileReference(factory, filename, NULL, file);
3982 return hr;
3985 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3987 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3989 *file = NULL;
3991 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
3992 return E_FAIL;
3994 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
3997 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3999 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4000 WCHAR name_buf[256], *name = name_buf;
4001 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4002 HRESULT hr = S_OK;
4003 LONG r;
4005 *current = FALSE;
4006 enumerator->index++;
4008 /* iterate until we find next string value */
4009 for (;;) {
4010 do {
4011 name_count = max_name_count;
4012 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4014 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4015 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4016 if (r == ERROR_MORE_DATA) {
4017 if (name_count >= max_name_count) {
4018 if (name != name_buf) heap_free(name);
4019 max_name_count *= 2;
4020 name = heap_alloc(max_name_count * sizeof(*name));
4021 if (!name) return E_OUTOFMEMORY;
4023 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4024 heap_free(enumerator->filename);
4025 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4026 enumerator->filename = heap_alloc(enumerator->filename_size);
4027 if (!enumerator->filename) {
4028 hr = E_OUTOFMEMORY;
4029 goto err;
4033 } while (r == ERROR_MORE_DATA);
4035 if (r != ERROR_SUCCESS) {
4036 enumerator->filename[0] = 0;
4037 break;
4039 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4040 if (type == REG_SZ && *name != '@') {
4041 *current = TRUE;
4042 break;
4044 enumerator->index++;
4046 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4048 err:
4049 if (name != name_buf) heap_free(name);
4050 return hr;
4053 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4055 systemfontfileenumerator_QueryInterface,
4056 systemfontfileenumerator_AddRef,
4057 systemfontfileenumerator_Release,
4058 systemfontfileenumerator_MoveNext,
4059 systemfontfileenumerator_GetCurrentFontFile
4062 static HRESULT create_system_fontfile_enumerator(IDWriteFactory5 *factory, IDWriteFontFileEnumerator **ret)
4064 struct system_fontfile_enumerator *enumerator;
4065 static const WCHAR fontslistW[] = {
4066 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4067 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4068 'F','o','n','t','s',0
4071 *ret = NULL;
4073 enumerator = heap_alloc(sizeof(*enumerator));
4074 if (!enumerator)
4075 return E_OUTOFMEMORY;
4077 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4078 enumerator->ref = 1;
4079 enumerator->factory = factory;
4080 enumerator->index = -1;
4081 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4082 enumerator->filename = heap_alloc(enumerator->filename_size);
4083 if (!enumerator->filename) {
4084 heap_free(enumerator);
4085 return E_OUTOFMEMORY;
4088 IDWriteFactory5_AddRef(factory);
4090 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
4091 ERR("failed to open fonts list key\n");
4092 IDWriteFactory5_Release(factory);
4093 heap_free(enumerator->filename);
4094 heap_free(enumerator);
4095 return E_FAIL;
4098 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4100 return S_OK;
4103 HRESULT get_system_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **collection)
4105 IDWriteFontFileEnumerator *enumerator;
4106 HRESULT hr;
4108 *collection = NULL;
4110 hr = create_system_fontfile_enumerator(factory, &enumerator);
4111 if (FAILED(hr))
4112 return hr;
4114 TRACE("building system font collection for factory %p\n", factory);
4115 hr = create_font_collection(factory, enumerator, TRUE, collection);
4116 IDWriteFontFileEnumerator_Release(enumerator);
4117 return hr;
4120 static HRESULT eudc_collection_add_family(IDWriteFactory5 *factory, struct dwrite_fontcollection *collection,
4121 const WCHAR *keynameW, const WCHAR *pathW)
4123 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};
4124 static const WCHAR emptyW[] = {0};
4125 struct dwrite_fontfamily_data *family_data;
4126 IDWriteLocalizedStrings *names;
4127 DWRITE_FONT_FACE_TYPE face_type;
4128 DWRITE_FONT_FILE_TYPE file_type;
4129 IDWriteFontFileStream *stream;
4130 IDWriteFontFile *file;
4131 UINT32 face_count, i;
4132 BOOL supported;
4133 HRESULT hr;
4135 /* create font file from this path */
4136 hr = create_local_file_reference(factory, pathW, &file);
4137 if (FAILED(hr))
4138 return S_FALSE;
4140 if (FAILED(get_filestream_from_file(file, &stream))) {
4141 IDWriteFontFile_Release(file);
4142 return S_FALSE;
4145 /* Unsupported formats are skipped. */
4146 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4147 if (FAILED(hr) || !supported || face_count == 0) {
4148 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4149 IDWriteFontFileStream_Release(stream);
4150 IDWriteFontFile_Release(file);
4151 return S_FALSE;
4154 /* create and init new family */
4156 /* Family names are added for non-specific locale, represented with empty string.
4157 Default family appears with empty family name. */
4158 create_localizedstrings(&names);
4159 if (!strcmpiW(keynameW, defaultfontW))
4160 add_localizedstring(names, emptyW, emptyW);
4161 else
4162 add_localizedstring(names, emptyW, keynameW);
4164 hr = init_fontfamily_data(names, &family_data);
4165 IDWriteLocalizedStrings_Release(names);
4166 if (hr != S_OK) {
4167 IDWriteFontFile_Release(file);
4168 return hr;
4171 /* fill with faces */
4172 for (i = 0; i < face_count; i++) {
4173 struct dwrite_font_data *font_data;
4174 struct fontface_desc desc;
4176 /* alloc and init new font data structure */
4177 desc.factory = factory;
4178 desc.face_type = face_type;
4179 desc.index = i;
4180 desc.files = &file;
4181 desc.stream = stream;
4182 desc.files_number = 1;
4183 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4184 desc.font_data = NULL;
4186 hr = init_font_data(&desc, &names, &font_data);
4187 if (FAILED(hr))
4188 continue;
4190 IDWriteLocalizedStrings_Release(names);
4192 /* add font to family */
4193 hr = fontfamily_add_font(family_data, font_data);
4194 if (hr != S_OK)
4195 release_font_data(font_data);
4198 /* add family to collection */
4199 hr = fontcollection_add_family(collection, family_data);
4200 if (FAILED(hr))
4201 release_fontfamily_data(family_data);
4202 IDWriteFontFileStream_Release(stream);
4203 IDWriteFontFile_Release(file);
4205 return hr;
4208 HRESULT get_eudc_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **ret)
4210 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4211 struct dwrite_fontcollection *collection;
4212 static const WCHAR emptyW[] = {0};
4213 WCHAR eudckeypathW[16];
4214 HKEY eudckey;
4215 DWORD index;
4216 BOOL exists;
4217 LONG retval;
4218 HRESULT hr;
4219 UINT32 i;
4221 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4223 *ret = NULL;
4225 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4226 if (!collection) return E_OUTOFMEMORY;
4228 hr = init_font_collection(collection, FALSE);
4229 if (FAILED(hr)) {
4230 heap_free(collection);
4231 return hr;
4234 *ret = &collection->IDWriteFontCollection1_iface;
4235 collection->factory = factory;
4236 IDWriteFactory5_AddRef(factory);
4238 /* return empty collection if EUDC fonts are not configured */
4239 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4240 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4241 return S_OK;
4243 retval = ERROR_SUCCESS;
4244 index = 0;
4245 while (retval != ERROR_NO_MORE_ITEMS) {
4246 WCHAR keynameW[64], pathW[MAX_PATH];
4247 DWORD type, path_len, name_len;
4249 path_len = ARRAY_SIZE(pathW);
4250 name_len = ARRAY_SIZE(keynameW);
4251 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4252 if (retval || type != REG_SZ)
4253 continue;
4255 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4256 if (hr != S_OK)
4257 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4259 RegCloseKey(eudckey);
4261 /* try to add global default if not defined for specific codepage */
4262 exists = FALSE;
4263 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
4264 &index, &exists);
4265 if (FAILED(hr) || !exists) {
4266 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4267 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4268 if (hr != S_OK)
4269 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4272 /* EUDC collection offers simulated faces too */
4273 for (i = 0; i < collection->family_count; i++) {
4274 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4275 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4278 return S_OK;
4281 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4283 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4285 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4287 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4289 *obj = iface;
4290 IDWriteFontFile_AddRef(iface);
4291 return S_OK;
4294 WARN("%s not implemented.\n", debugstr_guid(riid));
4296 *obj = NULL;
4297 return E_NOINTERFACE;
4300 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4302 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4303 ULONG ref = InterlockedIncrement(&This->ref);
4304 TRACE("(%p)->(%d)\n", This, ref);
4305 return ref;
4308 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4310 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4311 ULONG ref = InterlockedDecrement(&This->ref);
4313 TRACE("(%p)->(%d)\n", This, ref);
4315 if (!ref)
4317 IDWriteFontFileLoader_Release(This->loader);
4318 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4319 heap_free(This->reference_key);
4320 heap_free(This);
4323 return ref;
4326 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4328 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4329 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4330 *fontFileReferenceKey = This->reference_key;
4331 *fontFileReferenceKeySize = This->key_size;
4333 return S_OK;
4336 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4338 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4339 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4340 *fontFileLoader = This->loader;
4341 IDWriteFontFileLoader_AddRef(This->loader);
4343 return S_OK;
4346 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4347 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4349 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4350 IDWriteFontFileStream *stream;
4351 HRESULT hr;
4353 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4355 *is_supported = FALSE;
4356 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4357 if (face_type)
4358 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4359 *face_count = 0;
4361 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4362 if (FAILED(hr))
4363 return hr;
4365 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4367 /* TODO: Further Analysis */
4368 IDWriteFontFileStream_Release(stream);
4369 return S_OK;
4372 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4373 dwritefontfile_QueryInterface,
4374 dwritefontfile_AddRef,
4375 dwritefontfile_Release,
4376 dwritefontfile_GetReferenceKey,
4377 dwritefontfile_GetLoader,
4378 dwritefontfile_Analyze,
4381 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4382 IDWriteFontFile **ret)
4384 struct dwrite_fontfile *file;
4385 void *key;
4387 *ret = NULL;
4389 file = heap_alloc(sizeof(*file));
4390 key = heap_alloc(key_size);
4391 if (!file || !key) {
4392 heap_free(file);
4393 heap_free(key);
4394 return E_OUTOFMEMORY;
4397 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4398 file->ref = 1;
4399 IDWriteFontFileLoader_AddRef(loader);
4400 file->loader = loader;
4401 file->stream = NULL;
4402 file->reference_key = key;
4403 memcpy(file->reference_key, reference_key, key_size);
4404 file->key_size = key_size;
4406 *ret = &file->IDWriteFontFile_iface;
4408 return S_OK;
4411 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace4 **ret)
4413 struct file_stream_desc stream_desc;
4414 struct dwrite_fontface *fontface;
4415 HRESULT hr = S_OK;
4416 BOOL is_symbol;
4417 int i;
4419 *ret = NULL;
4421 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4422 if (!fontface)
4423 return E_OUTOFMEMORY;
4425 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4426 if (!fontface->files) {
4427 heap_free(fontface);
4428 return E_OUTOFMEMORY;
4431 fontface->IDWriteFontFace4_iface.lpVtbl = &dwritefontfacevtbl;
4432 fontface->ref = 1;
4433 fontface->type = desc->face_type;
4434 fontface->file_count = desc->files_number;
4435 fontface->cmap.exists = TRUE;
4436 fontface->vdmx.exists = TRUE;
4437 fontface->gasp.exists = TRUE;
4438 fontface->cpal.exists = TRUE;
4439 fontface->colr.exists = TRUE;
4440 fontface->index = desc->index;
4441 fontface->simulations = desc->simulations;
4442 IDWriteFactory5_AddRef(fontface->factory = desc->factory);
4444 for (i = 0; i < fontface->file_count; i++) {
4445 fontface->files[i] = desc->files[i];
4446 IDWriteFontFile_AddRef(fontface->files[i]);
4448 fontface->stream = desc->stream;
4449 IDWriteFontFileStream_AddRef(fontface->stream);
4451 stream_desc.stream = fontface->stream;
4452 stream_desc.face_type = desc->face_type;
4453 stream_desc.face_index = desc->index;
4454 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4455 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4456 /* TODO: test what happens if caret is already slanted */
4457 if (fontface->caret.slopeRise == 1) {
4458 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4459 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4463 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace4_iface, &is_symbol);
4464 if (is_symbol)
4465 fontface->flags |= FONTFACE_IS_SYMBOL;
4466 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace4_iface))
4467 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4468 if (freetype_is_monospaced(&fontface->IDWriteFontFace4_iface))
4469 fontface->flags |= FONTFACE_IS_MONOSPACED;
4470 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace4_iface))
4471 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4472 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace4_iface);
4474 /* Font properties are reused from font object when 'normal' face creation path is used:
4475 collection -> family -> matching font -> fontface.
4477 If face is created directly from factory we have to go through properties resolution.
4479 if (desc->font_data) {
4480 fontface->weight = desc->font_data->weight;
4481 fontface->style = desc->font_data->style;
4482 fontface->stretch = desc->font_data->stretch;
4483 fontface->panose = desc->font_data->panose;
4484 fontface->fontsig = desc->font_data->fontsig;
4485 fontface->lf = desc->font_data->lf;
4487 else {
4488 IDWriteLocalizedStrings *names;
4489 struct dwrite_font_data *data;
4491 hr = init_font_data(desc, &names, &data);
4492 if (FAILED(hr)) {
4493 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4494 return hr;
4497 fontface->weight = data->weight;
4498 fontface->style = data->style;
4499 fontface->stretch = data->stretch;
4500 fontface->panose = data->panose;
4501 fontface->fontsig = data->fontsig;
4502 fontface->lf = data->lf;
4504 IDWriteLocalizedStrings_Release(names);
4505 release_font_data(data);
4508 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace4_iface);
4510 *ret = &fontface->IDWriteFontFace4_iface;
4511 return S_OK;
4514 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4515 struct local_refkey
4517 FILETIME writetime;
4518 WCHAR name[1];
4521 struct local_cached_stream
4523 struct list entry;
4524 IDWriteFontFileStream *stream;
4525 struct local_refkey *key;
4526 UINT32 key_size;
4529 struct dwrite_localfontfilestream
4531 IDWriteFontFileStream IDWriteFontFileStream_iface;
4532 LONG ref;
4534 struct local_cached_stream *entry;
4535 const void *file_ptr;
4536 UINT64 size;
4539 struct dwrite_localfontfileloader {
4540 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4541 LONG ref;
4543 struct list streams;
4544 CRITICAL_SECTION cs;
4547 static struct dwrite_localfontfileloader local_fontfile_loader;
4549 struct dwrite_inmemory_stream_data
4551 LONG ref;
4552 IUnknown *owner;
4553 void *data;
4554 UINT32 size;
4557 struct dwrite_inmemory_filestream
4559 IDWriteFontFileStream IDWriteFontFileStream_iface;
4560 LONG ref;
4562 struct dwrite_inmemory_stream_data *data;
4565 struct dwrite_inmemory_fileloader
4567 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
4568 LONG ref;
4570 struct dwrite_inmemory_stream_data **streams;
4571 UINT32 filecount;
4572 UINT32 capacity;
4575 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4577 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4580 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4582 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4585 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
4587 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
4590 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4592 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
4595 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
4597 if (InterlockedDecrement(&stream->ref) == 0) {
4598 if (stream->owner)
4599 IUnknown_Release(stream->owner);
4600 else
4601 heap_free(stream->data);
4602 heap_free(stream);
4606 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4608 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4610 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4612 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
4613 IsEqualIID(riid, &IID_IUnknown))
4615 *obj = iface;
4616 if (InterlockedIncrement(&This->ref) == 1) {
4617 InterlockedDecrement(&This->ref);
4618 *obj = NULL;
4619 return E_FAIL;
4621 return S_OK;
4624 WARN("%s not implemented.\n", debugstr_guid(riid));
4626 *obj = NULL;
4627 return E_NOINTERFACE;
4630 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4632 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4633 ULONG ref = InterlockedIncrement(&This->ref);
4634 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4635 return ref;
4638 static inline void release_cached_stream(struct local_cached_stream *stream)
4640 list_remove(&stream->entry);
4641 heap_free(stream->key);
4642 heap_free(stream);
4645 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4647 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4648 ULONG ref = InterlockedDecrement(&This->ref);
4650 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4652 if (!ref) {
4653 UnmapViewOfFile(This->file_ptr);
4655 EnterCriticalSection(&local_fontfile_loader.cs);
4656 release_cached_stream(This->entry);
4657 LeaveCriticalSection(&local_fontfile_loader.cs);
4659 heap_free(This);
4662 return ref;
4665 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4666 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4668 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4670 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4671 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4673 *fragment_context = NULL;
4675 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4676 *fragment_start = NULL;
4677 return E_FAIL;
4680 *fragment_start = (char*)This->file_ptr + offset;
4681 return S_OK;
4684 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4686 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4687 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4690 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4692 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4693 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4694 *size = This->size;
4695 return S_OK;
4698 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4700 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4701 ULARGE_INTEGER li;
4703 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4705 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4706 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4707 *last_writetime = li.QuadPart;
4709 return S_OK;
4712 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4714 localfontfilestream_QueryInterface,
4715 localfontfilestream_AddRef,
4716 localfontfilestream_Release,
4717 localfontfilestream_ReadFileFragment,
4718 localfontfilestream_ReleaseFileFragment,
4719 localfontfilestream_GetFileSize,
4720 localfontfilestream_GetLastWriteTime
4723 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4725 struct dwrite_localfontfilestream *This;
4727 *ret = NULL;
4729 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4730 if (!This)
4731 return E_OUTOFMEMORY;
4733 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4734 This->ref = 1;
4736 This->file_ptr = file_ptr;
4737 This->size = size;
4738 This->entry = entry;
4740 *ret = &This->IDWriteFontFileStream_iface;
4741 return S_OK;
4744 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4746 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4748 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4750 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
4751 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
4752 IsEqualIID(riid, &IID_IUnknown))
4754 *obj = iface;
4755 IDWriteLocalFontFileLoader_AddRef(iface);
4756 return S_OK;
4759 WARN("%s not implemented.\n", debugstr_guid(riid));
4761 *obj = NULL;
4762 return E_NOINTERFACE;
4765 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4767 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4768 ULONG ref = InterlockedIncrement(&This->ref);
4769 TRACE("(%p)->(%d)\n", This, ref);
4770 return ref;
4773 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4775 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4776 ULONG ref = InterlockedDecrement(&This->ref);
4778 TRACE("(%p)->(%d)\n", This, ref);
4780 return ref;
4783 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
4785 const struct local_refkey *refkey = key;
4786 struct local_cached_stream *stream;
4787 IDWriteFontFileStream *filestream;
4788 HANDLE file, mapping;
4789 LARGE_INTEGER size;
4790 void *file_ptr;
4791 HRESULT hr = S_OK;
4793 *ret = NULL;
4795 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4796 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4797 if (file == INVALID_HANDLE_VALUE) {
4798 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
4799 return E_FAIL;
4802 GetFileSizeEx(file, &size);
4803 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4804 CloseHandle(file);
4805 if (!mapping)
4806 return E_FAIL;
4808 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4809 CloseHandle(mapping);
4810 if (!file_ptr) {
4811 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4812 return E_FAIL;
4815 stream = heap_alloc(sizeof(*stream));
4816 if (!stream) {
4817 UnmapViewOfFile(file_ptr);
4818 return E_OUTOFMEMORY;
4821 stream->key = heap_alloc(key_size);
4822 if (!stream->key) {
4823 UnmapViewOfFile(file_ptr);
4824 heap_free(stream);
4825 return E_OUTOFMEMORY;
4828 stream->key_size = key_size;
4829 memcpy(stream->key, key, key_size);
4831 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4832 if (FAILED(hr)) {
4833 UnmapViewOfFile(file_ptr);
4834 heap_free(stream->key);
4835 heap_free(stream);
4836 return hr;
4839 stream->stream = filestream;
4841 *ret = stream;
4843 return S_OK;
4846 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
4847 UINT32 key_size, IDWriteFontFileStream **ret)
4849 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4850 const struct local_refkey *refkey = key;
4851 struct local_cached_stream *stream;
4852 HRESULT hr = S_OK;
4854 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
4855 TRACE("name: %s\n", debugstr_w(refkey->name));
4857 EnterCriticalSection(&This->cs);
4859 *ret = NULL;
4861 /* search cache first */
4862 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4863 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4864 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
4865 break;
4869 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
4870 list_add_head(&This->streams, &stream->entry);
4871 *ret = stream->stream;
4874 LeaveCriticalSection(&This->cs);
4876 return hr;
4879 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4881 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4882 const struct local_refkey *refkey = key;
4884 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4886 *length = strlenW(refkey->name);
4887 return S_OK;
4890 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4892 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4893 const struct local_refkey *refkey = key;
4895 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4897 if (length < strlenW(refkey->name))
4898 return E_INVALIDARG;
4900 strcpyW(path, refkey->name);
4901 return S_OK;
4904 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
4905 UINT32 key_size, FILETIME *writetime)
4907 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4908 const struct local_refkey *refkey = key;
4910 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
4912 *writetime = refkey->writetime;
4913 return S_OK;
4916 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4917 localfontfileloader_QueryInterface,
4918 localfontfileloader_AddRef,
4919 localfontfileloader_Release,
4920 localfontfileloader_CreateStreamFromKey,
4921 localfontfileloader_GetFilePathLengthFromKey,
4922 localfontfileloader_GetFilePathFromKey,
4923 localfontfileloader_GetLastWriteTimeFromKey
4926 void init_local_fontfile_loader(void)
4928 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4929 local_fontfile_loader.ref = 1;
4930 list_init(&local_fontfile_loader.streams);
4931 InitializeCriticalSection(&local_fontfile_loader.cs);
4932 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
4935 IDWriteFontFileLoader *get_local_fontfile_loader(void)
4937 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
4940 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4942 struct local_refkey *refkey;
4944 if (!path)
4945 return E_INVALIDARG;
4947 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4948 *key = NULL;
4950 refkey = heap_alloc(*size);
4951 if (!refkey)
4952 return E_OUTOFMEMORY;
4954 if (writetime)
4955 refkey->writetime = *writetime;
4956 else {
4957 WIN32_FILE_ATTRIBUTE_DATA info;
4959 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4960 refkey->writetime = info.ftLastWriteTime;
4961 else
4962 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4964 strcpyW(refkey->name, path);
4966 *key = refkey;
4968 return S_OK;
4971 /* IDWriteGlyphRunAnalysis */
4972 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4974 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4976 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4978 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4979 IsEqualIID(riid, &IID_IUnknown))
4981 *ppv = iface;
4982 IDWriteGlyphRunAnalysis_AddRef(iface);
4983 return S_OK;
4986 WARN("%s not implemented.\n", debugstr_guid(riid));
4988 *ppv = NULL;
4989 return E_NOINTERFACE;
4992 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4994 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4995 ULONG ref = InterlockedIncrement(&This->ref);
4996 TRACE("(%p)->(%u)\n", This, ref);
4997 return ref;
5000 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5002 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5003 ULONG ref = InterlockedDecrement(&This->ref);
5005 TRACE("(%p)->(%u)\n", This, ref);
5007 if (!ref) {
5008 if (This->run.fontFace)
5009 IDWriteFontFace_Release(This->run.fontFace);
5010 heap_free(This->glyphs);
5011 heap_free(This->origins);
5012 heap_free(This->bitmap);
5013 heap_free(This);
5016 return ref;
5019 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5021 switch (mode)
5023 case DWRITE_RENDERING_MODE1_NATURAL:
5024 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5025 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5026 return TRUE;
5027 default:
5028 return FALSE;
5032 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5034 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5037 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5039 struct dwrite_glyphbitmap glyph_bitmap;
5040 IDWriteFontFace4 *fontface;
5041 HRESULT hr;
5042 UINT32 i;
5044 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5045 *bounds = analysis->bounds;
5046 return;
5049 if (analysis->run.isSideways)
5050 FIXME("sideways runs are not supported.\n");
5052 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5053 if (FAILED(hr))
5054 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5056 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5057 glyph_bitmap.fontface = fontface;
5058 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5059 glyph_bitmap.emsize = analysis->run.fontEmSize;
5060 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5061 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5062 glyph_bitmap.m = &analysis->m;
5064 for (i = 0; i < analysis->run.glyphCount; i++) {
5065 RECT *bbox = &glyph_bitmap.bbox;
5066 UINT32 bitmap_size;
5068 glyph_bitmap.index = analysis->run.glyphIndices[i];
5069 freetype_get_glyph_bbox(&glyph_bitmap);
5071 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5072 (bbox->bottom - bbox->top);
5073 if (bitmap_size > analysis->max_glyph_bitmap_size)
5074 analysis->max_glyph_bitmap_size = bitmap_size;
5076 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5077 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5080 IDWriteFontFace4_Release(fontface);
5082 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5083 *bounds = analysis->bounds;
5086 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5088 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5090 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5092 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5093 SetRectEmpty(bounds);
5094 return E_INVALIDARG;
5097 if (type != This->texture_type) {
5098 SetRectEmpty(bounds);
5099 return S_OK;
5102 glyphrunanalysis_get_texturebounds(This, bounds);
5103 return S_OK;
5106 static inline int get_dib_stride( int width, int bpp )
5108 return ((width * bpp + 31) >> 3) & ~3;
5111 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5113 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5114 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5115 (runbounds->left - bounds->left) * 3;
5116 else
5117 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5118 runbounds->left - bounds->left;
5121 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5123 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5124 struct dwrite_glyphbitmap glyph_bitmap;
5125 IDWriteFontFace4 *fontface;
5126 D2D_POINT_2F origin;
5127 UINT32 i, size;
5128 HRESULT hr;
5129 RECT *bbox;
5131 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5132 if (FAILED(hr)) {
5133 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5134 return hr;
5137 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5138 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5139 size *= 3;
5140 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5141 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5142 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5143 IDWriteFontFace4_Release(fontface);
5144 return E_OUTOFMEMORY;
5147 origin.x = origin.y = 0.0f;
5149 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5150 glyph_bitmap.fontface = fontface;
5151 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5152 glyph_bitmap.emsize = analysis->run.fontEmSize;
5153 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5154 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5155 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5156 glyph_bitmap.m = &analysis->m;
5157 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5158 IDWriteFontFace4_Release(fontface);
5159 return E_OUTOFMEMORY;
5162 bbox = &glyph_bitmap.bbox;
5164 for (i = 0; i < analysis->run.glyphCount; i++) {
5165 BYTE *src = glyph_bitmap.buf, *dst;
5166 int x, y, width, height;
5167 BOOL is_1bpp;
5169 glyph_bitmap.index = analysis->run.glyphIndices[i];
5170 freetype_get_glyph_bbox(&glyph_bitmap);
5172 if (IsRectEmpty(bbox))
5173 continue;
5175 width = bbox->right - bbox->left;
5176 height = bbox->bottom - bbox->top;
5178 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5179 memset(src, 0, height * glyph_bitmap.pitch);
5180 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5182 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5184 /* blit to analysis bitmap */
5185 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5187 if (is_1bpp) {
5188 /* convert 1bpp to 8bpp/24bpp */
5189 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5190 for (y = 0; y < height; y++) {
5191 for (x = 0; x < width; x++)
5192 if (src[x / 8] & masks[x % 8])
5193 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5194 src += glyph_bitmap.pitch;
5195 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5198 else {
5199 for (y = 0; y < height; y++) {
5200 for (x = 0; x < width; x++)
5201 if (src[x / 8] & masks[x % 8])
5202 dst[x] = DWRITE_ALPHA_MAX;
5203 src += glyph_bitmap.pitch;
5204 dst += analysis->bounds.right - analysis->bounds.left;
5208 else {
5209 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5210 for (y = 0; y < height; y++) {
5211 for (x = 0; x < width; x++)
5212 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5213 src += glyph_bitmap.pitch;
5214 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5217 else {
5218 for (y = 0; y < height; y++) {
5219 for (x = 0; x < width; x++)
5220 dst[x] |= src[x];
5221 src += glyph_bitmap.pitch;
5222 dst += analysis->bounds.right - analysis->bounds.left;
5227 heap_free(glyph_bitmap.buf);
5229 IDWriteFontFace4_Release(fontface);
5231 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5233 /* we don't need this anymore */
5234 heap_free(analysis->glyphs);
5235 heap_free(analysis->origins);
5236 IDWriteFontFace_Release(analysis->run.fontFace);
5238 analysis->glyphs = NULL;
5239 analysis->origins = NULL;
5240 analysis->run.glyphIndices = NULL;
5241 analysis->run.fontFace = NULL;
5243 return S_OK;
5246 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5247 RECT const *bounds, BYTE *bitmap, UINT32 size)
5249 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5250 UINT32 required;
5251 RECT runbounds;
5253 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5255 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5256 return E_INVALIDARG;
5258 /* make sure buffer is large enough for requested texture type */
5259 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5260 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5261 required *= 3;
5263 if (size < required)
5264 return E_NOT_SUFFICIENT_BUFFER;
5266 /* validate requested texture type */
5267 if (This->texture_type != type)
5268 return DWRITE_E_UNSUPPORTEDOPERATION;
5270 memset(bitmap, 0, size);
5271 glyphrunanalysis_get_texturebounds(This, &runbounds);
5272 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5273 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5274 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5275 int dst_width = (bounds->right - bounds->left) * pixel_size;
5276 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5277 BYTE *src, *dst;
5278 int y;
5280 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5281 HRESULT hr;
5283 if (FAILED(hr = glyphrunanalysis_render(This)))
5284 return hr;
5287 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5288 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5290 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5291 memcpy(dst, src, draw_width);
5292 src += src_width;
5293 dst += dst_width;
5297 return S_OK;
5300 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5301 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5303 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5305 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5307 if (!params)
5308 return E_INVALIDARG;
5310 switch (This->rendering_mode)
5312 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5313 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5315 UINT value = 0;
5316 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5317 *gamma = (FLOAT)value / 1000.0f;
5318 *contrast = 0.0f;
5319 *cleartypelevel = 1.0f;
5320 break;
5322 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5323 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5324 /* fallthrough */
5325 case DWRITE_RENDERING_MODE1_ALIASED:
5326 case DWRITE_RENDERING_MODE1_NATURAL:
5327 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5328 *gamma = IDWriteRenderingParams_GetGamma(params);
5329 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5330 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5331 break;
5332 default:
5336 return S_OK;
5339 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5340 glyphrunanalysis_QueryInterface,
5341 glyphrunanalysis_AddRef,
5342 glyphrunanalysis_Release,
5343 glyphrunanalysis_GetAlphaTextureBounds,
5344 glyphrunanalysis_CreateAlphaTexture,
5345 glyphrunanalysis_GetAlphaBlendParams
5348 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5350 D2D_POINT_2F ret;
5351 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5352 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5353 *point = ret;
5356 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5358 struct dwrite_glyphrunanalysis *analysis;
5359 DWRITE_FONT_METRICS metrics;
5360 IDWriteFontFace1 *fontface1;
5361 D2D_POINT_2F origin;
5362 FLOAT rtl_factor;
5363 HRESULT hr;
5364 UINT32 i;
5366 *ret = NULL;
5368 /* Check rendering, antialising, measuring, and grid fitting modes. */
5369 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5370 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5371 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5372 return E_INVALIDARG;
5374 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5375 return E_INVALIDARG;
5377 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5378 return E_INVALIDARG;
5380 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5381 return E_INVALIDARG;
5383 analysis = heap_alloc(sizeof(*analysis));
5384 if (!analysis)
5385 return E_OUTOFMEMORY;
5387 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5388 analysis->ref = 1;
5389 analysis->rendering_mode = desc->rendering_mode;
5391 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5392 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5393 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5394 else
5395 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5397 analysis->flags = 0;
5398 analysis->bitmap = NULL;
5399 analysis->max_glyph_bitmap_size = 0;
5400 SetRectEmpty(&analysis->bounds);
5401 analysis->run = *desc->run;
5402 IDWriteFontFace_AddRef(analysis->run.fontFace);
5403 analysis->glyphs = heap_alloc(desc->run->glyphCount * sizeof(*analysis->glyphs));
5404 analysis->origins = heap_alloc(desc->run->glyphCount * sizeof(*analysis->origins));
5406 if (!analysis->glyphs || !analysis->origins) {
5407 heap_free(analysis->glyphs);
5408 heap_free(analysis->origins);
5410 analysis->glyphs = NULL;
5411 analysis->origins = NULL;
5413 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5414 return E_OUTOFMEMORY;
5417 /* check if transform is usable */
5418 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5419 analysis->m = *desc->transform;
5420 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5422 else
5423 memset(&analysis->m, 0, sizeof(analysis->m));
5425 analysis->run.glyphIndices = analysis->glyphs;
5426 analysis->run.glyphAdvances = NULL;
5427 analysis->run.glyphOffsets = NULL;
5429 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5431 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5433 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
5434 if (FAILED(hr = IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1)))
5435 WARN("Failed to get IDWriteFontFace1, %#x.\n", hr);
5437 origin.x = desc->origin.x;
5438 origin.y = desc->origin.y;
5439 for (i = 0; i < desc->run->glyphCount; i++) {
5440 FLOAT advance;
5442 /* Use nominal advances if not provided by caller. */
5443 if (desc->run->glyphAdvances)
5444 advance = rtl_factor * desc->run->glyphAdvances[i];
5445 else {
5446 INT32 a;
5448 advance = 0.0f;
5449 switch (desc->measuring_mode)
5451 case DWRITE_MEASURING_MODE_NATURAL:
5452 if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a,
5453 desc->run->isSideways)))
5454 advance = rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics);
5455 break;
5456 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5457 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5458 if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize,
5459 1.0f, desc->transform, desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL,
5460 desc->run->isSideways, 1, desc->run->glyphIndices + i, &a)))
5461 advance = rtl_factor * floorf(a * desc->run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5462 break;
5463 default:
5468 analysis->origins[i] = origin;
5470 /* Offsets are optional, appled to pre-transformed origin. */
5471 if (desc->run->glyphOffsets) {
5472 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5473 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5475 if (desc->run->isSideways) {
5476 analysis->origins[i].x += ascenderoffset;
5477 analysis->origins[i].y += advanceoffset;
5479 else {
5480 analysis->origins[i].x += advanceoffset;
5481 analysis->origins[i].y += ascenderoffset;
5485 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5486 transform_point(analysis->origins + i, &analysis->m);
5488 if (desc->run->isSideways)
5489 origin.y += advance;
5490 else
5491 origin.x += advance;
5494 IDWriteFontFace1_Release(fontface1);
5496 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5497 return S_OK;
5500 /* IDWriteColorGlyphRunEnumerator */
5501 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5503 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5505 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5507 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5508 IsEqualIID(riid, &IID_IUnknown))
5510 *ppv = iface;
5511 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5512 return S_OK;
5515 WARN("%s not implemented.\n", debugstr_guid(riid));
5517 *ppv = NULL;
5518 return E_NOINTERFACE;
5521 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5523 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5524 ULONG ref = InterlockedIncrement(&This->ref);
5525 TRACE("(%p)->(%u)\n", This, ref);
5526 return ref;
5529 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5531 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5532 ULONG ref = InterlockedDecrement(&This->ref);
5534 TRACE("(%p)->(%u)\n", This, ref);
5536 if (!ref) {
5537 heap_free(This->advances);
5538 heap_free(This->color_advances);
5539 heap_free(This->offsets);
5540 heap_free(This->color_offsets);
5541 heap_free(This->glyphindices);
5542 heap_free(This->glyphs);
5543 if (This->colr.context)
5544 IDWriteFontFace4_ReleaseFontTable(This->fontface, This->colr.context);
5545 IDWriteFontFace4_Release(This->fontface);
5546 heap_free(This);
5549 return ref;
5552 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5554 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5555 FLOAT origin = 0.0f;
5557 if (g == 0)
5558 return 0.0f;
5560 while (g--)
5561 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5562 return origin;
5565 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5567 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5568 FLOAT advance_adj = 0.0f;
5569 BOOL got_palette_index;
5570 UINT32 g;
5572 /* start with regular glyphs */
5573 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5574 UINT32 first_glyph = 0;
5576 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5577 if (glyphenum->glyphs[g].num_layers == 0) {
5578 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5579 first_glyph = min(first_glyph, g);
5581 else
5582 glyphenum->glyphindices[g] = 1;
5583 glyphenum->color_advances[g] = glyphenum->advances[g];
5584 if (glyphenum->color_offsets)
5585 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5588 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5589 colorrun->baselineOriginY = glyphenum->origin_y;
5590 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5591 colorrun->paletteIndex = 0xffff;
5592 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5593 glyphenum->has_regular_glyphs = FALSE;
5594 return TRUE;
5596 else {
5597 colorrun->glyphRun.glyphCount = 0;
5598 got_palette_index = FALSE;
5601 advance_adj = 0.0f;
5602 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5604 glyphenum->glyphindices[g] = 1;
5606 /* all glyph layers were returned */
5607 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5608 advance_adj += glyphenum->advances[g];
5609 continue;
5612 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5613 UINT32 index = colorrun->glyphRun.glyphCount;
5614 if (!got_palette_index) {
5615 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5616 /* use foreground color or request one from the font */
5617 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5618 if (colorrun->paletteIndex != 0xffff) {
5619 HRESULT hr = IDWriteFontFace4_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5620 1, &colorrun->runColor);
5621 if (FAILED(hr))
5622 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5623 glyphenum->palette, colorrun->paletteIndex, hr);
5625 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5626 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5627 colorrun->baselineOriginY = glyphenum->origin_y;
5628 glyphenum->color_advances[index] = glyphenum->advances[g];
5629 got_palette_index = TRUE;
5632 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5633 /* offsets are relative to glyph origin, nothing to fix up */
5634 if (glyphenum->color_offsets)
5635 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5636 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5637 if (index)
5638 glyphenum->color_advances[index-1] += advance_adj;
5639 colorrun->glyphRun.glyphCount++;
5640 advance_adj = 0.0f;
5642 else
5643 advance_adj += glyphenum->advances[g];
5646 /* reset last advance */
5647 if (colorrun->glyphRun.glyphCount)
5648 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5650 return colorrun->glyphRun.glyphCount > 0;
5653 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5655 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5657 TRACE("(%p)->(%p)\n", This, has_run);
5659 *has_run = FALSE;
5661 This->colorrun.glyphRun.glyphCount = 0;
5662 while (This->current_layer < This->max_layer_num) {
5663 if (colorglyphenum_build_color_run(This))
5664 break;
5665 else
5666 This->current_layer++;
5669 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5671 return S_OK;
5674 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5676 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5678 TRACE("(%p)->(%p)\n", This, run);
5680 if (This->colorrun.glyphRun.glyphCount == 0) {
5681 *run = NULL;
5682 return E_NOT_VALID_STATE;
5685 *run = &This->colorrun;
5686 return S_OK;
5689 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5690 colorglyphenum_QueryInterface,
5691 colorglyphenum_AddRef,
5692 colorglyphenum_Release,
5693 colorglyphenum_MoveNext,
5694 colorglyphenum_GetCurrentRun
5697 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5698 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5700 struct dwrite_colorglyphenum *colorglyphenum;
5701 BOOL colorfont, has_colored_glyph;
5702 IDWriteFontFace4 *fontface;
5703 HRESULT hr;
5704 UINT32 i;
5706 *ret = NULL;
5708 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace4, (void**)&fontface);
5709 if (FAILED(hr)) {
5710 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5711 return hr;
5714 colorfont = IDWriteFontFace4_IsColorFont(fontface) && IDWriteFontFace4_GetColorPaletteCount(fontface) > palette;
5715 if (!colorfont) {
5716 hr = DWRITE_E_NOCOLOR;
5717 goto failed;
5720 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5721 if (!colorglyphenum) {
5722 hr = E_OUTOFMEMORY;
5723 goto failed;
5726 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5727 colorglyphenum->ref = 1;
5728 colorglyphenum->origin_x = originX;
5729 colorglyphenum->origin_y = originY;
5730 colorglyphenum->fontface = fontface;
5731 colorglyphenum->glyphs = NULL;
5732 colorglyphenum->run = *run;
5733 colorglyphenum->run.glyphIndices = NULL;
5734 colorglyphenum->run.glyphAdvances = NULL;
5735 colorglyphenum->run.glyphOffsets = NULL;
5736 colorglyphenum->palette = palette;
5737 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5738 colorglyphenum->colr.exists = TRUE;
5739 get_fontface_table(fontface, MS_COLR_TAG, &colorglyphenum->colr);
5740 colorglyphenum->current_layer = 0;
5741 colorglyphenum->max_layer_num = 0;
5743 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5745 has_colored_glyph = FALSE;
5746 colorglyphenum->has_regular_glyphs = FALSE;
5747 for (i = 0; i < run->glyphCount; i++) {
5748 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5749 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5750 has_colored_glyph = TRUE;
5752 if (colorglyphenum->glyphs[i].num_layers == 0)
5753 colorglyphenum->has_regular_glyphs = TRUE;
5756 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5757 is supposed to proceed normally, like if font had no color info at all. */
5758 if (!has_colored_glyph) {
5759 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5760 return DWRITE_E_NOCOLOR;
5763 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5764 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5765 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5766 if (run->glyphOffsets) {
5767 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5768 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5769 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5772 colorglyphenum->colorrun.glyphRun.fontFace = (IDWriteFontFace*)fontface;
5773 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
5774 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5775 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5776 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5777 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5779 if (run->glyphAdvances)
5780 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5781 else {
5782 DWRITE_FONT_METRICS metrics;
5784 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5785 for (i = 0; i < run->glyphCount; i++) {
5786 HRESULT hr;
5787 INT32 a;
5789 switch (measuring_mode)
5791 case DWRITE_MEASURING_MODE_NATURAL:
5792 hr = IDWriteFontFace4_GetDesignGlyphAdvances(fontface, 1, run->glyphIndices + i, &a, run->isSideways);
5793 if (FAILED(hr))
5794 a = 0;
5795 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5796 break;
5797 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5798 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5799 hr = IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(fontface, run->fontEmSize, 1.0f, transform,
5800 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5801 if (FAILED(hr))
5802 colorglyphenum->advances[i] = 0.0f;
5803 else
5804 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5805 break;
5806 default:
5812 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5813 return S_OK;
5815 failed:
5816 IDWriteFontFace4_Release(fontface);
5817 return hr;
5820 /* IDWriteFontFaceReference */
5821 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5823 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5825 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5827 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5828 *obj = iface;
5829 IDWriteFontFaceReference_AddRef(iface);
5830 return S_OK;
5833 WARN("%s not implemented.\n", debugstr_guid(riid));
5835 *obj = NULL;
5837 return E_NOINTERFACE;
5840 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5842 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5843 ULONG ref = InterlockedIncrement(&This->ref);
5844 TRACE("(%p)->(%u)\n", This, ref);
5845 return ref;
5848 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5850 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5851 ULONG ref = InterlockedDecrement(&This->ref);
5853 TRACE("(%p)->(%u)\n", This, ref);
5855 if (!ref) {
5856 IDWriteFontFile_Release(This->file);
5857 IDWriteFactory5_Release(This->factory);
5858 heap_free(This);
5861 return ref;
5864 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5866 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5868 TRACE("(%p)->(%p)\n", This, fontface);
5870 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5873 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5874 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5876 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5877 DWRITE_FONT_FILE_TYPE file_type;
5878 DWRITE_FONT_FACE_TYPE face_type;
5879 IDWriteFontFace *fontface;
5880 BOOL is_supported;
5881 UINT32 face_num;
5882 HRESULT hr;
5884 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5886 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5887 if (FAILED(hr))
5888 return hr;
5890 hr = IDWriteFactory5_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5891 if (SUCCEEDED(hr)) {
5892 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
5893 IDWriteFontFace_Release(fontface);
5896 return hr;
5899 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5901 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5902 IDWriteFontFile *file;
5903 BOOL ret;
5905 TRACE("(%p)->(%p)\n", This, ref);
5907 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5908 return FALSE;
5910 ret = is_same_fontfile(This->file, file) &&
5911 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5912 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5913 IDWriteFontFile_Release(file);
5915 return ret;
5918 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5920 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5922 TRACE("(%p)\n", This);
5924 return This->index;
5927 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5929 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5931 TRACE("(%p)\n", This);
5933 return This->simulations;
5936 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5938 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5939 IDWriteFontFileLoader *loader;
5940 const void *key;
5941 UINT32 key_size;
5942 HRESULT hr;
5944 TRACE("(%p)->(%p)\n", This, file);
5946 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5947 if (FAILED(hr))
5948 return hr;
5950 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5951 if (FAILED(hr))
5952 return hr;
5954 hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5955 IDWriteFontFileLoader_Release(loader);
5957 return hr;
5960 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5962 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5964 FIXME("(%p): stub\n", This);
5966 return 0;
5969 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5971 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5973 FIXME("(%p): stub\n", This);
5975 return 0;
5978 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5980 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5982 FIXME("(%p)->(%p): stub\n", This, writetime);
5984 return E_NOTIMPL;
5987 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5989 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5991 FIXME("(%p): stub\n", This);
5993 return DWRITE_LOCALITY_LOCAL;
5996 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5998 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6000 FIXME("(%p): stub\n", This);
6002 return E_NOTIMPL;
6005 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
6006 UINT32 count)
6008 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6010 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
6012 return E_NOTIMPL;
6015 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
6016 UINT32 count)
6018 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6020 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
6022 return E_NOTIMPL;
6025 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
6026 UINT64 offset, UINT64 size)
6028 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6030 FIXME("(%p)->(0x%s 0x%s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6032 return E_NOTIMPL;
6035 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
6036 fontfacereference_QueryInterface,
6037 fontfacereference_AddRef,
6038 fontfacereference_Release,
6039 fontfacereference_CreateFontFace,
6040 fontfacereference_CreateFontFaceWithSimulations,
6041 fontfacereference_Equals,
6042 fontfacereference_GetFontFaceIndex,
6043 fontfacereference_GetSimulations,
6044 fontfacereference_GetFontFile,
6045 fontfacereference_GetLocalFileSize,
6046 fontfacereference_GetFileSize,
6047 fontfacereference_GetFileTime,
6048 fontfacereference_GetLocality,
6049 fontfacereference_EnqueueFontDownloadRequest,
6050 fontfacereference_EnqueueCharacterDownloadRequest,
6051 fontfacereference_EnqueueGlyphDownloadRequest,
6052 fontfacereference_EnqueueFileFragmentDownloadRequest
6055 HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file, UINT32 index,
6056 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
6058 struct dwrite_fontfacereference *ref;
6060 *ret = NULL;
6062 if (!is_simulation_valid(simulations))
6063 return E_INVALIDARG;
6065 ref = heap_alloc(sizeof(*ref));
6066 if (!ref)
6067 return E_OUTOFMEMORY;
6069 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
6070 ref->ref = 1;
6072 ref->factory = factory;
6073 IDWriteFactory5_AddRef(ref->factory);
6074 ref->file = file;
6075 IDWriteFontFile_AddRef(ref->file);
6076 ref->index = index;
6077 ref->simulations = simulations;
6078 *ret = &ref->IDWriteFontFaceReference_iface;
6080 return S_OK;
6083 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6085 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6087 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6089 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6090 *obj = iface;
6091 IDWriteFontFileStream_AddRef(iface);
6092 return S_OK;
6095 *obj = NULL;
6097 WARN("%s not implemented.\n", debugstr_guid(riid));
6098 return E_NOINTERFACE;
6101 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6103 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6104 ULONG ref = InterlockedIncrement(&stream->ref);
6105 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6106 return ref;
6109 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6111 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6112 ULONG ref = InterlockedDecrement(&stream->ref);
6114 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6116 if (!ref) {
6117 release_inmemory_stream(stream->data);
6118 heap_free(stream);
6121 return ref;
6124 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6125 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6127 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6129 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6130 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6132 *fragment_context = NULL;
6134 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6135 *fragment_start = NULL;
6136 return E_FAIL;
6139 *fragment_start = (char *)stream->data->data + offset;
6140 return S_OK;
6143 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6145 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6147 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6150 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6152 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6154 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6156 *size = stream->data->size;
6158 return S_OK;
6161 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6163 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6165 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6167 *last_writetime = 0;
6169 return E_NOTIMPL;
6172 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6173 inmemoryfilestream_QueryInterface,
6174 inmemoryfilestream_AddRef,
6175 inmemoryfilestream_Release,
6176 inmemoryfilestream_ReadFileFragment,
6177 inmemoryfilestream_ReleaseFileFragment,
6178 inmemoryfilestream_GetFileSize,
6179 inmemoryfilestream_GetLastWriteTime,
6182 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6183 REFIID riid, void **obj)
6185 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6187 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6189 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6190 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6191 IsEqualIID(riid, &IID_IUnknown))
6193 *obj = iface;
6194 IDWriteInMemoryFontFileLoader_AddRef(iface);
6195 return S_OK;
6198 WARN("%s not implemented.\n", debugstr_guid(riid));
6200 *obj = NULL;
6202 return E_NOINTERFACE;
6205 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6207 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6208 ULONG ref = InterlockedIncrement(&loader->ref);
6209 TRACE("(%p)->(%u)\n", loader, ref);
6210 return ref;
6213 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6215 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6216 ULONG ref = InterlockedDecrement(&loader->ref);
6218 TRACE("(%p)->(%u)\n", loader, ref);
6220 if (!ref) {
6221 UINT32 i;
6223 for (i = 0; i < loader->filecount; i++)
6224 release_inmemory_stream(loader->streams[i]);
6225 heap_free(loader->streams);
6226 heap_free(loader);
6229 return ref;
6232 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6233 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6235 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6236 struct dwrite_inmemory_filestream *stream;
6237 DWORD index;
6239 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6241 *ret = NULL;
6243 if (key_size != sizeof(DWORD))
6244 return E_INVALIDARG;
6246 index = *(DWORD *)key;
6248 if (index >= loader->filecount)
6249 return E_INVALIDARG;
6251 if (!(stream = heap_alloc(sizeof(*stream))))
6252 return E_OUTOFMEMORY;
6254 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6255 stream->ref = 1;
6256 stream->data = loader->streams[index];
6257 InterlockedIncrement(&stream->data->ref);
6259 *ret = &stream->IDWriteFontFileStream_iface;
6261 return S_OK;
6264 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6265 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6267 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6268 struct dwrite_inmemory_stream_data *stream;
6269 DWORD key;
6271 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6273 *fontfile = NULL;
6275 if (loader->filecount == loader->capacity) {
6276 if (loader->streams) {
6277 struct dwrite_inmemory_stream_data **ptr;
6279 if (!(ptr = heap_realloc(loader->streams, 2 * loader->capacity * sizeof(*loader->streams))))
6280 return E_OUTOFMEMORY;
6282 loader->streams = ptr;
6283 loader->capacity *= 2;
6285 else {
6286 loader->capacity = 16;
6287 loader->streams = heap_alloc(loader->capacity * sizeof(*loader->streams));
6291 if (!(stream = heap_alloc(sizeof(*stream))))
6292 return E_OUTOFMEMORY;
6294 stream->ref = 1;
6295 stream->size = data_size;
6296 stream->owner = owner;
6297 if (stream->owner) {
6298 IUnknown_AddRef(stream->owner);
6299 stream->data = (void *)data;
6301 else {
6302 if (!(stream->data = heap_alloc(data_size))) {
6303 heap_free(stream);
6304 return E_OUTOFMEMORY;
6306 memcpy(stream->data, data, data_size);
6309 key = loader->filecount;
6310 loader->streams[loader->filecount++] = stream;
6312 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6313 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6316 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6318 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6320 TRACE("(%p)\n", loader);
6322 return loader->filecount;
6325 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6327 inmemoryfontfileloader_QueryInterface,
6328 inmemoryfontfileloader_AddRef,
6329 inmemoryfontfileloader_Release,
6330 inmemoryfontfileloader_CreateStreamFromKey,
6331 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6332 inmemoryfontfileloader_GetFileCount,
6335 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6337 struct dwrite_inmemory_fileloader *loader;
6339 *ret = NULL;
6341 loader = heap_alloc_zero(sizeof(*loader));
6342 if (!loader)
6343 return E_OUTOFMEMORY;
6345 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6346 loader->ref = 1;
6348 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6350 return S_OK;