reg/tests: Test line concatenation with comments, new lines and comma variations...
[wine.git] / dlls / dwrite / font.c
blob0332587eb6278d42e0014afd846f9b1618d18d08
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 struct dwrite_font_propvec propvec;
81 DWRITE_FONT_METRICS1 metrics;
82 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
83 IDWriteLocalizedStrings *names;
85 /* data needed to create fontface instance */
86 DWRITE_FONT_FACE_TYPE face_type;
87 IDWriteFontFile *file;
88 UINT32 face_index;
90 WCHAR *facename;
92 USHORT simulations;
94 LOGFONTW lf;
96 /* used to mark font as tested when scanning for simulation candidate */
97 BOOL bold_sim_tested : 1;
98 BOOL oblique_sim_tested : 1;
101 struct dwrite_fontfamily_data {
102 LONG ref;
104 IDWriteLocalizedStrings *familyname;
106 struct dwrite_font_data **fonts;
107 UINT32 font_count;
108 UINT32 font_alloc;
109 BOOL has_normal_face : 1;
110 BOOL has_oblique_face : 1;
111 BOOL has_italic_face : 1;
114 struct dwrite_fontcollection {
115 IDWriteFontCollection1 IDWriteFontCollection1_iface;
116 LONG ref;
118 IDWriteFactory5 *factory;
119 struct dwrite_fontfamily_data **family_data;
120 UINT32 family_count;
121 UINT32 family_alloc;
124 struct dwrite_fontfamily {
125 IDWriteFontFamily1 IDWriteFontFamily1_iface;
126 LONG ref;
128 struct dwrite_fontfamily_data *data;
129 struct dwrite_fontcollection *collection;
132 struct dwrite_fontlist {
133 IDWriteFontList1 IDWriteFontList1_iface;
134 LONG ref;
136 struct dwrite_font_data **fonts;
137 UINT32 font_count;
138 struct dwrite_fontfamily *family;
141 struct dwrite_font {
142 IDWriteFont3 IDWriteFont3_iface;
143 LONG ref;
145 DWRITE_FONT_STYLE style;
146 struct dwrite_font_data *data;
147 struct dwrite_fontfamily *family;
150 struct dwrite_fonttable {
151 void *data;
152 void *context;
153 UINT32 size;
154 BOOL exists;
157 enum runanalysis_flags {
158 RUNANALYSIS_BOUNDS_READY = 1 << 0,
159 RUNANALYSIS_BITMAP_READY = 1 << 1,
160 RUNANALYSIS_USE_TRANSFORM = 1 << 2
163 struct dwrite_glyphrunanalysis {
164 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
165 LONG ref;
167 DWRITE_RENDERING_MODE1 rendering_mode;
168 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
169 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
170 DWRITE_MATRIX m;
171 UINT16 *glyphs;
172 D2D_POINT_2F *origins;
174 UINT8 flags;
175 RECT bounds;
176 BYTE *bitmap;
177 UINT32 max_glyph_bitmap_size;
180 struct dwrite_colorglyphenum {
181 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
182 LONG ref;
184 FLOAT origin_x; /* original run origin */
185 FLOAT origin_y;
187 IDWriteFontFace4 *fontface; /* for convenience */
188 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
189 DWRITE_GLYPH_RUN run; /* base run */
190 UINT32 palette; /* palette index to get layer color from */
191 FLOAT *advances; /* original or measured advances for base glyphs */
192 FLOAT *color_advances; /* returned color run points to this */
193 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
194 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
195 UINT16 *glyphindices; /* returned color run points to this */
196 struct dwrite_colorglyph *glyphs; /* current glyph color info */
197 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
198 UINT16 current_layer; /* enumerator position, updated with MoveNext */
199 UINT16 max_layer_num; /* max number of layers for this run */
200 struct dwrite_fonttable colr; /* used to access layers */
203 #define GLYPH_BLOCK_SHIFT 8
204 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
205 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
206 #define GLYPH_MAX 65536
208 enum fontface_flags {
209 FONTFACE_IS_SYMBOL = 1 << 0,
210 FONTFACE_IS_MONOSPACED = 1 << 1,
211 FONTFACE_HAS_KERNING_PAIRS = 1 << 2,
212 FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
215 struct dwrite_fontface {
216 IDWriteFontFace4 IDWriteFontFace4_iface;
217 LONG ref;
219 IDWriteFontFileStream **streams;
220 IDWriteFontFile **files;
221 UINT32 file_count;
222 UINT32 index;
224 IDWriteFactory5 *factory;
225 struct fontfacecached *cached;
227 USHORT simulations;
228 DWRITE_FONT_FACE_TYPE type;
229 DWRITE_FONT_METRICS1 metrics;
230 DWRITE_CARET_METRICS caret;
231 INT charmap;
232 UINT16 flags;
234 struct dwrite_fonttable cmap;
235 struct dwrite_fonttable vdmx;
236 struct dwrite_fonttable gasp;
237 struct dwrite_fonttable cpal;
238 struct dwrite_fonttable colr;
239 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
241 DWRITE_FONT_STYLE style;
242 DWRITE_FONT_STRETCH stretch;
243 DWRITE_FONT_WEIGHT weight;
244 DWRITE_PANOSE panose;
245 UINT32 glyph_image_formats;
247 LOGFONTW lf;
250 struct dwrite_fontfile {
251 IDWriteFontFile IDWriteFontFile_iface;
252 LONG ref;
254 IDWriteFontFileLoader *loader;
255 void *reference_key;
256 UINT32 key_size;
257 IDWriteFontFileStream *stream;
260 struct dwrite_fontfacereference {
261 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
262 LONG ref;
264 IDWriteFontFile *file;
265 UINT32 index;
266 USHORT simulations;
267 IDWriteFactory5 *factory;
270 static inline struct dwrite_fontface *impl_from_IDWriteFontFace4(IDWriteFontFace4 *iface)
272 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
275 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
277 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
280 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
282 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
285 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
287 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
290 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
292 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
295 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
297 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
300 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
302 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
305 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
307 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
310 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
312 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
315 static inline const char *debugstr_tag(UINT32 tag)
317 return debugstr_an((char*)&tag, 4);
320 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
322 static const DWRITE_GLYPH_METRICS nil;
323 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
325 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
326 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
327 return S_OK;
330 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
332 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
334 if (!*block) {
335 /* start new block */
336 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
337 if (!*block)
338 return E_OUTOFMEMORY;
341 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
342 return S_OK;
345 static void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table)
347 HRESULT hr;
349 if (table->data || !table->exists)
350 return table->data;
352 table->exists = FALSE;
353 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
354 &table->exists);
355 if (FAILED(hr) || !table->exists) {
356 WARN("Font does not have a %s table\n", debugstr_tag(tag));
357 return NULL;
360 return table->data;
363 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
364 struct dwrite_font_propvec *vec)
366 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
367 vec->style = style * 7.0f;
368 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
371 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
373 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
376 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
378 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
381 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
383 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CMAP_TAG, &fontface->cmap);
386 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
388 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx);
391 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
393 void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp);
394 *size = fontface->gasp.size;
395 return ptr;
398 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
400 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal);
403 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
405 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &fontface->colr);
408 static void addref_font_data(struct dwrite_font_data *data)
410 InterlockedIncrement(&data->ref);
413 static void release_font_data(struct dwrite_font_data *data)
415 int i;
417 if (InterlockedDecrement(&data->ref) > 0)
418 return;
420 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
421 if (data->info_strings[i])
422 IDWriteLocalizedStrings_Release(data->info_strings[i]);
424 if (data->names)
425 IDWriteLocalizedStrings_Release(data->names);
427 IDWriteFontFile_Release(data->file);
428 heap_free(data->facename);
429 heap_free(data);
432 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
434 int i;
436 if (InterlockedDecrement(&data->ref) > 0)
437 return;
439 for (i = 0; i < data->font_count; i++)
440 release_font_data(data->fonts[i]);
441 heap_free(data->fonts);
442 IDWriteLocalizedStrings_Release(data->familyname);
443 heap_free(data);
446 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace4 *iface, REFIID riid, void **obj)
448 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
450 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
452 if (IsEqualIID(riid, &IID_IDWriteFontFace4) ||
453 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
454 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
455 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
456 IsEqualIID(riid, &IID_IDWriteFontFace) ||
457 IsEqualIID(riid, &IID_IUnknown))
459 *obj = iface;
460 IDWriteFontFace4_AddRef(iface);
461 return S_OK;
464 *obj = NULL;
465 return E_NOINTERFACE;
468 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace4 *iface)
470 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
471 ULONG ref = InterlockedIncrement(&This->ref);
472 TRACE("(%p)->(%d)\n", This, ref);
473 return ref;
476 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
478 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
479 ULONG ref = InterlockedDecrement(&This->ref);
481 TRACE("(%p)->(%d)\n", This, ref);
483 if (!ref) {
484 UINT32 i;
486 if (This->cmap.context)
487 IDWriteFontFace4_ReleaseFontTable(iface, This->cmap.context);
488 if (This->vdmx.context)
489 IDWriteFontFace4_ReleaseFontTable(iface, This->vdmx.context);
490 if (This->gasp.context)
491 IDWriteFontFace4_ReleaseFontTable(iface, This->gasp.context);
492 if (This->cpal.context)
493 IDWriteFontFace4_ReleaseFontTable(iface, This->cpal.context);
494 if (This->colr.context)
495 IDWriteFontFace4_ReleaseFontTable(iface, This->colr.context);
496 for (i = 0; i < This->file_count; i++) {
497 if (This->streams[i])
498 IDWriteFontFileStream_Release(This->streams[i]);
499 if (This->files[i])
500 IDWriteFontFile_Release(This->files[i]);
502 heap_free(This->streams);
503 heap_free(This->files);
505 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
506 heap_free(This->glyphs[i]);
508 freetype_notify_cacheremove(iface);
509 if (This->cached)
510 factory_release_cached_fontface(This->cached);
511 if (This->factory)
512 IDWriteFactory5_Release(This->factory);
513 heap_free(This);
516 return ref;
519 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace4 *iface)
521 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
522 TRACE("(%p)\n", This);
523 return This->type;
526 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace4 *iface, UINT32 *number_of_files,
527 IDWriteFontFile **fontfiles)
529 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
530 int i;
532 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
533 if (fontfiles == NULL)
535 *number_of_files = This->file_count;
536 return S_OK;
538 if (*number_of_files < This->file_count)
539 return E_INVALIDARG;
541 for (i = 0; i < This->file_count; i++)
543 IDWriteFontFile_AddRef(This->files[i]);
544 fontfiles[i] = This->files[i];
547 return S_OK;
550 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace4 *iface)
552 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
553 TRACE("(%p)\n", This);
554 return This->index;
557 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace4 *iface)
559 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
560 TRACE("(%p)\n", This);
561 return This->simulations;
564 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace4 *iface)
566 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
567 TRACE("(%p)\n", This);
568 return !!(This->flags & FONTFACE_IS_SYMBOL);
571 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS *metrics)
573 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
574 TRACE("(%p)->(%p)\n", This, metrics);
575 memcpy(metrics, &This->metrics, sizeof(*metrics));
578 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface)
580 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
581 TRACE("(%p)\n", This);
582 return freetype_get_glyphcount(iface);
585 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface,
586 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
588 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
589 HRESULT hr;
590 UINT32 i;
592 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
594 if (!glyphs)
595 return E_INVALIDARG;
597 if (is_sideways)
598 FIXME("sideways metrics are not supported.\n");
600 for (i = 0; i < glyph_count; i++) {
601 DWRITE_GLYPH_METRICS metrics;
603 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
604 if (hr != S_OK) {
605 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
606 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
607 if (FAILED(hr))
608 return hr;
610 ret[i] = metrics;
613 return S_OK;
616 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
617 UINT32 count, UINT16 *glyphs)
619 if (!glyphs)
620 return E_INVALIDARG;
622 if (!codepoints) {
623 memset(glyphs, 0, count * sizeof(*glyphs));
624 return E_INVALIDARG;
627 freetype_get_glyphs(&fontface->IDWriteFontFace4_iface, fontface->charmap, codepoints, count, glyphs);
628 return S_OK;
631 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace4 *iface, UINT32 const *codepoints,
632 UINT32 count, UINT16 *glyphs)
634 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
636 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyphs);
638 return fontface_get_glyphs(This, codepoints, count, glyphs);
641 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace4 *iface, UINT32 table_tag,
642 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
644 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
645 struct file_stream_desc stream_desc;
647 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
649 stream_desc.stream = This->streams[0];
650 stream_desc.face_type = This->type;
651 stream_desc.face_index = This->index;
652 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
655 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace4 *iface, void *table_context)
657 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
659 TRACE("(%p)->(%p)\n", This, table_context);
661 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
664 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, FLOAT emSize,
665 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
666 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
668 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
670 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
671 count, is_sideways, is_rtl, sink);
673 if (!glyphs || !sink)
674 return E_INVALIDARG;
676 if (is_sideways)
677 FIXME("sideways mode is not supported.\n");
679 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
682 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
683 FLOAT ppem, WORD gasp)
685 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
687 switch (measuring)
689 case DWRITE_MEASURING_MODE_NATURAL:
691 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
692 mode = DWRITE_RENDERING_MODE_NATURAL;
693 else
694 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
695 break;
697 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
698 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
699 break;
700 case DWRITE_MEASURING_MODE_GDI_NATURAL:
701 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
702 break;
703 default:
707 return mode;
710 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
711 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
713 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
714 WORD gasp, *ptr;
715 UINT32 size;
716 FLOAT ppem;
718 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
720 if (!params) {
721 *mode = DWRITE_RENDERING_MODE_DEFAULT;
722 return E_INVALIDARG;
725 *mode = IDWriteRenderingParams_GetRenderingMode(params);
726 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
727 return S_OK;
729 ppem = emSize * ppdip;
731 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
732 *mode = DWRITE_RENDERING_MODE_OUTLINE;
733 return S_OK;
736 ptr = get_fontface_gasp(This, &size);
737 gasp = opentype_get_gasp_flags(ptr, size, ppem);
738 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
739 return S_OK;
742 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT pixels_per_dip,
743 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
745 DWRITE_FONT_METRICS1 metrics1;
746 HRESULT hr = IDWriteFontFace4_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
747 memcpy(metrics, &metrics1, sizeof(*metrics));
748 return hr;
751 static inline int round_metric(FLOAT metric)
753 return (int)floorf(metric + 0.5f);
756 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
758 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
759 return 0;
761 return (fontface->metrics.designUnitsPerEm + 49) / 50;
764 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip,
765 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
766 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
768 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
769 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
770 DWRITE_MEASURING_MODE mode;
771 FLOAT scale, size;
772 HRESULT hr;
773 UINT32 i;
775 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
776 glyph_count, metrics, is_sideways);
778 if (m && memcmp(m, &identity, sizeof(*m)))
779 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
781 size = emSize * ppdip;
782 scale = size / This->metrics.designUnitsPerEm;
783 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
785 for (i = 0; i < glyph_count; i++) {
786 DWRITE_GLYPH_METRICS *ret = metrics + i;
787 DWRITE_GLYPH_METRICS design;
788 BOOL has_contours;
790 hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
791 if (FAILED(hr))
792 return hr;
794 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
795 if (has_contours)
796 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment);
797 else
798 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
800 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
801 SCALE_METRIC(leftSideBearing);
802 SCALE_METRIC(rightSideBearing);
803 SCALE_METRIC(topSideBearing);
804 SCALE_METRIC(advanceHeight);
805 SCALE_METRIC(bottomSideBearing);
806 SCALE_METRIC(verticalOriginY);
807 #undef SCALE_METRIC
810 return S_OK;
813 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS1 *metrics)
815 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
816 TRACE("(%p)->(%p)\n", This, metrics);
817 *metrics = This->metrics;
820 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT em_size, FLOAT pixels_per_dip,
821 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
823 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
824 const DWRITE_FONT_METRICS1 *design = &This->metrics;
825 UINT16 ascent, descent;
826 FLOAT scale;
828 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
830 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
831 memset(metrics, 0, sizeof(*metrics));
832 return E_INVALIDARG;
835 em_size *= pixels_per_dip;
836 if (m && m->m22 != 0.0f)
837 em_size *= fabs(m->m22);
839 scale = em_size / design->designUnitsPerEm;
840 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
841 ascent = round_metric(design->ascent * scale);
842 descent = round_metric(design->descent * scale);
845 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
846 metrics->designUnitsPerEm = design->designUnitsPerEm;
847 metrics->ascent = round_metric(ascent / scale);
848 metrics->descent = round_metric(descent / scale);
850 SCALE_METRIC(lineGap);
851 SCALE_METRIC(capHeight);
852 SCALE_METRIC(xHeight);
853 SCALE_METRIC(underlinePosition);
854 SCALE_METRIC(underlineThickness);
855 SCALE_METRIC(strikethroughPosition);
856 SCALE_METRIC(strikethroughThickness);
857 SCALE_METRIC(glyphBoxLeft);
858 SCALE_METRIC(glyphBoxTop);
859 SCALE_METRIC(glyphBoxRight);
860 SCALE_METRIC(glyphBoxBottom);
861 SCALE_METRIC(subscriptPositionX);
862 SCALE_METRIC(subscriptPositionY);
863 SCALE_METRIC(subscriptSizeX);
864 SCALE_METRIC(subscriptSizeY);
865 SCALE_METRIC(superscriptPositionX);
866 SCALE_METRIC(superscriptPositionY);
867 SCALE_METRIC(superscriptSizeX);
868 SCALE_METRIC(superscriptSizeY);
870 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
871 #undef SCALE_METRIC
873 return S_OK;
876 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace4 *iface, DWRITE_CARET_METRICS *metrics)
878 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
879 TRACE("(%p)->(%p)\n", This, metrics);
880 *metrics = This->caret;
883 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, UINT32 max_count,
884 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
886 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
888 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
890 *count = 0;
891 if (max_count && !ranges)
892 return E_INVALIDARG;
894 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
897 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface)
899 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
900 TRACE("(%p)\n", This);
901 return !!(This->flags & FONTFACE_IS_MONOSPACED);
904 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *iface,
905 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
907 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
908 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
909 UINT32 i;
911 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
913 if (is_sideways)
914 FIXME("sideways mode not supported\n");
916 for (i = 0; i < glyph_count; i++) {
917 BOOL has_contours;
919 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i],
920 DWRITE_MEASURING_MODE_NATURAL, &has_contours);
921 if (has_contours)
922 advances[i] += adjustment;
925 return S_OK;
928 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4 *iface,
929 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
930 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
932 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
933 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
934 DWRITE_MEASURING_MODE mode;
935 UINT32 i;
937 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
938 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
940 if (em_size < 0.0f || ppdip <= 0.0f) {
941 memset(advances, 0, sizeof(*advances) * glyph_count);
942 return E_INVALIDARG;
945 em_size *= ppdip;
946 if (em_size == 0.0f) {
947 memset(advances, 0, sizeof(*advances) * glyph_count);
948 return S_OK;
951 if (m && memcmp(m, &identity, sizeof(*m)))
952 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
954 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
955 for (i = 0; i < glyph_count; i++) {
956 BOOL has_contours;
958 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode, &has_contours);
959 if (has_contours)
960 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size + adjustment);
961 else
962 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
965 return S_OK;
968 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace4 *iface, UINT32 count,
969 const UINT16 *indices, INT32 *adjustments)
971 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
972 UINT32 i;
974 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
976 if (!(indices || adjustments) || !count)
977 return E_INVALIDARG;
979 if (!indices || count == 1) {
980 memset(adjustments, 0, count*sizeof(INT32));
981 return E_INVALIDARG;
984 if (!(This->flags & FONTFACE_HAS_KERNING_PAIRS)) {
985 memset(adjustments, 0, count*sizeof(INT32));
986 return S_OK;
989 for (i = 0; i < count-1; i++)
990 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
991 adjustments[count-1] = 0;
993 return S_OK;
996 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace4 *iface)
998 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
999 TRACE("(%p)\n", This);
1000 return !!(This->flags & FONTFACE_HAS_KERNING_PAIRS);
1003 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace4 *iface,
1004 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1005 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1007 DWRITE_GRID_FIT_MODE gridfitmode;
1008 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1009 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1012 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace4 *iface, UINT32 glyph_count,
1013 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1015 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1016 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1017 return E_NOTIMPL;
1020 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace4 *iface)
1022 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1023 TRACE("(%p)\n", This);
1024 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1027 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace4 *iface)
1029 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1030 TRACE("(%p)\n", This);
1031 return get_fontface_cpal(This) && get_fontface_colr(This);
1034 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace4 *iface)
1036 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1037 TRACE("(%p)\n", This);
1038 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1041 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace4 *iface)
1043 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1044 TRACE("(%p)\n", This);
1045 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1048 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace4 *iface, UINT32 palette_index,
1049 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1051 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1052 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1053 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1056 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
1057 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1058 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1059 DWRITE_GRID_FIT_MODE *gridfitmode)
1061 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1062 FLOAT emthreshold;
1063 WORD gasp, *ptr;
1064 UINT32 size;
1066 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1067 measuringmode, params, renderingmode, gridfitmode);
1069 if (m)
1070 FIXME("transform not supported %s\n", debugstr_matrix(m));
1072 if (is_sideways)
1073 FIXME("sideways mode not supported\n");
1075 emSize *= max(dpiX, dpiY) / 96.0f;
1077 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1078 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1079 if (params) {
1080 IDWriteRenderingParams2 *params2;
1081 HRESULT hr;
1083 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1084 if (hr == S_OK) {
1085 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1086 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1087 IDWriteRenderingParams2_Release(params2);
1089 else
1090 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1093 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1095 ptr = get_fontface_gasp(This, &size);
1096 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1098 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1099 if (emSize >= emthreshold)
1100 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1101 else
1102 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1105 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1106 if (emSize >= emthreshold)
1107 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1108 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1109 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1110 else
1111 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1114 return S_OK;
1117 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace4 *iface, IDWriteFontFaceReference **ref)
1119 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1120 FIXME("(%p)->(%p): stub\n", This, ref);
1121 return E_NOTIMPL;
1124 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace4 *iface, DWRITE_PANOSE *panose)
1126 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1127 TRACE("(%p)->(%p)\n", This, panose);
1128 *panose = This->panose;
1131 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace4 *iface)
1133 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1134 TRACE("(%p)\n", This);
1135 return This->weight;
1138 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace4 *iface)
1140 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1141 TRACE("(%p)\n", This);
1142 return This->stretch;
1145 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace4 *iface)
1147 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1148 TRACE("(%p)\n", This);
1149 return This->style;
1152 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1154 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1155 FIXME("(%p)->(%p): stub\n", This, names);
1156 return E_NOTIMPL;
1159 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1161 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1162 FIXME("(%p)->(%p): stub\n", This, names);
1163 return E_NOTIMPL;
1166 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace4 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1167 IDWriteLocalizedStrings **strings, BOOL *exists)
1169 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1170 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1171 return E_NOTIMPL;
1174 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace4 *iface, UINT32 ch)
1176 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1177 UINT16 index;
1179 TRACE("(%p)->(0x%08x)\n", This, ch);
1181 index = 0;
1182 if (FAILED(fontface_get_glyphs(This, &ch, 1, &index)))
1183 return FALSE;
1185 return index != 0;
1188 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1189 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1190 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1192 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1193 FLOAT emthreshold;
1194 WORD gasp, *ptr;
1195 UINT32 size;
1197 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1198 measuring_mode, params, rendering_mode, gridfit_mode);
1200 if (m)
1201 FIXME("transform not supported %s\n", debugstr_matrix(m));
1203 if (is_sideways)
1204 FIXME("sideways mode not supported\n");
1206 emSize *= max(dpiX, dpiY) / 96.0f;
1208 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1209 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1210 if (params) {
1211 IDWriteRenderingParams3 *params3;
1212 HRESULT hr;
1214 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1215 if (hr == S_OK) {
1216 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1217 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1218 IDWriteRenderingParams3_Release(params3);
1220 else
1221 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1224 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1226 ptr = get_fontface_gasp(This, &size);
1227 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1229 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1230 if (emSize >= emthreshold)
1231 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1232 else
1233 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp);
1236 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1237 if (emSize >= emthreshold)
1238 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1239 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1240 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1241 else
1242 *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1245 return S_OK;
1248 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace4 *iface, UINT32 ch)
1250 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1251 FIXME("(%p)->(0x%x): stub\n", This, ch);
1252 return FALSE;
1255 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace4 *iface, UINT16 glyph)
1257 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1258 FIXME("(%p)->(%u): stub\n", This, glyph);
1259 return FALSE;
1262 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace4 *iface, WCHAR const *text,
1263 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1265 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1266 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1267 return E_NOTIMPL;
1270 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace4 *iface, UINT16 const *glyphs,
1271 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1273 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1274 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1275 return E_NOTIMPL;
1278 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace4 *iface, UINT16 glyph,
1279 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1281 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1282 FIXME("(%p)->(%u %u %u %p): stub\n", This, glyph, ppem_first, ppem_last, formats);
1283 return E_NOTIMPL;
1286 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace4 *iface)
1288 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1290 TRACE("(%p)\n", This);
1292 return This->glyph_image_formats;
1295 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace4 *iface, UINT16 glyph,
1296 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1298 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1299 FIXME("(%p)->(%u %u %d %p %p): stub\n", This, glyph, ppem, format, data, context);
1300 return E_NOTIMPL;
1303 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace4 *iface, void *context)
1305 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1306 FIXME("(%p)->(%p): stub\n", This, context);
1309 static const IDWriteFontFace4Vtbl dwritefontfacevtbl = {
1310 dwritefontface_QueryInterface,
1311 dwritefontface_AddRef,
1312 dwritefontface_Release,
1313 dwritefontface_GetType,
1314 dwritefontface_GetFiles,
1315 dwritefontface_GetIndex,
1316 dwritefontface_GetSimulations,
1317 dwritefontface_IsSymbolFont,
1318 dwritefontface_GetMetrics,
1319 dwritefontface_GetGlyphCount,
1320 dwritefontface_GetDesignGlyphMetrics,
1321 dwritefontface_GetGlyphIndices,
1322 dwritefontface_TryGetFontTable,
1323 dwritefontface_ReleaseFontTable,
1324 dwritefontface_GetGlyphRunOutline,
1325 dwritefontface_GetRecommendedRenderingMode,
1326 dwritefontface_GetGdiCompatibleMetrics,
1327 dwritefontface_GetGdiCompatibleGlyphMetrics,
1328 dwritefontface1_GetMetrics,
1329 dwritefontface1_GetGdiCompatibleMetrics,
1330 dwritefontface1_GetCaretMetrics,
1331 dwritefontface1_GetUnicodeRanges,
1332 dwritefontface1_IsMonospacedFont,
1333 dwritefontface1_GetDesignGlyphAdvances,
1334 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1335 dwritefontface1_GetKerningPairAdjustments,
1336 dwritefontface1_HasKerningPairs,
1337 dwritefontface1_GetRecommendedRenderingMode,
1338 dwritefontface1_GetVerticalGlyphVariants,
1339 dwritefontface1_HasVerticalGlyphVariants,
1340 dwritefontface2_IsColorFont,
1341 dwritefontface2_GetColorPaletteCount,
1342 dwritefontface2_GetPaletteEntryCount,
1343 dwritefontface2_GetPaletteEntries,
1344 dwritefontface2_GetRecommendedRenderingMode,
1345 dwritefontface3_GetFontFaceReference,
1346 dwritefontface3_GetPanose,
1347 dwritefontface3_GetWeight,
1348 dwritefontface3_GetStretch,
1349 dwritefontface3_GetStyle,
1350 dwritefontface3_GetFamilyNames,
1351 dwritefontface3_GetFaceNames,
1352 dwritefontface3_GetInformationalStrings,
1353 dwritefontface3_HasCharacter,
1354 dwritefontface3_GetRecommendedRenderingMode,
1355 dwritefontface3_IsCharacterLocal,
1356 dwritefontface3_IsGlyphLocal,
1357 dwritefontface3_AreCharactersLocal,
1358 dwritefontface3_AreGlyphsLocal,
1359 dwritefontface4_GetGlyphImageFormats_,
1360 dwritefontface4_GetGlyphImageFormats,
1361 dwritefontface4_GetGlyphImageData,
1362 dwritefontface4_ReleaseGlyphImageData
1365 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace4 **fontface)
1367 struct dwrite_font_data *data = font->data;
1368 struct fontface_desc desc;
1369 struct list *cached_list;
1370 HRESULT hr;
1372 *fontface = NULL;
1374 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1375 font->data->simulations, (IDWriteFontFace **)fontface, &cached_list);
1376 if (hr == S_OK) {
1377 IDWriteFontFace4_AddRef(*fontface);
1378 return hr;
1381 desc.factory = font->family->collection->factory;
1382 desc.face_type = data->face_type;
1383 desc.files = &data->file;
1384 desc.files_number = 1;
1385 desc.index = data->face_index;
1386 desc.simulations = data->simulations;
1387 desc.font_data = data;
1388 return create_fontface(&desc, cached_list, fontface);
1391 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1393 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1395 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1397 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1398 IsEqualIID(riid, &IID_IDWriteFont2) ||
1399 IsEqualIID(riid, &IID_IDWriteFont1) ||
1400 IsEqualIID(riid, &IID_IDWriteFont) ||
1401 IsEqualIID(riid, &IID_IUnknown))
1403 *obj = iface;
1404 IDWriteFont3_AddRef(iface);
1405 return S_OK;
1408 *obj = NULL;
1409 return E_NOINTERFACE;
1412 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1414 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1415 ULONG ref = InterlockedIncrement(&This->ref);
1416 TRACE("(%p)->(%d)\n", This, ref);
1417 return ref;
1420 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1422 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1423 ULONG ref = InterlockedDecrement(&This->ref);
1425 TRACE("(%p)->(%d)\n", This, ref);
1427 if (!ref) {
1428 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1429 release_font_data(This->data);
1430 heap_free(This);
1433 return ref;
1436 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1438 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1439 TRACE("(%p)->(%p)\n", This, family);
1441 *family = (IDWriteFontFamily*)This->family;
1442 IDWriteFontFamily_AddRef(*family);
1443 return S_OK;
1446 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1448 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1449 TRACE("(%p)\n", This);
1450 return This->data->weight;
1453 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1455 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1456 TRACE("(%p)\n", This);
1457 return This->data->stretch;
1460 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1462 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1463 TRACE("(%p)\n", This);
1464 return This->style;
1467 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1469 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1470 IDWriteFontFace4 *fontface;
1471 HRESULT hr;
1472 BOOL ret;
1474 TRACE("(%p)\n", This);
1476 hr = get_fontface_from_font(This, &fontface);
1477 if (FAILED(hr))
1478 return FALSE;
1480 ret = IDWriteFontFace4_IsSymbolFont(fontface);
1481 IDWriteFontFace4_Release(fontface);
1482 return ret;
1485 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1487 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1488 TRACE("(%p)->(%p)\n", This, names);
1489 return clone_localizedstring(This->data->names, names);
1492 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1493 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1495 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1496 struct dwrite_font_data *data = This->data;
1497 HRESULT hr;
1499 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1501 *exists = FALSE;
1502 *strings = NULL;
1504 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1505 return S_OK;
1507 if (!data->info_strings[stringid]) {
1508 IDWriteFontFace4 *fontface;
1509 const void *table_data;
1510 BOOL table_exists;
1511 void *context;
1512 UINT32 size;
1514 hr = get_fontface_from_font(This, &fontface);
1515 if (FAILED(hr))
1516 return hr;
1518 table_exists = FALSE;
1519 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1520 if (FAILED(hr) || !table_exists)
1521 WARN("no NAME table found.\n");
1523 if (table_exists) {
1524 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1525 IDWriteFontFace4_ReleaseFontTable(fontface, context);
1526 if (FAILED(hr) || !data->info_strings[stringid])
1527 return hr;
1529 IDWriteFontFace4_Release(fontface);
1532 hr = clone_localizedstring(data->info_strings[stringid], strings);
1533 if (FAILED(hr))
1534 return hr;
1536 *exists = TRUE;
1537 return S_OK;
1540 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1542 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1543 TRACE("(%p)\n", This);
1544 return This->data->simulations;
1547 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1549 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1551 TRACE("(%p)->(%p)\n", This, metrics);
1552 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1555 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1557 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1558 IDWriteFontFace4 *fontface;
1559 UINT16 index;
1560 HRESULT hr;
1562 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1564 *exists = FALSE;
1566 hr = get_fontface_from_font(This, &fontface);
1567 if (FAILED(hr))
1568 return hr;
1570 index = 0;
1571 hr = IDWriteFontFace4_GetGlyphIndices(fontface, &value, 1, &index);
1572 if (FAILED(hr))
1573 return hr;
1574 IDWriteFontFace4_Release(fontface);
1576 *exists = index != 0;
1577 return S_OK;
1580 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1582 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1583 TRACE("(%p)->(%p)\n", This, fontface);
1584 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1587 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1589 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1590 TRACE("(%p)->(%p)\n", This, metrics);
1591 *metrics = This->data->metrics;
1594 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1596 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1597 TRACE("(%p)->(%p)\n", This, panose);
1598 *panose = This->data->panose;
1601 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1603 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1604 IDWriteFontFace4 *fontface;
1605 HRESULT hr;
1607 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1609 hr = get_fontface_from_font(This, &fontface);
1610 if (FAILED(hr))
1611 return hr;
1613 hr = IDWriteFontFace4_GetUnicodeRanges(fontface, max_count, ranges, count);
1614 IDWriteFontFace4_Release(fontface);
1615 return hr;
1618 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1620 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1621 IDWriteFontFace4 *fontface;
1622 HRESULT hr;
1623 BOOL ret;
1625 TRACE("(%p)\n", This);
1627 hr = get_fontface_from_font(This, &fontface);
1628 if (FAILED(hr))
1629 return FALSE;
1631 ret = IDWriteFontFace4_IsMonospacedFont(fontface);
1632 IDWriteFontFace4_Release(fontface);
1633 return ret;
1636 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1638 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1639 IDWriteFontFace4 *fontface;
1640 HRESULT hr;
1641 BOOL ret;
1643 TRACE("(%p)\n", This);
1645 hr = get_fontface_from_font(This, &fontface);
1646 if (FAILED(hr))
1647 return FALSE;
1649 ret = IDWriteFontFace4_IsColorFont(fontface);
1650 IDWriteFontFace4_Release(fontface);
1651 return ret;
1654 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1656 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1658 TRACE("(%p)->(%p)\n", This, fontface);
1660 return get_fontface_from_font(This, (IDWriteFontFace4 **)fontface);
1663 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1665 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1666 FIXME("(%p)->(%p): stub\n", This, font);
1667 return FALSE;
1670 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1672 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1674 TRACE("(%p)->(%p)\n", This, reference);
1676 return IDWriteFactory5_CreateFontFaceReference_(This->family->collection->factory, This->data->file,
1677 This->data->face_index, This->data->simulations, reference);
1680 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1682 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1683 HRESULT hr;
1684 BOOL ret;
1686 TRACE("(%p)->(0x%x)\n", This, ch);
1688 hr = IDWriteFont_HasCharacter((IDWriteFont*)iface, ch, &ret);
1689 return hr == S_OK && ret;
1692 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1694 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1695 FIXME("(%p): stub\n", This);
1696 return DWRITE_LOCALITY_LOCAL;
1699 static const IDWriteFont3Vtbl dwritefontvtbl = {
1700 dwritefont_QueryInterface,
1701 dwritefont_AddRef,
1702 dwritefont_Release,
1703 dwritefont_GetFontFamily,
1704 dwritefont_GetWeight,
1705 dwritefont_GetStretch,
1706 dwritefont_GetStyle,
1707 dwritefont_IsSymbolFont,
1708 dwritefont_GetFaceNames,
1709 dwritefont_GetInformationalStrings,
1710 dwritefont_GetSimulations,
1711 dwritefont_GetMetrics,
1712 dwritefont_HasCharacter,
1713 dwritefont_CreateFontFace,
1714 dwritefont1_GetMetrics,
1715 dwritefont1_GetPanose,
1716 dwritefont1_GetUnicodeRanges,
1717 dwritefont1_IsMonospacedFont,
1718 dwritefont2_IsColorFont,
1719 dwritefont3_CreateFontFace,
1720 dwritefont3_Equals,
1721 dwritefont3_GetFontFaceReference,
1722 dwritefont3_HasCharacter,
1723 dwritefont3_GetLocality
1726 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1728 if (!iface)
1729 return NULL;
1730 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1731 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1734 static struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1736 if (!iface)
1737 return NULL;
1738 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1739 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
1742 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1744 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1745 *lf = font->data->lf;
1748 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1750 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1751 *lf = fontface->lf;
1754 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1756 struct dwrite_font *This;
1758 *font = NULL;
1760 This = heap_alloc(sizeof(*This));
1761 if (!This)
1762 return E_OUTOFMEMORY;
1764 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1765 This->ref = 1;
1766 This->family = family;
1767 IDWriteFontFamily1_AddRef(&family->IDWriteFontFamily1_iface);
1768 This->data = family->data->fonts[index];
1769 This->style = This->data->style;
1770 addref_font_data(This->data);
1772 *font = &This->IDWriteFont3_iface;
1774 return S_OK;
1777 /* IDWriteFontList1 */
1778 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1780 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1782 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1784 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1785 IsEqualIID(riid, &IID_IDWriteFontList) ||
1786 IsEqualIID(riid, &IID_IUnknown))
1788 *obj = iface;
1789 IDWriteFontList1_AddRef(iface);
1790 return S_OK;
1793 *obj = NULL;
1794 return E_NOINTERFACE;
1797 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1799 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1800 ULONG ref = InterlockedIncrement(&This->ref);
1801 TRACE("(%p)->(%d)\n", This, ref);
1802 return ref;
1805 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1807 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1808 ULONG ref = InterlockedDecrement(&This->ref);
1810 TRACE("(%p)->(%d)\n", This, ref);
1812 if (!ref) {
1813 UINT32 i;
1815 for (i = 0; i < This->font_count; i++)
1816 release_font_data(This->fonts[i]);
1817 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1818 heap_free(This->fonts);
1819 heap_free(This);
1822 return ref;
1825 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1827 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1828 return IDWriteFontFamily1_GetFontCollection(&This->family->IDWriteFontFamily1_iface, collection);
1831 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1833 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1834 TRACE("(%p)\n", This);
1835 return This->font_count;
1838 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1840 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1842 TRACE("(%p)->(%u %p)\n", This, index, font);
1844 *font = NULL;
1846 if (This->font_count == 0)
1847 return S_FALSE;
1849 if (index >= This->font_count)
1850 return E_INVALIDARG;
1852 return create_font(This->family, index, (IDWriteFont3 **)font);
1855 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1857 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1859 FIXME("(%p)->(%u): stub\n", This, index);
1861 return DWRITE_LOCALITY_LOCAL;
1864 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1866 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1868 TRACE("(%p)->(%u %p)\n", This, index, font);
1870 *font = NULL;
1872 if (This->font_count == 0)
1873 return S_FALSE;
1875 if (index >= This->font_count)
1876 return E_FAIL;
1878 return create_font(This->family, index, font);
1881 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1882 IDWriteFontFaceReference **reference)
1884 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1885 IDWriteFont3 *font;
1886 HRESULT hr;
1888 TRACE("(%p)->(%u %p)\n", This, index, reference);
1890 *reference = NULL;
1892 hr = IDWriteFontList1_GetFont(iface, index, &font);
1893 if (FAILED(hr))
1894 return hr;
1896 hr = IDWriteFont3_GetFontFaceReference(font, reference);
1897 IDWriteFont3_Release(font);
1899 return hr;
1902 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1903 dwritefontlist_QueryInterface,
1904 dwritefontlist_AddRef,
1905 dwritefontlist_Release,
1906 dwritefontlist_GetFontCollection,
1907 dwritefontlist_GetFontCount,
1908 dwritefontlist_GetFont,
1909 dwritefontlist1_GetFontLocality,
1910 dwritefontlist1_GetFont,
1911 dwritefontlist1_GetFontFaceReference
1914 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1916 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1918 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1920 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1921 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1922 IsEqualIID(riid, &IID_IDWriteFontList) ||
1923 IsEqualIID(riid, &IID_IUnknown))
1925 *obj = iface;
1926 IDWriteFontFamily1_AddRef(iface);
1927 return S_OK;
1930 *obj = NULL;
1931 return E_NOINTERFACE;
1934 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1936 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1937 ULONG ref = InterlockedIncrement(&This->ref);
1938 TRACE("(%p)->(%d)\n", This, ref);
1939 return ref;
1942 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1944 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1945 ULONG ref = InterlockedDecrement(&This->ref);
1947 TRACE("(%p)->(%d)\n", This, ref);
1949 if (!ref)
1951 IDWriteFontCollection1_Release(&This->collection->IDWriteFontCollection1_iface);
1952 release_fontfamily_data(This->data);
1953 heap_free(This);
1956 return ref;
1959 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1961 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1963 TRACE("(%p)->(%p)\n", This, collection);
1965 *collection = (IDWriteFontCollection*)This->collection;
1966 IDWriteFontCollection_AddRef(*collection);
1967 return S_OK;
1970 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1972 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1973 TRACE("(%p)\n", This);
1974 return This->data->font_count;
1977 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1979 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1981 TRACE("(%p)->(%u %p)\n", This, index, font);
1983 *font = NULL;
1985 if (This->data->font_count == 0)
1986 return S_FALSE;
1988 if (index >= This->data->font_count)
1989 return E_INVALIDARG;
1991 return create_font(This, index, (IDWriteFont3 **)font);
1994 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1996 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1997 return clone_localizedstring(This->data->familyname, names);
2000 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2001 const struct dwrite_font_propvec *req)
2003 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2004 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2005 FLOAT cur_req_prod, next_req_prod;
2007 if (next_to_req < cur_to_req)
2008 return TRUE;
2010 if (next_to_req > cur_to_req)
2011 return FALSE;
2013 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2014 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2016 if (next_req_prod > cur_req_prod)
2017 return TRUE;
2019 if (next_req_prod < cur_req_prod)
2020 return FALSE;
2022 if (next->stretch > cur->stretch)
2023 return TRUE;
2024 if (next->stretch < cur->stretch)
2025 return FALSE;
2027 if (next->style > cur->style)
2028 return TRUE;
2029 if (next->style < cur->style)
2030 return FALSE;
2032 if (next->weight > cur->weight)
2033 return TRUE;
2034 if (next->weight < cur->weight)
2035 return FALSE;
2037 /* full match, no reason to prefer new variant */
2038 return FALSE;
2041 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2042 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2044 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2045 struct dwrite_font_propvec req;
2046 UINT32 i, match;
2048 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
2050 if (This->data->font_count == 0) {
2051 *font = NULL;
2052 return DWRITE_E_NOFONT;
2055 init_font_prop_vec(weight, stretch, style, &req);
2056 match = 0;
2058 for (i = 1; i < This->data->font_count; i++) {
2059 if (is_better_font_match(&This->data->fonts[i]->propvec, &This->data->fonts[match]->propvec, &req))
2060 match = i;
2063 return create_font(This, match, (IDWriteFont3 **)font);
2066 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2068 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2070 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2073 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2075 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2078 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2080 UINT32 b = fonts->font_count - 1, j, t;
2082 while (1) {
2083 t = b;
2085 for (j = 0; j < b; j++) {
2086 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2087 struct dwrite_font_data *s = fonts->fonts[j];
2088 fonts->fonts[j] = fonts->fonts[j+1];
2089 fonts->fonts[j+1] = s;
2090 t = j;
2094 if (t == b)
2095 break;
2096 b = t;
2100 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2101 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2103 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2104 matching_filter_func func = NULL;
2105 struct dwrite_font_propvec req;
2106 struct dwrite_fontlist *fonts;
2107 UINT32 i;
2109 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
2111 *ret = NULL;
2113 fonts = heap_alloc(sizeof(*fonts));
2114 if (!fonts)
2115 return E_OUTOFMEMORY;
2117 /* Allocate as many as family has, not all of them will be necessary used. */
2118 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
2119 if (!fonts->fonts) {
2120 heap_free(fonts);
2121 return E_OUTOFMEMORY;
2124 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2125 fonts->ref = 1;
2126 fonts->family = This;
2127 IDWriteFontFamily1_AddRef(&fonts->family->IDWriteFontFamily1_iface);
2128 fonts->font_count = 0;
2130 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2131 if (style == DWRITE_FONT_STYLE_NORMAL) {
2132 if (This->data->has_normal_face || This->data->has_italic_face)
2133 func = is_font_acceptable_for_normal;
2135 else /* requested oblique or italic */ {
2136 if (This->data->has_oblique_face || This->data->has_italic_face)
2137 func = is_font_acceptable_for_oblique_italic;
2140 for (i = 0; i < This->data->font_count; i++) {
2141 if (!func || func(This->data->fonts[i])) {
2142 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2143 addref_font_data(This->data->fonts[i]);
2144 fonts->font_count++;
2148 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2149 init_font_prop_vec(weight, stretch, style, &req);
2150 matchingfonts_sort(fonts, &req);
2152 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2153 return S_OK;
2156 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2158 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2160 FIXME("(%p)->(%u): stub\n", This, index);
2162 return DWRITE_LOCALITY_LOCAL;
2165 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2167 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2169 TRACE("(%p)->(%u %p)\n", This, index, font);
2171 *font = NULL;
2173 if (This->data->font_count == 0)
2174 return S_FALSE;
2176 if (index >= This->data->font_count)
2177 return E_FAIL;
2179 return create_font(This, index, font);
2182 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2183 IDWriteFontFaceReference **reference)
2185 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2186 IDWriteFont3 *font;
2187 HRESULT hr;
2189 TRACE("(%p)->(%u %p)\n", This, index, reference);
2191 *reference = NULL;
2193 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2194 if (FAILED(hr))
2195 return hr;
2197 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2198 IDWriteFont3_Release(font);
2200 return hr;
2203 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2204 dwritefontfamily_QueryInterface,
2205 dwritefontfamily_AddRef,
2206 dwritefontfamily_Release,
2207 dwritefontfamily_GetFontCollection,
2208 dwritefontfamily_GetFontCount,
2209 dwritefontfamily_GetFont,
2210 dwritefontfamily_GetFamilyNames,
2211 dwritefontfamily_GetFirstMatchingFont,
2212 dwritefontfamily_GetMatchingFonts,
2213 dwritefontfamily1_GetFontLocality,
2214 dwritefontfamily1_GetFont,
2215 dwritefontfamily1_GetFontFaceReference
2218 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index, IDWriteFontFamily1 **family)
2220 struct dwrite_fontfamily *This;
2222 *family = NULL;
2224 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2225 if (!This) return E_OUTOFMEMORY;
2227 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2228 This->ref = 1;
2229 This->collection = collection;
2230 IDWriteFontCollection1_AddRef(&collection->IDWriteFontCollection1_iface);
2231 This->data = collection->family_data[index];
2232 InterlockedIncrement(&This->data->ref);
2234 *family = &This->IDWriteFontFamily1_iface;
2236 return S_OK;
2239 BOOL is_system_collection(IDWriteFontCollection *collection)
2241 void *obj;
2242 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2245 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2247 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2248 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2250 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2251 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2252 IsEqualIID(riid, &IID_IUnknown))
2254 *obj = iface;
2255 IDWriteFontCollection1_AddRef(iface);
2256 return S_OK;
2259 *obj = NULL;
2261 if (IsEqualIID(riid, &IID_issystemcollection))
2262 return S_OK;
2264 return E_NOINTERFACE;
2267 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2269 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2270 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2272 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2273 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2274 IsEqualIID(riid, &IID_IUnknown))
2276 *obj = iface;
2277 IDWriteFontCollection1_AddRef(iface);
2278 return S_OK;
2281 *obj = NULL;
2283 return E_NOINTERFACE;
2286 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2288 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2289 ULONG ref = InterlockedIncrement(&This->ref);
2290 TRACE("(%p)->(%d)\n", This, ref);
2291 return ref;
2294 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2296 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2297 ULONG ref = InterlockedDecrement(&This->ref);
2299 TRACE("(%p)->(%d)\n", This, ref);
2301 if (!ref) {
2302 int i;
2304 factory_detach_fontcollection(This->factory, iface);
2305 for (i = 0; i < This->family_count; i++)
2306 release_fontfamily_data(This->family_data[i]);
2307 heap_free(This->family_data);
2308 heap_free(This);
2311 return ref;
2314 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2316 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2317 TRACE("(%p)\n", This);
2318 return This->family_count;
2321 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2323 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2325 TRACE("(%p)->(%u %p)\n", This, index, family);
2327 if (index >= This->family_count) {
2328 *family = NULL;
2329 return E_FAIL;
2332 return create_fontfamily(This, index, (IDWriteFontFamily1 **)family);
2335 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2337 UINT32 i;
2339 for (i = 0; i < collection->family_count; i++) {
2340 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2341 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2342 HRESULT hr;
2344 for (j = 0; j < count; j++) {
2345 WCHAR buffer[255];
2346 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2347 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2348 return i;
2352 return ~0u;
2355 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2357 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2358 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2359 *index = collection_find_family(This, name);
2360 *exists = *index != ~0u;
2361 return S_OK;
2364 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2366 UINT32 left_key_size, right_key_size;
2367 const void *left_key, *right_key;
2368 HRESULT hr;
2370 if (left == right)
2371 return TRUE;
2373 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2374 if (FAILED(hr))
2375 return FALSE;
2377 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2378 if (FAILED(hr))
2379 return FALSE;
2381 if (left_key_size != right_key_size)
2382 return FALSE;
2384 return !memcmp(left_key, right_key, left_key_size);
2387 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2389 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2390 IDWriteFontFamily1 *family;
2391 UINT32 i, j, face_index;
2392 BOOL found_font = FALSE;
2393 IDWriteFontFile *file;
2394 HRESULT hr;
2396 TRACE("(%p)->(%p %p)\n", This, face, font);
2398 *font = NULL;
2400 if (!face)
2401 return E_INVALIDARG;
2403 i = 1;
2404 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2405 if (FAILED(hr))
2406 return hr;
2407 face_index = IDWriteFontFace_GetIndex(face);
2409 found_font = FALSE;
2410 for (i = 0; i < This->family_count; i++) {
2411 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2413 for (j = 0; j < family_data->font_count; j++) {
2414 struct dwrite_font_data *font_data = family_data->fonts[j];
2416 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2417 found_font = TRUE;
2418 break;
2422 if (found_font)
2423 break;
2425 IDWriteFontFile_Release(file);
2427 if (!found_font)
2428 return DWRITE_E_NOFONT;
2430 hr = create_fontfamily(This, i, &family);
2431 if (FAILED(hr))
2432 return hr;
2434 hr = create_font(impl_from_IDWriteFontFamily1(family), j, (IDWriteFont3 **)font);
2435 IDWriteFontFamily1_Release(family);
2436 return hr;
2439 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2441 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2443 FIXME("(%p)->(%p): stub\n", This, fontset);
2445 return E_NOTIMPL;
2448 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2450 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2452 TRACE("(%p)->(%u %p)\n", This, index, family);
2454 if (index >= This->family_count) {
2455 *family = NULL;
2456 return E_FAIL;
2459 return create_fontfamily(This, index, family);
2462 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2463 dwritefontcollection_QueryInterface,
2464 dwritefontcollection_AddRef,
2465 dwritefontcollection_Release,
2466 dwritefontcollection_GetFontFamilyCount,
2467 dwritefontcollection_GetFontFamily,
2468 dwritefontcollection_FindFamilyName,
2469 dwritefontcollection_GetFontFromFontFace,
2470 dwritefontcollection1_GetFontSet,
2471 dwritefontcollection1_GetFontFamily
2474 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2475 dwritesystemfontcollection_QueryInterface,
2476 dwritefontcollection_AddRef,
2477 dwritefontcollection_Release,
2478 dwritefontcollection_GetFontFamilyCount,
2479 dwritefontcollection_GetFontFamily,
2480 dwritefontcollection_FindFamilyName,
2481 dwritefontcollection_GetFontFromFontFace,
2482 dwritefontcollection1_GetFontSet,
2483 dwritefontcollection1_GetFontFamily
2486 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2488 if (family_data->font_count + 1 >= family_data->font_alloc) {
2489 struct dwrite_font_data **new_list;
2490 UINT32 new_alloc;
2492 new_alloc = family_data->font_alloc * 2;
2493 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2494 if (!new_list)
2495 return E_OUTOFMEMORY;
2496 family_data->fonts = new_list;
2497 family_data->font_alloc = new_alloc;
2500 family_data->fonts[family_data->font_count] = font_data;
2501 family_data->font_count++;
2502 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2503 family_data->has_normal_face = 1;
2504 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2505 family_data->has_oblique_face = 1;
2506 else
2507 family_data->has_italic_face = 1;
2508 return S_OK;
2511 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2513 if (collection->family_alloc < collection->family_count + 1) {
2514 struct dwrite_fontfamily_data **new_list;
2515 UINT32 new_alloc;
2517 new_alloc = collection->family_alloc * 2;
2518 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2519 if (!new_list)
2520 return E_OUTOFMEMORY;
2522 collection->family_alloc = new_alloc;
2523 collection->family_data = new_list;
2526 collection->family_data[collection->family_count++] = family;
2527 return S_OK;
2530 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2532 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2533 collection->ref = 1;
2534 collection->family_count = 0;
2535 collection->family_alloc = is_system ? 30 : 5;
2536 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2537 if (!collection->family_data)
2538 return E_OUTOFMEMORY;
2540 return S_OK;
2543 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2545 IDWriteFontFileLoader *loader;
2546 const void *key;
2547 UINT32 key_size;
2548 HRESULT hr;
2550 *stream = NULL;
2552 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2553 if (FAILED(hr))
2554 return hr;
2556 hr = IDWriteFontFile_GetLoader(file, &loader);
2557 if (FAILED(hr))
2558 return hr;
2560 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2561 IDWriteFontFileLoader_Release(loader);
2562 if (FAILED(hr))
2563 return hr;
2565 return hr;
2568 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2570 BOOL exists = FALSE;
2571 UINT32 index;
2572 HRESULT hr;
2574 buffer[0] = 0;
2575 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2576 if (FAILED(hr) || !exists)
2577 return;
2579 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2582 static int trim_spaces(WCHAR *in, WCHAR *ret)
2584 int len;
2586 while (isspaceW(*in))
2587 in++;
2589 ret[0] = 0;
2590 if (!(len = strlenW(in)))
2591 return 0;
2593 while (isspaceW(in[len-1]))
2594 len--;
2596 memcpy(ret, in, len*sizeof(WCHAR));
2597 ret[len] = 0;
2599 return len;
2602 struct name_token {
2603 struct list entry;
2604 const WCHAR *ptr;
2605 INT len; /* token length */
2606 INT fulllen; /* full length including following separators */
2609 static inline BOOL is_name_separator_char(WCHAR ch)
2611 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2614 struct name_pattern {
2615 const WCHAR *part1; /* NULL indicates end of list */
2616 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2619 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2621 const struct name_pattern *pattern;
2622 struct name_token *token;
2623 int i = 0;
2625 while ((pattern = &patterns[i++])->part1) {
2626 int len_part1 = strlenW(pattern->part1);
2627 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2629 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2630 if (len_part2 == 0) {
2631 /* simple case with single part pattern */
2632 if (token->len != len_part1)
2633 continue;
2635 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2636 if (match) *match = *token;
2637 list_remove(&token->entry);
2638 heap_free(token);
2639 return TRUE;
2642 else {
2643 struct name_token *next_token;
2644 struct list *next_entry;
2646 /* pattern parts are stored in reading order, tokens list is reversed */
2647 if (token->len < len_part2)
2648 continue;
2650 /* it's possible to have combined string as a token, like ExtraCondensed */
2651 if (token->len == len_part1 + len_part2) {
2652 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2653 continue;
2655 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2656 continue;
2658 /* combined string match */
2659 if (match) *match = *token;
2660 list_remove(&token->entry);
2661 heap_free(token);
2662 return TRUE;
2665 /* now it's only possible to have two tokens matched to respective pattern parts */
2666 if (token->len != len_part2)
2667 continue;
2669 next_entry = list_next(tokens, &token->entry);
2670 if (next_entry) {
2671 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2672 if (next_token->len != len_part1)
2673 continue;
2675 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2676 continue;
2678 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2679 continue;
2681 /* both parts matched, remove tokens */
2682 if (match) {
2683 match->ptr = next_token->ptr;
2684 match->len = (token->ptr - next_token->ptr) + token->len;
2686 list_remove(&token->entry);
2687 list_remove(&next_token->entry);
2688 heap_free(next_token);
2689 heap_free(token);
2690 return TRUE;
2696 if (match) {
2697 match->ptr = NULL;
2698 match->len = 0;
2700 return FALSE;
2703 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2705 static const WCHAR itaW[] = {'i','t','a',0};
2706 static const WCHAR italW[] = {'i','t','a','l',0};
2707 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2708 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2710 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2711 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2712 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2713 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2715 static const struct name_pattern italic_patterns[] = {
2716 { itaW },
2717 { italW },
2718 { italicW },
2719 { cursiveW },
2720 { kursivW },
2721 { NULL }
2724 static const struct name_pattern oblique_patterns[] = {
2725 { inclinedW },
2726 { obliqueW },
2727 { backslantedW },
2728 { backslantW },
2729 { slantedW },
2730 { NULL }
2733 /* italic patterns first */
2734 if (match_pattern_list(tokens, italic_patterns, match))
2735 return DWRITE_FONT_STYLE_ITALIC;
2737 /* oblique patterns */
2738 if (match_pattern_list(tokens, oblique_patterns, match))
2739 return DWRITE_FONT_STYLE_OBLIQUE;
2741 return style;
2744 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2745 struct name_token *match)
2747 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2748 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2749 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2750 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2751 static const WCHAR wideW[] = {'w','i','d','e',0};
2752 static const WCHAR condW[] = {'c','o','n','d',0};
2754 static const struct name_pattern ultracondensed_patterns[] = {
2755 { extraW, compressedW },
2756 { extW, compressedW },
2757 { ultraW, compressedW },
2758 { ultraW, condensedW },
2759 { ultraW, condW },
2760 { NULL }
2763 static const struct name_pattern extracondensed_patterns[] = {
2764 { compressedW },
2765 { extraW, condensedW },
2766 { extW, condensedW },
2767 { extraW, condW },
2768 { extW, condW },
2769 { NULL }
2772 static const struct name_pattern semicondensed_patterns[] = {
2773 { narrowW },
2774 { compactW },
2775 { semiW, condensedW },
2776 { semiW, condW },
2777 { NULL }
2780 static const struct name_pattern semiexpanded_patterns[] = {
2781 { wideW },
2782 { semiW, expandedW },
2783 { semiW, extendedW },
2784 { NULL }
2787 static const struct name_pattern extraexpanded_patterns[] = {
2788 { extraW, expandedW },
2789 { extW, expandedW },
2790 { extraW, extendedW },
2791 { extW, extendedW },
2792 { NULL }
2795 static const struct name_pattern ultraexpanded_patterns[] = {
2796 { ultraW, expandedW },
2797 { ultraW, extendedW },
2798 { NULL }
2801 static const struct name_pattern condensed_patterns[] = {
2802 { condensedW },
2803 { condW },
2804 { NULL }
2807 static const struct name_pattern expanded_patterns[] = {
2808 { expandedW },
2809 { extendedW },
2810 { NULL }
2813 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2814 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2816 if (match_pattern_list(tokens, extracondensed_patterns, match))
2817 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2819 if (match_pattern_list(tokens, semicondensed_patterns, match))
2820 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2822 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2823 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2825 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2826 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2828 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2829 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2831 if (match_pattern_list(tokens, condensed_patterns, match))
2832 return DWRITE_FONT_STRETCH_CONDENSED;
2834 if (match_pattern_list(tokens, expanded_patterns, match))
2835 return DWRITE_FONT_STRETCH_EXPANDED;
2837 return stretch;
2840 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2841 struct name_token *match)
2843 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2844 static const WCHAR nordW[] = {'n','o','r','d',0};
2846 static const struct name_pattern thin_patterns[] = {
2847 { extraW, thinW },
2848 { extW, thinW },
2849 { ultraW, thinW },
2850 { NULL }
2853 static const struct name_pattern extralight_patterns[] = {
2854 { extraW, lightW },
2855 { extW, lightW },
2856 { ultraW, lightW },
2857 { NULL }
2860 static const struct name_pattern semilight_patterns[] = {
2861 { semiW, lightW },
2862 { NULL }
2865 static const struct name_pattern demibold_patterns[] = {
2866 { semiW, boldW },
2867 { demiW, boldW },
2868 { NULL }
2871 static const struct name_pattern extrabold_patterns[] = {
2872 { extraW, boldW },
2873 { extW, boldW },
2874 { ultraW, boldW },
2875 { NULL }
2878 static const struct name_pattern extrablack_patterns[] = {
2879 { extraW, blackW },
2880 { extW, blackW },
2881 { ultraW, blackW },
2882 { NULL }
2885 static const struct name_pattern bold_patterns[] = {
2886 { boldW },
2887 { NULL }
2890 static const struct name_pattern thin2_patterns[] = {
2891 { thinW },
2892 { NULL }
2895 static const struct name_pattern light_patterns[] = {
2896 { lightW },
2897 { NULL }
2900 static const struct name_pattern medium_patterns[] = {
2901 { mediumW },
2902 { NULL }
2905 static const struct name_pattern black_patterns[] = {
2906 { blackW },
2907 { heavyW },
2908 { nordW },
2909 { NULL }
2912 static const struct name_pattern demibold2_patterns[] = {
2913 { demiW },
2914 { NULL }
2917 static const struct name_pattern extrabold2_patterns[] = {
2918 { ultraW },
2919 { NULL }
2922 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2923 matching pattern. */
2925 if (match_pattern_list(tokens, thin_patterns, match))
2926 return DWRITE_FONT_WEIGHT_THIN;
2928 if (match_pattern_list(tokens, extralight_patterns, match))
2929 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2931 if (match_pattern_list(tokens, semilight_patterns, match))
2932 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2934 if (match_pattern_list(tokens, demibold_patterns, match))
2935 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2937 if (match_pattern_list(tokens, extrabold_patterns, match))
2938 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2940 if (match_pattern_list(tokens, extrablack_patterns, match))
2941 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2943 if (match_pattern_list(tokens, bold_patterns, match))
2944 return DWRITE_FONT_WEIGHT_BOLD;
2946 if (match_pattern_list(tokens, thin2_patterns, match))
2947 return DWRITE_FONT_WEIGHT_THIN;
2949 if (match_pattern_list(tokens, light_patterns, match))
2950 return DWRITE_FONT_WEIGHT_LIGHT;
2952 if (match_pattern_list(tokens, medium_patterns, match))
2953 return DWRITE_FONT_WEIGHT_MEDIUM;
2955 if (match_pattern_list(tokens, black_patterns, match))
2956 return DWRITE_FONT_WEIGHT_BLACK;
2958 if (match_pattern_list(tokens, black_patterns, match))
2959 return DWRITE_FONT_WEIGHT_BLACK;
2961 if (match_pattern_list(tokens, demibold2_patterns, match))
2962 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2964 if (match_pattern_list(tokens, extrabold2_patterns, match))
2965 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2967 /* FIXME: use abbreviated names to extract weight */
2969 return weight;
2972 struct knownweight_entry {
2973 const WCHAR *nameW;
2974 DWRITE_FONT_WEIGHT weight;
2977 static int compare_knownweights(const void *a, const void* b)
2979 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2980 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2981 int ret = 0;
2983 if (target > entry->weight)
2984 ret = 1;
2985 else if (target < entry->weight)
2986 ret = -1;
2988 return ret;
2991 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2993 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2994 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2995 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2996 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2997 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2998 const struct knownweight_entry *ptr;
3000 static const struct knownweight_entry knownweights[] = {
3001 { thinW, DWRITE_FONT_WEIGHT_THIN },
3002 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3003 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3004 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3005 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3006 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3007 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3008 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3009 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3010 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3013 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
3014 compare_knownweights);
3015 if (!ptr) {
3016 nameW[0] = 0;
3017 return FALSE;
3020 strcpyW(nameW, ptr->nameW);
3021 return TRUE;
3024 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3026 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3027 strW[name->len] = 0;
3030 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3031 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3033 static const WCHAR bookW[] = {'B','o','o','k',0};
3034 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3035 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3036 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3037 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3039 static const WCHAR *regular_patterns[] = {
3040 bookW,
3041 normalW,
3042 regularW,
3043 romanW,
3044 uprightW,
3045 NULL
3048 const WCHAR *regular_ptr = NULL, *ptr;
3049 int i = 0;
3051 if (len == -1)
3052 len = strlenW(facenameW);
3054 /* remove rightmost regular variant from face name */
3055 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3056 int pattern_len = strlenW(ptr);
3057 WCHAR *src;
3059 if (pattern_len > len)
3060 continue;
3062 src = facenameW + len - pattern_len;
3063 while (src >= facenameW) {
3064 if (!strncmpiW(src, ptr, pattern_len)) {
3065 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3066 len = strlenW(facenameW);
3067 regular_ptr = ptr;
3068 break;
3070 else
3071 src--;
3075 return regular_ptr;
3078 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3080 const WCHAR *ptr;
3082 list_init(tokens);
3083 ptr = nameW;
3085 while (*ptr) {
3086 struct name_token *token = heap_alloc(sizeof(*token));
3087 token->ptr = ptr;
3088 token->len = 0;
3089 token->fulllen = 0;
3091 while (*ptr && !is_name_separator_char(*ptr)) {
3092 token->len++;
3093 token->fulllen++;
3094 ptr++;
3097 /* skip separators */
3098 while (is_name_separator_char(*ptr)) {
3099 token->fulllen++;
3100 ptr++;
3103 list_add_head(tokens, &token->entry);
3107 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3109 struct name_token *token, *token2;
3110 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3111 int len;
3113 list_remove(&token->entry);
3115 /* don't include last separator */
3116 len = list_empty(tokens) ? token->len : token->fulllen;
3117 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3118 nameW += len;
3120 heap_free(token);
3122 *nameW = 0;
3125 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3127 struct name_token stretch_name, weight_name, style_name;
3128 WCHAR familynameW[255], facenameW[255], finalW[255];
3129 WCHAR weightW[32], stretchW[32], styleW[32];
3130 const WCHAR *regular_ptr = NULL;
3131 DWRITE_FONT_STRETCH stretch;
3132 DWRITE_FONT_WEIGHT weight;
3133 struct list tokens;
3134 int len;
3136 /* remove leading and trailing spaces from family and face name */
3137 trim_spaces(familyW, familynameW);
3138 len = trim_spaces(faceW, facenameW);
3140 /* remove rightmost regular variant from face name */
3141 regular_ptr = facename_remove_regular_term(facenameW, len);
3143 /* append face name to family name, FIXME check if face name is a substring of family name */
3144 if (*facenameW) {
3145 strcatW(familynameW, spaceW);
3146 strcatW(familynameW, facenameW);
3149 /* tokenize with " .-_" */
3150 fontname_tokenize(&tokens, familynameW);
3152 /* extract and resolve style */
3153 font->style = font_extract_style(&tokens, font->style, &style_name);
3155 /* extract stretch */
3156 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3158 /* extract weight */
3159 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3161 /* resolve weight */
3162 if (weight != font->weight) {
3163 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3164 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3165 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3166 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3167 !(abs(weight - font->weight) <= 150 &&
3168 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3169 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3170 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3172 font->weight = weight;
3176 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3177 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3178 stretch itself is normal (extracted stretch is never normal). */
3179 if (stretch != font->stretch) {
3180 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3181 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3182 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3184 font->stretch = stretch;
3188 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3190 /* get final combined string from what's left in token list, list is released */
3191 fontname_tokens_to_str(&tokens, finalW);
3193 if (!strcmpW(familyW, finalW))
3194 return FALSE;
3196 /* construct face name */
3197 strcpyW(familyW, finalW);
3199 /* resolved weight name */
3200 if (weight_name.ptr)
3201 font_name_token_to_str(&weight_name, weightW);
3202 /* ignore normal weight */
3203 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3204 weightW[0] = 0;
3205 /* for known weight values use appropriate names */
3206 else if (is_known_weight_value(font->weight, weightW)) {
3208 /* use Wnnn format as a fallback in case weight is not one of known values */
3209 else {
3210 static const WCHAR fmtW[] = {'W','%','d',0};
3211 sprintfW(weightW, fmtW, font->weight);
3214 /* resolved stretch name */
3215 if (stretch_name.ptr)
3216 font_name_token_to_str(&stretch_name, stretchW);
3217 /* ignore normal stretch */
3218 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3219 stretchW[0] = 0;
3220 /* use predefined stretch names */
3221 else {
3222 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3223 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3224 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3225 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3226 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3227 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3229 static const WCHAR *stretchnamesW[] = {
3230 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3231 ultracondensedW,
3232 extracondensedW,
3233 condensedW,
3234 semicondensedW,
3235 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3236 semiexpandedW,
3237 expandedW,
3238 extraexpandedW,
3239 ultraexpandedW
3241 strcpyW(stretchW, stretchnamesW[font->stretch]);
3244 /* resolved style name */
3245 if (style_name.ptr)
3246 font_name_token_to_str(&style_name, styleW);
3247 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3248 styleW[0] = 0;
3249 /* use predefined names */
3250 else {
3251 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3252 strcpyW(styleW, italicW);
3253 else
3254 strcpyW(styleW, obliqueW);
3257 /* use Regular match if it was found initially */
3258 if (!*weightW && !*stretchW && !*styleW)
3259 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3260 else {
3261 faceW[0] = 0;
3262 if (*stretchW)
3263 strcpyW(faceW, stretchW);
3264 if (*weightW) {
3265 if (*faceW)
3266 strcatW(faceW, spaceW);
3267 strcatW(faceW, weightW);
3269 if (*styleW) {
3270 if (*faceW)
3271 strcatW(faceW, spaceW);
3272 strcatW(faceW, styleW);
3276 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3277 return TRUE;
3280 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
3282 struct file_stream_desc stream_desc;
3283 struct dwrite_font_props props;
3284 struct dwrite_font_data *data;
3285 IDWriteFontFileStream *stream;
3286 WCHAR familyW[255], faceW[255];
3287 HRESULT hr;
3289 *ret = NULL;
3290 data = heap_alloc_zero(sizeof(*data));
3291 if (!data)
3292 return E_OUTOFMEMORY;
3294 hr = get_filestream_from_file(desc->files[0], &stream);
3295 if (FAILED(hr)) {
3296 heap_free(data);
3297 return hr;
3300 data->ref = 1;
3301 data->file = desc->files[0];
3302 data->face_index = desc->index;
3303 data->face_type = desc->face_type;
3304 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3305 data->bold_sim_tested = 0;
3306 data->oblique_sim_tested = 0;
3307 IDWriteFontFile_AddRef(data->file);
3309 stream_desc.stream = stream;
3310 stream_desc.face_type = desc->face_type;
3311 stream_desc.face_index = desc->index;
3312 opentype_get_font_properties(&stream_desc, &props);
3313 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3314 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3316 /* get family name from font file */
3317 hr = opentype_get_font_familyname(&stream_desc, family_name);
3318 IDWriteFontFileStream_Release(stream);
3319 if (FAILED(hr)) {
3320 WARN("unable to get family name from font\n");
3321 release_font_data(data);
3322 return hr;
3325 data->style = props.style;
3326 data->stretch = props.stretch;
3327 data->weight = props.weight;
3328 data->panose = props.panose;
3329 data->lf = props.lf;
3331 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3332 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3333 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3334 set_en_localizedstring(*family_name, familyW);
3335 set_en_localizedstring(data->names, faceW);
3338 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3340 *ret = data;
3341 return S_OK;
3344 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3345 const WCHAR *facenameW, struct dwrite_font_data **ret)
3347 struct dwrite_font_data *data;
3349 *ret = NULL;
3351 data = heap_alloc_zero(sizeof(*data));
3352 if (!data)
3353 return E_OUTOFMEMORY;
3355 *data = *src;
3356 data->ref = 1;
3357 data->simulations |= sim;
3358 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3359 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3360 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3361 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3362 memset(data->info_strings, 0, sizeof(data->info_strings));
3363 data->names = NULL;
3364 IDWriteFontFile_AddRef(data->file);
3366 create_localizedstrings(&data->names);
3367 add_localizedstring(data->names, enusW, facenameW);
3369 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3371 *ret = data;
3372 return S_OK;
3375 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3377 struct dwrite_fontfamily_data *data;
3379 data = heap_alloc(sizeof(*data));
3380 if (!data)
3381 return E_OUTOFMEMORY;
3383 data->ref = 1;
3384 data->font_count = 0;
3385 data->font_alloc = 2;
3386 data->has_normal_face = 0;
3387 data->has_oblique_face = 0;
3388 data->has_italic_face = 0;
3390 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3391 if (!data->fonts) {
3392 heap_free(data);
3393 return E_OUTOFMEMORY;
3396 data->familyname = familyname;
3397 IDWriteLocalizedStrings_AddRef(familyname);
3399 *ret = data;
3400 return S_OK;
3403 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3405 UINT32 i, j, heaviest;
3407 for (i = 0; i < family->font_count; i++) {
3408 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3409 heaviest = i;
3411 if (family->fonts[i]->bold_sim_tested)
3412 continue;
3414 family->fonts[i]->bold_sim_tested = 1;
3415 for (j = i; j < family->font_count; j++) {
3416 if (family->fonts[j]->bold_sim_tested)
3417 continue;
3419 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3420 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3421 if (family->fonts[j]->weight > weight) {
3422 weight = family->fonts[j]->weight;
3423 heaviest = j;
3425 family->fonts[j]->bold_sim_tested = 1;
3429 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3430 static const struct name_pattern weightsim_patterns[] = {
3431 { extraW, lightW },
3432 { extW, lightW },
3433 { ultraW, lightW },
3434 { semiW, lightW },
3435 { semiW, boldW },
3436 { demiW, boldW },
3437 { boldW },
3438 { thinW },
3439 { lightW },
3440 { mediumW },
3441 { demiW },
3442 { NULL }
3445 WCHAR facenameW[255], initialW[255];
3446 struct dwrite_font_data *boldface;
3447 struct list tokens;
3449 /* add Bold simulation based on heaviest face data */
3451 /* Simulated face name should only contain Bold as weight term,
3452 so remove existing regular and weight terms. */
3453 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3454 facename_remove_regular_term(initialW, -1);
3456 /* remove current weight pattern */
3457 fontname_tokenize(&tokens, initialW);
3458 match_pattern_list(&tokens, weightsim_patterns, NULL);
3459 fontname_tokens_to_str(&tokens, facenameW);
3461 /* Bold suffix for new name */
3462 if (*facenameW)
3463 strcatW(facenameW, spaceW);
3464 strcatW(facenameW, boldW);
3466 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3467 boldface->bold_sim_tested = 1;
3468 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3469 fontfamily_add_font(family, boldface);
3475 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3477 UINT32 i, j;
3479 for (i = 0; i < family->font_count; i++) {
3480 UINT32 regular = ~0u, oblique = ~0u;
3481 struct dwrite_font_data *obliqueface;
3482 WCHAR facenameW[255];
3484 if (family->fonts[i]->oblique_sim_tested)
3485 continue;
3487 family->fonts[i]->oblique_sim_tested = 1;
3488 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3489 regular = i;
3490 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3491 oblique = i;
3493 /* find regular style with same weight/stretch values */
3494 for (j = i; j < family->font_count; j++) {
3495 if (family->fonts[j]->oblique_sim_tested)
3496 continue;
3498 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3499 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3501 family->fonts[j]->oblique_sim_tested = 1;
3502 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3503 regular = j;
3505 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3506 oblique = j;
3509 if (regular != ~0u && oblique != ~0u)
3510 break;
3513 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3514 if (regular == ~0u)
3515 continue;
3517 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3518 if (oblique != ~0u)
3519 continue;
3521 /* add oblique simulation based on this regular face */
3523 /* remove regular term if any, append 'Oblique' */
3524 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3525 facename_remove_regular_term(facenameW, -1);
3527 if (*facenameW)
3528 strcatW(facenameW, spaceW);
3529 strcatW(facenameW, obliqueW);
3531 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3532 obliqueface->oblique_sim_tested = 1;
3533 obliqueface->lf.lfItalic = 1;
3534 fontfamily_add_font(family, obliqueface);
3539 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3540 const WCHAR *replacement_name)
3542 UINT32 i = collection_find_family(collection, replacement_name);
3543 struct dwrite_fontfamily_data *target;
3544 IDWriteLocalizedStrings *strings;
3545 HRESULT hr;
3547 /* replacement does not exist */
3548 if (i == ~0u)
3549 return FALSE;
3551 hr = create_localizedstrings(&strings);
3552 if (FAILED(hr))
3553 return FALSE;
3555 /* add a new family with target name, reuse font data from replacement */
3556 add_localizedstring(strings, enusW, target_name);
3557 hr = init_fontfamily_data(strings, &target);
3558 if (hr == S_OK) {
3559 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3560 WCHAR nameW[255];
3562 for (i = 0; i < replacement->font_count; i++) {
3563 fontfamily_add_font(target, replacement->fonts[i]);
3564 addref_font_data(replacement->fonts[i]);
3567 fontcollection_add_family(collection, target);
3568 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3569 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3571 IDWriteLocalizedStrings_Release(strings);
3572 return TRUE;
3575 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3576 system font collections. */
3577 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3579 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3580 WCHAR *name;
3581 void *data;
3582 HKEY hkey;
3584 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3585 return;
3587 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3588 RegCloseKey(hkey);
3589 return;
3592 max_namelen++; /* returned value doesn't include room for '\0' */
3593 name = heap_alloc(max_namelen * sizeof(WCHAR));
3594 data = heap_alloc(max_datalen);
3596 datalen = max_datalen;
3597 namelen = max_namelen;
3598 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3599 if (collection_find_family(collection, name) == ~0u) {
3600 if (type == REG_MULTI_SZ) {
3601 WCHAR *replacement = data;
3602 while (*replacement) {
3603 if (fontcollection_add_replacement(collection, name, replacement))
3604 break;
3605 replacement += strlenW(replacement) + 1;
3608 else if (type == REG_SZ)
3609 fontcollection_add_replacement(collection, name, data);
3611 else
3612 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3614 datalen = max_datalen;
3615 namelen = max_namelen;
3618 heap_free(data);
3619 heap_free(name);
3620 RegCloseKey(hkey);
3623 HRESULT create_font_collection(IDWriteFactory5 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3624 IDWriteFontCollection1 **ret)
3626 struct fontfile_enum {
3627 struct list entry;
3628 IDWriteFontFile *file;
3630 struct fontfile_enum *fileenum, *fileenum2;
3631 struct dwrite_fontcollection *collection;
3632 struct list scannedfiles;
3633 BOOL current = FALSE;
3634 HRESULT hr = S_OK;
3635 UINT32 i;
3637 *ret = NULL;
3639 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3640 if (!collection) return E_OUTOFMEMORY;
3642 hr = init_font_collection(collection, is_system);
3643 if (FAILED(hr)) {
3644 heap_free(collection);
3645 return hr;
3648 *ret = &collection->IDWriteFontCollection1_iface;
3650 TRACE("building font collection:\n");
3652 list_init(&scannedfiles);
3653 while (hr == S_OK) {
3654 DWRITE_FONT_FACE_TYPE face_type;
3655 DWRITE_FONT_FILE_TYPE file_type;
3656 BOOL supported, same = FALSE;
3657 IDWriteFontFile *file;
3658 UINT32 face_count;
3660 current = FALSE;
3661 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3662 if (FAILED(hr) || !current)
3663 break;
3665 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3666 if (FAILED(hr))
3667 break;
3669 /* check if we've scanned this file already */
3670 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3671 if ((same = is_same_fontfile(fileenum->file, file)))
3672 break;
3675 if (same) {
3676 IDWriteFontFile_Release(file);
3677 continue;
3680 /* failed font files are skipped */
3681 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3682 if (FAILED(hr) || !supported || face_count == 0) {
3683 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3684 IDWriteFontFile_Release(file);
3685 hr = S_OK;
3686 continue;
3689 /* add to scanned list */
3690 fileenum = heap_alloc(sizeof(*fileenum));
3691 fileenum->file = file;
3692 list_add_tail(&scannedfiles, &fileenum->entry);
3694 for (i = 0; i < face_count; i++) {
3695 IDWriteLocalizedStrings *family_name = NULL;
3696 struct dwrite_font_data *font_data;
3697 struct fontface_desc desc;
3698 WCHAR familyW[255];
3699 UINT32 index;
3701 desc.factory = factory;
3702 desc.face_type = face_type;
3703 desc.files = &file;
3704 desc.files_number = 1;
3705 desc.index = i;
3706 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3707 desc.font_data = NULL;
3709 /* alloc and init new font data structure */
3710 hr = init_font_data(&desc, &family_name, &font_data);
3711 if (FAILED(hr)) {
3712 /* move to next one */
3713 hr = S_OK;
3714 continue;
3717 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3719 /* ignore dot named faces */
3720 if (familyW[0] == '.') {
3721 WARN("Ignoring face %s\n", debugstr_w(familyW));
3722 IDWriteLocalizedStrings_Release(family_name);
3723 release_font_data(font_data);
3724 continue;
3727 index = collection_find_family(collection, familyW);
3728 if (index != ~0u)
3729 hr = fontfamily_add_font(collection->family_data[index], font_data);
3730 else {
3731 struct dwrite_fontfamily_data *family_data;
3733 /* create and init new family */
3734 hr = init_fontfamily_data(family_name, &family_data);
3735 if (hr == S_OK) {
3736 /* add font to family, family - to collection */
3737 hr = fontfamily_add_font(family_data, font_data);
3738 if (hr == S_OK)
3739 hr = fontcollection_add_family(collection, family_data);
3741 if (FAILED(hr))
3742 release_fontfamily_data(family_data);
3746 IDWriteLocalizedStrings_Release(family_name);
3748 if (FAILED(hr))
3749 break;
3753 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3754 IDWriteFontFile_Release(fileenum->file);
3755 list_remove(&fileenum->entry);
3756 heap_free(fileenum);
3759 for (i = 0; i < collection->family_count; i++) {
3760 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3761 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3764 if (is_system)
3765 fontcollection_add_replacements(collection);
3767 collection->factory = factory;
3768 IDWriteFactory5_AddRef(factory);
3770 return hr;
3773 struct system_fontfile_enumerator
3775 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3776 LONG ref;
3778 IDWriteFactory5 *factory;
3779 HKEY hkey;
3780 int index;
3782 WCHAR *value;
3783 DWORD max_val_count;
3786 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3788 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3791 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3793 *obj = NULL;
3795 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3796 IDWriteFontFileEnumerator_AddRef(iface);
3797 *obj = iface;
3798 return S_OK;
3801 return E_NOINTERFACE;
3804 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3806 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3807 return InterlockedIncrement(&enumerator->ref);
3810 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3812 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3813 ULONG ref = InterlockedDecrement(&enumerator->ref);
3815 if (!ref) {
3816 IDWriteFactory5_Release(enumerator->factory);
3817 RegCloseKey(enumerator->hkey);
3818 heap_free(enumerator->value);
3819 heap_free(enumerator);
3822 return ref;
3825 static HRESULT create_local_file_reference(IDWriteFactory5 *factory, const WCHAR *filename, IDWriteFontFile **file)
3827 HRESULT hr;
3829 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3830 if (!strchrW(filename, '\\')) {
3831 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3832 WCHAR fullpathW[MAX_PATH];
3834 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3835 strcatW(fullpathW, fontsW);
3836 strcatW(fullpathW, filename);
3838 hr = IDWriteFactory5_CreateFontFileReference(factory, fullpathW, NULL, file);
3840 else
3841 hr = IDWriteFactory5_CreateFontFileReference(factory, filename, NULL, file);
3843 return hr;
3846 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3848 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3849 DWORD ret, type, val_count, count;
3850 WCHAR *value, *filename;
3851 HRESULT hr;
3853 *file = NULL;
3855 if (enumerator->index < 0)
3856 return E_FAIL;
3858 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3859 if (ret != ERROR_SUCCESS)
3860 return E_FAIL;
3862 val_count++;
3863 value = heap_alloc( val_count * sizeof(value[0]) );
3864 filename = heap_alloc(count);
3865 if (!value || !filename) {
3866 heap_free(value);
3867 heap_free(filename);
3868 return E_OUTOFMEMORY;
3871 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3872 if (ret) {
3873 heap_free(value);
3874 heap_free(filename);
3875 return E_FAIL;
3878 hr = create_local_file_reference(enumerator->factory, filename, file);
3880 heap_free(value);
3881 heap_free(filename);
3882 return hr;
3885 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3887 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3889 *current = FALSE;
3890 enumerator->index++;
3892 if (!enumerator->value) {
3893 if (RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3894 &enumerator->max_val_count, NULL, NULL, NULL))
3895 return E_FAIL;
3897 enumerator->max_val_count++;
3898 if (!(enumerator->value = heap_alloc(enumerator->max_val_count * sizeof(*enumerator->value))))
3899 return E_OUTOFMEMORY;
3902 /* iterate until we find next string value */
3903 for (;;) {
3904 DWORD type = 0, count, val_count;
3906 val_count = enumerator->max_val_count;
3907 *enumerator->value = 0;
3908 if (RegEnumValueW(enumerator->hkey, enumerator->index, enumerator->value, &val_count,
3909 NULL, &type, NULL, &count))
3910 break;
3911 if (type == REG_SZ && *enumerator->value && *enumerator->value != '@') {
3912 *current = TRUE;
3913 break;
3915 enumerator->index++;
3918 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3919 return S_OK;
3922 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3924 systemfontfileenumerator_QueryInterface,
3925 systemfontfileenumerator_AddRef,
3926 systemfontfileenumerator_Release,
3927 systemfontfileenumerator_MoveNext,
3928 systemfontfileenumerator_GetCurrentFontFile
3931 static HRESULT create_system_fontfile_enumerator(IDWriteFactory5 *factory, IDWriteFontFileEnumerator **ret)
3933 struct system_fontfile_enumerator *enumerator;
3934 static const WCHAR fontslistW[] = {
3935 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3936 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3937 'F','o','n','t','s',0
3940 *ret = NULL;
3942 enumerator = heap_alloc(sizeof(*enumerator));
3943 if (!enumerator)
3944 return E_OUTOFMEMORY;
3946 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3947 enumerator->ref = 1;
3948 enumerator->factory = factory;
3949 enumerator->index = -1;
3950 enumerator->value = NULL;
3951 enumerator->max_val_count = 0;
3952 IDWriteFactory5_AddRef(factory);
3954 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3955 ERR("failed to open fonts list key\n");
3956 IDWriteFactory5_Release(factory);
3957 heap_free(enumerator);
3958 return E_FAIL;
3961 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3963 return S_OK;
3966 HRESULT get_system_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **collection)
3968 IDWriteFontFileEnumerator *enumerator;
3969 HRESULT hr;
3971 *collection = NULL;
3973 hr = create_system_fontfile_enumerator(factory, &enumerator);
3974 if (FAILED(hr))
3975 return hr;
3977 TRACE("building system font collection for factory %p\n", factory);
3978 hr = create_font_collection(factory, enumerator, TRUE, collection);
3979 IDWriteFontFileEnumerator_Release(enumerator);
3980 return hr;
3983 static HRESULT eudc_collection_add_family(IDWriteFactory5 *factory, struct dwrite_fontcollection *collection,
3984 const WCHAR *keynameW, const WCHAR *pathW)
3986 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};
3987 static const WCHAR emptyW[] = {0};
3988 IDWriteLocalizedStrings *names;
3989 DWRITE_FONT_FACE_TYPE face_type;
3990 DWRITE_FONT_FILE_TYPE file_type;
3991 BOOL supported;
3992 UINT32 face_count, i;
3993 IDWriteFontFile *file;
3994 HRESULT hr;
3995 struct dwrite_fontfamily_data *family_data;
3997 /* create font file from this path */
3998 hr = create_local_file_reference(factory, pathW, &file);
3999 if (FAILED(hr))
4000 return S_FALSE;
4002 /* failed font files are skipped */
4003 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
4004 if (FAILED(hr) || !supported || face_count == 0) {
4005 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4006 IDWriteFontFile_Release(file);
4007 return S_FALSE;
4010 /* create and init new family */
4012 /* Family names are added for non-specific locale, represented with empty string.
4013 Default family appears with empty family name. */
4014 create_localizedstrings(&names);
4015 if (!strcmpiW(keynameW, defaultfontW))
4016 add_localizedstring(names, emptyW, emptyW);
4017 else
4018 add_localizedstring(names, emptyW, keynameW);
4020 hr = init_fontfamily_data(names, &family_data);
4021 IDWriteLocalizedStrings_Release(names);
4022 if (hr != S_OK) {
4023 IDWriteFontFile_Release(file);
4024 return hr;
4027 /* fill with faces */
4028 for (i = 0; i < face_count; i++) {
4029 struct dwrite_font_data *font_data;
4030 struct fontface_desc desc;
4032 /* alloc and init new font data structure */
4033 desc.factory = factory;
4034 desc.face_type = face_type;
4035 desc.index = i;
4036 desc.files = &file;
4037 desc.files_number = 1;
4038 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4039 desc.font_data = NULL;
4041 hr = init_font_data(&desc, &names, &font_data);
4042 if (FAILED(hr))
4043 continue;
4045 IDWriteLocalizedStrings_Release(names);
4047 /* add font to family */
4048 hr = fontfamily_add_font(family_data, font_data);
4049 if (hr != S_OK)
4050 release_font_data(font_data);
4053 /* add family to collection */
4054 hr = fontcollection_add_family(collection, family_data);
4055 if (FAILED(hr))
4056 release_fontfamily_data(family_data);
4057 IDWriteFontFile_Release(file);
4059 return hr;
4062 HRESULT get_eudc_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **ret)
4064 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4065 struct dwrite_fontcollection *collection;
4066 static const WCHAR emptyW[] = {0};
4067 WCHAR eudckeypathW[16];
4068 HKEY eudckey;
4069 DWORD index;
4070 BOOL exists;
4071 LONG retval;
4072 HRESULT hr;
4073 UINT32 i;
4075 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4077 *ret = NULL;
4079 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4080 if (!collection) return E_OUTOFMEMORY;
4082 hr = init_font_collection(collection, FALSE);
4083 if (FAILED(hr)) {
4084 heap_free(collection);
4085 return hr;
4088 *ret = &collection->IDWriteFontCollection1_iface;
4089 collection->factory = factory;
4090 IDWriteFactory5_AddRef(factory);
4092 /* return empty collection if EUDC fonts are not configured */
4093 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4094 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4095 return S_OK;
4097 retval = ERROR_SUCCESS;
4098 index = 0;
4099 while (retval != ERROR_NO_MORE_ITEMS) {
4100 WCHAR keynameW[64], pathW[MAX_PATH];
4101 DWORD type, path_len, name_len;
4103 path_len = sizeof(pathW)/sizeof(*pathW);
4104 name_len = sizeof(keynameW)/sizeof(*keynameW);
4105 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4106 if (retval || type != REG_SZ)
4107 continue;
4109 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4110 if (hr != S_OK)
4111 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4113 RegCloseKey(eudckey);
4115 /* try to add global default if not defined for specific codepage */
4116 exists = FALSE;
4117 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
4118 &index, &exists);
4119 if (FAILED(hr) || !exists) {
4120 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4121 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4122 if (hr != S_OK)
4123 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4126 /* EUDC collection offers simulated faces too */
4127 for (i = 0; i < collection->family_count; i++) {
4128 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4129 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4132 return S_OK;
4135 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4137 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4139 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4141 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4143 *obj = iface;
4144 IDWriteFontFile_AddRef(iface);
4145 return S_OK;
4148 *obj = NULL;
4149 return E_NOINTERFACE;
4152 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4154 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4155 ULONG ref = InterlockedIncrement(&This->ref);
4156 TRACE("(%p)->(%d)\n", This, ref);
4157 return ref;
4160 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4162 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4163 ULONG ref = InterlockedDecrement(&This->ref);
4165 TRACE("(%p)->(%d)\n", This, ref);
4167 if (!ref)
4169 IDWriteFontFileLoader_Release(This->loader);
4170 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4171 heap_free(This->reference_key);
4172 heap_free(This);
4175 return ref;
4178 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4180 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4181 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4182 *fontFileReferenceKey = This->reference_key;
4183 *fontFileReferenceKeySize = This->key_size;
4185 return S_OK;
4188 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4190 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4191 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4192 *fontFileLoader = This->loader;
4193 IDWriteFontFileLoader_AddRef(This->loader);
4195 return S_OK;
4198 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
4199 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
4201 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4202 IDWriteFontFileStream *stream;
4203 HRESULT hr;
4205 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
4207 *isSupportedFontType = FALSE;
4208 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4209 if (fontFaceType)
4210 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4211 *numberOfFaces = 0;
4213 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4214 if (FAILED(hr))
4215 return hr;
4217 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
4219 /* TODO: Further Analysis */
4220 IDWriteFontFileStream_Release(stream);
4221 return S_OK;
4224 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4225 dwritefontfile_QueryInterface,
4226 dwritefontfile_AddRef,
4227 dwritefontfile_Release,
4228 dwritefontfile_GetReferenceKey,
4229 dwritefontfile_GetLoader,
4230 dwritefontfile_Analyze,
4233 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4234 IDWriteFontFile **ret)
4236 struct dwrite_fontfile *file;
4237 void *key;
4239 *ret = NULL;
4241 file = heap_alloc(sizeof(*file));
4242 key = heap_alloc(key_size);
4243 if (!file || !key) {
4244 heap_free(file);
4245 heap_free(key);
4246 return E_OUTOFMEMORY;
4249 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4250 file->ref = 1;
4251 IDWriteFontFileLoader_AddRef(loader);
4252 file->loader = loader;
4253 file->stream = NULL;
4254 file->reference_key = key;
4255 memcpy(file->reference_key, reference_key, key_size);
4256 file->key_size = key_size;
4258 *ret = &file->IDWriteFontFile_iface;
4260 return S_OK;
4263 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
4265 IDWriteFontFileLoader *loader;
4266 UINT32 key_size;
4267 const void *key;
4268 HRESULT hr;
4270 *stream = NULL;
4271 hr = IDWriteFontFile_GetLoader(file, &loader);
4272 if (FAILED(hr))
4273 return hr;
4275 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
4276 if (FAILED(hr)) {
4277 IDWriteFontFileLoader_Release(loader);
4278 return hr;
4281 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
4282 IDWriteFontFileLoader_Release(loader);
4284 return hr;
4287 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace4 **ret)
4289 struct file_stream_desc stream_desc;
4290 struct dwrite_fontface *fontface;
4291 HRESULT hr = S_OK;
4292 BOOL is_symbol;
4293 int i;
4295 *ret = NULL;
4297 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4298 if (!fontface)
4299 return E_OUTOFMEMORY;
4301 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4302 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * desc->files_number);
4304 if (!fontface->files || !fontface->streams) {
4305 heap_free(fontface->files);
4306 heap_free(fontface->streams);
4307 heap_free(fontface);
4308 return E_OUTOFMEMORY;
4311 fontface->IDWriteFontFace4_iface.lpVtbl = &dwritefontfacevtbl;
4312 fontface->ref = 1;
4313 fontface->type = desc->face_type;
4314 fontface->file_count = desc->files_number;
4315 fontface->cmap.exists = TRUE;
4316 fontface->vdmx.exists = TRUE;
4317 fontface->gasp.exists = TRUE;
4318 fontface->cpal.exists = TRUE;
4319 fontface->colr.exists = TRUE;
4320 fontface->index = desc->index;
4321 fontface->simulations = desc->simulations;
4323 for (i = 0; i < fontface->file_count; i++) {
4324 hr = get_stream_from_file(desc->files[i], &fontface->streams[i]);
4325 if (FAILED(hr)) {
4326 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4327 return hr;
4330 fontface->files[i] = desc->files[i];
4331 IDWriteFontFile_AddRef(fontface->files[i]);
4334 stream_desc.stream = fontface->streams[0];
4335 stream_desc.face_type = desc->face_type;
4336 stream_desc.face_index = desc->index;
4337 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4338 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4339 /* TODO: test what happens if caret is already slanted */
4340 if (fontface->caret.slopeRise == 1) {
4341 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4342 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4346 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace4_iface, &is_symbol);
4347 if (is_symbol)
4348 fontface->flags |= FONTFACE_IS_SYMBOL;
4349 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace4_iface))
4350 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4351 if (freetype_is_monospaced(&fontface->IDWriteFontFace4_iface))
4352 fontface->flags |= FONTFACE_IS_MONOSPACED;
4353 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace4_iface))
4354 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4355 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace4_iface);
4357 /* Font properties are reused from font object when 'normal' face creation path is used:
4358 collection -> family -> matching font -> fontface.
4360 If face is created directly from factory we have to go through properties resolution.
4362 if (desc->font_data) {
4363 fontface->weight = desc->font_data->weight;
4364 fontface->style = desc->font_data->style;
4365 fontface->stretch = desc->font_data->stretch;
4366 fontface->panose = desc->font_data->panose;
4367 fontface->lf = desc->font_data->lf;
4369 else {
4370 IDWriteLocalizedStrings *names;
4371 struct dwrite_font_data *data;
4373 hr = init_font_data(desc, &names, &data);
4374 if (FAILED(hr)) {
4375 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4376 return hr;
4379 fontface->weight = data->weight;
4380 fontface->style = data->style;
4381 fontface->stretch = data->stretch;
4382 fontface->panose = data->panose;
4383 fontface->lf = data->lf;
4385 IDWriteLocalizedStrings_Release(names);
4386 release_font_data(data);
4389 fontface->cached = factory_cache_fontface(cached_list, &fontface->IDWriteFontFace4_iface);
4390 IDWriteFactory5_AddRef(fontface->factory = desc->factory);
4392 *ret = &fontface->IDWriteFontFace4_iface;
4393 return S_OK;
4396 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4397 struct local_refkey
4399 FILETIME writetime;
4400 WCHAR name[1];
4403 struct local_cached_stream
4405 struct list entry;
4406 IDWriteFontFileStream *stream;
4407 struct local_refkey *key;
4408 UINT32 key_size;
4411 struct dwrite_localfontfilestream
4413 IDWriteFontFileStream IDWriteFontFileStream_iface;
4414 LONG ref;
4416 struct local_cached_stream *entry;
4417 const void *file_ptr;
4418 UINT64 size;
4421 struct dwrite_localfontfileloader {
4422 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4423 LONG ref;
4425 struct list streams;
4428 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4430 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4433 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4435 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4438 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4440 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4441 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4442 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4444 *obj = iface;
4445 IDWriteFontFileStream_AddRef(iface);
4446 return S_OK;
4449 *obj = NULL;
4450 return E_NOINTERFACE;
4453 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4455 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4456 ULONG ref = InterlockedIncrement(&This->ref);
4457 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4458 return ref;
4461 static inline void release_cached_stream(struct local_cached_stream *stream)
4463 list_remove(&stream->entry);
4464 heap_free(stream->key);
4465 heap_free(stream);
4468 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4470 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4471 ULONG ref = InterlockedDecrement(&This->ref);
4473 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4475 if (!ref) {
4476 UnmapViewOfFile(This->file_ptr);
4477 release_cached_stream(This->entry);
4478 heap_free(This);
4481 return ref;
4484 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4485 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4487 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4489 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4490 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4492 *fragment_context = NULL;
4494 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4495 *fragment_start = NULL;
4496 return E_FAIL;
4499 *fragment_start = (char*)This->file_ptr + offset;
4500 return S_OK;
4503 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4505 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4506 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4509 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4511 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4512 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4513 *size = This->size;
4514 return S_OK;
4517 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4519 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4520 ULARGE_INTEGER li;
4522 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4524 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4525 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4526 *last_writetime = li.QuadPart;
4528 return S_OK;
4531 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4533 localfontfilestream_QueryInterface,
4534 localfontfilestream_AddRef,
4535 localfontfilestream_Release,
4536 localfontfilestream_ReadFileFragment,
4537 localfontfilestream_ReleaseFileFragment,
4538 localfontfilestream_GetFileSize,
4539 localfontfilestream_GetLastWriteTime
4542 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4544 struct dwrite_localfontfilestream *This;
4546 *ret = NULL;
4548 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4549 if (!This)
4550 return E_OUTOFMEMORY;
4552 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4553 This->ref = 1;
4555 This->file_ptr = file_ptr;
4556 This->size = size;
4557 This->entry = entry;
4559 *ret = &This->IDWriteFontFileStream_iface;
4560 return S_OK;
4563 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4565 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4567 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4569 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4571 *obj = iface;
4572 IDWriteLocalFontFileLoader_AddRef(iface);
4573 return S_OK;
4576 *obj = NULL;
4577 return E_NOINTERFACE;
4580 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4582 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4583 ULONG ref = InterlockedIncrement(&This->ref);
4584 TRACE("(%p)->(%d)\n", This, ref);
4585 return ref;
4588 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4590 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4591 ULONG ref = InterlockedDecrement(&This->ref);
4593 TRACE("(%p)->(%d)\n", This, ref);
4595 if (!ref) {
4596 struct local_cached_stream *stream, *stream2;
4598 /* This will detach all entries from cache. Entries are released together with streams,
4599 so stream controls cache entry lifetime. */
4600 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4601 list_init(&stream->entry);
4603 heap_free(This);
4606 return ref;
4609 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4611 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4612 const struct local_refkey *refkey = key;
4613 struct local_cached_stream *stream;
4614 IDWriteFontFileStream *filestream;
4615 HANDLE file, mapping;
4616 LARGE_INTEGER size;
4617 void *file_ptr;
4618 HRESULT hr;
4620 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4621 TRACE("name: %s\n", debugstr_w(refkey->name));
4623 /* search cache first */
4624 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4625 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4626 *ret = stream->stream;
4627 IDWriteFontFileStream_AddRef(*ret);
4628 return S_OK;
4632 *ret = NULL;
4634 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4635 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4636 if (file == INVALID_HANDLE_VALUE)
4637 return E_FAIL;
4639 GetFileSizeEx(file, &size);
4640 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4641 CloseHandle(file);
4642 if (!mapping)
4643 return E_FAIL;
4645 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4646 CloseHandle(mapping);
4647 if (!file_ptr) {
4648 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4649 return E_FAIL;
4652 stream = heap_alloc(sizeof(*stream));
4653 if (!stream) {
4654 UnmapViewOfFile(file_ptr);
4655 return E_OUTOFMEMORY;
4658 stream->key = heap_alloc(key_size);
4659 if (!stream->key) {
4660 UnmapViewOfFile(file_ptr);
4661 heap_free(stream);
4662 return E_OUTOFMEMORY;
4665 stream->key_size = key_size;
4666 memcpy(stream->key, key, key_size);
4668 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4669 if (FAILED(hr)) {
4670 UnmapViewOfFile(file_ptr);
4671 heap_free(stream->key);
4672 heap_free(stream);
4673 return hr;
4676 stream->stream = filestream;
4677 list_add_head(&This->streams, &stream->entry);
4679 *ret = stream->stream;
4681 return S_OK;
4684 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4686 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4687 const struct local_refkey *refkey = key;
4689 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4691 *length = strlenW(refkey->name);
4692 return S_OK;
4695 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4697 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4698 const struct local_refkey *refkey = key;
4700 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4702 if (length < strlenW(refkey->name))
4703 return E_INVALIDARG;
4705 strcpyW(path, refkey->name);
4706 return S_OK;
4709 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4711 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4712 const struct local_refkey *refkey = key;
4714 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4716 *writetime = refkey->writetime;
4717 return S_OK;
4720 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4721 localfontfileloader_QueryInterface,
4722 localfontfileloader_AddRef,
4723 localfontfileloader_Release,
4724 localfontfileloader_CreateStreamFromKey,
4725 localfontfileloader_GetFilePathLengthFromKey,
4726 localfontfileloader_GetFilePathFromKey,
4727 localfontfileloader_GetLastWriteTimeFromKey
4730 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4732 struct dwrite_localfontfileloader *This;
4734 *ret = NULL;
4736 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4737 if (!This)
4738 return E_OUTOFMEMORY;
4740 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4741 This->ref = 1;
4742 list_init(&This->streams);
4744 *ret = &This->IDWriteLocalFontFileLoader_iface;
4745 return S_OK;
4748 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4750 struct local_refkey *refkey;
4752 if (!path)
4753 return E_INVALIDARG;
4755 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4756 *key = NULL;
4758 refkey = heap_alloc(*size);
4759 if (!refkey)
4760 return E_OUTOFMEMORY;
4762 if (writetime)
4763 refkey->writetime = *writetime;
4764 else {
4765 WIN32_FILE_ATTRIBUTE_DATA info;
4767 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4768 refkey->writetime = info.ftLastWriteTime;
4769 else
4770 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4772 strcpyW(refkey->name, path);
4774 *key = refkey;
4776 return S_OK;
4779 /* IDWriteGlyphRunAnalysis */
4780 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4782 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4784 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4786 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4787 IsEqualIID(riid, &IID_IUnknown))
4789 *ppv = iface;
4790 IDWriteGlyphRunAnalysis_AddRef(iface);
4791 return S_OK;
4794 *ppv = NULL;
4795 return E_NOINTERFACE;
4798 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4800 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4801 ULONG ref = InterlockedIncrement(&This->ref);
4802 TRACE("(%p)->(%u)\n", This, ref);
4803 return ref;
4806 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4808 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4809 ULONG ref = InterlockedDecrement(&This->ref);
4811 TRACE("(%p)->(%u)\n", This, ref);
4813 if (!ref) {
4814 if (This->run.fontFace)
4815 IDWriteFontFace_Release(This->run.fontFace);
4816 heap_free(This->glyphs);
4817 heap_free(This->origins);
4818 heap_free(This->bitmap);
4819 heap_free(This);
4822 return ref;
4825 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
4827 switch (mode)
4829 case DWRITE_RENDERING_MODE1_NATURAL:
4830 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
4831 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
4832 return TRUE;
4833 default:
4834 return FALSE;
4838 static UINT32 get_glyph_bitmap_pitch(DWRITE_TEXTURE_TYPE type, INT width)
4840 return type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? (width + 3) / 4 * 4 :
4841 ((width + 31) >> 5) << 2;
4844 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4846 struct dwrite_glyphbitmap glyph_bitmap;
4847 IDWriteFontFace4 *fontface;
4848 HRESULT hr;
4849 UINT32 i;
4851 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4852 *bounds = analysis->bounds;
4853 return;
4856 if (analysis->run.isSideways)
4857 FIXME("sideways runs are not supported.\n");
4859 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
4860 if (FAILED(hr))
4861 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
4863 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4864 glyph_bitmap.fontface = fontface;
4865 glyph_bitmap.emsize = analysis->run.fontEmSize;
4866 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
4867 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4868 glyph_bitmap.m = &analysis->m;
4870 for (i = 0; i < analysis->run.glyphCount; i++) {
4871 RECT *bbox = &glyph_bitmap.bbox;
4872 UINT32 bitmap_size;
4874 glyph_bitmap.index = analysis->run.glyphIndices[i];
4875 freetype_get_glyph_bbox(&glyph_bitmap);
4877 bitmap_size = get_glyph_bitmap_pitch(analysis->texture_type, bbox->right - bbox->left) *
4878 (bbox->bottom - bbox->top);
4879 if (bitmap_size > analysis->max_glyph_bitmap_size)
4880 analysis->max_glyph_bitmap_size = bitmap_size;
4882 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
4883 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4886 IDWriteFontFace4_Release(fontface);
4888 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4889 *bounds = analysis->bounds;
4892 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4894 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4896 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4898 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4899 SetRectEmpty(bounds);
4900 return E_INVALIDARG;
4903 if (type != This->texture_type) {
4904 SetRectEmpty(bounds);
4905 return S_OK;
4908 glyphrunanalysis_get_texturebounds(This, bounds);
4909 return S_OK;
4912 static inline int get_dib_stride( int width, int bpp )
4914 return ((width * bpp + 31) >> 3) & ~3;
4917 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4919 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4920 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4921 (runbounds->left - bounds->left) * 3;
4922 else
4923 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4924 runbounds->left - bounds->left;
4927 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
4929 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4930 struct dwrite_glyphbitmap glyph_bitmap;
4931 IDWriteFontFace4 *fontface;
4932 D2D_POINT_2F origin;
4933 UINT32 i, size;
4934 HRESULT hr;
4935 RECT *bbox;
4937 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
4938 if (FAILED(hr)) {
4939 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
4940 return hr;
4943 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4944 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4945 size *= 3;
4946 if (!(analysis->bitmap = heap_alloc_zero(size))) {
4947 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
4948 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
4949 IDWriteFontFace4_Release(fontface);
4950 return E_OUTOFMEMORY;
4953 origin.x = origin.y = 0.0f;
4955 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4956 glyph_bitmap.fontface = fontface;
4957 glyph_bitmap.emsize = analysis->run.fontEmSize;
4958 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
4959 glyph_bitmap.type = analysis->texture_type;
4960 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4961 glyph_bitmap.m = &analysis->m;
4962 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
4963 IDWriteFontFace4_Release(fontface);
4964 return E_OUTOFMEMORY;
4967 bbox = &glyph_bitmap.bbox;
4969 for (i = 0; i < analysis->run.glyphCount; i++) {
4970 BYTE *src = glyph_bitmap.buf, *dst;
4971 int x, y, width, height;
4972 BOOL is_1bpp;
4974 glyph_bitmap.index = analysis->run.glyphIndices[i];
4975 freetype_get_glyph_bbox(&glyph_bitmap);
4977 if (IsRectEmpty(bbox))
4978 continue;
4980 width = bbox->right - bbox->left;
4981 height = bbox->bottom - bbox->top;
4983 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->texture_type, width);
4984 memset(src, 0, height * glyph_bitmap.pitch);
4985 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4987 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
4989 /* blit to analysis bitmap */
4990 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
4992 if (is_1bpp) {
4993 /* convert 1bpp to 8bpp/24bpp */
4994 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4995 for (y = 0; y < height; y++) {
4996 for (x = 0; x < width; x++)
4997 if (src[x / 8] & masks[x % 8])
4998 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4999 src += glyph_bitmap.pitch;
5000 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5003 else {
5004 for (y = 0; y < height; y++) {
5005 for (x = 0; x < width; x++)
5006 if (src[x / 8] & masks[x % 8])
5007 dst[x] = DWRITE_ALPHA_MAX;
5008 src += get_dib_stride(width, 1);
5009 dst += analysis->bounds.right - analysis->bounds.left;
5013 else {
5014 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
5015 for (y = 0; y < height; y++) {
5016 for (x = 0; x < width; x++)
5017 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5018 src += glyph_bitmap.pitch;
5019 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5023 heap_free(glyph_bitmap.buf);
5025 IDWriteFontFace4_Release(fontface);
5027 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5029 /* we don't need this anymore */
5030 heap_free(analysis->glyphs);
5031 heap_free(analysis->origins);
5032 IDWriteFontFace_Release(analysis->run.fontFace);
5034 analysis->glyphs = NULL;
5035 analysis->origins = NULL;
5036 analysis->run.glyphIndices = NULL;
5037 analysis->run.fontFace = NULL;
5039 return S_OK;
5042 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5043 RECT const *bounds, BYTE *bitmap, UINT32 size)
5045 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5046 UINT32 required;
5047 RECT runbounds;
5049 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5051 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5052 return E_INVALIDARG;
5054 /* make sure buffer is large enough for requested texture type */
5055 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5056 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5057 required *= 3;
5059 if (size < required)
5060 return E_NOT_SUFFICIENT_BUFFER;
5062 /* validate requested texture type */
5063 if (This->texture_type != type)
5064 return DWRITE_E_UNSUPPORTEDOPERATION;
5066 memset(bitmap, 0, size);
5067 glyphrunanalysis_get_texturebounds(This, &runbounds);
5068 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5069 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5070 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5071 int dst_width = (bounds->right - bounds->left) * pixel_size;
5072 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5073 BYTE *src, *dst;
5074 int y;
5076 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5077 HRESULT hr;
5079 if (FAILED(hr = glyphrunanalysis_render(This)))
5080 return hr;
5083 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5084 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5086 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5087 memcpy(dst, src, draw_width);
5088 src += src_width;
5089 dst += dst_width;
5093 return S_OK;
5096 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5097 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5099 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5101 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5103 if (!params)
5104 return E_INVALIDARG;
5106 switch (This->rendering_mode)
5108 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5109 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5111 UINT value = 0;
5112 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5113 *gamma = (FLOAT)value / 1000.0f;
5114 *contrast = 0.0f;
5115 *cleartypelevel = 1.0f;
5116 break;
5118 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5119 WARN("Downsampled mode is ignored.\n");
5120 /* fallthrough */
5121 case DWRITE_RENDERING_MODE1_ALIASED:
5122 case DWRITE_RENDERING_MODE1_NATURAL:
5123 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5124 *gamma = IDWriteRenderingParams_GetGamma(params);
5125 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5126 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5127 break;
5128 default:
5132 return S_OK;
5135 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5136 glyphrunanalysis_QueryInterface,
5137 glyphrunanalysis_AddRef,
5138 glyphrunanalysis_Release,
5139 glyphrunanalysis_GetAlphaTextureBounds,
5140 glyphrunanalysis_CreateAlphaTexture,
5141 glyphrunanalysis_GetAlphaBlendParams
5144 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5146 D2D_POINT_2F ret;
5147 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5148 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5149 *point = ret;
5152 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5154 struct dwrite_glyphrunanalysis *analysis;
5155 DWRITE_FONT_METRICS metrics;
5156 IDWriteFontFace1 *fontface1;
5157 D2D_POINT_2F origin;
5158 FLOAT rtl_factor;
5159 HRESULT hr;
5160 UINT32 i;
5162 *ret = NULL;
5164 /* check for valid rendering mode */
5165 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5166 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5167 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5168 return E_INVALIDARG;
5170 analysis = heap_alloc(sizeof(*analysis));
5171 if (!analysis)
5172 return E_OUTOFMEMORY;
5174 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5175 analysis->ref = 1;
5176 analysis->rendering_mode = desc->rendering_mode;
5178 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED)
5179 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5180 else
5181 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5183 analysis->flags = 0;
5184 analysis->bitmap = NULL;
5185 analysis->max_glyph_bitmap_size = 0;
5186 SetRectEmpty(&analysis->bounds);
5187 analysis->run = *desc->run;
5188 analysis->run.fontEmSize *= desc->ppdip;
5189 IDWriteFontFace_AddRef(analysis->run.fontFace);
5190 analysis->glyphs = heap_alloc(desc->run->glyphCount * sizeof(*analysis->glyphs));
5191 analysis->origins = heap_alloc(desc->run->glyphCount * sizeof(*analysis->origins));
5193 if (!analysis->glyphs || !analysis->origins) {
5194 heap_free(analysis->glyphs);
5195 heap_free(analysis->origins);
5197 analysis->glyphs = NULL;
5198 analysis->origins = NULL;
5200 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5201 return E_OUTOFMEMORY;
5204 /* check if transform is usable */
5205 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5206 analysis->m = *desc->transform;
5207 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5209 else
5210 memset(&analysis->m, 0, sizeof(analysis->m));
5212 analysis->run.glyphIndices = analysis->glyphs;
5213 analysis->run.glyphAdvances = NULL;
5214 analysis->run.glyphOffsets = NULL;
5216 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5218 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5220 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
5221 if (FAILED(hr = IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1)))
5222 WARN("Failed to get IDWriteFontFace1, %#x.\n", hr);
5224 origin.x = desc->origin_x * desc->ppdip;
5225 origin.y = desc->origin_y * desc->ppdip;
5226 for (i = 0; i < desc->run->glyphCount; i++) {
5227 FLOAT advance;
5229 /* Use nominal advances if not provided by caller. */
5230 if (desc->run->glyphAdvances)
5231 advance = rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip;
5232 else {
5233 INT32 a;
5235 advance = 0.0f;
5236 switch (desc->measuring_mode)
5238 case DWRITE_MEASURING_MODE_NATURAL:
5239 if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a,
5240 desc->run->isSideways)))
5241 advance = rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip;
5242 break;
5243 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5244 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5245 if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize,
5246 desc->ppdip, desc->transform, desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL,
5247 desc->run->isSideways, 1, desc->run->glyphIndices + i, &a)))
5248 advance = rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f);
5249 break;
5250 default:
5255 analysis->origins[i] = origin;
5257 /* Offsets are optional, appled to pre-transformed origin. */
5258 if (desc->run->glyphOffsets) {
5259 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip;
5260 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip;
5262 if (desc->run->isSideways) {
5263 analysis->origins[i].x += ascenderoffset;
5264 analysis->origins[i].y += advanceoffset;
5266 else {
5267 analysis->origins[i].x += advanceoffset;
5268 analysis->origins[i].y += ascenderoffset;
5272 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5273 transform_point(analysis->origins + i, &analysis->m);
5275 if (desc->run->isSideways)
5276 origin.y += advance;
5277 else
5278 origin.x += advance;
5281 IDWriteFontFace1_Release(fontface1);
5283 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5284 return S_OK;
5287 /* IDWriteColorGlyphRunEnumerator */
5288 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5290 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5292 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5294 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5295 IsEqualIID(riid, &IID_IUnknown))
5297 *ppv = iface;
5298 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5299 return S_OK;
5302 *ppv = NULL;
5303 return E_NOINTERFACE;
5306 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5308 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5309 ULONG ref = InterlockedIncrement(&This->ref);
5310 TRACE("(%p)->(%u)\n", This, ref);
5311 return ref;
5314 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5316 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5317 ULONG ref = InterlockedDecrement(&This->ref);
5319 TRACE("(%p)->(%u)\n", This, ref);
5321 if (!ref) {
5322 heap_free(This->advances);
5323 heap_free(This->color_advances);
5324 heap_free(This->offsets);
5325 heap_free(This->color_offsets);
5326 heap_free(This->glyphindices);
5327 heap_free(This->glyphs);
5328 if (This->colr.context)
5329 IDWriteFontFace4_ReleaseFontTable(This->fontface, This->colr.context);
5330 IDWriteFontFace4_Release(This->fontface);
5331 heap_free(This);
5334 return ref;
5337 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5339 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5340 FLOAT origin = 0.0f;
5342 if (g == 0)
5343 return 0.0f;
5345 while (g--)
5346 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5347 return origin;
5350 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5352 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5353 FLOAT advance_adj = 0.0f;
5354 BOOL got_palette_index;
5355 UINT32 g;
5357 /* start with regular glyphs */
5358 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5359 UINT32 first_glyph = 0;
5361 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5362 if (glyphenum->glyphs[g].num_layers == 0) {
5363 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5364 first_glyph = min(first_glyph, g);
5366 else
5367 glyphenum->glyphindices[g] = 1;
5368 glyphenum->color_advances[g] = glyphenum->advances[g];
5369 if (glyphenum->color_offsets)
5370 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5373 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5374 colorrun->baselineOriginY = glyphenum->origin_y;
5375 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5376 colorrun->paletteIndex = 0xffff;
5377 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5378 glyphenum->has_regular_glyphs = FALSE;
5379 return TRUE;
5381 else {
5382 colorrun->glyphRun.glyphCount = 0;
5383 got_palette_index = FALSE;
5386 advance_adj = 0.0f;
5387 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5389 glyphenum->glyphindices[g] = 1;
5391 /* all glyph layers were returned */
5392 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5393 advance_adj += glyphenum->advances[g];
5394 continue;
5397 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5398 UINT32 index = colorrun->glyphRun.glyphCount;
5399 if (!got_palette_index) {
5400 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5401 /* use foreground color or request one from the font */
5402 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5403 if (colorrun->paletteIndex != 0xffff) {
5404 HRESULT hr = IDWriteFontFace4_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5405 1, &colorrun->runColor);
5406 if (FAILED(hr))
5407 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5408 glyphenum->palette, colorrun->paletteIndex, hr);
5410 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5411 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5412 colorrun->baselineOriginY = glyphenum->origin_y;
5413 glyphenum->color_advances[index] = glyphenum->advances[g];
5414 got_palette_index = TRUE;
5417 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5418 /* offsets are relative to glyph origin, nothing to fix up */
5419 if (glyphenum->color_offsets)
5420 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5421 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5422 if (index)
5423 glyphenum->color_advances[index-1] += advance_adj;
5424 colorrun->glyphRun.glyphCount++;
5425 advance_adj = 0.0f;
5427 else
5428 advance_adj += glyphenum->advances[g];
5431 /* reset last advance */
5432 if (colorrun->glyphRun.glyphCount)
5433 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5435 return colorrun->glyphRun.glyphCount > 0;
5438 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5440 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5442 TRACE("(%p)->(%p)\n", This, has_run);
5444 *has_run = FALSE;
5446 This->colorrun.glyphRun.glyphCount = 0;
5447 while (This->current_layer < This->max_layer_num) {
5448 if (colorglyphenum_build_color_run(This))
5449 break;
5450 else
5451 This->current_layer++;
5454 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5456 return S_OK;
5459 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5461 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5463 TRACE("(%p)->(%p)\n", This, run);
5465 if (This->colorrun.glyphRun.glyphCount == 0) {
5466 *run = NULL;
5467 return E_NOT_VALID_STATE;
5470 *run = &This->colorrun;
5471 return S_OK;
5474 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5475 colorglyphenum_QueryInterface,
5476 colorglyphenum_AddRef,
5477 colorglyphenum_Release,
5478 colorglyphenum_MoveNext,
5479 colorglyphenum_GetCurrentRun
5482 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5483 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5485 struct dwrite_colorglyphenum *colorglyphenum;
5486 BOOL colorfont, has_colored_glyph;
5487 IDWriteFontFace4 *fontface;
5488 HRESULT hr;
5489 UINT32 i;
5491 *ret = NULL;
5493 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace4, (void**)&fontface);
5494 if (FAILED(hr)) {
5495 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5496 return hr;
5499 colorfont = IDWriteFontFace4_IsColorFont(fontface) && IDWriteFontFace4_GetColorPaletteCount(fontface) > palette;
5500 if (!colorfont) {
5501 hr = DWRITE_E_NOCOLOR;
5502 goto failed;
5505 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5506 if (!colorglyphenum) {
5507 hr = E_OUTOFMEMORY;
5508 goto failed;
5511 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5512 colorglyphenum->ref = 1;
5513 colorglyphenum->origin_x = originX;
5514 colorglyphenum->origin_y = originY;
5515 colorglyphenum->fontface = fontface;
5516 colorglyphenum->glyphs = NULL;
5517 colorglyphenum->run = *run;
5518 colorglyphenum->run.glyphIndices = NULL;
5519 colorglyphenum->run.glyphAdvances = NULL;
5520 colorglyphenum->run.glyphOffsets = NULL;
5521 colorglyphenum->palette = palette;
5522 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5523 colorglyphenum->colr.exists = TRUE;
5524 get_fontface_table(fontface, MS_COLR_TAG, &colorglyphenum->colr);
5525 colorglyphenum->current_layer = 0;
5526 colorglyphenum->max_layer_num = 0;
5528 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5530 has_colored_glyph = FALSE;
5531 colorglyphenum->has_regular_glyphs = FALSE;
5532 for (i = 0; i < run->glyphCount; i++) {
5533 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5534 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5535 has_colored_glyph = TRUE;
5537 if (colorglyphenum->glyphs[i].num_layers == 0)
5538 colorglyphenum->has_regular_glyphs = TRUE;
5541 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5542 is supposed to proceed normally, like if font had no color info at all. */
5543 if (!has_colored_glyph) {
5544 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5545 return DWRITE_E_NOCOLOR;
5548 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5549 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5550 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5551 if (run->glyphOffsets) {
5552 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5553 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5554 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5557 colorglyphenum->colorrun.glyphRun.fontFace = (IDWriteFontFace*)fontface;
5558 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
5559 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5560 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5561 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5562 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5564 if (run->glyphAdvances)
5565 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5566 else {
5567 DWRITE_FONT_METRICS metrics;
5569 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5570 for (i = 0; i < run->glyphCount; i++) {
5571 HRESULT hr;
5572 INT32 a;
5574 switch (measuring_mode)
5576 case DWRITE_MEASURING_MODE_NATURAL:
5577 hr = IDWriteFontFace4_GetDesignGlyphAdvances(fontface, 1, run->glyphIndices + i, &a, run->isSideways);
5578 if (FAILED(hr))
5579 a = 0;
5580 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5581 break;
5582 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5583 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5584 hr = IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(fontface, run->fontEmSize, 1.0f, transform,
5585 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5586 if (FAILED(hr))
5587 colorglyphenum->advances[i] = 0.0f;
5588 else
5589 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5590 break;
5591 default:
5597 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5598 return S_OK;
5600 failed:
5601 IDWriteFontFace4_Release(fontface);
5602 return hr;
5605 /* IDWriteFontFaceReference */
5606 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5608 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5610 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5612 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5613 *obj = iface;
5614 IDWriteFontFaceReference_AddRef(iface);
5615 return S_OK;
5618 *obj = NULL;
5620 return E_NOINTERFACE;
5623 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5625 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5626 ULONG ref = InterlockedIncrement(&This->ref);
5627 TRACE("(%p)->(%u)\n", This, ref);
5628 return ref;
5631 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5633 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5634 ULONG ref = InterlockedDecrement(&This->ref);
5636 TRACE("(%p)->(%u)\n", This, ref);
5638 if (!ref) {
5639 IDWriteFontFile_Release(This->file);
5640 IDWriteFactory5_Release(This->factory);
5641 heap_free(This);
5644 return ref;
5647 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5649 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5651 TRACE("(%p)->(%p)\n", This, fontface);
5653 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5656 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5657 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5659 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5660 DWRITE_FONT_FILE_TYPE file_type;
5661 DWRITE_FONT_FACE_TYPE face_type;
5662 IDWriteFontFace *fontface;
5663 BOOL is_supported;
5664 UINT32 face_num;
5665 HRESULT hr;
5667 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5669 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5670 if (FAILED(hr))
5671 return hr;
5673 hr = IDWriteFactory5_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5674 if (SUCCEEDED(hr)) {
5675 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
5676 IDWriteFontFace_Release(fontface);
5679 return hr;
5682 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5684 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5685 IDWriteFontFile *file;
5686 BOOL ret;
5688 TRACE("(%p)->(%p)\n", This, ref);
5690 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5691 return FALSE;
5693 ret = is_same_fontfile(This->file, file) &&
5694 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5695 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5696 IDWriteFontFile_Release(file);
5698 return ret;
5701 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5703 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5705 TRACE("(%p)\n", This);
5707 return This->index;
5710 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5712 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5714 TRACE("(%p)\n", This);
5716 return This->simulations;
5719 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5721 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5722 IDWriteFontFileLoader *loader;
5723 const void *key;
5724 UINT32 key_size;
5725 HRESULT hr;
5727 TRACE("(%p)->(%p)\n", This, file);
5729 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5730 if (FAILED(hr))
5731 return hr;
5733 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5734 if (FAILED(hr))
5735 return hr;
5737 hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5738 IDWriteFontFileLoader_Release(loader);
5740 return hr;
5743 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5745 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5747 FIXME("(%p): stub\n", This);
5749 return 0;
5752 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5754 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5756 FIXME("(%p): stub\n", This);
5758 return 0;
5761 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5763 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5765 FIXME("(%p)->(%p): stub\n", This, writetime);
5767 return E_NOTIMPL;
5770 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5772 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5774 FIXME("(%p): stub\n", This);
5776 return DWRITE_LOCALITY_LOCAL;
5779 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5781 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5783 FIXME("(%p): stub\n", This);
5785 return E_NOTIMPL;
5788 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5789 UINT32 count)
5791 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5793 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5795 return E_NOTIMPL;
5798 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5799 UINT32 count)
5801 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5803 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5805 return E_NOTIMPL;
5808 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5809 UINT64 offset, UINT64 size)
5811 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5813 FIXME("(%p)->(0x%s 0x%s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5815 return E_NOTIMPL;
5818 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5819 fontfacereference_QueryInterface,
5820 fontfacereference_AddRef,
5821 fontfacereference_Release,
5822 fontfacereference_CreateFontFace,
5823 fontfacereference_CreateFontFaceWithSimulations,
5824 fontfacereference_Equals,
5825 fontfacereference_GetFontFaceIndex,
5826 fontfacereference_GetSimulations,
5827 fontfacereference_GetFontFile,
5828 fontfacereference_GetLocalFileSize,
5829 fontfacereference_GetFileSize,
5830 fontfacereference_GetFileTime,
5831 fontfacereference_GetLocality,
5832 fontfacereference_EnqueueFontDownloadRequest,
5833 fontfacereference_EnqueueCharacterDownloadRequest,
5834 fontfacereference_EnqueueGlyphDownloadRequest,
5835 fontfacereference_EnqueueFileFragmentDownloadRequest
5838 HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file, UINT32 index,
5839 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5841 struct dwrite_fontfacereference *ref;
5843 *ret = NULL;
5845 if (!is_simulation_valid(simulations))
5846 return E_INVALIDARG;
5848 ref = heap_alloc(sizeof(*ref));
5849 if (!ref)
5850 return E_OUTOFMEMORY;
5852 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
5853 ref->ref = 1;
5855 ref->factory = factory;
5856 IDWriteFactory5_AddRef(ref->factory);
5857 ref->file = file;
5858 IDWriteFontFile_AddRef(ref->file);
5859 ref->index = index;
5860 ref->simulations = simulations;
5861 *ret = &ref->IDWriteFontFaceReference_iface;
5863 return S_OK;