dwrite: Remove flag marking system collections.
[wine.git] / dlls / dwrite / font.c
blob0c04d563825c3f97551461c3972ab8733b5609fd
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <math.h>
24 #define COBJMACROS
26 #include "wine/list.h"
27 #include "dwrite_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
30 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
32 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
33 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
34 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
35 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
36 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
37 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
38 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
39 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
41 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
43 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
44 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
45 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
47 static const WCHAR extraW[] = {'e','x','t','r','a',0};
48 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
49 static const WCHAR semiW[] = {'s','e','m','i',0};
50 static const WCHAR extW[] = {'e','x','t',0};
51 static const WCHAR thinW[] = {'t','h','i','n',0};
52 static const WCHAR lightW[] = {'l','i','g','h','t',0};
53 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
54 static const WCHAR blackW[] = {'b','l','a','c','k',0};
55 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
56 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
57 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
58 static const WCHAR boldW[] = {'B','o','l','d',0};
59 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
60 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
61 static const WCHAR demiW[] = {'d','e','m','i',0};
62 static const WCHAR spaceW[] = {' ',0};
63 static const WCHAR enusW[] = {'e','n','-','u','s',0};
65 struct dwrite_font_propvec {
66 FLOAT stretch;
67 FLOAT style;
68 FLOAT weight;
71 struct dwrite_font_data {
72 LONG ref;
74 DWRITE_FONT_STYLE style;
75 DWRITE_FONT_STRETCH stretch;
76 DWRITE_FONT_WEIGHT weight;
77 DWRITE_PANOSE panose;
78 struct dwrite_font_propvec propvec;
80 DWRITE_FONT_METRICS1 metrics;
81 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
82 IDWriteLocalizedStrings *names;
84 /* data needed to create fontface instance */
85 IDWriteFactory2 *factory;
86 DWRITE_FONT_FACE_TYPE face_type;
87 IDWriteFontFile *file;
88 UINT32 face_index;
90 WCHAR *facename;
92 USHORT simulations;
94 /* used to mark font as tested when scanning for simulation candidate */
95 BOOL bold_sim_tested : 1;
96 BOOL oblique_sim_tested : 1;
99 struct dwrite_fontlist {
100 IDWriteFontList IDWriteFontList_iface;
101 LONG ref;
103 IDWriteFontFamily1 *family;
104 struct dwrite_font_data **fonts;
105 UINT32 font_count;
108 struct dwrite_fontfamily_data {
109 LONG ref;
111 IDWriteLocalizedStrings *familyname;
113 struct dwrite_font_data **fonts;
114 UINT32 font_count;
115 UINT32 font_alloc;
116 BOOL has_normal_face : 1;
117 BOOL has_oblique_face : 1;
118 BOOL has_italic_face : 1;
121 struct dwrite_fontcollection {
122 IDWriteFontCollection1 IDWriteFontCollection1_iface;
123 LONG ref;
125 struct dwrite_fontfamily_data **family_data;
126 UINT32 family_count;
127 UINT32 family_alloc;
130 struct dwrite_fontfamily {
131 IDWriteFontFamily1 IDWriteFontFamily1_iface;
132 LONG ref;
134 struct dwrite_fontfamily_data *data;
136 IDWriteFontCollection* collection;
139 struct dwrite_font {
140 IDWriteFont3 IDWriteFont3_iface;
141 LONG ref;
143 IDWriteFontFamily1 *family;
145 DWRITE_FONT_STYLE style;
146 struct dwrite_font_data *data;
149 struct dwrite_fonttable {
150 void *data;
151 void *context;
152 UINT32 size;
153 BOOL exists;
156 enum runanalysis_flags {
157 RUNANALYSIS_BOUNDS_READY = 1 << 0,
158 RUNANALYSIS_BITMAP_READY = 1 << 1,
159 RUNANALYSIS_USE_TRANSFORM = 1 << 2
162 struct dwrite_glyphrunanalysis {
163 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
164 LONG ref;
166 DWRITE_RENDERING_MODE rendering_mode;
167 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
168 DWRITE_MATRIX m;
169 FLOAT ppdip;
170 UINT16 *glyphs;
171 D2D_POINT_2F origin;
172 D2D_POINT_2F *advances;
173 D2D_POINT_2F *advanceoffsets;
174 D2D_POINT_2F *ascenderoffsets;
176 UINT8 flags;
177 RECT bounds;
178 BYTE *bitmap;
181 struct dwrite_colorglyphenum {
182 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
183 LONG ref;
185 FLOAT origin_x; /* original run origin */
186 FLOAT origin_y;
188 IDWriteFontFace3 *fontface; /* for convenience */
189 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
190 DWRITE_GLYPH_RUN run; /* base run */
191 UINT32 palette; /* palette index to get layer color from */
192 FLOAT *advances; /* original or measured advances for base glyphs */
193 FLOAT *color_advances; /* returned color run points to this */
194 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
195 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
196 UINT16 *glyphindices; /* returned color run points to this */
197 struct dwrite_colorglyph *glyphs; /* current glyph color info */
198 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
199 UINT16 current_layer; /* enumerator position, updated with MoveNext */
200 UINT16 max_layer_num; /* max number of layers for this run */
201 struct dwrite_fonttable colr; /* used to access layers */
204 #define GLYPH_BLOCK_SHIFT 8
205 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
206 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
207 #define GLYPH_MAX 65536
209 struct dwrite_fontface {
210 IDWriteFontFace3 IDWriteFontFace3_iface;
211 LONG ref;
213 IDWriteFontFileStream **streams;
214 IDWriteFontFile **files;
215 UINT32 file_count;
216 UINT32 index;
218 USHORT simulations;
219 DWRITE_FONT_FACE_TYPE type;
220 DWRITE_FONT_METRICS1 metrics;
221 DWRITE_CARET_METRICS caret;
222 INT charmap;
223 BOOL is_symbol;
224 BOOL has_kerning_pairs : 1;
225 BOOL is_monospaced : 1;
227 struct dwrite_fonttable cmap;
228 struct dwrite_fonttable vdmx;
229 struct dwrite_fonttable gasp;
230 struct dwrite_fonttable cpal;
231 struct dwrite_fonttable colr;
232 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
235 struct dwrite_fontfile {
236 IDWriteFontFile IDWriteFontFile_iface;
237 LONG ref;
239 IDWriteFontFileLoader *loader;
240 void *reference_key;
241 UINT32 key_size;
242 IDWriteFontFileStream *stream;
245 static inline struct dwrite_fontface *impl_from_IDWriteFontFace3(IDWriteFontFace3 *iface)
247 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace3_iface);
250 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
252 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
255 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
257 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
260 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
262 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
265 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
267 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
270 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
272 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
275 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
277 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
280 static inline struct dwrite_fontlist *impl_from_IDWriteFontList(IDWriteFontList *iface)
282 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList_iface);
285 static inline const char *debugstr_tag(UINT32 tag)
287 return debugstr_an((char*)&tag, 4);
290 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
292 static const DWRITE_GLYPH_METRICS nil;
293 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
295 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
296 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
297 return S_OK;
300 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
302 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
304 if (!*block) {
305 /* start new block */
306 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
307 if (!*block)
308 return E_OUTOFMEMORY;
311 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
312 return S_OK;
315 static void* get_fontface_table(IDWriteFontFace3 *fontface, UINT32 tag, struct dwrite_fonttable *table)
317 HRESULT hr;
319 if (table->data || !table->exists)
320 return table->data;
322 table->exists = FALSE;
323 hr = IDWriteFontFace3_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
324 &table->exists);
325 if (FAILED(hr) || !table->exists) {
326 WARN("Font does not have a %s table\n", debugstr_tag(tag));
327 return NULL;
330 return table->data;
333 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
334 struct dwrite_font_propvec *vec)
336 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
337 vec->style = style * 7.0f;
338 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
341 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
343 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
346 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
348 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
351 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
353 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CMAP_TAG, &fontface->cmap);
356 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
358 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_VDMX_TAG, &fontface->vdmx);
361 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
363 void *ptr = get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_GASP_TAG, &fontface->gasp);
364 *size = fontface->gasp.size;
365 return ptr;
368 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
370 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CPAL_TAG, &fontface->cpal);
373 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
375 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_COLR_TAG, &fontface->colr);
378 static void release_font_data(struct dwrite_font_data *data)
380 int i;
382 if (InterlockedDecrement(&data->ref) > 0)
383 return;
385 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
386 if (data->info_strings[i])
387 IDWriteLocalizedStrings_Release(data->info_strings[i]);
389 if (data->names)
390 IDWriteLocalizedStrings_Release(data->names);
392 IDWriteFontFile_Release(data->file);
393 IDWriteFactory2_Release(data->factory);
394 heap_free(data->facename);
395 heap_free(data);
398 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
400 int i;
402 if (InterlockedDecrement(&data->ref) > 0)
403 return;
405 for (i = 0; i < data->font_count; i++)
406 release_font_data(data->fonts[i]);
407 heap_free(data->fonts);
408 IDWriteLocalizedStrings_Release(data->familyname);
409 heap_free(data);
412 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace3 *iface, REFIID riid, void **obj)
414 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
416 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
418 if (IsEqualIID(riid, &IID_IDWriteFontFace3) ||
419 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
420 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
421 IsEqualIID(riid, &IID_IDWriteFontFace) ||
422 IsEqualIID(riid, &IID_IUnknown))
424 *obj = iface;
425 IDWriteFontFace3_AddRef(iface);
426 return S_OK;
429 *obj = NULL;
430 return E_NOINTERFACE;
433 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace3 *iface)
435 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
436 ULONG ref = InterlockedIncrement(&This->ref);
437 TRACE("(%p)->(%d)\n", This, ref);
438 return ref;
441 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace3 *iface)
443 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
444 ULONG ref = InterlockedDecrement(&This->ref);
446 TRACE("(%p)->(%d)\n", This, ref);
448 if (!ref) {
449 UINT32 i;
451 if (This->cmap.context)
452 IDWriteFontFace3_ReleaseFontTable(iface, This->cmap.context);
453 if (This->vdmx.context)
454 IDWriteFontFace3_ReleaseFontTable(iface, This->vdmx.context);
455 if (This->gasp.context)
456 IDWriteFontFace3_ReleaseFontTable(iface, This->gasp.context);
457 if (This->cpal.context)
458 IDWriteFontFace3_ReleaseFontTable(iface, This->cpal.context);
459 if (This->colr.context)
460 IDWriteFontFace3_ReleaseFontTable(iface, This->colr.context);
461 for (i = 0; i < This->file_count; i++) {
462 if (This->streams[i])
463 IDWriteFontFileStream_Release(This->streams[i]);
464 if (This->files[i])
465 IDWriteFontFile_Release(This->files[i]);
467 heap_free(This->streams);
468 heap_free(This->files);
470 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
471 heap_free(This->glyphs[i]);
473 freetype_notify_cacheremove(iface);
474 heap_free(This);
477 return ref;
480 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace3 *iface)
482 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
483 TRACE("(%p)\n", This);
484 return This->type;
487 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace3 *iface, UINT32 *number_of_files,
488 IDWriteFontFile **fontfiles)
490 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
491 int i;
493 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
494 if (fontfiles == NULL)
496 *number_of_files = This->file_count;
497 return S_OK;
499 if (*number_of_files < This->file_count)
500 return E_INVALIDARG;
502 for (i = 0; i < This->file_count; i++)
504 IDWriteFontFile_AddRef(This->files[i]);
505 fontfiles[i] = This->files[i];
508 return S_OK;
511 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace3 *iface)
513 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
514 TRACE("(%p)\n", This);
515 return This->index;
518 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace3 *iface)
520 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
521 TRACE("(%p)\n", This);
522 return This->simulations;
525 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace3 *iface)
527 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
528 TRACE("(%p)\n", This);
529 return This->is_symbol;
532 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS *metrics)
534 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
535 TRACE("(%p)->(%p)\n", This, metrics);
536 memcpy(metrics, &This->metrics, sizeof(*metrics));
539 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace3 *iface)
541 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
542 TRACE("(%p)\n", This);
543 return freetype_get_glyphcount(iface);
546 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace3 *iface,
547 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
549 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
550 HRESULT hr;
551 UINT32 i;
553 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
555 if (!glyphs)
556 return E_INVALIDARG;
558 if (is_sideways)
559 FIXME("sideways metrics are not supported.\n");
561 for (i = 0; i < glyph_count; i++) {
562 DWRITE_GLYPH_METRICS metrics;
564 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
565 if (hr != S_OK) {
566 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
567 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
568 if (FAILED(hr))
569 return hr;
571 ret[i] = metrics;
574 return S_OK;
577 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace3 *iface, UINT32 const *codepoints,
578 UINT32 count, UINT16 *glyph_indices)
580 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
582 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
584 if (!glyph_indices)
585 return E_INVALIDARG;
587 if (!codepoints) {
588 memset(glyph_indices, 0, count*sizeof(UINT16));
589 return E_INVALIDARG;
592 freetype_get_glyphs(iface, This->charmap, codepoints, count, glyph_indices);
593 return S_OK;
596 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace3 *iface, UINT32 table_tag,
597 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
599 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
601 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
603 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
606 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace3 *iface, void *table_context)
608 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
610 TRACE("(%p)->(%p)\n", This, table_context);
612 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
615 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace3 *iface, FLOAT emSize,
616 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
617 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
619 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
621 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
622 count, is_sideways, is_rtl, sink);
624 if (!glyphs || !sink)
625 return E_INVALIDARG;
627 if (is_sideways)
628 FIXME("sideways mode is not supported.\n");
630 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
633 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
634 FLOAT ppem, WORD gasp)
636 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
638 switch (measuring)
640 case DWRITE_MEASURING_MODE_NATURAL:
642 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
643 mode = DWRITE_RENDERING_MODE_NATURAL;
644 else
645 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
646 break;
648 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
649 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
650 break;
651 case DWRITE_MEASURING_MODE_GDI_NATURAL:
652 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
653 break;
654 default:
658 return mode;
661 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
662 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
664 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
665 WORD gasp, *ptr;
666 UINT32 size;
667 FLOAT ppem;
669 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
671 if (!params) {
672 *mode = DWRITE_RENDERING_MODE_DEFAULT;
673 return E_INVALIDARG;
676 *mode = IDWriteRenderingParams_GetRenderingMode(params);
677 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
678 return S_OK;
680 ppem = emSize * ppdip;
682 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
683 *mode = DWRITE_RENDERING_MODE_OUTLINE;
684 return S_OK;
687 ptr = get_fontface_gasp(This, &size);
688 gasp = opentype_get_gasp_flags(ptr, size, ppem);
689 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
690 return S_OK;
693 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT pixels_per_dip,
694 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
696 DWRITE_FONT_METRICS1 metrics1;
697 HRESULT hr = IDWriteFontFace3_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
698 memcpy(metrics, &metrics1, sizeof(*metrics));
699 return hr;
702 static inline int round_metric(FLOAT metric)
704 return (int)floorf(metric + 0.5f);
707 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT ppdip,
708 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
709 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
711 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
712 DWRITE_MEASURING_MODE mode;
713 FLOAT scale, size;
714 HRESULT hr;
715 UINT32 i;
717 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
718 glyph_count, metrics, is_sideways);
720 if (m && memcmp(m, &identity, sizeof(*m)))
721 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
723 size = emSize * ppdip;
724 scale = size / This->metrics.designUnitsPerEm;
725 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
727 for (i = 0; i < glyph_count; i++) {
728 DWRITE_GLYPH_METRICS *ret = metrics + i;
729 DWRITE_GLYPH_METRICS design;
731 hr = IDWriteFontFace3_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
732 if (FAILED(hr))
733 return hr;
735 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
736 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
738 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
739 SCALE_METRIC(leftSideBearing);
740 SCALE_METRIC(rightSideBearing);
741 SCALE_METRIC(topSideBearing);
742 SCALE_METRIC(advanceHeight);
743 SCALE_METRIC(bottomSideBearing);
744 SCALE_METRIC(verticalOriginY);
745 #undef SCALE_METRIC
748 return S_OK;
751 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS1 *metrics)
753 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
754 TRACE("(%p)->(%p)\n", This, metrics);
755 *metrics = This->metrics;
758 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT em_size, FLOAT pixels_per_dip,
759 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
761 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
762 const DWRITE_FONT_METRICS1 *design = &This->metrics;
763 UINT16 ascent, descent;
764 FLOAT scale;
766 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
768 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
769 memset(metrics, 0, sizeof(*metrics));
770 return E_INVALIDARG;
773 em_size *= pixels_per_dip;
774 if (m && m->m22 != 0.0f)
775 em_size *= fabs(m->m22);
777 scale = em_size / design->designUnitsPerEm;
778 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
779 ascent = round_metric(design->ascent * scale);
780 descent = round_metric(design->descent * scale);
783 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
784 metrics->designUnitsPerEm = design->designUnitsPerEm;
785 metrics->ascent = round_metric(ascent / scale);
786 metrics->descent = round_metric(descent / scale);
788 SCALE_METRIC(lineGap);
789 SCALE_METRIC(capHeight);
790 SCALE_METRIC(xHeight);
791 SCALE_METRIC(underlinePosition);
792 SCALE_METRIC(underlineThickness);
793 SCALE_METRIC(strikethroughPosition);
794 SCALE_METRIC(strikethroughThickness);
795 SCALE_METRIC(glyphBoxLeft);
796 SCALE_METRIC(glyphBoxTop);
797 SCALE_METRIC(glyphBoxRight);
798 SCALE_METRIC(glyphBoxBottom);
799 SCALE_METRIC(subscriptPositionX);
800 SCALE_METRIC(subscriptPositionY);
801 SCALE_METRIC(subscriptSizeX);
802 SCALE_METRIC(subscriptSizeY);
803 SCALE_METRIC(superscriptPositionX);
804 SCALE_METRIC(superscriptPositionY);
805 SCALE_METRIC(superscriptSizeX);
806 SCALE_METRIC(superscriptSizeY);
808 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
809 #undef SCALE_METRIC
811 return S_OK;
814 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace3 *iface, DWRITE_CARET_METRICS *metrics)
816 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
817 TRACE("(%p)->(%p)\n", This, metrics);
818 *metrics = This->caret;
821 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace3 *iface, UINT32 max_count,
822 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
824 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
826 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
828 *count = 0;
829 if (max_count && !ranges)
830 return E_INVALIDARG;
832 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
835 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
837 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
838 TRACE("(%p)\n", This);
839 return This->is_monospaced;
842 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
843 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
845 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
846 UINT32 i;
848 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
850 if (is_sideways)
851 FIXME("sideways mode not supported\n");
853 for (i = 0; i < glyph_count; i++)
854 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
856 return S_OK;
859 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3 *iface,
860 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
861 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
863 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
864 DWRITE_MEASURING_MODE mode;
865 UINT32 i;
867 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
868 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
870 if (em_size < 0.0f || ppdip <= 0.0f) {
871 memset(advances, 0, sizeof(*advances) * glyph_count);
872 return E_INVALIDARG;
875 em_size *= ppdip;
876 if (em_size == 0.0f) {
877 memset(advances, 0, sizeof(*advances) * glyph_count);
878 return S_OK;
881 if (m && memcmp(m, &identity, sizeof(*m)))
882 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
884 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
885 for (i = 0; i < glyph_count; i++) {
886 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
887 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
890 return S_OK;
893 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3 *iface, UINT32 count,
894 const UINT16 *indices, INT32 *adjustments)
896 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
897 UINT32 i;
899 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
901 if (!(indices || adjustments) || !count)
902 return E_INVALIDARG;
904 if (!indices || count == 1) {
905 memset(adjustments, 0, count*sizeof(INT32));
906 return E_INVALIDARG;
909 if (!This->has_kerning_pairs) {
910 memset(adjustments, 0, count*sizeof(INT32));
911 return S_OK;
914 for (i = 0; i < count-1; i++)
915 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
916 adjustments[count-1] = 0;
918 return S_OK;
921 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
923 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
924 TRACE("(%p)\n", This);
925 return This->has_kerning_pairs;
928 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
929 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
930 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
932 DWRITE_GRID_FIT_MODE gridfitmode;
933 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
934 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
937 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3 *iface, UINT32 glyph_count,
938 const UINT16 *nominal_indices, UINT16 *vertical_indices)
940 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
941 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
942 return E_NOTIMPL;
945 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
947 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
948 FIXME("(%p): stub\n", This);
949 return FALSE;
952 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
954 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
955 TRACE("(%p)\n", This);
956 return get_fontface_cpal(This) && get_fontface_colr(This);
959 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace3 *iface)
961 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
962 TRACE("(%p)\n", This);
963 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
966 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3 *iface)
968 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
969 TRACE("(%p)\n", This);
970 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
973 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace3 *iface, UINT32 palette_index,
974 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
976 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
977 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
978 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
981 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
982 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
983 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
984 DWRITE_GRID_FIT_MODE *gridfitmode)
986 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
987 FLOAT emthreshold;
988 WORD gasp, *ptr;
989 UINT32 size;
991 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
992 measuringmode, params, renderingmode, gridfitmode);
994 if (m)
995 FIXME("transform not supported %s\n", debugstr_matrix(m));
997 if (is_sideways)
998 FIXME("sideways mode not supported\n");
1000 emSize *= max(dpiX, dpiY) / 96.0f;
1002 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1003 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1004 if (params) {
1005 IDWriteRenderingParams2 *params2;
1006 HRESULT hr;
1008 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1009 if (hr == S_OK) {
1010 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1011 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1012 IDWriteRenderingParams2_Release(params2);
1014 else
1015 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1018 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1020 ptr = get_fontface_gasp(This, &size);
1021 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1023 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1024 if (emSize >= emthreshold)
1025 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1026 else
1027 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1030 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1031 if (emSize >= emthreshold)
1032 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1033 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1034 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1035 else
1036 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1039 return S_OK;
1042 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace3 *iface, IDWriteFontFaceReference **ref)
1044 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1045 FIXME("(%p)->(%p): stub\n", This, ref);
1046 return E_NOTIMPL;
1049 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace3 *iface, DWRITE_PANOSE *panose)
1051 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1052 FIXME("(%p)->(%p): stub\n", This, panose);
1055 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace3 *iface)
1057 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1058 FIXME("(%p): stub\n", This);
1059 return DWRITE_FONT_WEIGHT_NORMAL;
1062 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace3 *iface)
1064 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1065 FIXME("(%p): stub\n", This);
1066 return DWRITE_FONT_STRETCH_NORMAL;
1069 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace3 *iface)
1071 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1072 FIXME("(%p): stub\n", This);
1073 return DWRITE_FONT_STYLE_NORMAL;
1076 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1078 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1079 FIXME("(%p)->(%p): stub\n", This, names);
1080 return E_NOTIMPL;
1083 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1085 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1086 FIXME("(%p)->(%p): stub\n", This, names);
1087 return E_NOTIMPL;
1090 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace3 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1091 IDWriteLocalizedStrings **strings, BOOL *exists)
1093 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1094 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1095 return E_NOTIMPL;
1098 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace3 *iface, UINT32 ch)
1100 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1101 UINT16 index;
1102 HRESULT hr;
1104 TRACE("(%p)->(0x%08x)\n", This, ch);
1106 index = 0;
1107 hr = IDWriteFontFace3_GetGlyphIndices(iface, &ch, 1, &index);
1108 if (FAILED(hr))
1109 return FALSE;
1111 return index != 0;
1114 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emsize, FLOAT dpi_x, FLOAT dpi_y,
1115 DWRITE_MATRIX const *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1116 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1118 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1119 FIXME("(%p)->(%f %f %f %p %d %u %u %p %p %p): stub\n", This, emsize, dpi_x, dpi_y, transform, is_sideways, threshold,
1120 measuring_mode, params, rendering_mode, gridfit_mode);
1121 return E_NOTIMPL;
1124 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace3 *iface, UINT32 ch)
1126 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1127 FIXME("(%p)->(0x%x): stub\n", This, ch);
1128 return FALSE;
1131 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace3 *iface, UINT16 glyph)
1133 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1134 FIXME("(%p)->(%u): stub\n", This, glyph);
1135 return FALSE;
1138 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace3 *iface, WCHAR const *text,
1139 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1141 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1142 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1143 return E_NOTIMPL;
1146 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace3 *iface, UINT16 const *glyphs,
1147 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1149 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1150 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1151 return E_NOTIMPL;
1154 static const IDWriteFontFace3Vtbl dwritefontfacevtbl = {
1155 dwritefontface_QueryInterface,
1156 dwritefontface_AddRef,
1157 dwritefontface_Release,
1158 dwritefontface_GetType,
1159 dwritefontface_GetFiles,
1160 dwritefontface_GetIndex,
1161 dwritefontface_GetSimulations,
1162 dwritefontface_IsSymbolFont,
1163 dwritefontface_GetMetrics,
1164 dwritefontface_GetGlyphCount,
1165 dwritefontface_GetDesignGlyphMetrics,
1166 dwritefontface_GetGlyphIndices,
1167 dwritefontface_TryGetFontTable,
1168 dwritefontface_ReleaseFontTable,
1169 dwritefontface_GetGlyphRunOutline,
1170 dwritefontface_GetRecommendedRenderingMode,
1171 dwritefontface_GetGdiCompatibleMetrics,
1172 dwritefontface_GetGdiCompatibleGlyphMetrics,
1173 dwritefontface1_GetMetrics,
1174 dwritefontface1_GetGdiCompatibleMetrics,
1175 dwritefontface1_GetCaretMetrics,
1176 dwritefontface1_GetUnicodeRanges,
1177 dwritefontface1_IsMonospacedFont,
1178 dwritefontface1_GetDesignGlyphAdvances,
1179 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1180 dwritefontface1_GetKerningPairAdjustments,
1181 dwritefontface1_HasKerningPairs,
1182 dwritefontface1_GetRecommendedRenderingMode,
1183 dwritefontface1_GetVerticalGlyphVariants,
1184 dwritefontface1_HasVerticalGlyphVariants,
1185 dwritefontface2_IsColorFont,
1186 dwritefontface2_GetColorPaletteCount,
1187 dwritefontface2_GetPaletteEntryCount,
1188 dwritefontface2_GetPaletteEntries,
1189 dwritefontface2_GetRecommendedRenderingMode,
1190 dwritefontface3_GetFontFaceReference,
1191 dwritefontface3_GetPanose,
1192 dwritefontface3_GetWeight,
1193 dwritefontface3_GetStretch,
1194 dwritefontface3_GetStyle,
1195 dwritefontface3_GetFamilyNames,
1196 dwritefontface3_GetFaceNames,
1197 dwritefontface3_GetInformationalStrings,
1198 dwritefontface3_HasCharacter,
1199 dwritefontface3_GetRecommendedRenderingMode,
1200 dwritefontface3_IsCharacterLocal,
1201 dwritefontface3_IsGlyphLocal,
1202 dwritefontface3_AreCharactersLocal,
1203 dwritefontface3_AreGlyphsLocal
1206 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace3 **fontface)
1208 struct dwrite_font_data *data = font->data;
1209 IDWriteFontFace *face;
1210 HRESULT hr;
1212 *fontface = NULL;
1214 hr = IDWriteFactory2_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1215 data->face_index, font->data->simulations, &face);
1216 if (FAILED(hr))
1217 return hr;
1219 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void**)fontface);
1220 IDWriteFontFace_Release(face);
1222 return hr;
1225 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1227 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1229 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1231 if (IsEqualIID(riid, &IID_IDWriteFont2) ||
1232 IsEqualIID(riid, &IID_IDWriteFont1) ||
1233 IsEqualIID(riid, &IID_IDWriteFont) ||
1234 IsEqualIID(riid, &IID_IUnknown))
1236 *obj = iface;
1237 IDWriteFont3_AddRef(iface);
1238 return S_OK;
1241 *obj = NULL;
1242 return E_NOINTERFACE;
1245 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1247 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1248 ULONG ref = InterlockedIncrement(&This->ref);
1249 TRACE("(%p)->(%d)\n", This, ref);
1250 return ref;
1253 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1255 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1256 ULONG ref = InterlockedDecrement(&This->ref);
1258 TRACE("(%p)->(%d)\n", This, ref);
1260 if (!ref) {
1261 IDWriteFontFamily1_Release(This->family);
1262 release_font_data(This->data);
1263 heap_free(This);
1266 return ref;
1269 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1271 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1272 TRACE("(%p)->(%p)\n", This, family);
1274 *family = (IDWriteFontFamily*)This->family;
1275 IDWriteFontFamily_AddRef(*family);
1276 return S_OK;
1279 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1281 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1282 TRACE("(%p)\n", This);
1283 return This->data->weight;
1286 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1288 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1289 TRACE("(%p)\n", This);
1290 return This->data->stretch;
1293 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1295 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1296 TRACE("(%p)\n", This);
1297 return This->style;
1300 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1302 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1303 IDWriteFontFace3 *fontface;
1304 HRESULT hr;
1306 TRACE("(%p)\n", This);
1308 hr = get_fontface_from_font(This, &fontface);
1309 if (FAILED(hr))
1310 return FALSE;
1312 return IDWriteFontFace3_IsSymbolFont(fontface);
1315 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1317 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1318 TRACE("(%p)->(%p)\n", This, names);
1319 return clone_localizedstring(This->data->names, names);
1322 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1323 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1325 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1326 struct dwrite_font_data *data = This->data;
1327 HRESULT hr;
1329 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1331 *exists = FALSE;
1332 *strings = NULL;
1334 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1335 return S_OK;
1337 if (!data->info_strings[stringid]) {
1338 IDWriteFontFace3 *fontface;
1339 const void *table_data;
1340 BOOL table_exists;
1341 void *context;
1342 UINT32 size;
1344 hr = get_fontface_from_font(This, &fontface);
1345 if (FAILED(hr))
1346 return hr;
1348 table_exists = FALSE;
1349 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1350 if (FAILED(hr) || !table_exists)
1351 WARN("no NAME table found.\n");
1353 if (table_exists) {
1354 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1355 if (FAILED(hr) || !data->info_strings[stringid])
1356 return hr;
1357 IDWriteFontFace3_ReleaseFontTable(fontface, context);
1361 hr = clone_localizedstring(data->info_strings[stringid], strings);
1362 if (FAILED(hr))
1363 return hr;
1365 *exists = TRUE;
1366 return S_OK;
1369 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1371 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1372 TRACE("(%p)\n", This);
1373 return This->data->simulations;
1376 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1378 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1380 TRACE("(%p)->(%p)\n", This, metrics);
1381 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1384 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1386 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1387 IDWriteFontFace3 *fontface;
1388 UINT16 index;
1389 HRESULT hr;
1391 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1393 *exists = FALSE;
1395 hr = get_fontface_from_font(This, &fontface);
1396 if (FAILED(hr))
1397 return hr;
1399 index = 0;
1400 hr = IDWriteFontFace3_GetGlyphIndices(fontface, &value, 1, &index);
1401 if (FAILED(hr))
1402 return hr;
1404 *exists = index != 0;
1405 return S_OK;
1408 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **face)
1410 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1411 HRESULT hr;
1413 TRACE("(%p)->(%p)\n", This, face);
1415 hr = get_fontface_from_font(This, (IDWriteFontFace3**)face);
1416 if (hr == S_OK)
1417 IDWriteFontFace_AddRef(*face);
1419 return hr;
1422 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1424 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1425 TRACE("(%p)->(%p)\n", This, metrics);
1426 *metrics = This->data->metrics;
1429 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1431 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1432 TRACE("(%p)->(%p)\n", This, panose);
1433 *panose = This->data->panose;
1436 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1438 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1439 IDWriteFontFace3 *fontface;
1440 HRESULT hr;
1442 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1444 hr = get_fontface_from_font(This, &fontface);
1445 if (FAILED(hr))
1446 return hr;
1448 return IDWriteFontFace3_GetUnicodeRanges(fontface, max_count, ranges, count);
1451 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1453 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1454 IDWriteFontFace3 *fontface;
1455 HRESULT hr;
1457 TRACE("(%p)\n", This);
1459 hr = get_fontface_from_font(This, &fontface);
1460 if (FAILED(hr))
1461 return FALSE;
1463 return IDWriteFontFace3_IsMonospacedFont(fontface);
1466 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1468 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1469 IDWriteFontFace3 *fontface;
1470 HRESULT hr;
1472 TRACE("(%p)\n", This);
1474 hr = get_fontface_from_font(This, &fontface);
1475 if (FAILED(hr))
1476 return FALSE;
1478 return IDWriteFontFace3_IsColorFont(fontface);
1481 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1483 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1484 FIXME("(%p)->(%p): stub\n", This, fontface);
1485 return E_NOTIMPL;
1488 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1490 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1491 FIXME("(%p)->(%p): stub\n", This, font);
1492 return FALSE;
1495 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1497 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1498 FIXME("(%p)->(%p): stub\n", This, reference);
1499 return E_NOTIMPL;
1502 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1504 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1505 FIXME("(%p)->(0x%x): stub\n", This, ch);
1506 return FALSE;
1509 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1511 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1512 FIXME("(%p): stub\n", This);
1513 return DWRITE_LOCALITY_LOCAL;
1516 static const IDWriteFont3Vtbl dwritefontvtbl = {
1517 dwritefont_QueryInterface,
1518 dwritefont_AddRef,
1519 dwritefont_Release,
1520 dwritefont_GetFontFamily,
1521 dwritefont_GetWeight,
1522 dwritefont_GetStretch,
1523 dwritefont_GetStyle,
1524 dwritefont_IsSymbolFont,
1525 dwritefont_GetFaceNames,
1526 dwritefont_GetInformationalStrings,
1527 dwritefont_GetSimulations,
1528 dwritefont_GetMetrics,
1529 dwritefont_HasCharacter,
1530 dwritefont_CreateFontFace,
1531 dwritefont1_GetMetrics,
1532 dwritefont1_GetPanose,
1533 dwritefont1_GetUnicodeRanges,
1534 dwritefont1_IsMonospacedFont,
1535 dwritefont2_IsColorFont,
1536 dwritefont3_CreateFontFace,
1537 dwritefont3_Equals,
1538 dwritefont3_GetFontFaceReference,
1539 dwritefont3_HasCharacter,
1540 dwritefont3_GetLocality
1543 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily1 *family, IDWriteFont3 **font)
1545 struct dwrite_font *This;
1546 *font = NULL;
1548 This = heap_alloc(sizeof(struct dwrite_font));
1549 if (!This) return E_OUTOFMEMORY;
1551 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1552 This->ref = 1;
1553 This->family = family;
1554 IDWriteFontFamily1_AddRef(family);
1555 This->style = data->style;
1556 This->data = data;
1557 InterlockedIncrement(&This->data->ref);
1559 *font = &This->IDWriteFont3_iface;
1561 return S_OK;
1564 /* IDWriteFontList */
1565 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList *iface, REFIID riid, void **obj)
1567 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1569 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1571 if (IsEqualIID(riid, &IID_IDWriteFontList) ||
1572 IsEqualIID(riid, &IID_IUnknown))
1574 *obj = iface;
1575 IDWriteFontList_AddRef(iface);
1576 return S_OK;
1579 *obj = NULL;
1580 return E_NOINTERFACE;
1583 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList *iface)
1585 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1586 ULONG ref = InterlockedIncrement(&This->ref);
1587 TRACE("(%p)->(%d)\n", This, ref);
1588 return ref;
1591 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList *iface)
1593 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1594 ULONG ref = InterlockedDecrement(&This->ref);
1596 TRACE("(%p)->(%d)\n", This, ref);
1598 if (!ref) {
1599 UINT32 i;
1601 for (i = 0; i < This->font_count; i++)
1602 release_font_data(This->fonts[i]);
1603 IDWriteFontFamily1_Release(This->family);
1604 heap_free(This);
1607 return ref;
1610 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList *iface, IDWriteFontCollection **collection)
1612 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1613 return IDWriteFontFamily1_GetFontCollection(This->family, collection);
1616 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList *iface)
1618 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1619 TRACE("(%p)\n", This);
1620 return This->font_count;
1623 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList *iface, UINT32 index, IDWriteFont **font)
1625 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1627 TRACE("(%p)->(%u %p)\n", This, index, font);
1629 *font = NULL;
1631 if (This->font_count == 0)
1632 return S_FALSE;
1634 if (index >= This->font_count)
1635 return E_INVALIDARG;
1637 return create_font(This->fonts[index], This->family, (IDWriteFont3**)font);
1640 static const IDWriteFontListVtbl dwritefontlistvtbl = {
1641 dwritefontlist_QueryInterface,
1642 dwritefontlist_AddRef,
1643 dwritefontlist_Release,
1644 dwritefontlist_GetFontCollection,
1645 dwritefontlist_GetFontCount,
1646 dwritefontlist_GetFont
1649 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1651 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1653 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1655 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1656 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1657 IsEqualIID(riid, &IID_IDWriteFontList) ||
1658 IsEqualIID(riid, &IID_IUnknown))
1660 *obj = iface;
1661 IDWriteFontFamily1_AddRef(iface);
1662 return S_OK;
1665 *obj = NULL;
1666 return E_NOINTERFACE;
1669 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1671 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1672 ULONG ref = InterlockedIncrement(&This->ref);
1673 TRACE("(%p)->(%d)\n", This, ref);
1674 return ref;
1677 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1679 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1680 ULONG ref = InterlockedDecrement(&This->ref);
1682 TRACE("(%p)->(%d)\n", This, ref);
1684 if (!ref)
1686 IDWriteFontCollection_Release(This->collection);
1687 release_fontfamily_data(This->data);
1688 heap_free(This);
1691 return ref;
1694 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1696 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1697 TRACE("(%p)->(%p)\n", This, collection);
1699 *collection = This->collection;
1700 IDWriteFontCollection_AddRef(This->collection);
1701 return S_OK;
1704 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1706 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1707 TRACE("(%p)\n", This);
1708 return This->data->font_count;
1711 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1713 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1715 TRACE("(%p)->(%u %p)\n", This, index, font);
1717 *font = NULL;
1719 if (This->data->font_count == 0)
1720 return S_FALSE;
1722 if (index >= This->data->font_count)
1723 return E_INVALIDARG;
1725 return create_font(This->data->fonts[index], iface, (IDWriteFont3**)font);
1728 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1730 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1731 return clone_localizedstring(This->data->familyname, names);
1734 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1735 const struct dwrite_font_propvec *req)
1737 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1738 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1739 FLOAT cur_req_prod, next_req_prod;
1741 if (next_to_req < cur_to_req)
1742 return TRUE;
1744 if (next_to_req > cur_to_req)
1745 return FALSE;
1747 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1748 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1750 if (next_req_prod > cur_req_prod)
1751 return TRUE;
1753 if (next_req_prod < cur_req_prod)
1754 return FALSE;
1756 if (next->stretch > cur->stretch)
1757 return TRUE;
1758 if (next->stretch < cur->stretch)
1759 return FALSE;
1761 if (next->style > cur->style)
1762 return TRUE;
1763 if (next->style < cur->style)
1764 return FALSE;
1766 if (next->weight > cur->weight)
1767 return TRUE;
1768 if (next->weight < cur->weight)
1769 return FALSE;
1771 /* full match, no reason to prefer new variant */
1772 return FALSE;
1775 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1776 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1778 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1779 struct dwrite_font_propvec req;
1780 struct dwrite_font_data *match;
1781 UINT32 i;
1783 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1785 if (This->data->font_count == 0) {
1786 *font = NULL;
1787 return DWRITE_E_NOFONT;
1790 init_font_prop_vec(weight, stretch, style, &req);
1791 match = This->data->fonts[0];
1793 for (i = 1; i < This->data->font_count; i++) {
1794 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1795 match = This->data->fonts[i];
1798 return create_font(match, iface, (IDWriteFont3**)font);
1801 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1803 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1805 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1808 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1810 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1813 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1815 UINT32 b = fonts->font_count - 1, j, t;
1817 while (1) {
1818 t = b;
1820 for (j = 0; j < b; j++) {
1821 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1822 struct dwrite_font_data *s = fonts->fonts[j];
1823 fonts->fonts[j] = fonts->fonts[j+1];
1824 fonts->fonts[j+1] = s;
1825 t = j;
1829 if (t == b)
1830 break;
1831 b = t;
1835 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1836 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1838 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1839 matching_filter_func func = NULL;
1840 struct dwrite_font_propvec req;
1841 struct dwrite_fontlist *fonts;
1842 UINT32 i;
1844 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1846 *ret = NULL;
1848 fonts = heap_alloc(sizeof(*fonts));
1849 if (!fonts)
1850 return E_OUTOFMEMORY;
1852 /* Allocate as many as family has, not all of them will be necessary used. */
1853 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1854 if (!fonts->fonts) {
1855 heap_free(fonts);
1856 return E_OUTOFMEMORY;
1859 fonts->IDWriteFontList_iface.lpVtbl = &dwritefontlistvtbl;
1860 fonts->ref = 1;
1861 fonts->family = iface;
1862 IDWriteFontFamily1_AddRef(fonts->family);
1863 fonts->font_count = 0;
1865 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1866 if (style == DWRITE_FONT_STYLE_NORMAL) {
1867 if (This->data->has_normal_face || This->data->has_italic_face)
1868 func = is_font_acceptable_for_normal;
1870 else /* requested oblique or italic */ {
1871 if (This->data->has_oblique_face || This->data->has_italic_face)
1872 func = is_font_acceptable_for_oblique_italic;
1875 for (i = 0; i < This->data->font_count; i++) {
1876 if (!func || func(This->data->fonts[i])) {
1877 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1878 InterlockedIncrement(&This->data->fonts[i]->ref);
1879 fonts->font_count++;
1883 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1884 init_font_prop_vec(weight, stretch, style, &req);
1885 matchingfonts_sort(fonts, &req);
1887 *ret = &fonts->IDWriteFontList_iface;
1888 return S_OK;
1891 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
1893 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1895 FIXME("(%p)->(%u): stub\n", This, index);
1897 return DWRITE_LOCALITY_LOCAL;
1900 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
1902 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1904 TRACE("(%p)->(%u %p)\n", This, index, font);
1906 *font = NULL;
1908 if (This->data->font_count == 0)
1909 return S_FALSE;
1911 if (index >= This->data->font_count)
1912 return E_FAIL;
1914 return create_font(This->data->fonts[index], iface, font);
1917 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
1918 IDWriteFontFaceReference **ref)
1920 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1922 FIXME("(%p)->(%u %p): stub\n", This, index, ref);
1924 return E_NOTIMPL;
1927 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
1928 dwritefontfamily_QueryInterface,
1929 dwritefontfamily_AddRef,
1930 dwritefontfamily_Release,
1931 dwritefontfamily_GetFontCollection,
1932 dwritefontfamily_GetFontCount,
1933 dwritefontfamily_GetFont,
1934 dwritefontfamily_GetFamilyNames,
1935 dwritefontfamily_GetFirstMatchingFont,
1936 dwritefontfamily_GetMatchingFonts,
1937 dwritefontfamily1_GetFontLocality,
1938 dwritefontfamily1_GetFont,
1939 dwritefontfamily1_GetFontFaceReference
1942 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily1 **family)
1944 struct dwrite_fontfamily *This;
1946 *family = NULL;
1948 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1949 if (!This) return E_OUTOFMEMORY;
1951 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
1952 This->ref = 1;
1953 This->collection = collection;
1954 IDWriteFontCollection_AddRef(collection);
1955 This->data = data;
1956 InterlockedIncrement(&This->data->ref);
1958 *family = &This->IDWriteFontFamily1_iface;
1960 return S_OK;
1963 BOOL is_system_collection(IDWriteFontCollection *collection)
1965 void *obj;
1966 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1969 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
1971 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
1972 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1974 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
1975 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
1976 IsEqualIID(riid, &IID_IUnknown))
1978 *obj = iface;
1979 IDWriteFontCollection1_AddRef(iface);
1980 return S_OK;
1983 *obj = NULL;
1985 if (IsEqualIID(riid, &IID_issystemcollection))
1986 return S_OK;
1988 return E_NOINTERFACE;
1991 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
1993 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
1994 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1996 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
1997 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
1998 IsEqualIID(riid, &IID_IUnknown))
2000 *obj = iface;
2001 IDWriteFontCollection1_AddRef(iface);
2002 return S_OK;
2005 *obj = NULL;
2007 return E_NOINTERFACE;
2010 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2012 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2013 ULONG ref = InterlockedIncrement(&This->ref);
2014 TRACE("(%p)->(%d)\n", This, ref);
2015 return ref;
2018 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2020 unsigned int i;
2021 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2022 ULONG ref = InterlockedDecrement(&This->ref);
2023 TRACE("(%p)->(%d)\n", This, ref);
2025 if (!ref) {
2026 for (i = 0; i < This->family_count; i++)
2027 release_fontfamily_data(This->family_data[i]);
2028 heap_free(This->family_data);
2029 heap_free(This);
2032 return ref;
2035 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2037 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2038 TRACE("(%p)\n", This);
2039 return This->family_count;
2042 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2044 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2046 TRACE("(%p)->(%u %p)\n", This, index, family);
2048 if (index >= This->family_count) {
2049 *family = NULL;
2050 return E_FAIL;
2053 return create_fontfamily(This->family_data[index], (IDWriteFontCollection*)iface, (IDWriteFontFamily1**)family);
2056 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2058 UINT32 i;
2060 for (i = 0; i < collection->family_count; i++) {
2061 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2062 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2063 HRESULT hr;
2065 for (j = 0; j < count; j++) {
2066 WCHAR buffer[255];
2067 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2068 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2069 return i;
2073 return ~0u;
2076 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2078 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2079 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2080 *index = collection_find_family(This, name);
2081 *exists = *index != ~0u;
2082 return S_OK;
2085 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2087 UINT32 left_key_size, right_key_size;
2088 const void *left_key, *right_key;
2089 HRESULT hr;
2091 if (left == right)
2092 return TRUE;
2094 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2095 if (FAILED(hr))
2096 return FALSE;
2098 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2099 if (FAILED(hr))
2100 return FALSE;
2102 if (left_key_size != right_key_size)
2103 return FALSE;
2105 return !memcmp(left_key, right_key, left_key_size);
2108 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2110 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2111 struct dwrite_fontfamily_data *found_family = NULL;
2112 struct dwrite_font_data *found_font = NULL;
2113 IDWriteFontFamily1 *family;
2114 UINT32 i, j, face_index;
2115 IDWriteFontFile *file;
2116 HRESULT hr;
2118 TRACE("(%p)->(%p %p)\n", This, face, font);
2120 *font = NULL;
2122 if (!face)
2123 return E_INVALIDARG;
2125 i = 1;
2126 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2127 if (FAILED(hr))
2128 return hr;
2129 face_index = IDWriteFontFace_GetIndex(face);
2131 for (i = 0; i < This->family_count; i++) {
2132 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2133 for (j = 0; j < family_data->font_count; j++) {
2134 struct dwrite_font_data *font_data = family_data->fonts[j];
2136 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2137 found_font = font_data;
2138 found_family = family_data;
2139 break;
2144 if (!found_font)
2145 return DWRITE_E_NOFONT;
2147 hr = create_fontfamily(found_family, (IDWriteFontCollection*)iface, &family);
2148 if (FAILED(hr))
2149 return hr;
2151 hr = create_font(found_font, family, (IDWriteFont3**)font);
2152 IDWriteFontFamily1_Release(family);
2153 return hr;
2156 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2158 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2160 FIXME("(%p)->(%p): stub\n", This, fontset);
2162 return E_NOTIMPL;
2165 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2167 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2169 FIXME("(%p)->(%p): stub\n", This, family);
2171 return E_NOTIMPL;
2174 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2175 dwritefontcollection_QueryInterface,
2176 dwritefontcollection_AddRef,
2177 dwritefontcollection_Release,
2178 dwritefontcollection_GetFontFamilyCount,
2179 dwritefontcollection_GetFontFamily,
2180 dwritefontcollection_FindFamilyName,
2181 dwritefontcollection_GetFontFromFontFace,
2182 dwritefontcollection1_GetFontSet,
2183 dwritefontcollection1_GetFontFamily
2186 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2187 dwritesystemfontcollection_QueryInterface,
2188 dwritefontcollection_AddRef,
2189 dwritefontcollection_Release,
2190 dwritefontcollection_GetFontFamilyCount,
2191 dwritefontcollection_GetFontFamily,
2192 dwritefontcollection_FindFamilyName,
2193 dwritefontcollection_GetFontFromFontFace,
2194 dwritefontcollection1_GetFontSet,
2195 dwritefontcollection1_GetFontFamily
2198 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2200 if (family_data->font_count + 1 >= family_data->font_alloc) {
2201 struct dwrite_font_data **new_list;
2202 UINT32 new_alloc;
2204 new_alloc = family_data->font_alloc * 2;
2205 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2206 if (!new_list)
2207 return E_OUTOFMEMORY;
2208 family_data->fonts = new_list;
2209 family_data->font_alloc = new_alloc;
2212 family_data->fonts[family_data->font_count] = font_data;
2213 family_data->font_count++;
2214 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2215 family_data->has_normal_face = 1;
2216 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2217 family_data->has_oblique_face = 1;
2218 else
2219 family_data->has_italic_face = 1;
2220 return S_OK;
2223 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2225 if (collection->family_alloc < collection->family_count + 1) {
2226 struct dwrite_fontfamily_data **new_list;
2227 UINT32 new_alloc;
2229 new_alloc = collection->family_alloc * 2;
2230 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2231 if (!new_list)
2232 return E_OUTOFMEMORY;
2234 collection->family_alloc = new_alloc;
2235 collection->family_data = new_list;
2238 collection->family_data[collection->family_count] = family;
2239 collection->family_count++;
2241 return S_OK;
2244 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2246 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2247 collection->ref = 1;
2248 collection->family_count = 0;
2249 collection->family_alloc = is_system ? 30 : 5;
2250 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2251 if (!collection->family_data)
2252 return E_OUTOFMEMORY;
2254 return S_OK;
2257 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2259 IDWriteFontFileLoader *loader;
2260 const void *key;
2261 UINT32 key_size;
2262 HRESULT hr;
2264 *stream = NULL;
2266 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2267 if (FAILED(hr))
2268 return hr;
2270 hr = IDWriteFontFile_GetLoader(file, &loader);
2271 if (FAILED(hr))
2272 return hr;
2274 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2275 IDWriteFontFileLoader_Release(loader);
2276 if (FAILED(hr))
2277 return hr;
2279 return hr;
2282 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2284 BOOL exists = FALSE;
2285 UINT32 index;
2286 HRESULT hr;
2288 buffer[0] = 0;
2289 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2290 if (FAILED(hr) || !exists)
2291 return;
2293 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2296 static int trim_spaces(WCHAR *in, WCHAR *ret)
2298 int len;
2300 while (isspaceW(*in))
2301 in++;
2303 ret[0] = 0;
2304 if (!(len = strlenW(in)))
2305 return 0;
2307 while (isspaceW(in[len-1]))
2308 len--;
2310 memcpy(ret, in, len*sizeof(WCHAR));
2311 ret[len] = 0;
2313 return len;
2316 struct name_token {
2317 struct list entry;
2318 const WCHAR *ptr;
2319 INT len; /* token length */
2320 INT fulllen; /* full length including following separators */
2323 static inline BOOL is_name_separator_char(WCHAR ch)
2325 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2328 struct name_pattern {
2329 const WCHAR *part1; /* NULL indicates end of list */
2330 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2333 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2335 const struct name_pattern *pattern;
2336 struct name_token *token;
2337 int i = 0;
2339 while ((pattern = &patterns[i++])->part1) {
2340 int len_part1 = strlenW(pattern->part1);
2341 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2343 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2344 if (len_part2 == 0) {
2345 /* simple case with single part pattern */
2346 if (token->len != len_part1)
2347 continue;
2349 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2350 if (match) *match = *token;
2351 list_remove(&token->entry);
2352 heap_free(token);
2353 return TRUE;
2356 else {
2357 struct name_token *next_token;
2358 struct list *next_entry;
2360 /* pattern parts are stored in reading order, tokens list is reversed */
2361 if (token->len < len_part2)
2362 continue;
2364 /* it's possible to have combined string as a token, like ExtraCondensed */
2365 if (token->len == len_part1 + len_part2) {
2366 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2367 continue;
2369 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2370 continue;
2372 /* combined string match */
2373 if (match) *match = *token;
2374 list_remove(&token->entry);
2375 heap_free(token);
2376 return TRUE;
2379 /* now it's only possible to have two tokens matched to respective pattern parts */
2380 if (token->len != len_part2)
2381 continue;
2383 next_entry = list_next(tokens, &token->entry);
2384 if (next_entry) {
2385 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2386 if (next_token->len != len_part1)
2387 continue;
2389 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2390 continue;
2392 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2393 continue;
2395 /* both parts matched, remove tokens */
2396 if (match) {
2397 match->ptr = next_token->ptr;
2398 match->len = (token->ptr - next_token->ptr) + token->len;
2400 list_remove(&token->entry);
2401 list_remove(&next_token->entry);
2402 heap_free(next_token);
2403 heap_free(token);
2404 return TRUE;
2410 if (match) {
2411 match->ptr = NULL;
2412 match->len = 0;
2414 return FALSE;
2417 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2419 static const WCHAR itaW[] = {'i','t','a',0};
2420 static const WCHAR italW[] = {'i','t','a','l',0};
2421 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2422 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2424 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2425 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2426 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2427 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2429 static const struct name_pattern italic_patterns[] = {
2430 { itaW },
2431 { italW },
2432 { italicW },
2433 { cursiveW },
2434 { kursivW },
2435 { NULL }
2438 static const struct name_pattern oblique_patterns[] = {
2439 { inclinedW },
2440 { obliqueW },
2441 { backslantedW },
2442 { backslantW },
2443 { slantedW },
2444 { NULL }
2447 /* italic patterns first */
2448 if (match_pattern_list(tokens, italic_patterns, match))
2449 return DWRITE_FONT_STYLE_ITALIC;
2451 /* oblique patterns */
2452 if (match_pattern_list(tokens, oblique_patterns, match))
2453 return DWRITE_FONT_STYLE_OBLIQUE;
2455 return style;
2458 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2459 struct name_token *match)
2461 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2462 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2463 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2464 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2465 static const WCHAR wideW[] = {'w','i','d','e',0};
2466 static const WCHAR condW[] = {'c','o','n','d',0};
2468 static const struct name_pattern ultracondensed_patterns[] = {
2469 { extraW, compressedW },
2470 { extW, compressedW },
2471 { ultraW, compressedW },
2472 { ultraW, condensedW },
2473 { ultraW, condW },
2474 { NULL }
2477 static const struct name_pattern extracondensed_patterns[] = {
2478 { compressedW },
2479 { extraW, condensedW },
2480 { extW, condensedW },
2481 { extraW, condW },
2482 { extW, condW },
2483 { NULL }
2486 static const struct name_pattern semicondensed_patterns[] = {
2487 { narrowW },
2488 { compactW },
2489 { semiW, condensedW },
2490 { semiW, condW },
2491 { NULL }
2494 static const struct name_pattern semiexpanded_patterns[] = {
2495 { wideW },
2496 { semiW, expandedW },
2497 { semiW, extendedW },
2498 { NULL }
2501 static const struct name_pattern extraexpanded_patterns[] = {
2502 { extraW, expandedW },
2503 { extW, expandedW },
2504 { extraW, extendedW },
2505 { extW, extendedW },
2506 { NULL }
2509 static const struct name_pattern ultraexpanded_patterns[] = {
2510 { ultraW, expandedW },
2511 { ultraW, extendedW },
2512 { NULL }
2515 static const struct name_pattern condensed_patterns[] = {
2516 { condensedW },
2517 { condW },
2518 { NULL }
2521 static const struct name_pattern expanded_patterns[] = {
2522 { expandedW },
2523 { extendedW },
2524 { NULL }
2527 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2528 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2530 if (match_pattern_list(tokens, extracondensed_patterns, match))
2531 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2533 if (match_pattern_list(tokens, semicondensed_patterns, match))
2534 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2536 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2537 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2539 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2540 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2542 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2543 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2545 if (match_pattern_list(tokens, condensed_patterns, match))
2546 return DWRITE_FONT_STRETCH_CONDENSED;
2548 if (match_pattern_list(tokens, expanded_patterns, match))
2549 return DWRITE_FONT_STRETCH_EXPANDED;
2551 return stretch;
2554 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2555 struct name_token *match)
2557 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2558 static const WCHAR nordW[] = {'n','o','r','d',0};
2560 static const struct name_pattern thin_patterns[] = {
2561 { extraW, thinW },
2562 { extW, thinW },
2563 { ultraW, thinW },
2564 { NULL }
2567 static const struct name_pattern extralight_patterns[] = {
2568 { extraW, lightW },
2569 { extW, lightW },
2570 { ultraW, lightW },
2571 { NULL }
2574 static const struct name_pattern semilight_patterns[] = {
2575 { semiW, lightW },
2576 { NULL }
2579 static const struct name_pattern demibold_patterns[] = {
2580 { semiW, boldW },
2581 { demiW, boldW },
2582 { NULL }
2585 static const struct name_pattern extrabold_patterns[] = {
2586 { extraW, boldW },
2587 { extW, boldW },
2588 { ultraW, boldW },
2589 { NULL }
2592 static const struct name_pattern extrablack_patterns[] = {
2593 { extraW, blackW },
2594 { extW, blackW },
2595 { ultraW, blackW },
2596 { NULL }
2599 static const struct name_pattern bold_patterns[] = {
2600 { boldW },
2601 { NULL }
2604 static const struct name_pattern thin2_patterns[] = {
2605 { thinW },
2606 { NULL }
2609 static const struct name_pattern light_patterns[] = {
2610 { lightW },
2611 { NULL }
2614 static const struct name_pattern medium_patterns[] = {
2615 { mediumW },
2616 { NULL }
2619 static const struct name_pattern black_patterns[] = {
2620 { blackW },
2621 { heavyW },
2622 { nordW },
2623 { NULL }
2626 static const struct name_pattern demibold2_patterns[] = {
2627 { demiW },
2628 { NULL }
2631 static const struct name_pattern extrabold2_patterns[] = {
2632 { ultraW },
2633 { NULL }
2636 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2637 matching pattern. */
2639 if (match_pattern_list(tokens, thin_patterns, match))
2640 return DWRITE_FONT_WEIGHT_THIN;
2642 if (match_pattern_list(tokens, extralight_patterns, match))
2643 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2645 if (match_pattern_list(tokens, semilight_patterns, match))
2646 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2648 if (match_pattern_list(tokens, demibold_patterns, match))
2649 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2651 if (match_pattern_list(tokens, extrabold_patterns, match))
2652 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2654 if (match_pattern_list(tokens, extrablack_patterns, match))
2655 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2657 if (match_pattern_list(tokens, bold_patterns, match))
2658 return DWRITE_FONT_WEIGHT_BOLD;
2660 if (match_pattern_list(tokens, thin2_patterns, match))
2661 return DWRITE_FONT_WEIGHT_THIN;
2663 if (match_pattern_list(tokens, light_patterns, match))
2664 return DWRITE_FONT_WEIGHT_LIGHT;
2666 if (match_pattern_list(tokens, medium_patterns, match))
2667 return DWRITE_FONT_WEIGHT_MEDIUM;
2669 if (match_pattern_list(tokens, black_patterns, match))
2670 return DWRITE_FONT_WEIGHT_BLACK;
2672 if (match_pattern_list(tokens, black_patterns, match))
2673 return DWRITE_FONT_WEIGHT_BLACK;
2675 if (match_pattern_list(tokens, demibold2_patterns, match))
2676 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2678 if (match_pattern_list(tokens, extrabold2_patterns, match))
2679 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2681 /* FIXME: use abbreviated names to extract weight */
2683 return weight;
2686 struct knownweight_entry {
2687 const WCHAR *nameW;
2688 DWRITE_FONT_WEIGHT weight;
2691 static int compare_knownweights(const void *a, const void* b)
2693 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2694 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2695 int ret = 0;
2697 if (target > entry->weight)
2698 ret = 1;
2699 else if (target < entry->weight)
2700 ret = -1;
2702 return ret;
2705 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2707 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2708 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2709 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2710 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2711 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2712 const struct knownweight_entry *ptr;
2714 static const struct knownweight_entry knownweights[] = {
2715 { thinW, DWRITE_FONT_WEIGHT_THIN },
2716 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2717 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2718 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2719 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2720 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2721 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2722 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2723 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2724 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2727 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2728 compare_knownweights);
2729 if (!ptr) {
2730 nameW[0] = 0;
2731 return FALSE;
2734 strcpyW(nameW, ptr->nameW);
2735 return TRUE;
2738 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2740 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2741 strW[name->len] = 0;
2744 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2745 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2747 static const WCHAR bookW[] = {'B','o','o','k',0};
2748 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2749 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2750 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2751 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2753 static const WCHAR *regular_patterns[] = {
2754 bookW,
2755 normalW,
2756 regularW,
2757 romanW,
2758 uprightW,
2759 NULL
2762 const WCHAR *regular_ptr = NULL, *ptr;
2763 int i = 0;
2765 if (len == -1)
2766 len = strlenW(facenameW);
2768 /* remove rightmost regular variant from face name */
2769 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2770 int pattern_len = strlenW(ptr);
2771 WCHAR *src;
2773 if (pattern_len > len)
2774 continue;
2776 src = facenameW + len - pattern_len;
2777 while (src >= facenameW) {
2778 if (!strncmpiW(src, ptr, pattern_len)) {
2779 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2780 len = strlenW(facenameW);
2781 regular_ptr = ptr;
2782 break;
2784 else
2785 src--;
2789 return regular_ptr;
2792 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2794 const WCHAR *ptr;
2796 list_init(tokens);
2797 ptr = nameW;
2799 while (*ptr) {
2800 struct name_token *token = heap_alloc(sizeof(*token));
2801 token->ptr = ptr;
2802 token->len = 0;
2803 token->fulllen = 0;
2805 while (*ptr && !is_name_separator_char(*ptr)) {
2806 token->len++;
2807 token->fulllen++;
2808 ptr++;
2811 /* skip separators */
2812 while (is_name_separator_char(*ptr)) {
2813 token->fulllen++;
2814 ptr++;
2817 list_add_head(tokens, &token->entry);
2821 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2823 struct name_token *token, *token2;
2824 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2825 int len;
2827 list_remove(&token->entry);
2829 /* don't include last separator */
2830 len = list_empty(tokens) ? token->len : token->fulllen;
2831 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2832 nameW += len;
2834 heap_free(token);
2836 *nameW = 0;
2839 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2841 struct name_token stretch_name, weight_name, style_name;
2842 WCHAR familynameW[255], facenameW[255], finalW[255];
2843 WCHAR weightW[32], stretchW[32], styleW[32];
2844 const WCHAR *regular_ptr = NULL;
2845 DWRITE_FONT_STRETCH stretch;
2846 DWRITE_FONT_WEIGHT weight;
2847 struct list tokens;
2848 int len;
2850 /* remove leading and trailing spaces from family and face name */
2851 trim_spaces(familyW, familynameW);
2852 len = trim_spaces(faceW, facenameW);
2854 /* remove rightmost regular variant from face name */
2855 regular_ptr = facename_remove_regular_term(facenameW, len);
2857 /* append face name to family name, FIXME check if face name is a substring of family name */
2858 if (*facenameW) {
2859 strcatW(familynameW, spaceW);
2860 strcatW(familynameW, facenameW);
2863 /* tokenize with " .-_" */
2864 fontname_tokenize(&tokens, familynameW);
2866 /* extract and resolve style */
2867 font->style = font_extract_style(&tokens, font->style, &style_name);
2869 /* extract stretch */
2870 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2872 /* extract weight */
2873 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2875 /* resolve weight */
2876 if (weight != font->weight) {
2877 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2878 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2879 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2880 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2881 !(abs(weight - font->weight) <= 150 &&
2882 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2883 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2884 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2886 font->weight = weight;
2890 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2891 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2892 stretch itself is normal (extracted stretch is never normal). */
2893 if (stretch != font->stretch) {
2894 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2895 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2896 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2898 font->stretch = stretch;
2902 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2904 /* get final combined string from what's left in token list, list is released */
2905 fontname_tokens_to_str(&tokens, finalW);
2907 if (!strcmpW(familyW, finalW))
2908 return FALSE;
2910 /* construct face name */
2911 strcpyW(familyW, finalW);
2913 /* resolved weight name */
2914 if (weight_name.ptr)
2915 font_name_token_to_str(&weight_name, weightW);
2916 /* ignore normal weight */
2917 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2918 weightW[0] = 0;
2919 /* for known weight values use appropriate names */
2920 else if (is_known_weight_value(font->weight, weightW)) {
2922 /* use Wnnn format as a fallback in case weight is not one of known values */
2923 else {
2924 static const WCHAR fmtW[] = {'W','%','d',0};
2925 sprintfW(weightW, fmtW, font->weight);
2928 /* resolved stretch name */
2929 if (stretch_name.ptr)
2930 font_name_token_to_str(&stretch_name, stretchW);
2931 /* ignore normal stretch */
2932 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2933 stretchW[0] = 0;
2934 /* use predefined stretch names */
2935 else {
2936 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2937 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2938 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2939 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2940 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2941 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2943 static const WCHAR *stretchnamesW[] = {
2944 ultracondensedW,
2945 extracondensedW,
2946 condensedW,
2947 semicondensedW,
2948 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
2949 semiexpandedW,
2950 expandedW,
2951 extraexpandedW,
2952 ultraexpandedW
2954 strcpyW(stretchW, stretchnamesW[font->stretch]);
2957 /* resolved style name */
2958 if (style_name.ptr)
2959 font_name_token_to_str(&style_name, styleW);
2960 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
2961 styleW[0] = 0;
2962 /* use predefined names */
2963 else {
2964 if (font->style == DWRITE_FONT_STYLE_ITALIC)
2965 strcpyW(styleW, italicW);
2966 else
2967 strcpyW(styleW, obliqueW);
2970 /* use Regular match if it was found initially */
2971 if (!*weightW && !*stretchW && !*styleW)
2972 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
2973 else {
2974 faceW[0] = 0;
2975 if (*stretchW)
2976 strcpyW(faceW, stretchW);
2977 if (*weightW) {
2978 if (*faceW)
2979 strcatW(faceW, spaceW);
2980 strcatW(faceW, weightW);
2982 if (*styleW) {
2983 if (*faceW)
2984 strcatW(faceW, spaceW);
2985 strcatW(faceW, styleW);
2989 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
2990 return TRUE;
2993 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
2994 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
2996 struct dwrite_font_props props;
2997 struct dwrite_font_data *data;
2998 IDWriteFontFileStream *stream;
2999 WCHAR familyW[255], faceW[255];
3000 HRESULT hr;
3002 *ret = NULL;
3003 data = heap_alloc_zero(sizeof(*data));
3004 if (!data)
3005 return E_OUTOFMEMORY;
3007 hr = get_filestream_from_file(file, &stream);
3008 if (FAILED(hr)) {
3009 heap_free(data);
3010 return hr;
3013 data->ref = 1;
3014 data->factory = factory;
3015 data->file = file;
3016 data->face_index = face_index;
3017 data->face_type = face_type;
3018 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3019 data->bold_sim_tested = 0;
3020 data->oblique_sim_tested = 0;
3021 IDWriteFontFile_AddRef(file);
3022 IDWriteFactory2_AddRef(factory);
3024 opentype_get_font_properties(stream, face_type, face_index, &props);
3025 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
3026 opentype_get_font_facename(stream, face_type, face_index, &data->names);
3028 /* get family name from font file */
3029 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
3030 IDWriteFontFileStream_Release(stream);
3031 if (FAILED(hr)) {
3032 WARN("unable to get family name from font\n");
3033 release_font_data(data);
3034 return hr;
3037 data->style = props.style;
3038 data->stretch = props.stretch;
3039 data->weight = props.weight;
3040 data->panose = props.panose;
3042 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3043 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3044 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3045 set_en_localizedstring(*family_name, familyW);
3046 set_en_localizedstring(data->names, faceW);
3049 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3051 *ret = data;
3052 return S_OK;
3055 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
3056 struct dwrite_font_data **ret)
3058 struct dwrite_font_data *data;
3060 *ret = NULL;
3061 data = heap_alloc_zero(sizeof(*data));
3062 if (!data)
3063 return E_OUTOFMEMORY;
3065 *data = *src;
3066 data->ref = 1;
3067 data->simulations |= sim;
3068 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3069 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3070 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3071 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3072 memset(data->info_strings, 0, sizeof(data->info_strings));
3073 data->names = NULL;
3074 IDWriteFactory2_AddRef(data->factory);
3075 IDWriteFontFile_AddRef(data->file);
3077 create_localizedstrings(&data->names);
3078 add_localizedstring(data->names, enusW, facenameW);
3080 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3082 *ret = data;
3083 return S_OK;
3086 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3088 struct dwrite_fontfamily_data *data;
3090 data = heap_alloc(sizeof(*data));
3091 if (!data)
3092 return E_OUTOFMEMORY;
3094 data->ref = 1;
3095 data->font_count = 0;
3096 data->font_alloc = 2;
3097 data->has_normal_face = 0;
3098 data->has_oblique_face = 0;
3099 data->has_italic_face = 0;
3101 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3102 if (!data->fonts) {
3103 heap_free(data);
3104 return E_OUTOFMEMORY;
3107 data->familyname = familyname;
3108 IDWriteLocalizedStrings_AddRef(familyname);
3110 *ret = data;
3111 return S_OK;
3114 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3116 UINT32 i, j, heaviest;
3118 for (i = 0; i < family->font_count; i++) {
3119 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3120 heaviest = i;
3122 if (family->fonts[i]->bold_sim_tested)
3123 continue;
3125 family->fonts[i]->bold_sim_tested = 1;
3126 for (j = i; j < family->font_count; j++) {
3127 if (family->fonts[j]->bold_sim_tested)
3128 continue;
3130 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3131 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3132 if (family->fonts[j]->weight > weight) {
3133 weight = family->fonts[j]->weight;
3134 heaviest = j;
3136 family->fonts[j]->bold_sim_tested = 1;
3140 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3141 static const struct name_pattern weightsim_patterns[] = {
3142 { extraW, lightW },
3143 { extW, lightW },
3144 { ultraW, lightW },
3145 { semiW, lightW },
3146 { semiW, boldW },
3147 { demiW, boldW },
3148 { boldW },
3149 { thinW },
3150 { lightW },
3151 { mediumW },
3152 { demiW },
3153 { NULL }
3156 WCHAR facenameW[255], initialW[255];
3157 struct dwrite_font_data *boldface;
3158 struct list tokens;
3160 /* add Bold simulation based on heaviest face data */
3162 /* Simulated face name should only contain Bold as weight term,
3163 so remove existing regular and weight terms. */
3164 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3165 facename_remove_regular_term(initialW, -1);
3167 /* remove current weight pattern */
3168 fontname_tokenize(&tokens, initialW);
3169 match_pattern_list(&tokens, weightsim_patterns, NULL);
3170 fontname_tokens_to_str(&tokens, facenameW);
3172 /* Bold suffix for new name */
3173 if (*facenameW)
3174 strcatW(facenameW, spaceW);
3175 strcatW(facenameW, boldW);
3177 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3178 boldface->bold_sim_tested = 1;
3179 fontfamily_add_font(family, boldface);
3185 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3187 UINT32 i, j;
3189 for (i = 0; i < family->font_count; i++) {
3190 UINT32 regular = ~0u, oblique = ~0u;
3191 struct dwrite_font_data *obliqueface;
3192 WCHAR facenameW[255];
3194 if (family->fonts[i]->oblique_sim_tested)
3195 continue;
3197 family->fonts[i]->oblique_sim_tested = 1;
3198 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3199 regular = i;
3200 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3201 oblique = i;
3203 /* find regular style with same weight/stretch values */
3204 for (j = i; j < family->font_count; j++) {
3205 if (family->fonts[j]->oblique_sim_tested)
3206 continue;
3208 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3209 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3211 family->fonts[j]->oblique_sim_tested = 1;
3212 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3213 regular = j;
3215 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3216 oblique = j;
3219 if (regular != ~0u && oblique != ~0u)
3220 break;
3223 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3224 if (regular == ~0u)
3225 continue;
3227 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3228 if (oblique != ~0u)
3229 continue;
3231 /* add oblique simulation based on this regular face */
3233 /* remove regular term if any, append 'Oblique' */
3234 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3235 facename_remove_regular_term(facenameW, -1);
3237 if (*facenameW)
3238 strcatW(facenameW, spaceW);
3239 strcatW(facenameW, obliqueW);
3241 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3242 obliqueface->oblique_sim_tested = 1;
3243 fontfamily_add_font(family, obliqueface);
3248 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3249 const WCHAR *replacement_name)
3251 UINT32 i = collection_find_family(collection, replacement_name);
3252 struct dwrite_fontfamily_data *target;
3253 IDWriteLocalizedStrings *strings;
3254 HRESULT hr;
3256 /* replacement does not exist */
3257 if (i == ~0u)
3258 return FALSE;
3260 hr = create_localizedstrings(&strings);
3261 if (FAILED(hr))
3262 return FALSE;
3264 /* add a new family with target name, reuse font data from replacement */
3265 add_localizedstring(strings, enusW, target_name);
3266 hr = init_fontfamily_data(strings, &target);
3267 if (hr == S_OK) {
3268 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3269 WCHAR nameW[255];
3271 for (i = 0; i < replacement->font_count; i++)
3272 fontfamily_add_font(target, replacement->fonts[i]);
3274 fontcollection_add_family(collection, target);
3275 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3276 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3278 IDWriteLocalizedStrings_Release(strings);
3279 return TRUE;
3282 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3283 system font collections. */
3284 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3286 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3287 WCHAR *name;
3288 void *data;
3289 HKEY hkey;
3291 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3292 return;
3294 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3295 RegCloseKey(hkey);
3296 return;
3299 max_namelen++; /* returned value doesn't include room for '\0' */
3300 name = heap_alloc(max_namelen * sizeof(WCHAR));
3301 data = heap_alloc(max_datalen);
3303 datalen = max_datalen;
3304 namelen = max_namelen;
3305 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3306 if (collection_find_family(collection, name) == ~0u) {
3307 if (type == REG_MULTI_SZ) {
3308 WCHAR *replacement = data;
3309 while (*replacement) {
3310 if (fontcollection_add_replacement(collection, name, replacement))
3311 break;
3312 replacement += strlenW(replacement) + 1;
3315 else if (type == REG_SZ)
3316 fontcollection_add_replacement(collection, name, data);
3318 else
3319 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3321 datalen = max_datalen;
3322 namelen = max_namelen;
3325 heap_free(data);
3326 heap_free(name);
3327 RegCloseKey(hkey);
3330 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3332 struct fontfile_enum {
3333 struct list entry;
3334 IDWriteFontFile *file;
3336 struct fontfile_enum *fileenum, *fileenum2;
3337 struct dwrite_fontcollection *collection;
3338 struct list scannedfiles;
3339 BOOL current = FALSE;
3340 HRESULT hr = S_OK;
3341 UINT32 i;
3343 *ret = NULL;
3345 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3346 if (!collection) return E_OUTOFMEMORY;
3348 hr = init_font_collection(collection, is_system);
3349 if (FAILED(hr)) {
3350 heap_free(collection);
3351 return hr;
3354 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3356 TRACE("building font collection:\n");
3358 list_init(&scannedfiles);
3359 while (hr == S_OK) {
3360 DWRITE_FONT_FACE_TYPE face_type;
3361 DWRITE_FONT_FILE_TYPE file_type;
3362 BOOL supported, same = FALSE;
3363 IDWriteFontFile *file;
3364 UINT32 face_count;
3366 current = FALSE;
3367 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3368 if (FAILED(hr) || !current)
3369 break;
3371 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3372 if (FAILED(hr))
3373 break;
3375 /* check if we've scanned this file already */
3376 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3377 if ((same = is_same_fontfile(fileenum->file, file)))
3378 break;
3381 if (same) {
3382 IDWriteFontFile_Release(file);
3383 continue;
3386 /* failed font files are skipped */
3387 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3388 if (FAILED(hr) || !supported || face_count == 0) {
3389 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3390 IDWriteFontFile_Release(file);
3391 hr = S_OK;
3392 continue;
3395 /* add to scanned list */
3396 fileenum = heap_alloc(sizeof(*fileenum));
3397 fileenum->file = file;
3398 list_add_tail(&scannedfiles, &fileenum->entry);
3400 for (i = 0; i < face_count; i++) {
3401 IDWriteLocalizedStrings *family_name = NULL;
3402 struct dwrite_font_data *font_data;
3403 WCHAR familyW[255];
3404 UINT32 index;
3406 /* alloc and init new font data structure */
3407 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3408 if (FAILED(hr)) {
3409 /* move to next one */
3410 hr = S_OK;
3411 continue;
3414 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3416 index = collection_find_family(collection, familyW);
3417 if (index != ~0u)
3418 hr = fontfamily_add_font(collection->family_data[index], font_data);
3419 else {
3420 struct dwrite_fontfamily_data *family_data;
3422 /* create and init new family */
3423 hr = init_fontfamily_data(family_name, &family_data);
3424 if (hr == S_OK) {
3425 /* add font to family, family - to collection */
3426 hr = fontfamily_add_font(family_data, font_data);
3427 if (hr == S_OK)
3428 hr = fontcollection_add_family(collection, family_data);
3430 if (FAILED(hr))
3431 release_fontfamily_data(family_data);
3435 IDWriteLocalizedStrings_Release(family_name);
3437 if (FAILED(hr))
3438 break;
3442 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3443 IDWriteFontFile_Release(fileenum->file);
3444 list_remove(&fileenum->entry);
3445 heap_free(fileenum);
3448 for (i = 0; i < collection->family_count; i++) {
3449 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3450 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3453 if (is_system)
3454 fontcollection_add_replacements(collection);
3456 return hr;
3459 struct system_fontfile_enumerator
3461 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3462 LONG ref;
3464 IDWriteFactory2 *factory;
3465 HKEY hkey;
3466 int index;
3469 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3471 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3474 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3476 *obj = NULL;
3478 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3479 IDWriteFontFileEnumerator_AddRef(iface);
3480 *obj = iface;
3481 return S_OK;
3484 return E_NOINTERFACE;
3487 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3489 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3490 return InterlockedIncrement(&enumerator->ref);
3493 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3495 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3496 ULONG ref = InterlockedDecrement(&enumerator->ref);
3498 if (!ref) {
3499 IDWriteFactory2_Release(enumerator->factory);
3500 RegCloseKey(enumerator->hkey);
3501 heap_free(enumerator);
3504 return ref;
3507 static HRESULT create_local_file_reference(IDWriteFactory2 *factory, const WCHAR *filename, IDWriteFontFile **file)
3509 HRESULT hr;
3511 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3512 if (!strchrW(filename, '\\')) {
3513 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3514 WCHAR fullpathW[MAX_PATH];
3516 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3517 strcatW(fullpathW, fontsW);
3518 strcatW(fullpathW, filename);
3520 hr = IDWriteFactory2_CreateFontFileReference(factory, fullpathW, NULL, file);
3522 else
3523 hr = IDWriteFactory2_CreateFontFileReference(factory, filename, NULL, file);
3525 return hr;
3528 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3530 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3531 DWORD ret, type, val_count, count;
3532 WCHAR *value, *filename;
3533 HRESULT hr;
3535 *file = NULL;
3537 if (enumerator->index < 0)
3538 return E_FAIL;
3540 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3541 if (ret != ERROR_SUCCESS)
3542 return E_FAIL;
3544 val_count++;
3545 value = heap_alloc( val_count * sizeof(value[0]) );
3546 filename = heap_alloc(count);
3547 if (!value || !filename) {
3548 heap_free(value);
3549 heap_free(filename);
3550 return E_OUTOFMEMORY;
3553 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3554 if (ret) {
3555 heap_free(value);
3556 heap_free(filename);
3557 return E_FAIL;
3560 hr = create_local_file_reference(enumerator->factory, filename, file);
3562 heap_free(value);
3563 heap_free(filename);
3564 return hr;
3567 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3569 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3570 DWORD ret, max_val_count;
3571 WCHAR *value;
3573 *current = FALSE;
3574 enumerator->index++;
3576 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3577 if (ret != ERROR_SUCCESS)
3578 return E_FAIL;
3580 max_val_count++;
3581 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3582 return E_OUTOFMEMORY;
3584 /* iterate until we find next string value */
3585 while (1) {
3586 DWORD type = 0, count, val_count;
3587 val_count = max_val_count;
3588 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3589 break;
3590 if (type == REG_SZ) {
3591 *current = TRUE;
3592 break;
3594 enumerator->index++;
3597 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3598 heap_free(value);
3599 return S_OK;
3602 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3604 systemfontfileenumerator_QueryInterface,
3605 systemfontfileenumerator_AddRef,
3606 systemfontfileenumerator_Release,
3607 systemfontfileenumerator_MoveNext,
3608 systemfontfileenumerator_GetCurrentFontFile
3611 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
3613 struct system_fontfile_enumerator *enumerator;
3614 static const WCHAR fontslistW[] = {
3615 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3616 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3617 'F','o','n','t','s',0
3620 *ret = NULL;
3622 enumerator = heap_alloc(sizeof(*enumerator));
3623 if (!enumerator)
3624 return E_OUTOFMEMORY;
3626 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3627 enumerator->ref = 1;
3628 enumerator->factory = factory;
3629 enumerator->index = -1;
3630 IDWriteFactory2_AddRef(factory);
3632 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3633 ERR("failed to open fonts list key\n");
3634 IDWriteFactory2_Release(factory);
3635 heap_free(enumerator);
3636 return E_FAIL;
3639 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3641 return S_OK;
3644 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3646 IDWriteFontFileEnumerator *enumerator;
3647 HRESULT hr;
3649 *collection = NULL;
3651 hr = create_system_fontfile_enumerator(factory, &enumerator);
3652 if (FAILED(hr))
3653 return hr;
3655 TRACE("building system font collection for factory %p\n", factory);
3656 hr = create_font_collection(factory, enumerator, TRUE, collection);
3657 IDWriteFontFileEnumerator_Release(enumerator);
3658 return hr;
3661 static HRESULT eudc_collection_add_family(IDWriteFactory2 *factory, struct dwrite_fontcollection *collection,
3662 const WCHAR *keynameW, const WCHAR *pathW)
3664 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};
3665 static const WCHAR emptyW[] = {0};
3666 IDWriteLocalizedStrings *names;
3667 DWRITE_FONT_FACE_TYPE face_type;
3668 DWRITE_FONT_FILE_TYPE file_type;
3669 BOOL supported;
3670 UINT32 face_count, i;
3671 IDWriteFontFile *file;
3672 HRESULT hr;
3673 struct dwrite_fontfamily_data *family_data;
3675 /* create font file from this path */
3676 hr = create_local_file_reference(factory, pathW, &file);
3677 if (FAILED(hr))
3678 return S_FALSE;
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 return S_FALSE;
3688 /* create and init new family */
3690 /* Family names are added for non-specific locale, represented with empty string.
3691 Default family appears with empty family name. */
3692 create_localizedstrings(&names);
3693 if (!strcmpiW(keynameW, defaultfontW))
3694 add_localizedstring(names, emptyW, emptyW);
3695 else
3696 add_localizedstring(names, emptyW, keynameW);
3698 hr = init_fontfamily_data(names, &family_data);
3699 IDWriteLocalizedStrings_Release(names);
3700 if (hr != S_OK) {
3701 IDWriteFontFile_Release(file);
3702 return hr;
3705 /* fill with faces */
3706 for (i = 0; i < face_count; i++) {
3707 struct dwrite_font_data *font_data;
3709 /* alloc and init new font data structure */
3710 hr = init_font_data(factory, file, face_type, i, &names, &font_data);
3711 if (FAILED(hr))
3712 continue;
3714 IDWriteLocalizedStrings_Release(names);
3716 /* add font to family */
3717 hr = fontfamily_add_font(family_data, font_data);
3718 if (hr != S_OK)
3719 release_font_data(font_data);
3722 /* add family to collection */
3723 hr = fontcollection_add_family(collection, family_data);
3724 if (FAILED(hr))
3725 release_fontfamily_data(family_data);
3726 IDWriteFontFile_Release(file);
3728 return hr;
3731 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **ret)
3733 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3734 struct dwrite_fontcollection *collection;
3735 static const WCHAR emptyW[] = {0};
3736 WCHAR eudckeypathW[16];
3737 HKEY eudckey;
3738 DWORD index;
3739 BOOL exists;
3740 LONG retval;
3741 HRESULT hr;
3742 UINT32 i;
3744 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3746 *ret = NULL;
3748 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3749 if (!collection) return E_OUTOFMEMORY;
3751 hr = init_font_collection(collection, FALSE);
3752 if (FAILED(hr)) {
3753 heap_free(collection);
3754 return hr;
3757 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3759 /* return empty collection if EUDC fonts are not configured */
3760 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3761 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3762 return S_OK;
3764 retval = ERROR_SUCCESS;
3765 index = 0;
3766 while (retval != ERROR_NO_MORE_ITEMS) {
3767 WCHAR keynameW[64], pathW[MAX_PATH];
3768 DWORD type, path_len, name_len;
3770 path_len = sizeof(pathW)/sizeof(*pathW);
3771 name_len = sizeof(keynameW)/sizeof(*keynameW);
3772 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3773 if (retval || type != REG_SZ)
3774 continue;
3776 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3777 if (hr != S_OK)
3778 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3780 RegCloseKey(eudckey);
3782 /* try to add global default if not defined for specific codepage */
3783 exists = FALSE;
3784 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
3785 &index, &exists);
3786 if (FAILED(hr) || !exists) {
3787 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3788 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3789 if (hr != S_OK)
3790 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3793 /* EUDC collection offers simulated faces too */
3794 for (i = 0; i < collection->family_count; i++) {
3795 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3796 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3799 return S_OK;
3802 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3804 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3806 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3808 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3810 *obj = iface;
3811 IDWriteFontFile_AddRef(iface);
3812 return S_OK;
3815 *obj = NULL;
3816 return E_NOINTERFACE;
3819 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3821 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3822 ULONG ref = InterlockedIncrement(&This->ref);
3823 TRACE("(%p)->(%d)\n", This, ref);
3824 return ref;
3827 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3829 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3830 ULONG ref = InterlockedDecrement(&This->ref);
3832 TRACE("(%p)->(%d)\n", This, ref);
3834 if (!ref)
3836 IDWriteFontFileLoader_Release(This->loader);
3837 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3838 heap_free(This->reference_key);
3839 heap_free(This);
3842 return ref;
3845 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3847 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3848 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3849 *fontFileReferenceKey = This->reference_key;
3850 *fontFileReferenceKeySize = This->key_size;
3852 return S_OK;
3855 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3857 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3858 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3859 *fontFileLoader = This->loader;
3860 IDWriteFontFileLoader_AddRef(This->loader);
3862 return S_OK;
3865 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
3866 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3868 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3869 IDWriteFontFileStream *stream;
3870 HRESULT hr;
3872 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3874 *isSupportedFontType = FALSE;
3875 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3876 if (fontFaceType)
3877 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3878 *numberOfFaces = 0;
3880 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3881 if (FAILED(hr))
3882 return hr;
3884 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3886 /* TODO: Further Analysis */
3887 IDWriteFontFileStream_Release(stream);
3888 return S_OK;
3891 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3892 dwritefontfile_QueryInterface,
3893 dwritefontfile_AddRef,
3894 dwritefontfile_Release,
3895 dwritefontfile_GetReferenceKey,
3896 dwritefontfile_GetLoader,
3897 dwritefontfile_Analyze,
3900 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3902 struct dwrite_fontfile *This;
3904 This = heap_alloc(sizeof(struct dwrite_fontfile));
3905 if (!This) return E_OUTOFMEMORY;
3907 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3908 This->ref = 1;
3909 IDWriteFontFileLoader_AddRef(loader);
3910 This->loader = loader;
3911 This->stream = NULL;
3912 This->reference_key = heap_alloc(key_size);
3913 memcpy(This->reference_key, reference_key, key_size);
3914 This->key_size = key_size;
3916 *font_file = &This->IDWriteFontFile_iface;
3918 return S_OK;
3921 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3923 IDWriteFontFileLoader *loader;
3924 UINT32 key_size;
3925 const void *key;
3926 HRESULT hr;
3928 *stream = NULL;
3929 hr = IDWriteFontFile_GetLoader(file, &loader);
3930 if (FAILED(hr))
3931 return hr;
3933 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3934 if (FAILED(hr)) {
3935 IDWriteFontFileLoader_Release(loader);
3936 return hr;
3939 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3940 IDWriteFontFileLoader_Release(loader);
3942 return hr;
3945 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
3946 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
3948 struct dwrite_fontface *fontface;
3949 HRESULT hr = S_OK;
3950 int i;
3952 *ret = NULL;
3954 fontface = heap_alloc(sizeof(struct dwrite_fontface));
3955 if (!fontface)
3956 return E_OUTOFMEMORY;
3958 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
3959 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
3961 if (!fontface->files || !fontface->streams) {
3962 heap_free(fontface->files);
3963 heap_free(fontface->streams);
3964 heap_free(fontface);
3965 return E_OUTOFMEMORY;
3968 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
3969 fontface->ref = 1;
3970 fontface->type = facetype;
3971 fontface->file_count = files_number;
3972 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
3973 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
3974 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
3975 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
3976 memset(&fontface->colr, 0, sizeof(fontface->colr));
3977 fontface->cmap.exists = TRUE;
3978 fontface->vdmx.exists = TRUE;
3979 fontface->gasp.exists = TRUE;
3980 fontface->cpal.exists = TRUE;
3981 fontface->colr.exists = TRUE;
3982 fontface->index = index;
3983 fontface->simulations = simulations;
3984 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
3986 for (i = 0; i < fontface->file_count; i++) {
3987 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
3988 if (FAILED(hr)) {
3989 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
3990 return hr;
3993 fontface->files[i] = font_files[i];
3994 IDWriteFontFile_AddRef(font_files[i]);
3997 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
3998 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
3999 /* TODO: test what happens if caret is already slanted */
4000 if (fontface->caret.slopeRise == 1) {
4001 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4002 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4005 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
4006 fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
4007 fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
4009 *ret = &fontface->IDWriteFontFace3_iface;
4010 return S_OK;
4013 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4014 struct local_refkey
4016 FILETIME writetime;
4017 WCHAR name[1];
4020 struct local_cached_stream
4022 struct list entry;
4023 IDWriteFontFileStream *stream;
4024 struct local_refkey *key;
4025 UINT32 key_size;
4028 struct dwrite_localfontfilestream
4030 IDWriteFontFileStream IDWriteFontFileStream_iface;
4031 LONG ref;
4033 struct local_cached_stream *entry;
4034 const void *file_ptr;
4035 UINT64 size;
4038 struct dwrite_localfontfileloader {
4039 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4040 LONG ref;
4042 struct list streams;
4045 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4047 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4050 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4052 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4055 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4057 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4058 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4059 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4061 *obj = iface;
4062 IDWriteFontFileStream_AddRef(iface);
4063 return S_OK;
4066 *obj = NULL;
4067 return E_NOINTERFACE;
4070 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4072 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4073 ULONG ref = InterlockedIncrement(&This->ref);
4074 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4075 return ref;
4078 static inline void release_cached_stream(struct local_cached_stream *stream)
4080 list_remove(&stream->entry);
4081 heap_free(stream->key);
4082 heap_free(stream);
4085 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4087 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4088 ULONG ref = InterlockedDecrement(&This->ref);
4090 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4092 if (!ref) {
4093 UnmapViewOfFile(This->file_ptr);
4094 release_cached_stream(This->entry);
4095 heap_free(This);
4098 return ref;
4101 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
4103 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4105 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
4106 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4108 *fragment_context = NULL;
4110 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4111 *fragment_start = NULL;
4112 return E_FAIL;
4115 *fragment_start = (char*)This->file_ptr + offset;
4116 return S_OK;
4119 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4121 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4122 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4125 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4127 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4128 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4129 *size = This->size;
4130 return S_OK;
4133 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4135 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4136 ULARGE_INTEGER li;
4138 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4140 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4141 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4142 *last_writetime = li.QuadPart;
4144 return S_OK;
4147 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4149 localfontfilestream_QueryInterface,
4150 localfontfilestream_AddRef,
4151 localfontfilestream_Release,
4152 localfontfilestream_ReadFileFragment,
4153 localfontfilestream_ReleaseFileFragment,
4154 localfontfilestream_GetFileSize,
4155 localfontfilestream_GetLastWriteTime
4158 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4160 struct dwrite_localfontfilestream *This;
4162 *ret = NULL;
4164 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4165 if (!This)
4166 return E_OUTOFMEMORY;
4168 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4169 This->ref = 1;
4171 This->file_ptr = file_ptr;
4172 This->size = size;
4173 This->entry = entry;
4175 *ret = &This->IDWriteFontFileStream_iface;
4176 return S_OK;
4179 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4181 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4183 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4185 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4187 *obj = iface;
4188 IDWriteLocalFontFileLoader_AddRef(iface);
4189 return S_OK;
4192 *obj = NULL;
4193 return E_NOINTERFACE;
4196 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4198 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4199 ULONG ref = InterlockedIncrement(&This->ref);
4200 TRACE("(%p)->(%d)\n", This, ref);
4201 return ref;
4204 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4206 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4207 ULONG ref = InterlockedDecrement(&This->ref);
4209 TRACE("(%p)->(%d)\n", This, ref);
4211 if (!ref) {
4212 struct local_cached_stream *stream, *stream2;
4214 /* This will detach all entries from cache. Entries are released together with streams,
4215 so stream controls cache entry lifetime. */
4216 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4217 list_init(&stream->entry);
4219 heap_free(This);
4222 return ref;
4225 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4227 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4228 const struct local_refkey *refkey = key;
4229 struct local_cached_stream *stream;
4230 IDWriteFontFileStream *filestream;
4231 HANDLE file, mapping;
4232 LARGE_INTEGER size;
4233 void *file_ptr;
4234 HRESULT hr;
4236 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4237 TRACE("name: %s\n", debugstr_w(refkey->name));
4239 /* search cache first */
4240 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4241 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4242 *ret = stream->stream;
4243 IDWriteFontFileStream_AddRef(*ret);
4244 return S_OK;
4248 *ret = NULL;
4250 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4251 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4252 if (file == INVALID_HANDLE_VALUE)
4253 return E_FAIL;
4255 GetFileSizeEx(file, &size);
4256 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4257 CloseHandle(file);
4258 if (!mapping)
4259 return E_FAIL;
4261 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4262 CloseHandle(mapping);
4264 stream = heap_alloc(sizeof(*stream));
4265 if (!stream) {
4266 UnmapViewOfFile(file_ptr);
4267 return E_OUTOFMEMORY;
4270 stream->key = heap_alloc(key_size);
4271 if (!stream->key) {
4272 UnmapViewOfFile(file_ptr);
4273 heap_free(stream);
4274 return E_OUTOFMEMORY;
4277 stream->key_size = key_size;
4278 memcpy(stream->key, key, key_size);
4280 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4281 if (FAILED(hr)) {
4282 UnmapViewOfFile(file_ptr);
4283 heap_free(stream->key);
4284 heap_free(stream);
4285 return hr;
4288 stream->stream = filestream;
4289 list_add_head(&This->streams, &stream->entry);
4291 *ret = stream->stream;
4293 return S_OK;
4296 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4298 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4299 const struct local_refkey *refkey = key;
4301 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4303 *length = strlenW(refkey->name);
4304 return S_OK;
4307 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4309 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4310 const struct local_refkey *refkey = key;
4312 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4314 if (length < strlenW(refkey->name))
4315 return E_INVALIDARG;
4317 strcpyW(path, refkey->name);
4318 return S_OK;
4321 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4323 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4324 const struct local_refkey *refkey = key;
4326 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4328 *writetime = refkey->writetime;
4329 return S_OK;
4332 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4333 localfontfileloader_QueryInterface,
4334 localfontfileloader_AddRef,
4335 localfontfileloader_Release,
4336 localfontfileloader_CreateStreamFromKey,
4337 localfontfileloader_GetFilePathLengthFromKey,
4338 localfontfileloader_GetFilePathFromKey,
4339 localfontfileloader_GetLastWriteTimeFromKey
4342 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4344 struct dwrite_localfontfileloader *This;
4346 *ret = NULL;
4348 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4349 if (!This)
4350 return E_OUTOFMEMORY;
4352 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4353 This->ref = 1;
4354 list_init(&This->streams);
4356 *ret = &This->IDWriteLocalFontFileLoader_iface;
4357 return S_OK;
4360 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4362 struct local_refkey *refkey;
4364 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4365 *key = NULL;
4367 refkey = heap_alloc(*size);
4368 if (!refkey)
4369 return E_OUTOFMEMORY;
4371 if (writetime)
4372 refkey->writetime = *writetime;
4373 else {
4374 WIN32_FILE_ATTRIBUTE_DATA info;
4376 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4377 refkey->writetime = info.ftLastWriteTime;
4378 else
4379 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4381 strcpyW(refkey->name, path);
4383 *key = refkey;
4385 return S_OK;
4388 /* IDWriteGlyphRunAnalysis */
4389 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4391 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4393 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4395 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4396 IsEqualIID(riid, &IID_IUnknown))
4398 *ppv = iface;
4399 IDWriteGlyphRunAnalysis_AddRef(iface);
4400 return S_OK;
4403 *ppv = NULL;
4404 return E_NOINTERFACE;
4407 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4409 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4410 ULONG ref = InterlockedIncrement(&This->ref);
4411 TRACE("(%p)->(%u)\n", This, ref);
4412 return ref;
4415 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4417 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4418 ULONG ref = InterlockedDecrement(&This->ref);
4420 TRACE("(%p)->(%u)\n", This, ref);
4422 if (!ref) {
4423 if (This->run.fontFace)
4424 IDWriteFontFace_Release(This->run.fontFace);
4425 heap_free(This->glyphs);
4426 heap_free(This->advances);
4427 heap_free(This->advanceoffsets);
4428 heap_free(This->ascenderoffsets);
4429 heap_free(This->bitmap);
4430 heap_free(This);
4433 return ref;
4436 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4438 struct dwrite_glyphbitmap glyph_bitmap;
4439 IDWriteFontFace3 *fontface3;
4440 D2D_POINT_2F origin;
4441 BOOL is_rtl;
4442 HRESULT hr;
4443 UINT32 i;
4445 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4446 *bounds = analysis->bounds;
4447 return;
4450 if (analysis->run.isSideways)
4451 FIXME("sideways runs are not supported.\n");
4453 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4454 if (FAILED(hr))
4455 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4457 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4458 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4459 for any non-zero glyph ascender */
4460 origin.x = origin.y = 0.0f;
4461 is_rtl = analysis->run.bidiLevel & 1;
4463 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4464 glyph_bitmap.fontface = fontface3;
4465 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4466 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4467 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4468 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4469 glyph_bitmap.m = &analysis->m;
4471 for (i = 0; i < analysis->run.glyphCount; i++) {
4472 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4473 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4474 const D2D_POINT_2F *advance = analysis->advances + i;
4475 RECT *bbox = &glyph_bitmap.bbox;
4477 glyph_bitmap.index = analysis->run.glyphIndices[i];
4478 freetype_get_glyph_bbox(&glyph_bitmap);
4480 if (is_rtl)
4481 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4482 else
4483 OffsetRect(bbox, origin.x, origin.y);
4485 if (advanceoffset)
4486 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4488 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4489 origin.x += advance->x;
4490 origin.y += advance->y;
4493 IDWriteFontFace3_Release(fontface3);
4495 /* translate to given run origin */
4496 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4497 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4498 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4500 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4501 *bounds = analysis->bounds;
4504 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4506 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4508 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4510 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4511 memset(bounds, 0, sizeof(*bounds));
4512 return E_INVALIDARG;
4515 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4516 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4517 memset(bounds, 0, sizeof(*bounds));
4518 return S_OK;
4521 glyphrunanalysis_get_texturebounds(This, bounds);
4522 return S_OK;
4525 static inline int get_dib_stride( int width, int bpp )
4527 return ((width * bpp + 31) >> 3) & ~3;
4530 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4532 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4533 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4534 (runbounds->left - bounds->left) * 3;
4535 else
4536 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4537 runbounds->left - bounds->left;
4540 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4542 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4543 struct dwrite_glyphbitmap glyph_bitmap;
4544 IDWriteFontFace3 *fontface2;
4545 D2D_POINT_2F origin;
4546 UINT32 i, size;
4547 BOOL is_rtl;
4548 HRESULT hr;
4549 RECT *bbox;
4551 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4552 if (FAILED(hr)) {
4553 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4554 return;
4557 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4558 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4559 size *= 3;
4560 analysis->bitmap = heap_alloc_zero(size);
4562 origin.x = origin.y = 0.0f;
4563 is_rtl = analysis->run.bidiLevel & 1;
4565 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4566 glyph_bitmap.fontface = fontface2;
4567 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4568 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4569 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4570 glyph_bitmap.type = type;
4571 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4572 glyph_bitmap.m = &analysis->m;
4573 bbox = &glyph_bitmap.bbox;
4575 for (i = 0; i < analysis->run.glyphCount; i++) {
4576 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4577 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4578 const D2D_POINT_2F *advance = analysis->advances + i;
4579 int x, y, width, height;
4580 BYTE *src, *dst;
4581 BOOL is_1bpp;
4583 glyph_bitmap.index = analysis->run.glyphIndices[i];
4584 freetype_get_glyph_bbox(&glyph_bitmap);
4586 if (IsRectEmpty(bbox)) {
4587 origin.x += advance->x;
4588 origin.y += advance->y;
4589 continue;
4592 width = bbox->right - bbox->left;
4593 height = bbox->bottom - bbox->top;
4595 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4596 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4597 else
4598 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4600 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4601 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4603 if (is_rtl)
4604 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4605 else
4606 OffsetRect(bbox, origin.x, origin.y);
4608 if (advanceoffset)
4609 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4611 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4612 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4613 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4615 /* blit to analysis bitmap */
4616 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4618 if (is_1bpp) {
4619 /* convert 1bpp to 8bpp/24bpp */
4620 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4621 for (y = 0; y < height; y++) {
4622 for (x = 0; x < width; x++)
4623 if (src[x / 8] & masks[x % 8])
4624 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4625 src += glyph_bitmap.pitch;
4626 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4629 else {
4630 for (y = 0; y < height; y++) {
4631 for (x = 0; x < width; x++)
4632 if (src[x / 8] & masks[x % 8])
4633 dst[x] = DWRITE_ALPHA_MAX;
4634 src += get_dib_stride(width, 1);
4635 dst += analysis->bounds.right - analysis->bounds.left;
4639 else {
4640 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4641 for (y = 0; y < height; y++) {
4642 for (x = 0; x < width; x++)
4643 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4644 src += glyph_bitmap.pitch;
4645 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4649 heap_free(glyph_bitmap.buf);
4651 origin.x += advance->x;
4652 origin.y += advance->y;
4655 IDWriteFontFace3_Release(fontface2);
4657 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4659 /* we don't need this anymore */
4660 heap_free(analysis->glyphs);
4661 heap_free(analysis->advances);
4662 heap_free(analysis->advanceoffsets);
4663 heap_free(analysis->ascenderoffsets);
4664 IDWriteFontFace_Release(analysis->run.fontFace);
4666 analysis->glyphs = NULL;
4667 analysis->advances = NULL;
4668 analysis->advanceoffsets = NULL;
4669 analysis->ascenderoffsets = NULL;
4670 analysis->run.glyphIndices = NULL;
4671 analysis->run.fontFace = NULL;
4674 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4675 RECT const *bounds, BYTE *bitmap, UINT32 size)
4677 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4678 UINT32 required;
4679 RECT runbounds;
4681 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4683 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4684 return E_INVALIDARG;
4686 /* make sure buffer is large enough for requested texture type */
4687 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4688 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4689 required *= 3;
4691 if (size < required)
4692 return E_NOT_SUFFICIENT_BUFFER;
4694 /* validate requested texture type with rendering mode */
4695 switch (This->rendering_mode)
4697 case DWRITE_RENDERING_MODE_ALIASED:
4698 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4699 return DWRITE_E_UNSUPPORTEDOPERATION;
4700 break;
4701 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4702 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4703 case DWRITE_RENDERING_MODE_NATURAL:
4704 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4705 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4706 return DWRITE_E_UNSUPPORTEDOPERATION;
4707 break;
4708 default:
4712 memset(bitmap, 0, size);
4713 glyphrunanalysis_get_texturebounds(This, &runbounds);
4714 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4715 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4716 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4717 int dst_width = (bounds->right - bounds->left) * pixel_size;
4718 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4719 BYTE *src, *dst;
4720 int y;
4722 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4723 glyphrunanalysis_render(This, type);
4725 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4726 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4728 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4729 memcpy(dst, src, draw_width);
4730 src += src_width;
4731 dst += dst_width;
4735 return S_OK;
4738 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4739 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4741 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4743 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4745 if (!params)
4746 return E_INVALIDARG;
4748 switch (This->rendering_mode)
4750 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4751 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4753 UINT value = 0;
4754 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4755 *gamma = (FLOAT)value / 1000.0f;
4756 *contrast = 0.0f;
4757 *cleartypelevel = 1.0f;
4758 break;
4760 case DWRITE_RENDERING_MODE_ALIASED:
4761 case DWRITE_RENDERING_MODE_NATURAL:
4762 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4763 *gamma = IDWriteRenderingParams_GetGamma(params);
4764 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4765 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4766 break;
4767 default:
4771 return S_OK;
4774 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4775 glyphrunanalysis_QueryInterface,
4776 glyphrunanalysis_AddRef,
4777 glyphrunanalysis_Release,
4778 glyphrunanalysis_GetAlphaTextureBounds,
4779 glyphrunanalysis_CreateAlphaTexture,
4780 glyphrunanalysis_GetAlphaBlendParams
4783 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4785 if (is_vertical) {
4786 vec->x = 0.0f;
4787 vec->y = length;
4789 else {
4790 vec->x = length;
4791 vec->y = 0.0f;
4795 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4797 D2D_POINT_2F ret;
4798 ret.x = vec->x * m->m11 + vec->y * m->m21;
4799 ret.y = vec->x * m->m12 + vec->y * m->m22;
4800 *vec = ret;
4803 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4804 FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
4805 FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4807 struct dwrite_glyphrunanalysis *analysis;
4808 FLOAT rtl_factor;
4809 UINT32 i;
4811 *ret = NULL;
4813 /* check for valid rendering mode */
4814 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4815 return E_INVALIDARG;
4817 analysis = heap_alloc(sizeof(*analysis));
4818 if (!analysis)
4819 return E_OUTOFMEMORY;
4821 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4822 analysis->ref = 1;
4823 analysis->rendering_mode = rendering_mode;
4824 analysis->flags = 0;
4825 analysis->bitmap = NULL;
4826 analysis->ppdip = ppdip;
4827 analysis->origin.x = originX * ppdip;
4828 analysis->origin.y = originY * ppdip;
4829 SetRectEmpty(&analysis->bounds);
4830 analysis->run = *run;
4831 IDWriteFontFace_AddRef(analysis->run.fontFace);
4832 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4833 analysis->advances = heap_alloc(run->glyphCount*sizeof(*analysis->advances));
4834 if (run->glyphOffsets) {
4835 analysis->advanceoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->advanceoffsets));
4836 analysis->ascenderoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->ascenderoffsets));
4838 else {
4839 analysis->advanceoffsets = NULL;
4840 analysis->ascenderoffsets = NULL;
4843 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && run->glyphOffsets)) {
4844 heap_free(analysis->glyphs);
4845 heap_free(analysis->advances);
4846 heap_free(analysis->advanceoffsets);
4847 heap_free(analysis->ascenderoffsets);
4849 analysis->glyphs = NULL;
4850 analysis->advances = NULL;
4851 analysis->advanceoffsets = NULL;
4852 analysis->ascenderoffsets = NULL;
4854 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4855 return E_OUTOFMEMORY;
4858 /* check if transform is usable */
4859 if (transform && memcmp(transform, &identity, sizeof(*transform))) {
4860 analysis->m = *transform;
4861 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4863 else
4864 memset(&analysis->m, 0, sizeof(analysis->m));
4866 analysis->run.glyphIndices = analysis->glyphs;
4867 analysis->run.glyphAdvances = NULL;
4868 analysis->run.glyphOffsets = NULL;
4870 rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f;
4872 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4873 transform_2d_vec(&analysis->origin, &analysis->m);
4875 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4877 if (run->glyphAdvances) {
4878 for (i = 0; i < run->glyphCount; i++) {
4879 init_2d_vec(analysis->advances + i, rtl_factor * run->glyphAdvances[i] * ppdip, run->isSideways);
4880 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4881 transform_2d_vec(analysis->advances + i, &analysis->m);
4884 else {
4885 DWRITE_FONT_METRICS metrics;
4886 IDWriteFontFace1 *fontface1;
4888 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4889 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4891 for (i = 0; i < run->glyphCount; i++) {
4892 HRESULT hr;
4893 INT32 a;
4895 switch (measuring_mode)
4897 case DWRITE_MEASURING_MODE_NATURAL:
4898 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4899 if (FAILED(hr))
4900 a = 0;
4901 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics) * ppdip,
4902 run->isSideways);
4903 break;
4904 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4905 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4906 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, transform,
4907 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4908 if (FAILED(hr))
4909 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4910 else
4911 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f),
4912 run->isSideways);
4913 break;
4914 default:
4918 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4919 transform_2d_vec(analysis->advances + i, &analysis->m);
4922 IDWriteFontFace1_Release(fontface1);
4925 if (run->glyphOffsets) {
4926 for (i = 0; i < run->glyphCount; i++) {
4927 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
4928 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4929 init_2d_vec(analysis->ascenderoffsets + i, -run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
4930 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
4931 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
4932 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
4937 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
4938 return S_OK;
4941 /* IDWriteColorGlyphRunEnumerator */
4942 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
4944 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4946 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4948 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
4949 IsEqualIID(riid, &IID_IUnknown))
4951 *ppv = iface;
4952 IDWriteColorGlyphRunEnumerator_AddRef(iface);
4953 return S_OK;
4956 *ppv = NULL;
4957 return E_NOINTERFACE;
4960 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
4962 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4963 ULONG ref = InterlockedIncrement(&This->ref);
4964 TRACE("(%p)->(%u)\n", This, ref);
4965 return ref;
4968 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
4970 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4971 ULONG ref = InterlockedDecrement(&This->ref);
4973 TRACE("(%p)->(%u)\n", This, ref);
4975 if (!ref) {
4976 heap_free(This->advances);
4977 heap_free(This->color_advances);
4978 heap_free(This->offsets);
4979 heap_free(This->color_offsets);
4980 heap_free(This->glyphindices);
4981 heap_free(This->glyphs);
4982 if (This->colr.context)
4983 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
4984 IDWriteFontFace3_Release(This->fontface);
4985 heap_free(This);
4988 return ref;
4991 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
4993 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
4994 FLOAT origin = 0.0f;
4996 if (g == 0)
4997 return 0.0f;
4999 while (g--)
5000 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5001 return origin;
5004 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5006 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5007 FLOAT advance_adj = 0.0f;
5008 BOOL got_palette_index;
5009 UINT32 g;
5011 /* start with regular glyphs */
5012 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5013 UINT32 first_glyph = 0;
5015 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5016 if (glyphenum->glyphs[g].num_layers == 0) {
5017 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5018 first_glyph = min(first_glyph, g);
5020 else
5021 glyphenum->glyphindices[g] = 1;
5022 glyphenum->color_advances[g] = glyphenum->advances[g];
5023 if (glyphenum->color_offsets)
5024 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5027 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5028 colorrun->baselineOriginY = glyphenum->origin_y;
5029 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5030 colorrun->paletteIndex = 0xffff;
5031 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5032 glyphenum->has_regular_glyphs = FALSE;
5033 return TRUE;
5035 else {
5036 colorrun->glyphRun.glyphCount = 0;
5037 got_palette_index = FALSE;
5040 advance_adj = 0.0f;
5041 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5043 glyphenum->glyphindices[g] = 1;
5045 /* all glyph layers were returned */
5046 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5047 advance_adj += glyphenum->advances[g];
5048 continue;
5051 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5052 UINT32 index = colorrun->glyphRun.glyphCount;
5053 if (!got_palette_index) {
5054 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5055 /* use foreground color or request one from the font */
5056 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5057 if (colorrun->paletteIndex != 0xffff) {
5058 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5059 1, &colorrun->runColor);
5060 if (FAILED(hr))
5061 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5062 glyphenum->palette, colorrun->paletteIndex, hr);
5064 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5065 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5066 colorrun->baselineOriginY = glyphenum->origin_y;
5067 glyphenum->color_advances[index] = glyphenum->advances[g];
5068 got_palette_index = TRUE;
5071 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5072 /* offsets are relative to glyph origin, nothing to fix up */
5073 if (glyphenum->color_offsets)
5074 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5075 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5076 if (index)
5077 glyphenum->color_advances[index-1] += advance_adj;
5078 colorrun->glyphRun.glyphCount++;
5079 advance_adj = 0.0f;
5081 else
5082 advance_adj += glyphenum->advances[g];
5085 /* reset last advance */
5086 if (colorrun->glyphRun.glyphCount)
5087 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5089 return colorrun->glyphRun.glyphCount > 0;
5092 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5094 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5096 TRACE("(%p)->(%p)\n", This, has_run);
5098 *has_run = FALSE;
5100 This->colorrun.glyphRun.glyphCount = 0;
5101 while (This->current_layer < This->max_layer_num) {
5102 if (colorglyphenum_build_color_run(This))
5103 break;
5104 else
5105 This->current_layer++;
5108 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5110 return S_OK;
5113 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5115 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5117 TRACE("(%p)->(%p)\n", This, run);
5119 if (This->colorrun.glyphRun.glyphCount == 0) {
5120 *run = NULL;
5121 return E_NOT_VALID_STATE;
5124 *run = &This->colorrun;
5125 return S_OK;
5128 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5129 colorglyphenum_QueryInterface,
5130 colorglyphenum_AddRef,
5131 colorglyphenum_Release,
5132 colorglyphenum_MoveNext,
5133 colorglyphenum_GetCurrentRun
5136 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5137 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5139 struct dwrite_colorglyphenum *colorglyphenum;
5140 BOOL colorfont, has_colored_glyph;
5141 IDWriteFontFace3 *fontface3;
5142 HRESULT hr;
5143 UINT32 i;
5145 *ret = NULL;
5147 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5148 if (FAILED(hr)) {
5149 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5150 return hr;
5153 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5154 if (!colorfont) {
5155 hr = DWRITE_E_NOCOLOR;
5156 goto failed;
5159 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5160 if (!colorglyphenum) {
5161 hr = E_OUTOFMEMORY;
5162 goto failed;
5165 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5166 colorglyphenum->ref = 1;
5167 colorglyphenum->origin_x = originX;
5168 colorglyphenum->origin_y = originY;
5169 colorglyphenum->fontface = fontface3;
5170 colorglyphenum->glyphs = NULL;
5171 colorglyphenum->run = *run;
5172 colorglyphenum->run.glyphIndices = NULL;
5173 colorglyphenum->run.glyphAdvances = NULL;
5174 colorglyphenum->run.glyphOffsets = NULL;
5175 colorglyphenum->palette = palette;
5176 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5177 colorglyphenum->colr.exists = TRUE;
5178 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5179 colorglyphenum->current_layer = 0;
5180 colorglyphenum->max_layer_num = 0;
5182 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5184 has_colored_glyph = FALSE;
5185 colorglyphenum->has_regular_glyphs = FALSE;
5186 for (i = 0; i < run->glyphCount; i++) {
5187 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5188 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5189 has_colored_glyph = TRUE;
5191 if (colorglyphenum->glyphs[i].num_layers == 0)
5192 colorglyphenum->has_regular_glyphs = TRUE;
5195 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5196 is supposed to proceed normally, like if font had no color info at all. */
5197 if (!has_colored_glyph) {
5198 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5199 return DWRITE_E_NOCOLOR;
5202 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5203 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5204 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5205 if (run->glyphOffsets) {
5206 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5207 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5208 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5211 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5212 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5213 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5214 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5216 if (run->glyphAdvances)
5217 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5218 else {
5219 DWRITE_FONT_METRICS metrics;
5221 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5222 for (i = 0; i < run->glyphCount; i++) {
5223 HRESULT hr;
5224 INT32 a;
5226 switch (measuring_mode)
5228 case DWRITE_MEASURING_MODE_NATURAL:
5229 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5230 if (FAILED(hr))
5231 a = 0;
5232 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5233 break;
5234 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5235 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5236 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5237 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5238 if (FAILED(hr))
5239 colorglyphenum->advances[i] = 0.0f;
5240 else
5241 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5242 break;
5243 default:
5249 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5250 return S_OK;
5252 failed:
5253 IDWriteFontFace3_Release(fontface3);
5254 return hr;