dwrite: Update to IDWriteFontFamily1.
[wine.git] / dlls / dwrite / font.c
blob76321bb018907d4892264e3205b5d42bd8e9a987
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 IDWriteFontCollection IDWriteFontCollection_iface;
123 LONG ref;
125 struct dwrite_fontfamily_data **family_data;
126 UINT32 family_count;
127 UINT32 family_alloc;
128 BOOL is_system;
131 struct dwrite_fontfamily {
132 IDWriteFontFamily1 IDWriteFontFamily1_iface;
133 LONG ref;
135 struct dwrite_fontfamily_data *data;
137 IDWriteFontCollection* collection;
140 struct dwrite_font {
141 IDWriteFont3 IDWriteFont3_iface;
142 LONG ref;
144 IDWriteFontFamily1 *family;
146 DWRITE_FONT_STYLE style;
147 struct dwrite_font_data *data;
150 struct dwrite_fonttable {
151 void *data;
152 void *context;
153 UINT32 size;
154 BOOL exists;
157 enum runanalysis_flags {
158 RUNANALYSIS_BOUNDS_READY = 1 << 0,
159 RUNANALYSIS_BITMAP_READY = 1 << 1,
160 RUNANALYSIS_USE_TRANSFORM = 1 << 2
163 struct dwrite_glyphrunanalysis {
164 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
165 LONG ref;
167 DWRITE_RENDERING_MODE rendering_mode;
168 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
169 DWRITE_MATRIX m;
170 FLOAT ppdip;
171 UINT16 *glyphs;
172 D2D_POINT_2F origin;
173 D2D_POINT_2F *advances;
174 D2D_POINT_2F *advanceoffsets;
175 D2D_POINT_2F *ascenderoffsets;
177 UINT8 flags;
178 RECT bounds;
179 BYTE *bitmap;
182 struct dwrite_colorglyphenum {
183 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
184 LONG ref;
186 FLOAT origin_x; /* original run origin */
187 FLOAT origin_y;
189 IDWriteFontFace3 *fontface; /* for convenience */
190 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
191 DWRITE_GLYPH_RUN run; /* base run */
192 UINT32 palette; /* palette index to get layer color from */
193 FLOAT *advances; /* original or measured advances for base glyphs */
194 FLOAT *color_advances; /* returned color run points to this */
195 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
196 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
197 UINT16 *glyphindices; /* returned color run points to this */
198 struct dwrite_colorglyph *glyphs; /* current glyph color info */
199 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
200 UINT16 current_layer; /* enumerator position, updated with MoveNext */
201 UINT16 max_layer_num; /* max number of layers for this run */
202 struct dwrite_fonttable colr; /* used to access layers */
205 #define GLYPH_BLOCK_SHIFT 8
206 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
207 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
208 #define GLYPH_MAX 65536
210 struct dwrite_fontface {
211 IDWriteFontFace3 IDWriteFontFace3_iface;
212 LONG ref;
214 IDWriteFontFileStream **streams;
215 IDWriteFontFile **files;
216 UINT32 file_count;
217 UINT32 index;
219 USHORT simulations;
220 DWRITE_FONT_FACE_TYPE type;
221 DWRITE_FONT_METRICS1 metrics;
222 DWRITE_CARET_METRICS caret;
223 INT charmap;
224 BOOL is_symbol;
225 BOOL has_kerning_pairs : 1;
226 BOOL is_monospaced : 1;
228 struct dwrite_fonttable cmap;
229 struct dwrite_fonttable vdmx;
230 struct dwrite_fonttable gasp;
231 struct dwrite_fonttable cpal;
232 struct dwrite_fonttable colr;
233 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
236 struct dwrite_fontfile {
237 IDWriteFontFile IDWriteFontFile_iface;
238 LONG ref;
240 IDWriteFontFileLoader *loader;
241 void *reference_key;
242 UINT32 key_size;
243 IDWriteFontFileStream *stream;
246 static inline struct dwrite_fontface *impl_from_IDWriteFontFace3(IDWriteFontFace3 *iface)
248 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace3_iface);
251 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
253 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
256 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
258 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
261 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
263 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
266 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection(IDWriteFontCollection *iface)
268 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection_iface);
271 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
273 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
276 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
278 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
281 static inline struct dwrite_fontlist *impl_from_IDWriteFontList(IDWriteFontList *iface)
283 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList_iface);
286 static inline const char *debugstr_tag(UINT32 tag)
288 return debugstr_an((char*)&tag, 4);
291 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
293 static const DWRITE_GLYPH_METRICS nil;
294 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
296 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
297 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
298 return S_OK;
301 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
303 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
305 if (!*block) {
306 /* start new block */
307 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
308 if (!*block)
309 return E_OUTOFMEMORY;
312 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
313 return S_OK;
316 static void* get_fontface_table(IDWriteFontFace3 *fontface, UINT32 tag, struct dwrite_fonttable *table)
318 HRESULT hr;
320 if (table->data || !table->exists)
321 return table->data;
323 table->exists = FALSE;
324 hr = IDWriteFontFace3_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
325 &table->exists);
326 if (FAILED(hr) || !table->exists) {
327 WARN("Font does not have a %s table\n", debugstr_tag(tag));
328 return NULL;
331 return table->data;
334 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
335 struct dwrite_font_propvec *vec)
337 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
338 vec->style = style * 7.0f;
339 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
342 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
344 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
347 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
349 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
352 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
354 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CMAP_TAG, &fontface->cmap);
357 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
359 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_VDMX_TAG, &fontface->vdmx);
362 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
364 void *ptr = get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_GASP_TAG, &fontface->gasp);
365 *size = fontface->gasp.size;
366 return ptr;
369 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
371 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CPAL_TAG, &fontface->cpal);
374 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
376 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_COLR_TAG, &fontface->colr);
379 static void release_font_data(struct dwrite_font_data *data)
381 int i;
383 if (InterlockedDecrement(&data->ref) > 0)
384 return;
386 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
387 if (data->info_strings[i])
388 IDWriteLocalizedStrings_Release(data->info_strings[i]);
390 if (data->names)
391 IDWriteLocalizedStrings_Release(data->names);
393 IDWriteFontFile_Release(data->file);
394 IDWriteFactory2_Release(data->factory);
395 heap_free(data->facename);
396 heap_free(data);
399 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
401 int i;
403 if (InterlockedDecrement(&data->ref) > 0)
404 return;
406 for (i = 0; i < data->font_count; i++)
407 release_font_data(data->fonts[i]);
408 heap_free(data->fonts);
409 IDWriteLocalizedStrings_Release(data->familyname);
410 heap_free(data);
413 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace3 *iface, REFIID riid, void **obj)
415 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
417 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
419 if (IsEqualIID(riid, &IID_IDWriteFontFace3) ||
420 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
421 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
422 IsEqualIID(riid, &IID_IDWriteFontFace) ||
423 IsEqualIID(riid, &IID_IUnknown))
425 *obj = iface;
426 IDWriteFontFace3_AddRef(iface);
427 return S_OK;
430 *obj = NULL;
431 return E_NOINTERFACE;
434 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace3 *iface)
436 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
437 ULONG ref = InterlockedIncrement(&This->ref);
438 TRACE("(%p)->(%d)\n", This, ref);
439 return ref;
442 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace3 *iface)
444 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
445 ULONG ref = InterlockedDecrement(&This->ref);
447 TRACE("(%p)->(%d)\n", This, ref);
449 if (!ref) {
450 UINT32 i;
452 if (This->cmap.context)
453 IDWriteFontFace3_ReleaseFontTable(iface, This->cmap.context);
454 if (This->vdmx.context)
455 IDWriteFontFace3_ReleaseFontTable(iface, This->vdmx.context);
456 if (This->gasp.context)
457 IDWriteFontFace3_ReleaseFontTable(iface, This->gasp.context);
458 if (This->cpal.context)
459 IDWriteFontFace3_ReleaseFontTable(iface, This->cpal.context);
460 if (This->colr.context)
461 IDWriteFontFace3_ReleaseFontTable(iface, This->colr.context);
462 for (i = 0; i < This->file_count; i++) {
463 if (This->streams[i])
464 IDWriteFontFileStream_Release(This->streams[i]);
465 if (This->files[i])
466 IDWriteFontFile_Release(This->files[i]);
468 heap_free(This->streams);
469 heap_free(This->files);
471 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
472 heap_free(This->glyphs[i]);
474 freetype_notify_cacheremove(iface);
475 heap_free(This);
478 return ref;
481 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace3 *iface)
483 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
484 TRACE("(%p)\n", This);
485 return This->type;
488 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace3 *iface, UINT32 *number_of_files,
489 IDWriteFontFile **fontfiles)
491 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
492 int i;
494 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
495 if (fontfiles == NULL)
497 *number_of_files = This->file_count;
498 return S_OK;
500 if (*number_of_files < This->file_count)
501 return E_INVALIDARG;
503 for (i = 0; i < This->file_count; i++)
505 IDWriteFontFile_AddRef(This->files[i]);
506 fontfiles[i] = This->files[i];
509 return S_OK;
512 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace3 *iface)
514 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
515 TRACE("(%p)\n", This);
516 return This->index;
519 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace3 *iface)
521 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
522 TRACE("(%p)\n", This);
523 return This->simulations;
526 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace3 *iface)
528 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
529 TRACE("(%p)\n", This);
530 return This->is_symbol;
533 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS *metrics)
535 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
536 TRACE("(%p)->(%p)\n", This, metrics);
537 memcpy(metrics, &This->metrics, sizeof(*metrics));
540 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace3 *iface)
542 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
543 TRACE("(%p)\n", This);
544 return freetype_get_glyphcount(iface);
547 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace3 *iface,
548 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
550 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
551 HRESULT hr;
552 UINT32 i;
554 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
556 if (!glyphs)
557 return E_INVALIDARG;
559 if (is_sideways)
560 FIXME("sideways metrics are not supported.\n");
562 for (i = 0; i < glyph_count; i++) {
563 DWRITE_GLYPH_METRICS metrics;
565 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
566 if (hr != S_OK) {
567 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
568 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
569 if (FAILED(hr))
570 return hr;
572 ret[i] = metrics;
575 return S_OK;
578 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace3 *iface, UINT32 const *codepoints,
579 UINT32 count, UINT16 *glyph_indices)
581 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
583 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
585 if (!glyph_indices)
586 return E_INVALIDARG;
588 if (!codepoints) {
589 memset(glyph_indices, 0, count*sizeof(UINT16));
590 return E_INVALIDARG;
593 freetype_get_glyphs(iface, This->charmap, codepoints, count, glyph_indices);
594 return S_OK;
597 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace3 *iface, UINT32 table_tag,
598 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
600 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
602 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
604 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
607 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace3 *iface, void *table_context)
609 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
611 TRACE("(%p)->(%p)\n", This, table_context);
613 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
616 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace3 *iface, FLOAT emSize,
617 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
618 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
620 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
622 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
623 count, is_sideways, is_rtl, sink);
625 if (!glyphs || !sink)
626 return E_INVALIDARG;
628 if (is_sideways)
629 FIXME("sideways mode is not supported.\n");
631 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
634 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
635 FLOAT ppem, WORD gasp)
637 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
639 switch (measuring)
641 case DWRITE_MEASURING_MODE_NATURAL:
643 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
644 mode = DWRITE_RENDERING_MODE_NATURAL;
645 else
646 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
647 break;
649 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
650 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
651 break;
652 case DWRITE_MEASURING_MODE_GDI_NATURAL:
653 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
654 break;
655 default:
659 return mode;
662 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
663 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
665 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
666 WORD gasp, *ptr;
667 UINT32 size;
668 FLOAT ppem;
670 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
672 if (!params) {
673 *mode = DWRITE_RENDERING_MODE_DEFAULT;
674 return E_INVALIDARG;
677 *mode = IDWriteRenderingParams_GetRenderingMode(params);
678 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
679 return S_OK;
681 ppem = emSize * ppdip;
683 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
684 *mode = DWRITE_RENDERING_MODE_OUTLINE;
685 return S_OK;
688 ptr = get_fontface_gasp(This, &size);
689 gasp = opentype_get_gasp_flags(ptr, size, ppem);
690 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
691 return S_OK;
694 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT pixels_per_dip,
695 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
697 DWRITE_FONT_METRICS1 metrics1;
698 HRESULT hr = IDWriteFontFace3_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
699 memcpy(metrics, &metrics1, sizeof(*metrics));
700 return hr;
703 static inline int round_metric(FLOAT metric)
705 return (int)floorf(metric + 0.5f);
708 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT ppdip,
709 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
710 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
712 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
713 DWRITE_MEASURING_MODE mode;
714 FLOAT scale, size;
715 HRESULT hr;
716 UINT32 i;
718 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
719 glyph_count, metrics, is_sideways);
721 if (m && memcmp(m, &identity, sizeof(*m)))
722 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
724 size = emSize * ppdip;
725 scale = size / This->metrics.designUnitsPerEm;
726 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
728 for (i = 0; i < glyph_count; i++) {
729 DWRITE_GLYPH_METRICS *ret = metrics + i;
730 DWRITE_GLYPH_METRICS design;
732 hr = IDWriteFontFace3_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
733 if (FAILED(hr))
734 return hr;
736 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
737 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
739 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
740 SCALE_METRIC(leftSideBearing);
741 SCALE_METRIC(rightSideBearing);
742 SCALE_METRIC(topSideBearing);
743 SCALE_METRIC(advanceHeight);
744 SCALE_METRIC(bottomSideBearing);
745 SCALE_METRIC(verticalOriginY);
746 #undef SCALE_METRIC
749 return S_OK;
752 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS1 *metrics)
754 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
755 TRACE("(%p)->(%p)\n", This, metrics);
756 *metrics = This->metrics;
759 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT em_size, FLOAT pixels_per_dip,
760 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
762 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
763 const DWRITE_FONT_METRICS1 *design = &This->metrics;
764 UINT16 ascent, descent;
765 FLOAT scale;
767 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
769 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
770 memset(metrics, 0, sizeof(*metrics));
771 return E_INVALIDARG;
774 em_size *= pixels_per_dip;
775 if (m && m->m22 != 0.0f)
776 em_size *= fabs(m->m22);
778 scale = em_size / design->designUnitsPerEm;
779 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
780 ascent = round_metric(design->ascent * scale);
781 descent = round_metric(design->descent * scale);
784 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
785 metrics->designUnitsPerEm = design->designUnitsPerEm;
786 metrics->ascent = round_metric(ascent / scale);
787 metrics->descent = round_metric(descent / scale);
789 SCALE_METRIC(lineGap);
790 SCALE_METRIC(capHeight);
791 SCALE_METRIC(xHeight);
792 SCALE_METRIC(underlinePosition);
793 SCALE_METRIC(underlineThickness);
794 SCALE_METRIC(strikethroughPosition);
795 SCALE_METRIC(strikethroughThickness);
796 SCALE_METRIC(glyphBoxLeft);
797 SCALE_METRIC(glyphBoxTop);
798 SCALE_METRIC(glyphBoxRight);
799 SCALE_METRIC(glyphBoxBottom);
800 SCALE_METRIC(subscriptPositionX);
801 SCALE_METRIC(subscriptPositionY);
802 SCALE_METRIC(subscriptSizeX);
803 SCALE_METRIC(subscriptSizeY);
804 SCALE_METRIC(superscriptPositionX);
805 SCALE_METRIC(superscriptPositionY);
806 SCALE_METRIC(superscriptSizeX);
807 SCALE_METRIC(superscriptSizeY);
809 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
810 #undef SCALE_METRIC
812 return S_OK;
815 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace3 *iface, DWRITE_CARET_METRICS *metrics)
817 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
818 TRACE("(%p)->(%p)\n", This, metrics);
819 *metrics = This->caret;
822 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace3 *iface, UINT32 max_count,
823 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
825 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
827 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
829 *count = 0;
830 if (max_count && !ranges)
831 return E_INVALIDARG;
833 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
836 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
838 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
839 TRACE("(%p)\n", This);
840 return This->is_monospaced;
843 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
844 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
846 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
847 UINT32 i;
849 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
851 if (is_sideways)
852 FIXME("sideways mode not supported\n");
854 for (i = 0; i < glyph_count; i++)
855 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
857 return S_OK;
860 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3 *iface,
861 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
862 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
864 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
865 DWRITE_MEASURING_MODE mode;
866 UINT32 i;
868 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
869 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
871 if (em_size < 0.0f || ppdip <= 0.0f) {
872 memset(advances, 0, sizeof(*advances) * glyph_count);
873 return E_INVALIDARG;
876 em_size *= ppdip;
877 if (em_size == 0.0f) {
878 memset(advances, 0, sizeof(*advances) * glyph_count);
879 return S_OK;
882 if (m && memcmp(m, &identity, sizeof(*m)))
883 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
885 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
886 for (i = 0; i < glyph_count; i++) {
887 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
888 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
891 return S_OK;
894 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3 *iface, UINT32 count,
895 const UINT16 *indices, INT32 *adjustments)
897 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
898 UINT32 i;
900 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
902 if (!(indices || adjustments) || !count)
903 return E_INVALIDARG;
905 if (!indices || count == 1) {
906 memset(adjustments, 0, count*sizeof(INT32));
907 return E_INVALIDARG;
910 if (!This->has_kerning_pairs) {
911 memset(adjustments, 0, count*sizeof(INT32));
912 return S_OK;
915 for (i = 0; i < count-1; i++)
916 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
917 adjustments[count-1] = 0;
919 return S_OK;
922 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
924 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
925 TRACE("(%p)\n", This);
926 return This->has_kerning_pairs;
929 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
930 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
931 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
933 DWRITE_GRID_FIT_MODE gridfitmode;
934 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
935 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
938 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3 *iface, UINT32 glyph_count,
939 const UINT16 *nominal_indices, UINT16 *vertical_indices)
941 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
942 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
943 return E_NOTIMPL;
946 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
948 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
949 FIXME("(%p): stub\n", This);
950 return FALSE;
953 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
955 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
956 TRACE("(%p)\n", This);
957 return get_fontface_cpal(This) && get_fontface_colr(This);
960 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace3 *iface)
962 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
963 TRACE("(%p)\n", This);
964 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
967 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3 *iface)
969 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
970 TRACE("(%p)\n", This);
971 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
974 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace3 *iface, UINT32 palette_index,
975 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
977 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
978 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
979 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
982 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
983 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
984 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
985 DWRITE_GRID_FIT_MODE *gridfitmode)
987 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
988 FLOAT emthreshold;
989 WORD gasp, *ptr;
990 UINT32 size;
992 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
993 measuringmode, params, renderingmode, gridfitmode);
995 if (m)
996 FIXME("transform not supported %s\n", debugstr_matrix(m));
998 if (is_sideways)
999 FIXME("sideways mode not supported\n");
1001 emSize *= max(dpiX, dpiY) / 96.0f;
1003 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1004 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1005 if (params) {
1006 IDWriteRenderingParams2 *params2;
1007 HRESULT hr;
1009 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1010 if (hr == S_OK) {
1011 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1012 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1013 IDWriteRenderingParams2_Release(params2);
1015 else
1016 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1019 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1021 ptr = get_fontface_gasp(This, &size);
1022 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1024 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1025 if (emSize >= emthreshold)
1026 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1027 else
1028 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1031 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1032 if (emSize >= emthreshold)
1033 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1034 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1035 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1036 else
1037 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1040 return S_OK;
1043 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace3 *iface, IDWriteFontFaceReference **ref)
1045 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1046 FIXME("(%p)->(%p): stub\n", This, ref);
1047 return E_NOTIMPL;
1050 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace3 *iface, DWRITE_PANOSE *panose)
1052 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1053 FIXME("(%p)->(%p): stub\n", This, panose);
1056 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace3 *iface)
1058 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1059 FIXME("(%p): stub\n", This);
1060 return DWRITE_FONT_WEIGHT_NORMAL;
1063 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace3 *iface)
1065 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1066 FIXME("(%p): stub\n", This);
1067 return DWRITE_FONT_STRETCH_NORMAL;
1070 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace3 *iface)
1072 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1073 FIXME("(%p): stub\n", This);
1074 return DWRITE_FONT_STYLE_NORMAL;
1077 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1079 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1080 FIXME("(%p)->(%p): stub\n", This, names);
1081 return E_NOTIMPL;
1084 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1086 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1087 FIXME("(%p)->(%p): stub\n", This, names);
1088 return E_NOTIMPL;
1091 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace3 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1092 IDWriteLocalizedStrings **strings, BOOL *exists)
1094 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1095 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1096 return E_NOTIMPL;
1099 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace3 *iface, UINT32 ch)
1101 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1102 UINT16 index;
1103 HRESULT hr;
1105 TRACE("(%p)->(0x%08x)\n", This, ch);
1107 index = 0;
1108 hr = IDWriteFontFace3_GetGlyphIndices(iface, &ch, 1, &index);
1109 if (FAILED(hr))
1110 return FALSE;
1112 return index != 0;
1115 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emsize, FLOAT dpi_x, FLOAT dpi_y,
1116 DWRITE_MATRIX const *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1117 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1119 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1120 FIXME("(%p)->(%f %f %f %p %d %u %u %p %p %p): stub\n", This, emsize, dpi_x, dpi_y, transform, is_sideways, threshold,
1121 measuring_mode, params, rendering_mode, gridfit_mode);
1122 return E_NOTIMPL;
1125 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace3 *iface, UINT32 ch)
1127 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1128 FIXME("(%p)->(0x%x): stub\n", This, ch);
1129 return FALSE;
1132 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace3 *iface, UINT16 glyph)
1134 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1135 FIXME("(%p)->(%u): stub\n", This, glyph);
1136 return FALSE;
1139 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace3 *iface, WCHAR const *text,
1140 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1142 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1143 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1144 return E_NOTIMPL;
1147 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace3 *iface, UINT16 const *glyphs,
1148 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1150 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1151 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1152 return E_NOTIMPL;
1155 static const IDWriteFontFace3Vtbl dwritefontfacevtbl = {
1156 dwritefontface_QueryInterface,
1157 dwritefontface_AddRef,
1158 dwritefontface_Release,
1159 dwritefontface_GetType,
1160 dwritefontface_GetFiles,
1161 dwritefontface_GetIndex,
1162 dwritefontface_GetSimulations,
1163 dwritefontface_IsSymbolFont,
1164 dwritefontface_GetMetrics,
1165 dwritefontface_GetGlyphCount,
1166 dwritefontface_GetDesignGlyphMetrics,
1167 dwritefontface_GetGlyphIndices,
1168 dwritefontface_TryGetFontTable,
1169 dwritefontface_ReleaseFontTable,
1170 dwritefontface_GetGlyphRunOutline,
1171 dwritefontface_GetRecommendedRenderingMode,
1172 dwritefontface_GetGdiCompatibleMetrics,
1173 dwritefontface_GetGdiCompatibleGlyphMetrics,
1174 dwritefontface1_GetMetrics,
1175 dwritefontface1_GetGdiCompatibleMetrics,
1176 dwritefontface1_GetCaretMetrics,
1177 dwritefontface1_GetUnicodeRanges,
1178 dwritefontface1_IsMonospacedFont,
1179 dwritefontface1_GetDesignGlyphAdvances,
1180 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1181 dwritefontface1_GetKerningPairAdjustments,
1182 dwritefontface1_HasKerningPairs,
1183 dwritefontface1_GetRecommendedRenderingMode,
1184 dwritefontface1_GetVerticalGlyphVariants,
1185 dwritefontface1_HasVerticalGlyphVariants,
1186 dwritefontface2_IsColorFont,
1187 dwritefontface2_GetColorPaletteCount,
1188 dwritefontface2_GetPaletteEntryCount,
1189 dwritefontface2_GetPaletteEntries,
1190 dwritefontface2_GetRecommendedRenderingMode,
1191 dwritefontface3_GetFontFaceReference,
1192 dwritefontface3_GetPanose,
1193 dwritefontface3_GetWeight,
1194 dwritefontface3_GetStretch,
1195 dwritefontface3_GetStyle,
1196 dwritefontface3_GetFamilyNames,
1197 dwritefontface3_GetFaceNames,
1198 dwritefontface3_GetInformationalStrings,
1199 dwritefontface3_HasCharacter,
1200 dwritefontface3_GetRecommendedRenderingMode,
1201 dwritefontface3_IsCharacterLocal,
1202 dwritefontface3_IsGlyphLocal,
1203 dwritefontface3_AreCharactersLocal,
1204 dwritefontface3_AreGlyphsLocal
1207 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace3 **fontface)
1209 struct dwrite_font_data *data = font->data;
1210 IDWriteFontFace *face;
1211 HRESULT hr;
1213 *fontface = NULL;
1215 hr = IDWriteFactory2_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1216 data->face_index, font->data->simulations, &face);
1217 if (FAILED(hr))
1218 return hr;
1220 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace3, (void**)fontface);
1221 IDWriteFontFace_Release(face);
1223 return hr;
1226 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1228 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1230 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1232 if (IsEqualIID(riid, &IID_IDWriteFont2) ||
1233 IsEqualIID(riid, &IID_IDWriteFont1) ||
1234 IsEqualIID(riid, &IID_IDWriteFont) ||
1235 IsEqualIID(riid, &IID_IUnknown))
1237 *obj = iface;
1238 IDWriteFont3_AddRef(iface);
1239 return S_OK;
1242 *obj = NULL;
1243 return E_NOINTERFACE;
1246 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1248 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1249 ULONG ref = InterlockedIncrement(&This->ref);
1250 TRACE("(%p)->(%d)\n", This, ref);
1251 return ref;
1254 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1256 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1257 ULONG ref = InterlockedDecrement(&This->ref);
1259 TRACE("(%p)->(%d)\n", This, ref);
1261 if (!ref) {
1262 IDWriteFontFamily1_Release(This->family);
1263 release_font_data(This->data);
1264 heap_free(This);
1267 return ref;
1270 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1272 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1273 TRACE("(%p)->(%p)\n", This, family);
1275 *family = (IDWriteFontFamily*)This->family;
1276 IDWriteFontFamily_AddRef(*family);
1277 return S_OK;
1280 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1282 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1283 TRACE("(%p)\n", This);
1284 return This->data->weight;
1287 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1289 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1290 TRACE("(%p)\n", This);
1291 return This->data->stretch;
1294 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1296 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1297 TRACE("(%p)\n", This);
1298 return This->style;
1301 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1303 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1304 IDWriteFontFace3 *fontface;
1305 HRESULT hr;
1307 TRACE("(%p)\n", This);
1309 hr = get_fontface_from_font(This, &fontface);
1310 if (FAILED(hr))
1311 return FALSE;
1313 return IDWriteFontFace3_IsSymbolFont(fontface);
1316 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1318 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1319 TRACE("(%p)->(%p)\n", This, names);
1320 return clone_localizedstring(This->data->names, names);
1323 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1324 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1326 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1327 struct dwrite_font_data *data = This->data;
1328 HRESULT hr;
1330 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1332 *exists = FALSE;
1333 *strings = NULL;
1335 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1336 return S_OK;
1338 if (!data->info_strings[stringid]) {
1339 IDWriteFontFace3 *fontface;
1340 const void *table_data;
1341 BOOL table_exists;
1342 void *context;
1343 UINT32 size;
1345 hr = get_fontface_from_font(This, &fontface);
1346 if (FAILED(hr))
1347 return hr;
1349 table_exists = FALSE;
1350 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1351 if (FAILED(hr) || !table_exists)
1352 WARN("no NAME table found.\n");
1354 if (table_exists) {
1355 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1356 if (FAILED(hr) || !data->info_strings[stringid])
1357 return hr;
1358 IDWriteFontFace3_ReleaseFontTable(fontface, context);
1362 hr = clone_localizedstring(data->info_strings[stringid], strings);
1363 if (FAILED(hr))
1364 return hr;
1366 *exists = TRUE;
1367 return S_OK;
1370 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1372 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1373 TRACE("(%p)\n", This);
1374 return This->data->simulations;
1377 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1379 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1381 TRACE("(%p)->(%p)\n", This, metrics);
1382 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1385 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1387 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1388 IDWriteFontFace3 *fontface;
1389 UINT16 index;
1390 HRESULT hr;
1392 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1394 *exists = FALSE;
1396 hr = get_fontface_from_font(This, &fontface);
1397 if (FAILED(hr))
1398 return hr;
1400 index = 0;
1401 hr = IDWriteFontFace3_GetGlyphIndices(fontface, &value, 1, &index);
1402 if (FAILED(hr))
1403 return hr;
1405 *exists = index != 0;
1406 return S_OK;
1409 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **face)
1411 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1412 HRESULT hr;
1414 TRACE("(%p)->(%p)\n", This, face);
1416 hr = get_fontface_from_font(This, (IDWriteFontFace3**)face);
1417 if (hr == S_OK)
1418 IDWriteFontFace_AddRef(*face);
1420 return hr;
1423 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1425 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1426 TRACE("(%p)->(%p)\n", This, metrics);
1427 *metrics = This->data->metrics;
1430 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1432 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1433 TRACE("(%p)->(%p)\n", This, panose);
1434 *panose = This->data->panose;
1437 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1439 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1440 IDWriteFontFace3 *fontface;
1441 HRESULT hr;
1443 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1445 hr = get_fontface_from_font(This, &fontface);
1446 if (FAILED(hr))
1447 return hr;
1449 return IDWriteFontFace3_GetUnicodeRanges(fontface, max_count, ranges, count);
1452 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1454 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1455 IDWriteFontFace3 *fontface;
1456 HRESULT hr;
1458 TRACE("(%p)\n", This);
1460 hr = get_fontface_from_font(This, &fontface);
1461 if (FAILED(hr))
1462 return FALSE;
1464 return IDWriteFontFace3_IsMonospacedFont(fontface);
1467 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1469 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1470 IDWriteFontFace3 *fontface;
1471 HRESULT hr;
1473 TRACE("(%p)\n", This);
1475 hr = get_fontface_from_font(This, &fontface);
1476 if (FAILED(hr))
1477 return FALSE;
1479 return IDWriteFontFace3_IsColorFont(fontface);
1482 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1484 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1485 FIXME("(%p)->(%p): stub\n", This, fontface);
1486 return E_NOTIMPL;
1489 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1491 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1492 FIXME("(%p)->(%p): stub\n", This, font);
1493 return FALSE;
1496 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1498 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1499 FIXME("(%p)->(%p): stub\n", This, reference);
1500 return E_NOTIMPL;
1503 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1505 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1506 FIXME("(%p)->(0x%x): stub\n", This, ch);
1507 return FALSE;
1510 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1512 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1513 FIXME("(%p): stub\n", This);
1514 return DWRITE_LOCALITY_LOCAL;
1517 static const IDWriteFont3Vtbl dwritefontvtbl = {
1518 dwritefont_QueryInterface,
1519 dwritefont_AddRef,
1520 dwritefont_Release,
1521 dwritefont_GetFontFamily,
1522 dwritefont_GetWeight,
1523 dwritefont_GetStretch,
1524 dwritefont_GetStyle,
1525 dwritefont_IsSymbolFont,
1526 dwritefont_GetFaceNames,
1527 dwritefont_GetInformationalStrings,
1528 dwritefont_GetSimulations,
1529 dwritefont_GetMetrics,
1530 dwritefont_HasCharacter,
1531 dwritefont_CreateFontFace,
1532 dwritefont1_GetMetrics,
1533 dwritefont1_GetPanose,
1534 dwritefont1_GetUnicodeRanges,
1535 dwritefont1_IsMonospacedFont,
1536 dwritefont2_IsColorFont,
1537 dwritefont3_CreateFontFace,
1538 dwritefont3_Equals,
1539 dwritefont3_GetFontFaceReference,
1540 dwritefont3_HasCharacter,
1541 dwritefont3_GetLocality
1544 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily1 *family, IDWriteFont **font)
1546 struct dwrite_font *This;
1547 *font = NULL;
1549 This = heap_alloc(sizeof(struct dwrite_font));
1550 if (!This) return E_OUTOFMEMORY;
1552 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1553 This->ref = 1;
1554 This->family = family;
1555 IDWriteFontFamily1_AddRef(family);
1556 This->style = data->style;
1557 This->data = data;
1558 InterlockedIncrement(&This->data->ref);
1560 *font = (IDWriteFont*)&This->IDWriteFont3_iface;
1562 return S_OK;
1565 /* IDWriteFontList */
1566 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList *iface, REFIID riid, void **obj)
1568 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1570 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1572 if (IsEqualIID(riid, &IID_IDWriteFontList) ||
1573 IsEqualIID(riid, &IID_IUnknown))
1575 *obj = iface;
1576 IDWriteFontList_AddRef(iface);
1577 return S_OK;
1580 *obj = NULL;
1581 return E_NOINTERFACE;
1584 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList *iface)
1586 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1587 ULONG ref = InterlockedIncrement(&This->ref);
1588 TRACE("(%p)->(%d)\n", This, ref);
1589 return ref;
1592 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList *iface)
1594 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1595 ULONG ref = InterlockedDecrement(&This->ref);
1597 TRACE("(%p)->(%d)\n", This, ref);
1599 if (!ref) {
1600 UINT32 i;
1602 for (i = 0; i < This->font_count; i++)
1603 release_font_data(This->fonts[i]);
1604 IDWriteFontFamily1_Release(This->family);
1605 heap_free(This);
1608 return ref;
1611 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList *iface, IDWriteFontCollection **collection)
1613 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1614 return IDWriteFontFamily1_GetFontCollection(This->family, collection);
1617 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList *iface)
1619 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1620 TRACE("(%p)\n", This);
1621 return This->font_count;
1624 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList *iface, UINT32 index, IDWriteFont **font)
1626 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1628 TRACE("(%p)->(%u %p)\n", This, index, font);
1630 *font = NULL;
1632 if (This->font_count == 0)
1633 return S_FALSE;
1635 if (index >= This->font_count)
1636 return E_INVALIDARG;
1638 return create_font(This->fonts[index], This->family, font);
1641 static const IDWriteFontListVtbl dwritefontlistvtbl = {
1642 dwritefontlist_QueryInterface,
1643 dwritefontlist_AddRef,
1644 dwritefontlist_Release,
1645 dwritefontlist_GetFontCollection,
1646 dwritefontlist_GetFontCount,
1647 dwritefontlist_GetFont
1650 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1652 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1654 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1656 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1657 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1658 IsEqualIID(riid, &IID_IDWriteFontList) ||
1659 IsEqualIID(riid, &IID_IUnknown))
1661 *obj = iface;
1662 IDWriteFontFamily1_AddRef(iface);
1663 return S_OK;
1666 *obj = NULL;
1667 return E_NOINTERFACE;
1670 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1672 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1673 ULONG ref = InterlockedIncrement(&This->ref);
1674 TRACE("(%p)->(%d)\n", This, ref);
1675 return ref;
1678 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1680 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1681 ULONG ref = InterlockedDecrement(&This->ref);
1683 TRACE("(%p)->(%d)\n", This, ref);
1685 if (!ref)
1687 IDWriteFontCollection_Release(This->collection);
1688 release_fontfamily_data(This->data);
1689 heap_free(This);
1692 return ref;
1695 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1697 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1698 TRACE("(%p)->(%p)\n", This, collection);
1700 *collection = This->collection;
1701 IDWriteFontCollection_AddRef(This->collection);
1702 return S_OK;
1705 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1707 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1708 TRACE("(%p)\n", This);
1709 return This->data->font_count;
1712 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1714 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1716 TRACE("(%p)->(%u %p)\n", This, index, font);
1718 *font = NULL;
1720 if (This->data->font_count == 0)
1721 return S_FALSE;
1723 if (index >= This->data->font_count)
1724 return E_INVALIDARG;
1726 return create_font(This->data->fonts[index], iface, font);
1729 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1731 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1732 return clone_localizedstring(This->data->familyname, names);
1735 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1736 const struct dwrite_font_propvec *req)
1738 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1739 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1740 FLOAT cur_req_prod, next_req_prod;
1742 if (next_to_req < cur_to_req)
1743 return TRUE;
1745 if (next_to_req > cur_to_req)
1746 return FALSE;
1748 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1749 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1751 if (next_req_prod > cur_req_prod)
1752 return TRUE;
1754 if (next_req_prod < cur_req_prod)
1755 return FALSE;
1757 if (next->stretch > cur->stretch)
1758 return TRUE;
1759 if (next->stretch < cur->stretch)
1760 return FALSE;
1762 if (next->style > cur->style)
1763 return TRUE;
1764 if (next->style < cur->style)
1765 return FALSE;
1767 if (next->weight > cur->weight)
1768 return TRUE;
1769 if (next->weight < cur->weight)
1770 return FALSE;
1772 /* full match, no reason to prefer new variant */
1773 return FALSE;
1776 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1777 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1779 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1780 struct dwrite_font_propvec req;
1781 struct dwrite_font_data *match;
1782 UINT32 i;
1784 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1786 if (This->data->font_count == 0) {
1787 *font = NULL;
1788 return DWRITE_E_NOFONT;
1791 init_font_prop_vec(weight, stretch, style, &req);
1792 match = This->data->fonts[0];
1794 for (i = 1; i < This->data->font_count; i++) {
1795 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1796 match = This->data->fonts[i];
1799 return create_font(match, iface, font);
1802 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1804 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1806 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1809 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1811 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1814 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1816 UINT32 b = fonts->font_count - 1, j, t;
1818 while (1) {
1819 t = b;
1821 for (j = 0; j < b; j++) {
1822 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1823 struct dwrite_font_data *s = fonts->fonts[j];
1824 fonts->fonts[j] = fonts->fonts[j+1];
1825 fonts->fonts[j+1] = s;
1826 t = j;
1830 if (t == b)
1831 break;
1832 b = t;
1836 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1837 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1839 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1840 matching_filter_func func = NULL;
1841 struct dwrite_font_propvec req;
1842 struct dwrite_fontlist *fonts;
1843 UINT32 i;
1845 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1847 *ret = NULL;
1849 fonts = heap_alloc(sizeof(*fonts));
1850 if (!fonts)
1851 return E_OUTOFMEMORY;
1853 /* Allocate as many as family has, not all of them will be necessary used. */
1854 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1855 if (!fonts->fonts) {
1856 heap_free(fonts);
1857 return E_OUTOFMEMORY;
1860 fonts->IDWriteFontList_iface.lpVtbl = &dwritefontlistvtbl;
1861 fonts->ref = 1;
1862 fonts->family = iface;
1863 IDWriteFontFamily1_AddRef(fonts->family);
1864 fonts->font_count = 0;
1866 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1867 if (style == DWRITE_FONT_STYLE_NORMAL) {
1868 if (This->data->has_normal_face || This->data->has_italic_face)
1869 func = is_font_acceptable_for_normal;
1871 else /* requested oblique or italic */ {
1872 if (This->data->has_oblique_face || This->data->has_italic_face)
1873 func = is_font_acceptable_for_oblique_italic;
1876 for (i = 0; i < This->data->font_count; i++) {
1877 if (!func || func(This->data->fonts[i])) {
1878 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1879 InterlockedIncrement(&This->data->fonts[i]->ref);
1880 fonts->font_count++;
1884 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1885 init_font_prop_vec(weight, stretch, style, &req);
1886 matchingfonts_sort(fonts, &req);
1888 *ret = &fonts->IDWriteFontList_iface;
1889 return S_OK;
1892 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
1894 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1896 FIXME("(%p)->(%u): stub\n", This, index);
1898 return DWRITE_LOCALITY_LOCAL;
1901 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
1903 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1905 FIXME("(%p)->(%u %p): stub\n", This, index, font);
1907 return E_NOTIMPL;
1910 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
1911 IDWriteFontFaceReference **ref)
1913 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1915 FIXME("(%p)->(%u %p): stub\n", This, index, ref);
1917 return E_NOTIMPL;
1920 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
1921 dwritefontfamily_QueryInterface,
1922 dwritefontfamily_AddRef,
1923 dwritefontfamily_Release,
1924 dwritefontfamily_GetFontCollection,
1925 dwritefontfamily_GetFontCount,
1926 dwritefontfamily_GetFont,
1927 dwritefontfamily_GetFamilyNames,
1928 dwritefontfamily_GetFirstMatchingFont,
1929 dwritefontfamily_GetMatchingFonts,
1930 dwritefontfamily1_GetFontLocality,
1931 dwritefontfamily1_GetFont,
1932 dwritefontfamily1_GetFontFaceReference
1935 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily1 **family)
1937 struct dwrite_fontfamily *This;
1939 *family = NULL;
1941 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1942 if (!This) return E_OUTOFMEMORY;
1944 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
1945 This->ref = 1;
1946 This->collection = collection;
1947 IDWriteFontCollection_AddRef(collection);
1948 This->data = data;
1949 InterlockedIncrement(&This->data->ref);
1951 *family = &This->IDWriteFontFamily1_iface;
1953 return S_OK;
1956 BOOL is_system_collection(IDWriteFontCollection *collection)
1958 void *obj;
1959 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1962 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection *iface, REFIID riid, void **obj)
1964 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1965 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1967 if (IsEqualIID(riid, &IID_IUnknown) ||
1968 IsEqualIID(riid, &IID_IDWriteFontCollection))
1970 *obj = iface;
1971 IDWriteFontCollection_AddRef(iface);
1972 return S_OK;
1975 *obj = NULL;
1977 if (This->is_system && IsEqualIID(riid, &IID_issystemcollection))
1978 return S_OK;
1980 return E_NOINTERFACE;
1983 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection *iface)
1985 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1986 ULONG ref = InterlockedIncrement(&This->ref);
1987 TRACE("(%p)->(%d)\n", This, ref);
1988 return ref;
1991 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection *iface)
1993 unsigned int i;
1994 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1995 ULONG ref = InterlockedDecrement(&This->ref);
1996 TRACE("(%p)->(%d)\n", This, ref);
1998 if (!ref) {
1999 for (i = 0; i < This->family_count; i++)
2000 release_fontfamily_data(This->family_data[i]);
2001 heap_free(This->family_data);
2002 heap_free(This);
2005 return ref;
2008 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
2010 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
2011 TRACE("(%p)\n", This);
2012 return This->family_count;
2015 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
2017 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
2019 TRACE("(%p)->(%u %p)\n", This, index, family);
2021 if (index >= This->family_count) {
2022 *family = NULL;
2023 return E_FAIL;
2026 return create_fontfamily(This->family_data[index], iface, (IDWriteFontFamily1**)family);
2029 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2031 UINT32 i;
2033 for (i = 0; i < collection->family_count; i++) {
2034 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2035 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2036 HRESULT hr;
2038 for (j = 0; j < count; j++) {
2039 WCHAR buffer[255];
2040 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2041 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2042 return i;
2046 return ~0u;
2049 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2051 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
2052 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2053 *index = collection_find_family(This, name);
2054 *exists = *index != ~0u;
2055 return S_OK;
2058 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2060 UINT32 left_key_size, right_key_size;
2061 const void *left_key, *right_key;
2062 HRESULT hr;
2064 if (left == right)
2065 return TRUE;
2067 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2068 if (FAILED(hr))
2069 return FALSE;
2071 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2072 if (FAILED(hr))
2073 return FALSE;
2075 if (left_key_size != right_key_size)
2076 return FALSE;
2078 return !memcmp(left_key, right_key, left_key_size);
2081 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
2083 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
2084 struct dwrite_fontfamily_data *found_family = NULL;
2085 struct dwrite_font_data *found_font = NULL;
2086 IDWriteFontFamily1 *family;
2087 UINT32 i, j, face_index;
2088 IDWriteFontFile *file;
2089 HRESULT hr;
2091 TRACE("(%p)->(%p %p)\n", This, face, font);
2093 *font = NULL;
2095 if (!face)
2096 return E_INVALIDARG;
2098 i = 1;
2099 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2100 if (FAILED(hr))
2101 return hr;
2102 face_index = IDWriteFontFace_GetIndex(face);
2104 for (i = 0; i < This->family_count; i++) {
2105 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2106 for (j = 0; j < family_data->font_count; j++) {
2107 struct dwrite_font_data *font_data = family_data->fonts[j];
2109 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2110 found_font = font_data;
2111 found_family = family_data;
2112 break;
2117 if (!found_font)
2118 return DWRITE_E_NOFONT;
2120 hr = create_fontfamily(found_family, iface, &family);
2121 if (FAILED(hr))
2122 return hr;
2124 hr = create_font(found_font, family, font);
2125 IDWriteFontFamily1_Release(family);
2126 return hr;
2129 static const IDWriteFontCollectionVtbl fontcollectionvtbl = {
2130 dwritefontcollection_QueryInterface,
2131 dwritefontcollection_AddRef,
2132 dwritefontcollection_Release,
2133 dwritefontcollection_GetFontFamilyCount,
2134 dwritefontcollection_GetFontFamily,
2135 dwritefontcollection_FindFamilyName,
2136 dwritefontcollection_GetFontFromFontFace
2139 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2141 if (family_data->font_count + 1 >= family_data->font_alloc) {
2142 struct dwrite_font_data **new_list;
2143 UINT32 new_alloc;
2145 new_alloc = family_data->font_alloc * 2;
2146 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2147 if (!new_list)
2148 return E_OUTOFMEMORY;
2149 family_data->fonts = new_list;
2150 family_data->font_alloc = new_alloc;
2153 family_data->fonts[family_data->font_count] = font_data;
2154 family_data->font_count++;
2155 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2156 family_data->has_normal_face = 1;
2157 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2158 family_data->has_oblique_face = 1;
2159 else
2160 family_data->has_italic_face = 1;
2161 return S_OK;
2164 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2166 if (collection->family_alloc < collection->family_count + 1) {
2167 struct dwrite_fontfamily_data **new_list;
2168 UINT32 new_alloc;
2170 new_alloc = collection->family_alloc * 2;
2171 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2172 if (!new_list)
2173 return E_OUTOFMEMORY;
2175 collection->family_alloc = new_alloc;
2176 collection->family_data = new_list;
2179 collection->family_data[collection->family_count] = family;
2180 collection->family_count++;
2182 return S_OK;
2185 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2187 collection->IDWriteFontCollection_iface.lpVtbl = &fontcollectionvtbl;
2188 collection->ref = 1;
2189 collection->family_count = 0;
2190 collection->family_alloc = is_system ? 30 : 5;
2191 collection->is_system = is_system;
2193 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2194 if (!collection->family_data)
2195 return E_OUTOFMEMORY;
2197 return S_OK;
2200 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2202 IDWriteFontFileLoader *loader;
2203 const void *key;
2204 UINT32 key_size;
2205 HRESULT hr;
2207 *stream = NULL;
2209 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2210 if (FAILED(hr))
2211 return hr;
2213 hr = IDWriteFontFile_GetLoader(file, &loader);
2214 if (FAILED(hr))
2215 return hr;
2217 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2218 IDWriteFontFileLoader_Release(loader);
2219 if (FAILED(hr))
2220 return hr;
2222 return hr;
2225 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2227 BOOL exists = FALSE;
2228 UINT32 index;
2229 HRESULT hr;
2231 buffer[0] = 0;
2232 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2233 if (FAILED(hr) || !exists)
2234 return;
2236 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2239 static int trim_spaces(WCHAR *in, WCHAR *ret)
2241 int len;
2243 while (isspaceW(*in))
2244 in++;
2246 ret[0] = 0;
2247 if (!(len = strlenW(in)))
2248 return 0;
2250 while (isspaceW(in[len-1]))
2251 len--;
2253 memcpy(ret, in, len*sizeof(WCHAR));
2254 ret[len] = 0;
2256 return len;
2259 struct name_token {
2260 struct list entry;
2261 const WCHAR *ptr;
2262 INT len; /* token length */
2263 INT fulllen; /* full length including following separators */
2266 static inline BOOL is_name_separator_char(WCHAR ch)
2268 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2271 struct name_pattern {
2272 const WCHAR *part1; /* NULL indicates end of list */
2273 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2276 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2278 const struct name_pattern *pattern;
2279 struct name_token *token;
2280 int i = 0;
2282 while ((pattern = &patterns[i++])->part1) {
2283 int len_part1 = strlenW(pattern->part1);
2284 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2286 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2287 if (len_part2 == 0) {
2288 /* simple case with single part pattern */
2289 if (token->len != len_part1)
2290 continue;
2292 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2293 if (match) *match = *token;
2294 list_remove(&token->entry);
2295 heap_free(token);
2296 return TRUE;
2299 else {
2300 struct name_token *next_token;
2301 struct list *next_entry;
2303 /* pattern parts are stored in reading order, tokens list is reversed */
2304 if (token->len < len_part2)
2305 continue;
2307 /* it's possible to have combined string as a token, like ExtraCondensed */
2308 if (token->len == len_part1 + len_part2) {
2309 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2310 continue;
2312 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2313 continue;
2315 /* combined string match */
2316 if (match) *match = *token;
2317 list_remove(&token->entry);
2318 heap_free(token);
2319 return TRUE;
2322 /* now it's only possible to have two tokens matched to respective pattern parts */
2323 if (token->len != len_part2)
2324 continue;
2326 next_entry = list_next(tokens, &token->entry);
2327 if (next_entry) {
2328 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2329 if (next_token->len != len_part1)
2330 continue;
2332 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2333 continue;
2335 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2336 continue;
2338 /* both parts matched, remove tokens */
2339 if (match) {
2340 match->ptr = next_token->ptr;
2341 match->len = (token->ptr - next_token->ptr) + token->len;
2343 list_remove(&token->entry);
2344 list_remove(&next_token->entry);
2345 heap_free(next_token);
2346 heap_free(token);
2347 return TRUE;
2353 if (match) {
2354 match->ptr = NULL;
2355 match->len = 0;
2357 return FALSE;
2360 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2362 static const WCHAR itaW[] = {'i','t','a',0};
2363 static const WCHAR italW[] = {'i','t','a','l',0};
2364 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2365 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2367 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2368 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2369 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2370 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2372 static const struct name_pattern italic_patterns[] = {
2373 { itaW },
2374 { italW },
2375 { italicW },
2376 { cursiveW },
2377 { kursivW },
2378 { NULL }
2381 static const struct name_pattern oblique_patterns[] = {
2382 { inclinedW },
2383 { obliqueW },
2384 { backslantedW },
2385 { backslantW },
2386 { slantedW },
2387 { NULL }
2390 /* italic patterns first */
2391 if (match_pattern_list(tokens, italic_patterns, match))
2392 return DWRITE_FONT_STYLE_ITALIC;
2394 /* oblique patterns */
2395 if (match_pattern_list(tokens, oblique_patterns, match))
2396 return DWRITE_FONT_STYLE_OBLIQUE;
2398 return style;
2401 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2402 struct name_token *match)
2404 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2405 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2406 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2407 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2408 static const WCHAR wideW[] = {'w','i','d','e',0};
2409 static const WCHAR condW[] = {'c','o','n','d',0};
2411 static const struct name_pattern ultracondensed_patterns[] = {
2412 { extraW, compressedW },
2413 { extW, compressedW },
2414 { ultraW, compressedW },
2415 { ultraW, condensedW },
2416 { ultraW, condW },
2417 { NULL }
2420 static const struct name_pattern extracondensed_patterns[] = {
2421 { compressedW },
2422 { extraW, condensedW },
2423 { extW, condensedW },
2424 { extraW, condW },
2425 { extW, condW },
2426 { NULL }
2429 static const struct name_pattern semicondensed_patterns[] = {
2430 { narrowW },
2431 { compactW },
2432 { semiW, condensedW },
2433 { semiW, condW },
2434 { NULL }
2437 static const struct name_pattern semiexpanded_patterns[] = {
2438 { wideW },
2439 { semiW, expandedW },
2440 { semiW, extendedW },
2441 { NULL }
2444 static const struct name_pattern extraexpanded_patterns[] = {
2445 { extraW, expandedW },
2446 { extW, expandedW },
2447 { extraW, extendedW },
2448 { extW, extendedW },
2449 { NULL }
2452 static const struct name_pattern ultraexpanded_patterns[] = {
2453 { ultraW, expandedW },
2454 { ultraW, extendedW },
2455 { NULL }
2458 static const struct name_pattern condensed_patterns[] = {
2459 { condensedW },
2460 { condW },
2461 { NULL }
2464 static const struct name_pattern expanded_patterns[] = {
2465 { expandedW },
2466 { extendedW },
2467 { NULL }
2470 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2471 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2473 if (match_pattern_list(tokens, extracondensed_patterns, match))
2474 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2476 if (match_pattern_list(tokens, semicondensed_patterns, match))
2477 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2479 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2480 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2482 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2483 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2485 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2486 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2488 if (match_pattern_list(tokens, condensed_patterns, match))
2489 return DWRITE_FONT_STRETCH_CONDENSED;
2491 if (match_pattern_list(tokens, expanded_patterns, match))
2492 return DWRITE_FONT_STRETCH_EXPANDED;
2494 return stretch;
2497 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2498 struct name_token *match)
2500 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2501 static const WCHAR nordW[] = {'n','o','r','d',0};
2503 static const struct name_pattern thin_patterns[] = {
2504 { extraW, thinW },
2505 { extW, thinW },
2506 { ultraW, thinW },
2507 { NULL }
2510 static const struct name_pattern extralight_patterns[] = {
2511 { extraW, lightW },
2512 { extW, lightW },
2513 { ultraW, lightW },
2514 { NULL }
2517 static const struct name_pattern semilight_patterns[] = {
2518 { semiW, lightW },
2519 { NULL }
2522 static const struct name_pattern demibold_patterns[] = {
2523 { semiW, boldW },
2524 { demiW, boldW },
2525 { NULL }
2528 static const struct name_pattern extrabold_patterns[] = {
2529 { extraW, boldW },
2530 { extW, boldW },
2531 { ultraW, boldW },
2532 { NULL }
2535 static const struct name_pattern extrablack_patterns[] = {
2536 { extraW, blackW },
2537 { extW, blackW },
2538 { ultraW, blackW },
2539 { NULL }
2542 static const struct name_pattern bold_patterns[] = {
2543 { boldW },
2544 { NULL }
2547 static const struct name_pattern thin2_patterns[] = {
2548 { thinW },
2549 { NULL }
2552 static const struct name_pattern light_patterns[] = {
2553 { lightW },
2554 { NULL }
2557 static const struct name_pattern medium_patterns[] = {
2558 { mediumW },
2559 { NULL }
2562 static const struct name_pattern black_patterns[] = {
2563 { blackW },
2564 { heavyW },
2565 { nordW },
2566 { NULL }
2569 static const struct name_pattern demibold2_patterns[] = {
2570 { demiW },
2571 { NULL }
2574 static const struct name_pattern extrabold2_patterns[] = {
2575 { ultraW },
2576 { NULL }
2579 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2580 matching pattern. */
2582 if (match_pattern_list(tokens, thin_patterns, match))
2583 return DWRITE_FONT_WEIGHT_THIN;
2585 if (match_pattern_list(tokens, extralight_patterns, match))
2586 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2588 if (match_pattern_list(tokens, semilight_patterns, match))
2589 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2591 if (match_pattern_list(tokens, demibold_patterns, match))
2592 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2594 if (match_pattern_list(tokens, extrabold_patterns, match))
2595 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2597 if (match_pattern_list(tokens, extrablack_patterns, match))
2598 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2600 if (match_pattern_list(tokens, bold_patterns, match))
2601 return DWRITE_FONT_WEIGHT_BOLD;
2603 if (match_pattern_list(tokens, thin2_patterns, match))
2604 return DWRITE_FONT_WEIGHT_THIN;
2606 if (match_pattern_list(tokens, light_patterns, match))
2607 return DWRITE_FONT_WEIGHT_LIGHT;
2609 if (match_pattern_list(tokens, medium_patterns, match))
2610 return DWRITE_FONT_WEIGHT_MEDIUM;
2612 if (match_pattern_list(tokens, black_patterns, match))
2613 return DWRITE_FONT_WEIGHT_BLACK;
2615 if (match_pattern_list(tokens, black_patterns, match))
2616 return DWRITE_FONT_WEIGHT_BLACK;
2618 if (match_pattern_list(tokens, demibold2_patterns, match))
2619 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2621 if (match_pattern_list(tokens, extrabold2_patterns, match))
2622 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2624 /* FIXME: use abbreviated names to extract weight */
2626 return weight;
2629 struct knownweight_entry {
2630 const WCHAR *nameW;
2631 DWRITE_FONT_WEIGHT weight;
2634 static int compare_knownweights(const void *a, const void* b)
2636 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2637 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2638 int ret = 0;
2640 if (target > entry->weight)
2641 ret = 1;
2642 else if (target < entry->weight)
2643 ret = -1;
2645 return ret;
2648 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2650 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2651 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2652 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2653 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2654 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2655 const struct knownweight_entry *ptr;
2657 static const struct knownweight_entry knownweights[] = {
2658 { thinW, DWRITE_FONT_WEIGHT_THIN },
2659 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2660 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2661 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2662 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2663 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2664 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2665 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2666 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2667 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2670 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2671 compare_knownweights);
2672 if (!ptr) {
2673 nameW[0] = 0;
2674 return FALSE;
2677 strcpyW(nameW, ptr->nameW);
2678 return TRUE;
2681 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2683 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2684 strW[name->len] = 0;
2687 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2688 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2690 static const WCHAR bookW[] = {'B','o','o','k',0};
2691 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2692 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2693 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2694 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2696 static const WCHAR *regular_patterns[] = {
2697 bookW,
2698 normalW,
2699 regularW,
2700 romanW,
2701 uprightW,
2702 NULL
2705 const WCHAR *regular_ptr = NULL, *ptr;
2706 int i = 0;
2708 if (len == -1)
2709 len = strlenW(facenameW);
2711 /* remove rightmost regular variant from face name */
2712 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2713 int pattern_len = strlenW(ptr);
2714 WCHAR *src;
2716 if (pattern_len > len)
2717 continue;
2719 src = facenameW + len - pattern_len;
2720 while (src >= facenameW) {
2721 if (!strncmpiW(src, ptr, pattern_len)) {
2722 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2723 len = strlenW(facenameW);
2724 regular_ptr = ptr;
2725 break;
2727 else
2728 src--;
2732 return regular_ptr;
2735 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2737 const WCHAR *ptr;
2739 list_init(tokens);
2740 ptr = nameW;
2742 while (*ptr) {
2743 struct name_token *token = heap_alloc(sizeof(*token));
2744 token->ptr = ptr;
2745 token->len = 0;
2746 token->fulllen = 0;
2748 while (*ptr && !is_name_separator_char(*ptr)) {
2749 token->len++;
2750 token->fulllen++;
2751 ptr++;
2754 /* skip separators */
2755 while (is_name_separator_char(*ptr)) {
2756 token->fulllen++;
2757 ptr++;
2760 list_add_head(tokens, &token->entry);
2764 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2766 struct name_token *token, *token2;
2767 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2768 int len;
2770 list_remove(&token->entry);
2772 /* don't include last separator */
2773 len = list_empty(tokens) ? token->len : token->fulllen;
2774 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2775 nameW += len;
2777 heap_free(token);
2779 *nameW = 0;
2782 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2784 struct name_token stretch_name, weight_name, style_name;
2785 WCHAR familynameW[255], facenameW[255], finalW[255];
2786 WCHAR weightW[32], stretchW[32], styleW[32];
2787 const WCHAR *regular_ptr = NULL;
2788 DWRITE_FONT_STRETCH stretch;
2789 DWRITE_FONT_WEIGHT weight;
2790 struct list tokens;
2791 int len;
2793 /* remove leading and trailing spaces from family and face name */
2794 trim_spaces(familyW, familynameW);
2795 len = trim_spaces(faceW, facenameW);
2797 /* remove rightmost regular variant from face name */
2798 regular_ptr = facename_remove_regular_term(facenameW, len);
2800 /* append face name to family name, FIXME check if face name is a substring of family name */
2801 if (*facenameW) {
2802 strcatW(familynameW, spaceW);
2803 strcatW(familynameW, facenameW);
2806 /* tokenize with " .-_" */
2807 fontname_tokenize(&tokens, familynameW);
2809 /* extract and resolve style */
2810 font->style = font_extract_style(&tokens, font->style, &style_name);
2812 /* extract stretch */
2813 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2815 /* extract weight */
2816 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2818 /* resolve weight */
2819 if (weight != font->weight) {
2820 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2821 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2822 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2823 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2824 !(abs(weight - font->weight) <= 150 &&
2825 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2826 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2827 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2829 font->weight = weight;
2833 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2834 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2835 stretch itself is normal (extracted stretch is never normal). */
2836 if (stretch != font->stretch) {
2837 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2838 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2839 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2841 font->stretch = stretch;
2845 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2847 /* get final combined string from what's left in token list, list is released */
2848 fontname_tokens_to_str(&tokens, finalW);
2850 if (!strcmpW(familyW, finalW))
2851 return FALSE;
2853 /* construct face name */
2854 strcpyW(familyW, finalW);
2856 /* resolved weight name */
2857 if (weight_name.ptr)
2858 font_name_token_to_str(&weight_name, weightW);
2859 /* ignore normal weight */
2860 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2861 weightW[0] = 0;
2862 /* for known weight values use appropriate names */
2863 else if (is_known_weight_value(font->weight, weightW)) {
2865 /* use Wnnn format as a fallback in case weight is not one of known values */
2866 else {
2867 static const WCHAR fmtW[] = {'W','%','d',0};
2868 sprintfW(weightW, fmtW, font->weight);
2871 /* resolved stretch name */
2872 if (stretch_name.ptr)
2873 font_name_token_to_str(&stretch_name, stretchW);
2874 /* ignore normal stretch */
2875 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2876 stretchW[0] = 0;
2877 /* use predefined stretch names */
2878 else {
2879 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2880 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2881 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2882 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2883 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2884 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2886 static const WCHAR *stretchnamesW[] = {
2887 ultracondensedW,
2888 extracondensedW,
2889 condensedW,
2890 semicondensedW,
2891 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
2892 semiexpandedW,
2893 expandedW,
2894 extraexpandedW,
2895 ultraexpandedW
2897 strcpyW(stretchW, stretchnamesW[font->stretch]);
2900 /* resolved style name */
2901 if (style_name.ptr)
2902 font_name_token_to_str(&style_name, styleW);
2903 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
2904 styleW[0] = 0;
2905 /* use predefined names */
2906 else {
2907 if (font->style == DWRITE_FONT_STYLE_ITALIC)
2908 strcpyW(styleW, italicW);
2909 else
2910 strcpyW(styleW, obliqueW);
2913 /* use Regular match if it was found initially */
2914 if (!*weightW && !*stretchW && !*styleW)
2915 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
2916 else {
2917 faceW[0] = 0;
2918 if (*stretchW)
2919 strcpyW(faceW, stretchW);
2920 if (*weightW) {
2921 if (*faceW)
2922 strcatW(faceW, spaceW);
2923 strcatW(faceW, weightW);
2925 if (*styleW) {
2926 if (*faceW)
2927 strcatW(faceW, spaceW);
2928 strcatW(faceW, styleW);
2932 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
2933 return TRUE;
2936 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
2937 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
2939 struct dwrite_font_props props;
2940 struct dwrite_font_data *data;
2941 IDWriteFontFileStream *stream;
2942 WCHAR familyW[255], faceW[255];
2943 HRESULT hr;
2945 *ret = NULL;
2946 data = heap_alloc_zero(sizeof(*data));
2947 if (!data)
2948 return E_OUTOFMEMORY;
2950 hr = get_filestream_from_file(file, &stream);
2951 if (FAILED(hr)) {
2952 heap_free(data);
2953 return hr;
2956 data->ref = 1;
2957 data->factory = factory;
2958 data->file = file;
2959 data->face_index = face_index;
2960 data->face_type = face_type;
2961 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
2962 data->bold_sim_tested = 0;
2963 data->oblique_sim_tested = 0;
2964 IDWriteFontFile_AddRef(file);
2965 IDWriteFactory2_AddRef(factory);
2967 opentype_get_font_properties(stream, face_type, face_index, &props);
2968 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
2969 opentype_get_font_facename(stream, face_type, face_index, &data->names);
2971 /* get family name from font file */
2972 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
2973 IDWriteFontFileStream_Release(stream);
2974 if (FAILED(hr)) {
2975 WARN("unable to get family name from font\n");
2976 release_font_data(data);
2977 return hr;
2980 data->style = props.style;
2981 data->stretch = props.stretch;
2982 data->weight = props.weight;
2983 data->panose = props.panose;
2985 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
2986 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
2987 if (font_apply_differentiation_rules(data, familyW, faceW)) {
2988 set_en_localizedstring(*family_name, familyW);
2989 set_en_localizedstring(data->names, faceW);
2992 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2994 *ret = data;
2995 return S_OK;
2998 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
2999 struct dwrite_font_data **ret)
3001 struct dwrite_font_data *data;
3003 *ret = NULL;
3004 data = heap_alloc_zero(sizeof(*data));
3005 if (!data)
3006 return E_OUTOFMEMORY;
3008 *data = *src;
3009 data->ref = 1;
3010 data->simulations |= sim;
3011 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3012 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3013 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3014 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3015 memset(data->info_strings, 0, sizeof(data->info_strings));
3016 data->names = NULL;
3017 IDWriteFactory2_AddRef(data->factory);
3018 IDWriteFontFile_AddRef(data->file);
3020 create_localizedstrings(&data->names);
3021 add_localizedstring(data->names, enusW, facenameW);
3023 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3025 *ret = data;
3026 return S_OK;
3029 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3031 struct dwrite_fontfamily_data *data;
3033 data = heap_alloc(sizeof(*data));
3034 if (!data)
3035 return E_OUTOFMEMORY;
3037 data->ref = 1;
3038 data->font_count = 0;
3039 data->font_alloc = 2;
3040 data->has_normal_face = 0;
3041 data->has_oblique_face = 0;
3042 data->has_italic_face = 0;
3044 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3045 if (!data->fonts) {
3046 heap_free(data);
3047 return E_OUTOFMEMORY;
3050 data->familyname = familyname;
3051 IDWriteLocalizedStrings_AddRef(familyname);
3053 *ret = data;
3054 return S_OK;
3057 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3059 UINT32 i, j, heaviest;
3061 for (i = 0; i < family->font_count; i++) {
3062 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3063 heaviest = i;
3065 if (family->fonts[i]->bold_sim_tested)
3066 continue;
3068 family->fonts[i]->bold_sim_tested = 1;
3069 for (j = i; j < family->font_count; j++) {
3070 if (family->fonts[j]->bold_sim_tested)
3071 continue;
3073 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3074 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3075 if (family->fonts[j]->weight > weight) {
3076 weight = family->fonts[j]->weight;
3077 heaviest = j;
3079 family->fonts[j]->bold_sim_tested = 1;
3083 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3084 static const struct name_pattern weightsim_patterns[] = {
3085 { extraW, lightW },
3086 { extW, lightW },
3087 { ultraW, lightW },
3088 { semiW, lightW },
3089 { semiW, boldW },
3090 { demiW, boldW },
3091 { boldW },
3092 { thinW },
3093 { lightW },
3094 { mediumW },
3095 { demiW },
3096 { NULL }
3099 WCHAR facenameW[255], initialW[255];
3100 struct dwrite_font_data *boldface;
3101 struct list tokens;
3103 /* add Bold simulation based on heaviest face data */
3105 /* Simulated face name should only contain Bold as weight term,
3106 so remove existing regular and weight terms. */
3107 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3108 facename_remove_regular_term(initialW, -1);
3110 /* remove current weight pattern */
3111 fontname_tokenize(&tokens, initialW);
3112 match_pattern_list(&tokens, weightsim_patterns, NULL);
3113 fontname_tokens_to_str(&tokens, facenameW);
3115 /* Bold suffix for new name */
3116 if (*facenameW)
3117 strcatW(facenameW, spaceW);
3118 strcatW(facenameW, boldW);
3120 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3121 boldface->bold_sim_tested = 1;
3122 fontfamily_add_font(family, boldface);
3128 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3130 UINT32 i, j;
3132 for (i = 0; i < family->font_count; i++) {
3133 UINT32 regular = ~0u, oblique = ~0u;
3134 struct dwrite_font_data *obliqueface;
3135 WCHAR facenameW[255];
3137 if (family->fonts[i]->oblique_sim_tested)
3138 continue;
3140 family->fonts[i]->oblique_sim_tested = 1;
3141 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3142 regular = i;
3143 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3144 oblique = i;
3146 /* find regular style with same weight/stretch values */
3147 for (j = i; j < family->font_count; j++) {
3148 if (family->fonts[j]->oblique_sim_tested)
3149 continue;
3151 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3152 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3154 family->fonts[j]->oblique_sim_tested = 1;
3155 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3156 regular = j;
3158 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3159 oblique = j;
3162 if (regular != ~0u && oblique != ~0u)
3163 break;
3166 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3167 if (regular == ~0u)
3168 continue;
3170 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3171 if (oblique != ~0u)
3172 continue;
3174 /* add oblique simulation based on this regular face */
3176 /* remove regular term if any, append 'Oblique' */
3177 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3178 facename_remove_regular_term(facenameW, -1);
3180 if (*facenameW)
3181 strcatW(facenameW, spaceW);
3182 strcatW(facenameW, obliqueW);
3184 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3185 obliqueface->oblique_sim_tested = 1;
3186 fontfamily_add_font(family, obliqueface);
3191 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3192 const WCHAR *replacement_name)
3194 UINT32 i = collection_find_family(collection, replacement_name);
3195 struct dwrite_fontfamily_data *target;
3196 IDWriteLocalizedStrings *strings;
3197 HRESULT hr;
3199 /* replacement does not exist */
3200 if (i == ~0u)
3201 return FALSE;
3203 hr = create_localizedstrings(&strings);
3204 if (FAILED(hr))
3205 return FALSE;
3207 /* add a new family with target name, reuse font data from replacement */
3208 add_localizedstring(strings, enusW, target_name);
3209 hr = init_fontfamily_data(strings, &target);
3210 if (hr == S_OK) {
3211 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3212 WCHAR nameW[255];
3214 for (i = 0; i < replacement->font_count; i++)
3215 fontfamily_add_font(target, replacement->fonts[i]);
3217 fontcollection_add_family(collection, target);
3218 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3219 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3221 IDWriteLocalizedStrings_Release(strings);
3222 return TRUE;
3225 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3226 system font collections. */
3227 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3229 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3230 WCHAR *name;
3231 void *data;
3232 HKEY hkey;
3234 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3235 return;
3237 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3238 RegCloseKey(hkey);
3239 return;
3242 max_namelen++; /* returned value doesn't include room for '\0' */
3243 name = heap_alloc(max_namelen * sizeof(WCHAR));
3244 data = heap_alloc(max_datalen);
3246 datalen = max_datalen;
3247 namelen = max_namelen;
3248 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3249 if (collection_find_family(collection, name) == ~0u) {
3250 if (type == REG_MULTI_SZ) {
3251 WCHAR *replacement = data;
3252 while (*replacement) {
3253 if (fontcollection_add_replacement(collection, name, replacement))
3254 break;
3255 replacement += strlenW(replacement) + 1;
3258 else if (type == REG_SZ)
3259 fontcollection_add_replacement(collection, name, data);
3261 else
3262 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3264 datalen = max_datalen;
3265 namelen = max_namelen;
3268 heap_free(data);
3269 heap_free(name);
3270 RegCloseKey(hkey);
3273 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3275 struct fontfile_enum {
3276 struct list entry;
3277 IDWriteFontFile *file;
3279 struct fontfile_enum *fileenum, *fileenum2;
3280 struct dwrite_fontcollection *collection;
3281 struct list scannedfiles;
3282 BOOL current = FALSE;
3283 HRESULT hr = S_OK;
3284 UINT32 i;
3286 *ret = NULL;
3288 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3289 if (!collection) return E_OUTOFMEMORY;
3291 hr = init_font_collection(collection, is_system);
3292 if (FAILED(hr)) {
3293 heap_free(collection);
3294 return hr;
3297 *ret = &collection->IDWriteFontCollection_iface;
3299 TRACE("building font collection:\n");
3301 list_init(&scannedfiles);
3302 while (hr == S_OK) {
3303 DWRITE_FONT_FACE_TYPE face_type;
3304 DWRITE_FONT_FILE_TYPE file_type;
3305 BOOL supported, same = FALSE;
3306 IDWriteFontFile *file;
3307 UINT32 face_count;
3309 current = FALSE;
3310 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3311 if (FAILED(hr) || !current)
3312 break;
3314 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3315 if (FAILED(hr))
3316 break;
3318 /* check if we've scanned this file already */
3319 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3320 if ((same = is_same_fontfile(fileenum->file, file)))
3321 break;
3324 if (same) {
3325 IDWriteFontFile_Release(file);
3326 continue;
3329 /* failed font files are skipped */
3330 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3331 if (FAILED(hr) || !supported || face_count == 0) {
3332 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3333 IDWriteFontFile_Release(file);
3334 hr = S_OK;
3335 continue;
3338 /* add to scanned list */
3339 fileenum = heap_alloc(sizeof(*fileenum));
3340 fileenum->file = file;
3341 list_add_tail(&scannedfiles, &fileenum->entry);
3343 for (i = 0; i < face_count; i++) {
3344 IDWriteLocalizedStrings *family_name = NULL;
3345 struct dwrite_font_data *font_data;
3346 WCHAR familyW[255];
3347 UINT32 index;
3349 /* alloc and init new font data structure */
3350 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3351 if (FAILED(hr)) {
3352 /* move to next one */
3353 hr = S_OK;
3354 continue;
3357 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3359 index = collection_find_family(collection, familyW);
3360 if (index != ~0u)
3361 hr = fontfamily_add_font(collection->family_data[index], font_data);
3362 else {
3363 struct dwrite_fontfamily_data *family_data;
3365 /* create and init new family */
3366 hr = init_fontfamily_data(family_name, &family_data);
3367 if (hr == S_OK) {
3368 /* add font to family, family - to collection */
3369 hr = fontfamily_add_font(family_data, font_data);
3370 if (hr == S_OK)
3371 hr = fontcollection_add_family(collection, family_data);
3373 if (FAILED(hr))
3374 release_fontfamily_data(family_data);
3378 IDWriteLocalizedStrings_Release(family_name);
3380 if (FAILED(hr))
3381 break;
3385 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3386 IDWriteFontFile_Release(fileenum->file);
3387 list_remove(&fileenum->entry);
3388 heap_free(fileenum);
3391 for (i = 0; i < collection->family_count; i++) {
3392 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3393 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3396 if (is_system)
3397 fontcollection_add_replacements(collection);
3399 return hr;
3402 struct system_fontfile_enumerator
3404 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3405 LONG ref;
3407 IDWriteFactory2 *factory;
3408 HKEY hkey;
3409 int index;
3412 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3414 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3417 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3419 *obj = NULL;
3421 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3422 IDWriteFontFileEnumerator_AddRef(iface);
3423 *obj = iface;
3424 return S_OK;
3427 return E_NOINTERFACE;
3430 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3432 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3433 return InterlockedIncrement(&enumerator->ref);
3436 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3438 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3439 ULONG ref = InterlockedDecrement(&enumerator->ref);
3441 if (!ref) {
3442 IDWriteFactory2_Release(enumerator->factory);
3443 RegCloseKey(enumerator->hkey);
3444 heap_free(enumerator);
3447 return ref;
3450 static HRESULT create_local_file_reference(IDWriteFactory2 *factory, const WCHAR *filename, IDWriteFontFile **file)
3452 HRESULT hr;
3454 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3455 if (!strchrW(filename, '\\')) {
3456 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3457 WCHAR fullpathW[MAX_PATH];
3459 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3460 strcatW(fullpathW, fontsW);
3461 strcatW(fullpathW, filename);
3463 hr = IDWriteFactory2_CreateFontFileReference(factory, fullpathW, NULL, file);
3465 else
3466 hr = IDWriteFactory2_CreateFontFileReference(factory, filename, NULL, file);
3468 return hr;
3471 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3473 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3474 DWORD ret, type, val_count, count;
3475 WCHAR *value, *filename;
3476 HRESULT hr;
3478 *file = NULL;
3480 if (enumerator->index < 0)
3481 return E_FAIL;
3483 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3484 if (ret != ERROR_SUCCESS)
3485 return E_FAIL;
3487 val_count++;
3488 value = heap_alloc( val_count * sizeof(value[0]) );
3489 filename = heap_alloc(count);
3490 if (!value || !filename) {
3491 heap_free(value);
3492 heap_free(filename);
3493 return E_OUTOFMEMORY;
3496 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3497 if (ret) {
3498 heap_free(value);
3499 heap_free(filename);
3500 return E_FAIL;
3503 hr = create_local_file_reference(enumerator->factory, filename, file);
3505 heap_free(value);
3506 heap_free(filename);
3507 return hr;
3510 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3512 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3513 DWORD ret, max_val_count;
3514 WCHAR *value;
3516 *current = FALSE;
3517 enumerator->index++;
3519 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3520 if (ret != ERROR_SUCCESS)
3521 return E_FAIL;
3523 max_val_count++;
3524 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3525 return E_OUTOFMEMORY;
3527 /* iterate until we find next string value */
3528 while (1) {
3529 DWORD type = 0, count, val_count;
3530 val_count = max_val_count;
3531 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3532 break;
3533 if (type == REG_SZ) {
3534 *current = TRUE;
3535 break;
3537 enumerator->index++;
3540 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3541 heap_free(value);
3542 return S_OK;
3545 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3547 systemfontfileenumerator_QueryInterface,
3548 systemfontfileenumerator_AddRef,
3549 systemfontfileenumerator_Release,
3550 systemfontfileenumerator_MoveNext,
3551 systemfontfileenumerator_GetCurrentFontFile
3554 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
3556 struct system_fontfile_enumerator *enumerator;
3557 static const WCHAR fontslistW[] = {
3558 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3559 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3560 'F','o','n','t','s',0
3563 *ret = NULL;
3565 enumerator = heap_alloc(sizeof(*enumerator));
3566 if (!enumerator)
3567 return E_OUTOFMEMORY;
3569 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3570 enumerator->ref = 1;
3571 enumerator->factory = factory;
3572 enumerator->index = -1;
3573 IDWriteFactory2_AddRef(factory);
3575 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3576 ERR("failed to open fonts list key\n");
3577 IDWriteFactory2_Release(factory);
3578 heap_free(enumerator);
3579 return E_FAIL;
3582 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3584 return S_OK;
3587 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3589 IDWriteFontFileEnumerator *enumerator;
3590 HRESULT hr;
3592 *collection = NULL;
3594 hr = create_system_fontfile_enumerator(factory, &enumerator);
3595 if (FAILED(hr))
3596 return hr;
3598 TRACE("building system font collection for factory %p\n", factory);
3599 hr = create_font_collection(factory, enumerator, TRUE, collection);
3600 IDWriteFontFileEnumerator_Release(enumerator);
3601 return hr;
3604 static HRESULT eudc_collection_add_family(IDWriteFactory2 *factory, struct dwrite_fontcollection *collection,
3605 const WCHAR *keynameW, const WCHAR *pathW)
3607 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};
3608 static const WCHAR emptyW[] = {0};
3609 IDWriteLocalizedStrings *names;
3610 DWRITE_FONT_FACE_TYPE face_type;
3611 DWRITE_FONT_FILE_TYPE file_type;
3612 BOOL supported;
3613 UINT32 face_count, i;
3614 IDWriteFontFile *file;
3615 HRESULT hr;
3616 struct dwrite_fontfamily_data *family_data;
3618 /* create font file from this path */
3619 hr = create_local_file_reference(factory, pathW, &file);
3620 if (FAILED(hr))
3621 return S_FALSE;
3623 /* failed font files are skipped */
3624 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3625 if (FAILED(hr) || !supported || face_count == 0) {
3626 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3627 IDWriteFontFile_Release(file);
3628 return S_FALSE;
3631 /* create and init new family */
3633 /* Family names are added for non-specific locale, represented with empty string.
3634 Default family appears with empty family name. */
3635 create_localizedstrings(&names);
3636 if (!strcmpiW(keynameW, defaultfontW))
3637 add_localizedstring(names, emptyW, emptyW);
3638 else
3639 add_localizedstring(names, emptyW, keynameW);
3641 hr = init_fontfamily_data(names, &family_data);
3642 IDWriteLocalizedStrings_Release(names);
3643 if (hr != S_OK) {
3644 IDWriteFontFile_Release(file);
3645 return hr;
3648 /* fill with faces */
3649 for (i = 0; i < face_count; i++) {
3650 struct dwrite_font_data *font_data;
3652 /* alloc and init new font data structure */
3653 hr = init_font_data(factory, file, face_type, i, &names, &font_data);
3654 if (FAILED(hr))
3655 continue;
3657 IDWriteLocalizedStrings_Release(names);
3659 /* add font to family */
3660 hr = fontfamily_add_font(family_data, font_data);
3661 if (hr != S_OK)
3662 release_font_data(font_data);
3665 /* add family to collection */
3666 hr = fontcollection_add_family(collection, family_data);
3667 if (FAILED(hr))
3668 release_fontfamily_data(family_data);
3669 IDWriteFontFile_Release(file);
3671 return hr;
3674 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **ret)
3676 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3677 struct dwrite_fontcollection *collection;
3678 static const WCHAR emptyW[] = {0};
3679 WCHAR eudckeypathW[16];
3680 HKEY eudckey;
3681 DWORD index;
3682 BOOL exists;
3683 LONG retval;
3684 HRESULT hr;
3685 UINT32 i;
3687 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3689 *ret = NULL;
3691 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3692 if (!collection) return E_OUTOFMEMORY;
3694 hr = init_font_collection(collection, FALSE);
3695 if (FAILED(hr)) {
3696 heap_free(collection);
3697 return hr;
3700 *ret = &collection->IDWriteFontCollection_iface;
3702 /* return empty collection if EUDC fonts are not configured */
3703 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3704 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3705 return S_OK;
3707 retval = ERROR_SUCCESS;
3708 index = 0;
3709 while (retval != ERROR_NO_MORE_ITEMS) {
3710 WCHAR keynameW[64], pathW[MAX_PATH];
3711 DWORD type, path_len, name_len;
3713 path_len = sizeof(pathW)/sizeof(*pathW);
3714 name_len = sizeof(keynameW)/sizeof(*keynameW);
3715 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3716 if (retval || type != REG_SZ)
3717 continue;
3719 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3720 if (hr != S_OK)
3721 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3723 RegCloseKey(eudckey);
3725 /* try to add global default if not defined for specific codepage */
3726 exists = FALSE;
3727 hr = IDWriteFontCollection_FindFamilyName(&collection->IDWriteFontCollection_iface, emptyW,
3728 &index, &exists);
3729 if (FAILED(hr) || !exists) {
3730 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3731 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3732 if (hr != S_OK)
3733 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3736 /* EUDC collection offers simulated faces too */
3737 for (i = 0; i < collection->family_count; i++) {
3738 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3739 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3742 return S_OK;
3745 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3747 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3749 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3751 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3753 *obj = iface;
3754 IDWriteFontFile_AddRef(iface);
3755 return S_OK;
3758 *obj = NULL;
3759 return E_NOINTERFACE;
3762 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3764 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3765 ULONG ref = InterlockedIncrement(&This->ref);
3766 TRACE("(%p)->(%d)\n", This, ref);
3767 return ref;
3770 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3772 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3773 ULONG ref = InterlockedDecrement(&This->ref);
3775 TRACE("(%p)->(%d)\n", This, ref);
3777 if (!ref)
3779 IDWriteFontFileLoader_Release(This->loader);
3780 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3781 heap_free(This->reference_key);
3782 heap_free(This);
3785 return ref;
3788 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3790 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3791 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3792 *fontFileReferenceKey = This->reference_key;
3793 *fontFileReferenceKeySize = This->key_size;
3795 return S_OK;
3798 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3800 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3801 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3802 *fontFileLoader = This->loader;
3803 IDWriteFontFileLoader_AddRef(This->loader);
3805 return S_OK;
3808 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
3809 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3811 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3812 IDWriteFontFileStream *stream;
3813 HRESULT hr;
3815 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3817 *isSupportedFontType = FALSE;
3818 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3819 if (fontFaceType)
3820 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3821 *numberOfFaces = 0;
3823 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3824 if (FAILED(hr))
3825 return hr;
3827 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3829 /* TODO: Further Analysis */
3830 IDWriteFontFileStream_Release(stream);
3831 return S_OK;
3834 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3835 dwritefontfile_QueryInterface,
3836 dwritefontfile_AddRef,
3837 dwritefontfile_Release,
3838 dwritefontfile_GetReferenceKey,
3839 dwritefontfile_GetLoader,
3840 dwritefontfile_Analyze,
3843 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3845 struct dwrite_fontfile *This;
3847 This = heap_alloc(sizeof(struct dwrite_fontfile));
3848 if (!This) return E_OUTOFMEMORY;
3850 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3851 This->ref = 1;
3852 IDWriteFontFileLoader_AddRef(loader);
3853 This->loader = loader;
3854 This->stream = NULL;
3855 This->reference_key = heap_alloc(key_size);
3856 memcpy(This->reference_key, reference_key, key_size);
3857 This->key_size = key_size;
3859 *font_file = &This->IDWriteFontFile_iface;
3861 return S_OK;
3864 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3866 IDWriteFontFileLoader *loader;
3867 UINT32 key_size;
3868 const void *key;
3869 HRESULT hr;
3871 *stream = NULL;
3872 hr = IDWriteFontFile_GetLoader(file, &loader);
3873 if (FAILED(hr))
3874 return hr;
3876 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3877 if (FAILED(hr)) {
3878 IDWriteFontFileLoader_Release(loader);
3879 return hr;
3882 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3883 IDWriteFontFileLoader_Release(loader);
3885 return hr;
3888 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
3889 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
3891 struct dwrite_fontface *fontface;
3892 HRESULT hr = S_OK;
3893 int i;
3895 *ret = NULL;
3897 fontface = heap_alloc(sizeof(struct dwrite_fontface));
3898 if (!fontface)
3899 return E_OUTOFMEMORY;
3901 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
3902 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
3904 if (!fontface->files || !fontface->streams) {
3905 heap_free(fontface->files);
3906 heap_free(fontface->streams);
3907 heap_free(fontface);
3908 return E_OUTOFMEMORY;
3911 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
3912 fontface->ref = 1;
3913 fontface->type = facetype;
3914 fontface->file_count = files_number;
3915 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
3916 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
3917 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
3918 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
3919 memset(&fontface->colr, 0, sizeof(fontface->colr));
3920 fontface->cmap.exists = TRUE;
3921 fontface->vdmx.exists = TRUE;
3922 fontface->gasp.exists = TRUE;
3923 fontface->cpal.exists = TRUE;
3924 fontface->colr.exists = TRUE;
3925 fontface->index = index;
3926 fontface->simulations = simulations;
3927 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
3929 for (i = 0; i < fontface->file_count; i++) {
3930 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
3931 if (FAILED(hr)) {
3932 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
3933 return hr;
3936 fontface->files[i] = font_files[i];
3937 IDWriteFontFile_AddRef(font_files[i]);
3940 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
3941 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
3942 /* TODO: test what happens if caret is already slanted */
3943 if (fontface->caret.slopeRise == 1) {
3944 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
3945 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
3948 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
3949 fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
3950 fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
3952 *ret = &fontface->IDWriteFontFace3_iface;
3953 return S_OK;
3956 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3957 struct local_refkey
3959 FILETIME writetime;
3960 WCHAR name[1];
3963 struct local_cached_stream
3965 struct list entry;
3966 IDWriteFontFileStream *stream;
3967 struct local_refkey *key;
3968 UINT32 key_size;
3971 struct dwrite_localfontfilestream
3973 IDWriteFontFileStream IDWriteFontFileStream_iface;
3974 LONG ref;
3976 struct local_cached_stream *entry;
3977 const void *file_ptr;
3978 UINT64 size;
3981 struct dwrite_localfontfileloader {
3982 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
3983 LONG ref;
3985 struct list streams;
3988 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
3990 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
3993 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
3995 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
3998 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4000 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4001 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4002 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4004 *obj = iface;
4005 IDWriteFontFileStream_AddRef(iface);
4006 return S_OK;
4009 *obj = NULL;
4010 return E_NOINTERFACE;
4013 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4015 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4016 ULONG ref = InterlockedIncrement(&This->ref);
4017 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4018 return ref;
4021 static inline void release_cached_stream(struct local_cached_stream *stream)
4023 list_remove(&stream->entry);
4024 heap_free(stream->key);
4025 heap_free(stream);
4028 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4030 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4031 ULONG ref = InterlockedDecrement(&This->ref);
4033 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4035 if (!ref) {
4036 UnmapViewOfFile(This->file_ptr);
4037 release_cached_stream(This->entry);
4038 heap_free(This);
4041 return ref;
4044 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
4046 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4048 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
4049 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4051 *fragment_context = NULL;
4053 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4054 *fragment_start = NULL;
4055 return E_FAIL;
4058 *fragment_start = (char*)This->file_ptr + offset;
4059 return S_OK;
4062 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4064 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4065 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4068 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4070 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4071 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4072 *size = This->size;
4073 return S_OK;
4076 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4078 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4079 ULARGE_INTEGER li;
4081 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4083 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4084 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4085 *last_writetime = li.QuadPart;
4087 return S_OK;
4090 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4092 localfontfilestream_QueryInterface,
4093 localfontfilestream_AddRef,
4094 localfontfilestream_Release,
4095 localfontfilestream_ReadFileFragment,
4096 localfontfilestream_ReleaseFileFragment,
4097 localfontfilestream_GetFileSize,
4098 localfontfilestream_GetLastWriteTime
4101 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4103 struct dwrite_localfontfilestream *This;
4105 *ret = NULL;
4107 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4108 if (!This)
4109 return E_OUTOFMEMORY;
4111 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4112 This->ref = 1;
4114 This->file_ptr = file_ptr;
4115 This->size = size;
4116 This->entry = entry;
4118 *ret = &This->IDWriteFontFileStream_iface;
4119 return S_OK;
4122 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4124 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4126 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4128 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4130 *obj = iface;
4131 IDWriteLocalFontFileLoader_AddRef(iface);
4132 return S_OK;
4135 *obj = NULL;
4136 return E_NOINTERFACE;
4139 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4141 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4142 ULONG ref = InterlockedIncrement(&This->ref);
4143 TRACE("(%p)->(%d)\n", This, ref);
4144 return ref;
4147 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4149 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4150 ULONG ref = InterlockedDecrement(&This->ref);
4152 TRACE("(%p)->(%d)\n", This, ref);
4154 if (!ref) {
4155 struct local_cached_stream *stream, *stream2;
4157 /* This will detach all entries from cache. Entries are released together with streams,
4158 so stream controls cache entry lifetime. */
4159 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4160 list_init(&stream->entry);
4162 heap_free(This);
4165 return ref;
4168 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4170 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4171 const struct local_refkey *refkey = key;
4172 struct local_cached_stream *stream;
4173 IDWriteFontFileStream *filestream;
4174 HANDLE file, mapping;
4175 LARGE_INTEGER size;
4176 void *file_ptr;
4177 HRESULT hr;
4179 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4180 TRACE("name: %s\n", debugstr_w(refkey->name));
4182 /* search cache first */
4183 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4184 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4185 *ret = stream->stream;
4186 IDWriteFontFileStream_AddRef(*ret);
4187 return S_OK;
4191 *ret = NULL;
4193 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4194 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4195 if (file == INVALID_HANDLE_VALUE)
4196 return E_FAIL;
4198 GetFileSizeEx(file, &size);
4199 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4200 CloseHandle(file);
4201 if (!mapping)
4202 return E_FAIL;
4204 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4205 CloseHandle(mapping);
4207 stream = heap_alloc(sizeof(*stream));
4208 if (!stream) {
4209 UnmapViewOfFile(file_ptr);
4210 return E_OUTOFMEMORY;
4213 stream->key = heap_alloc(key_size);
4214 if (!stream->key) {
4215 UnmapViewOfFile(file_ptr);
4216 heap_free(stream);
4217 return E_OUTOFMEMORY;
4220 stream->key_size = key_size;
4221 memcpy(stream->key, key, key_size);
4223 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4224 if (FAILED(hr)) {
4225 UnmapViewOfFile(file_ptr);
4226 heap_free(stream->key);
4227 heap_free(stream);
4228 return hr;
4231 stream->stream = filestream;
4232 list_add_head(&This->streams, &stream->entry);
4234 *ret = stream->stream;
4236 return S_OK;
4239 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4241 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4242 const struct local_refkey *refkey = key;
4244 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4246 *length = strlenW(refkey->name);
4247 return S_OK;
4250 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4252 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4253 const struct local_refkey *refkey = key;
4255 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4257 if (length < strlenW(refkey->name))
4258 return E_INVALIDARG;
4260 strcpyW(path, refkey->name);
4261 return S_OK;
4264 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4266 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4267 const struct local_refkey *refkey = key;
4269 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4271 *writetime = refkey->writetime;
4272 return S_OK;
4275 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4276 localfontfileloader_QueryInterface,
4277 localfontfileloader_AddRef,
4278 localfontfileloader_Release,
4279 localfontfileloader_CreateStreamFromKey,
4280 localfontfileloader_GetFilePathLengthFromKey,
4281 localfontfileloader_GetFilePathFromKey,
4282 localfontfileloader_GetLastWriteTimeFromKey
4285 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4287 struct dwrite_localfontfileloader *This;
4289 *ret = NULL;
4291 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4292 if (!This)
4293 return E_OUTOFMEMORY;
4295 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4296 This->ref = 1;
4297 list_init(&This->streams);
4299 *ret = &This->IDWriteLocalFontFileLoader_iface;
4300 return S_OK;
4303 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4305 struct local_refkey *refkey;
4307 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4308 *key = NULL;
4310 refkey = heap_alloc(*size);
4311 if (!refkey)
4312 return E_OUTOFMEMORY;
4314 if (writetime)
4315 refkey->writetime = *writetime;
4316 else {
4317 WIN32_FILE_ATTRIBUTE_DATA info;
4319 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4320 refkey->writetime = info.ftLastWriteTime;
4321 else
4322 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4324 strcpyW(refkey->name, path);
4326 *key = refkey;
4328 return S_OK;
4331 /* IDWriteGlyphRunAnalysis */
4332 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4334 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4336 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4338 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4339 IsEqualIID(riid, &IID_IUnknown))
4341 *ppv = iface;
4342 IDWriteGlyphRunAnalysis_AddRef(iface);
4343 return S_OK;
4346 *ppv = NULL;
4347 return E_NOINTERFACE;
4350 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4352 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4353 ULONG ref = InterlockedIncrement(&This->ref);
4354 TRACE("(%p)->(%u)\n", This, ref);
4355 return ref;
4358 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4360 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4361 ULONG ref = InterlockedDecrement(&This->ref);
4363 TRACE("(%p)->(%u)\n", This, ref);
4365 if (!ref) {
4366 if (This->run.fontFace)
4367 IDWriteFontFace_Release(This->run.fontFace);
4368 heap_free(This->glyphs);
4369 heap_free(This->advances);
4370 heap_free(This->advanceoffsets);
4371 heap_free(This->ascenderoffsets);
4372 heap_free(This->bitmap);
4373 heap_free(This);
4376 return ref;
4379 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4381 struct dwrite_glyphbitmap glyph_bitmap;
4382 IDWriteFontFace3 *fontface3;
4383 D2D_POINT_2F origin;
4384 BOOL is_rtl;
4385 HRESULT hr;
4386 UINT32 i;
4388 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4389 *bounds = analysis->bounds;
4390 return;
4393 if (analysis->run.isSideways)
4394 FIXME("sideways runs are not supported.\n");
4396 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4397 if (FAILED(hr))
4398 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4400 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4401 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4402 for any non-zero glyph ascender */
4403 origin.x = origin.y = 0.0f;
4404 is_rtl = analysis->run.bidiLevel & 1;
4406 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4407 glyph_bitmap.fontface = fontface3;
4408 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4409 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4410 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4411 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4412 glyph_bitmap.m = &analysis->m;
4414 for (i = 0; i < analysis->run.glyphCount; i++) {
4415 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4416 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4417 const D2D_POINT_2F *advance = analysis->advances + i;
4418 RECT *bbox = &glyph_bitmap.bbox;
4420 glyph_bitmap.index = analysis->run.glyphIndices[i];
4421 freetype_get_glyph_bbox(&glyph_bitmap);
4423 if (is_rtl)
4424 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4425 else
4426 OffsetRect(bbox, origin.x, origin.y);
4428 if (advanceoffset)
4429 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4431 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4432 origin.x += advance->x;
4433 origin.y += advance->y;
4436 IDWriteFontFace3_Release(fontface3);
4438 /* translate to given run origin */
4439 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4440 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4441 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4443 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4444 *bounds = analysis->bounds;
4447 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4449 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4451 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4453 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4454 memset(bounds, 0, sizeof(*bounds));
4455 return E_INVALIDARG;
4458 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4459 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4460 memset(bounds, 0, sizeof(*bounds));
4461 return S_OK;
4464 glyphrunanalysis_get_texturebounds(This, bounds);
4465 return S_OK;
4468 static inline int get_dib_stride( int width, int bpp )
4470 return ((width * bpp + 31) >> 3) & ~3;
4473 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4475 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4476 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4477 (runbounds->left - bounds->left) * 3;
4478 else
4479 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4480 runbounds->left - bounds->left;
4483 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4485 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4486 struct dwrite_glyphbitmap glyph_bitmap;
4487 IDWriteFontFace3 *fontface2;
4488 D2D_POINT_2F origin;
4489 UINT32 i, size;
4490 BOOL is_rtl;
4491 HRESULT hr;
4492 RECT *bbox;
4494 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4495 if (FAILED(hr)) {
4496 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4497 return;
4500 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4501 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4502 size *= 3;
4503 analysis->bitmap = heap_alloc_zero(size);
4505 origin.x = origin.y = 0.0f;
4506 is_rtl = analysis->run.bidiLevel & 1;
4508 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4509 glyph_bitmap.fontface = fontface2;
4510 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4511 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4512 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4513 glyph_bitmap.type = type;
4514 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4515 glyph_bitmap.m = &analysis->m;
4516 bbox = &glyph_bitmap.bbox;
4518 for (i = 0; i < analysis->run.glyphCount; i++) {
4519 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4520 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4521 const D2D_POINT_2F *advance = analysis->advances + i;
4522 int x, y, width, height;
4523 BYTE *src, *dst;
4524 BOOL is_1bpp;
4526 glyph_bitmap.index = analysis->run.glyphIndices[i];
4527 freetype_get_glyph_bbox(&glyph_bitmap);
4529 if (IsRectEmpty(bbox)) {
4530 origin.x += advance->x;
4531 origin.y += advance->y;
4532 continue;
4535 width = bbox->right - bbox->left;
4536 height = bbox->bottom - bbox->top;
4538 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4539 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4540 else
4541 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4543 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4544 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4546 if (is_rtl)
4547 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4548 else
4549 OffsetRect(bbox, origin.x, origin.y);
4551 if (advanceoffset)
4552 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4554 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4555 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4556 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4558 /* blit to analysis bitmap */
4559 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4561 if (is_1bpp) {
4562 /* convert 1bpp to 8bpp/24bpp */
4563 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4564 for (y = 0; y < height; y++) {
4565 for (x = 0; x < width; x++)
4566 if (src[x / 8] & masks[x % 8])
4567 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4568 src += glyph_bitmap.pitch;
4569 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4572 else {
4573 for (y = 0; y < height; y++) {
4574 for (x = 0; x < width; x++)
4575 if (src[x / 8] & masks[x % 8])
4576 dst[x] = DWRITE_ALPHA_MAX;
4577 src += get_dib_stride(width, 1);
4578 dst += analysis->bounds.right - analysis->bounds.left;
4582 else {
4583 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4584 for (y = 0; y < height; y++) {
4585 for (x = 0; x < width; x++)
4586 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4587 src += glyph_bitmap.pitch;
4588 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4592 heap_free(glyph_bitmap.buf);
4594 origin.x += advance->x;
4595 origin.y += advance->y;
4598 IDWriteFontFace3_Release(fontface2);
4600 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4602 /* we don't need this anymore */
4603 heap_free(analysis->glyphs);
4604 heap_free(analysis->advances);
4605 heap_free(analysis->advanceoffsets);
4606 heap_free(analysis->ascenderoffsets);
4607 IDWriteFontFace_Release(analysis->run.fontFace);
4609 analysis->glyphs = NULL;
4610 analysis->advances = NULL;
4611 analysis->advanceoffsets = NULL;
4612 analysis->ascenderoffsets = NULL;
4613 analysis->run.glyphIndices = NULL;
4614 analysis->run.fontFace = NULL;
4617 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4618 RECT const *bounds, BYTE *bitmap, UINT32 size)
4620 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4621 UINT32 required;
4622 RECT runbounds;
4624 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4626 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4627 return E_INVALIDARG;
4629 /* make sure buffer is large enough for requested texture type */
4630 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4631 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4632 required *= 3;
4634 if (size < required)
4635 return E_NOT_SUFFICIENT_BUFFER;
4637 /* validate requested texture type with rendering mode */
4638 switch (This->rendering_mode)
4640 case DWRITE_RENDERING_MODE_ALIASED:
4641 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4642 return DWRITE_E_UNSUPPORTEDOPERATION;
4643 break;
4644 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4645 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4646 case DWRITE_RENDERING_MODE_NATURAL:
4647 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4648 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4649 return DWRITE_E_UNSUPPORTEDOPERATION;
4650 break;
4651 default:
4655 memset(bitmap, 0, size);
4656 glyphrunanalysis_get_texturebounds(This, &runbounds);
4657 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4658 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4659 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4660 int dst_width = (bounds->right - bounds->left) * pixel_size;
4661 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4662 BYTE *src, *dst;
4663 int y;
4665 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4666 glyphrunanalysis_render(This, type);
4668 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4669 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4671 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4672 memcpy(dst, src, draw_width);
4673 src += src_width;
4674 dst += dst_width;
4678 return S_OK;
4681 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4682 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4684 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4686 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4688 if (!params)
4689 return E_INVALIDARG;
4691 switch (This->rendering_mode)
4693 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4694 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4696 UINT value = 0;
4697 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4698 *gamma = (FLOAT)value / 1000.0f;
4699 *contrast = 0.0f;
4700 *cleartypelevel = 1.0f;
4701 break;
4703 case DWRITE_RENDERING_MODE_ALIASED:
4704 case DWRITE_RENDERING_MODE_NATURAL:
4705 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4706 *gamma = IDWriteRenderingParams_GetGamma(params);
4707 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4708 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4709 break;
4710 default:
4714 return S_OK;
4717 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4718 glyphrunanalysis_QueryInterface,
4719 glyphrunanalysis_AddRef,
4720 glyphrunanalysis_Release,
4721 glyphrunanalysis_GetAlphaTextureBounds,
4722 glyphrunanalysis_CreateAlphaTexture,
4723 glyphrunanalysis_GetAlphaBlendParams
4726 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4728 if (is_vertical) {
4729 vec->x = 0.0f;
4730 vec->y = length;
4732 else {
4733 vec->x = length;
4734 vec->y = 0.0f;
4738 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4740 D2D_POINT_2F ret;
4741 ret.x = vec->x * m->m11 + vec->y * m->m21;
4742 ret.y = vec->x * m->m12 + vec->y * m->m22;
4743 *vec = ret;
4746 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4747 FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
4748 FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4750 struct dwrite_glyphrunanalysis *analysis;
4751 FLOAT rtl_factor;
4752 UINT32 i;
4754 *ret = NULL;
4756 /* check for valid rendering mode */
4757 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4758 return E_INVALIDARG;
4760 analysis = heap_alloc(sizeof(*analysis));
4761 if (!analysis)
4762 return E_OUTOFMEMORY;
4764 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4765 analysis->ref = 1;
4766 analysis->rendering_mode = rendering_mode;
4767 analysis->flags = 0;
4768 analysis->bitmap = NULL;
4769 analysis->ppdip = ppdip;
4770 analysis->origin.x = originX * ppdip;
4771 analysis->origin.y = originY * ppdip;
4772 SetRectEmpty(&analysis->bounds);
4773 analysis->run = *run;
4774 IDWriteFontFace_AddRef(analysis->run.fontFace);
4775 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4776 analysis->advances = heap_alloc(run->glyphCount*sizeof(*analysis->advances));
4777 if (run->glyphOffsets) {
4778 analysis->advanceoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->advanceoffsets));
4779 analysis->ascenderoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->ascenderoffsets));
4781 else {
4782 analysis->advanceoffsets = NULL;
4783 analysis->ascenderoffsets = NULL;
4786 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && run->glyphOffsets)) {
4787 heap_free(analysis->glyphs);
4788 heap_free(analysis->advances);
4789 heap_free(analysis->advanceoffsets);
4790 heap_free(analysis->ascenderoffsets);
4792 analysis->glyphs = NULL;
4793 analysis->advances = NULL;
4794 analysis->advanceoffsets = NULL;
4795 analysis->ascenderoffsets = NULL;
4797 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4798 return E_OUTOFMEMORY;
4801 /* check if transform is usable */
4802 if (transform && memcmp(transform, &identity, sizeof(*transform))) {
4803 analysis->m = *transform;
4804 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4806 else
4807 memset(&analysis->m, 0, sizeof(analysis->m));
4809 analysis->run.glyphIndices = analysis->glyphs;
4810 analysis->run.glyphAdvances = NULL;
4811 analysis->run.glyphOffsets = NULL;
4813 rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f;
4815 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4816 transform_2d_vec(&analysis->origin, &analysis->m);
4818 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4820 if (run->glyphAdvances) {
4821 for (i = 0; i < run->glyphCount; i++) {
4822 init_2d_vec(analysis->advances + i, rtl_factor * run->glyphAdvances[i] * ppdip, run->isSideways);
4823 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4824 transform_2d_vec(analysis->advances + i, &analysis->m);
4827 else {
4828 DWRITE_FONT_METRICS metrics;
4829 IDWriteFontFace1 *fontface1;
4831 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4832 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4834 for (i = 0; i < run->glyphCount; i++) {
4835 HRESULT hr;
4836 INT32 a;
4838 switch (measuring_mode)
4840 case DWRITE_MEASURING_MODE_NATURAL:
4841 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4842 if (FAILED(hr))
4843 a = 0;
4844 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics) * ppdip,
4845 run->isSideways);
4846 break;
4847 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4848 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4849 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, transform,
4850 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4851 if (FAILED(hr))
4852 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4853 else
4854 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f),
4855 run->isSideways);
4856 break;
4857 default:
4861 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4862 transform_2d_vec(analysis->advances + i, &analysis->m);
4865 IDWriteFontFace1_Release(fontface1);
4868 if (run->glyphOffsets) {
4869 for (i = 0; i < run->glyphCount; i++) {
4870 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
4871 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4872 init_2d_vec(analysis->ascenderoffsets + i, -run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
4873 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
4874 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
4875 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
4880 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
4881 return S_OK;
4884 /* IDWriteColorGlyphRunEnumerator */
4885 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
4887 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4889 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4891 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
4892 IsEqualIID(riid, &IID_IUnknown))
4894 *ppv = iface;
4895 IDWriteColorGlyphRunEnumerator_AddRef(iface);
4896 return S_OK;
4899 *ppv = NULL;
4900 return E_NOINTERFACE;
4903 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
4905 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4906 ULONG ref = InterlockedIncrement(&This->ref);
4907 TRACE("(%p)->(%u)\n", This, ref);
4908 return ref;
4911 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
4913 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4914 ULONG ref = InterlockedDecrement(&This->ref);
4916 TRACE("(%p)->(%u)\n", This, ref);
4918 if (!ref) {
4919 heap_free(This->advances);
4920 heap_free(This->color_advances);
4921 heap_free(This->offsets);
4922 heap_free(This->color_offsets);
4923 heap_free(This->glyphindices);
4924 heap_free(This->glyphs);
4925 if (This->colr.context)
4926 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
4927 IDWriteFontFace3_Release(This->fontface);
4928 heap_free(This);
4931 return ref;
4934 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
4936 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
4937 FLOAT origin = 0.0f;
4939 if (g == 0)
4940 return 0.0f;
4942 while (g--)
4943 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
4944 return origin;
4947 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
4949 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
4950 FLOAT advance_adj = 0.0f;
4951 BOOL got_palette_index;
4952 UINT32 g;
4954 /* start with regular glyphs */
4955 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
4956 UINT32 first_glyph = 0;
4958 for (g = 0; g < glyphenum->run.glyphCount; g++) {
4959 if (glyphenum->glyphs[g].num_layers == 0) {
4960 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
4961 first_glyph = min(first_glyph, g);
4963 else
4964 glyphenum->glyphindices[g] = 1;
4965 glyphenum->color_advances[g] = glyphenum->advances[g];
4966 if (glyphenum->color_offsets)
4967 glyphenum->color_offsets[g] = glyphenum->offsets[g];
4970 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
4971 colorrun->baselineOriginY = glyphenum->origin_y;
4972 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
4973 colorrun->paletteIndex = 0xffff;
4974 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
4975 glyphenum->has_regular_glyphs = FALSE;
4976 return TRUE;
4978 else {
4979 colorrun->glyphRun.glyphCount = 0;
4980 got_palette_index = FALSE;
4983 advance_adj = 0.0f;
4984 for (g = 0; g < glyphenum->run.glyphCount; g++) {
4986 glyphenum->glyphindices[g] = 1;
4988 /* all glyph layers were returned */
4989 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
4990 advance_adj += glyphenum->advances[g];
4991 continue;
4994 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
4995 UINT32 index = colorrun->glyphRun.glyphCount;
4996 if (!got_palette_index) {
4997 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
4998 /* use foreground color or request one from the font */
4999 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5000 if (colorrun->paletteIndex != 0xffff) {
5001 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5002 1, &colorrun->runColor);
5003 if (FAILED(hr))
5004 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5005 glyphenum->palette, colorrun->paletteIndex, hr);
5007 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5008 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5009 colorrun->baselineOriginY = glyphenum->origin_y;
5010 glyphenum->color_advances[index] = glyphenum->advances[g];
5011 got_palette_index = TRUE;
5014 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5015 /* offsets are relative to glyph origin, nothing to fix up */
5016 if (glyphenum->color_offsets)
5017 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5018 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5019 if (index)
5020 glyphenum->color_advances[index-1] += advance_adj;
5021 colorrun->glyphRun.glyphCount++;
5022 advance_adj = 0.0f;
5024 else
5025 advance_adj += glyphenum->advances[g];
5028 /* reset last advance */
5029 if (colorrun->glyphRun.glyphCount)
5030 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5032 return colorrun->glyphRun.glyphCount > 0;
5035 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5037 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5039 TRACE("(%p)->(%p)\n", This, has_run);
5041 *has_run = FALSE;
5043 This->colorrun.glyphRun.glyphCount = 0;
5044 while (This->current_layer < This->max_layer_num) {
5045 if (colorglyphenum_build_color_run(This))
5046 break;
5047 else
5048 This->current_layer++;
5051 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5053 return S_OK;
5056 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5058 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5060 TRACE("(%p)->(%p)\n", This, run);
5062 if (This->colorrun.glyphRun.glyphCount == 0) {
5063 *run = NULL;
5064 return E_NOT_VALID_STATE;
5067 *run = &This->colorrun;
5068 return S_OK;
5071 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5072 colorglyphenum_QueryInterface,
5073 colorglyphenum_AddRef,
5074 colorglyphenum_Release,
5075 colorglyphenum_MoveNext,
5076 colorglyphenum_GetCurrentRun
5079 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5080 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5082 struct dwrite_colorglyphenum *colorglyphenum;
5083 BOOL colorfont, has_colored_glyph;
5084 IDWriteFontFace3 *fontface3;
5085 HRESULT hr;
5086 UINT32 i;
5088 *ret = NULL;
5090 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5091 if (FAILED(hr)) {
5092 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5093 return hr;
5096 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5097 if (!colorfont) {
5098 hr = DWRITE_E_NOCOLOR;
5099 goto failed;
5102 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5103 if (!colorglyphenum) {
5104 hr = E_OUTOFMEMORY;
5105 goto failed;
5108 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5109 colorglyphenum->ref = 1;
5110 colorglyphenum->origin_x = originX;
5111 colorglyphenum->origin_y = originY;
5112 colorglyphenum->fontface = fontface3;
5113 colorglyphenum->glyphs = NULL;
5114 colorglyphenum->run = *run;
5115 colorglyphenum->run.glyphIndices = NULL;
5116 colorglyphenum->run.glyphAdvances = NULL;
5117 colorglyphenum->run.glyphOffsets = NULL;
5118 colorglyphenum->palette = palette;
5119 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5120 colorglyphenum->colr.exists = TRUE;
5121 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5122 colorglyphenum->current_layer = 0;
5123 colorglyphenum->max_layer_num = 0;
5125 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5127 has_colored_glyph = FALSE;
5128 colorglyphenum->has_regular_glyphs = FALSE;
5129 for (i = 0; i < run->glyphCount; i++) {
5130 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5131 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5132 has_colored_glyph = TRUE;
5134 if (colorglyphenum->glyphs[i].num_layers == 0)
5135 colorglyphenum->has_regular_glyphs = TRUE;
5138 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5139 is supposed to proceed normally, like if font had no color info at all. */
5140 if (!has_colored_glyph) {
5141 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5142 return DWRITE_E_NOCOLOR;
5145 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5146 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5147 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5148 if (run->glyphOffsets) {
5149 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5150 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5151 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5154 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5155 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5156 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5157 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5159 if (run->glyphAdvances)
5160 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5161 else {
5162 DWRITE_FONT_METRICS metrics;
5164 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5165 for (i = 0; i < run->glyphCount; i++) {
5166 HRESULT hr;
5167 INT32 a;
5169 switch (measuring_mode)
5171 case DWRITE_MEASURING_MODE_NATURAL:
5172 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5173 if (FAILED(hr))
5174 a = 0;
5175 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5176 break;
5177 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5178 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5179 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5180 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5181 if (FAILED(hr))
5182 colorglyphenum->advances[i] = 0.0f;
5183 else
5184 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5185 break;
5186 default:
5192 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5193 return S_OK;
5195 failed:
5196 IDWriteFontFace3_Release(fontface3);
5197 return hr;