dwrite: Implement HasCharacter() for a fontface.
[wine.git] / dlls / dwrite / font.c
blob0ebb49c60739d60a655c1192360413b6e74c38d6
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 IDWriteFontFamily *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 IDWriteFontFamily IDWriteFontFamily_iface;
133 LONG ref;
135 struct dwrite_fontfamily_data *data;
137 IDWriteFontCollection* collection;
140 struct dwrite_font {
141 IDWriteFont2 IDWriteFont2_iface;
142 LONG ref;
144 IDWriteFontFamily *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_IDWriteFont2(IDWriteFont2 *iface)
253 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont2_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_IDWriteFontFamily(IDWriteFontFamily *iface)
263 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily_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(IDWriteFont2 *iface, REFIID riid, void **obj)
1228 struct dwrite_font *This = impl_from_IDWriteFont2(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 IDWriteFont2_AddRef(iface);
1239 return S_OK;
1242 *obj = NULL;
1243 return E_NOINTERFACE;
1246 static ULONG WINAPI dwritefont_AddRef(IDWriteFont2 *iface)
1248 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1249 ULONG ref = InterlockedIncrement(&This->ref);
1250 TRACE("(%p)->(%d)\n", This, ref);
1251 return ref;
1254 static ULONG WINAPI dwritefont_Release(IDWriteFont2 *iface)
1256 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1257 ULONG ref = InterlockedDecrement(&This->ref);
1259 TRACE("(%p)->(%d)\n", This, ref);
1261 if (!ref) {
1262 IDWriteFontFamily_Release(This->family);
1263 release_font_data(This->data);
1264 heap_free(This);
1267 return ref;
1270 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont2 *iface, IDWriteFontFamily **family)
1272 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1273 TRACE("(%p)->(%p)\n", This, family);
1275 *family = This->family;
1276 IDWriteFontFamily_AddRef(*family);
1277 return S_OK;
1280 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont2 *iface)
1282 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1283 TRACE("(%p)\n", This);
1284 return This->data->weight;
1287 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont2 *iface)
1289 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1290 TRACE("(%p)\n", This);
1291 return This->data->stretch;
1294 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont2 *iface)
1296 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1297 TRACE("(%p)\n", This);
1298 return This->style;
1301 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont2 *iface)
1303 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface, IDWriteLocalizedStrings **names)
1318 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1319 TRACE("(%p)->(%p)\n", This, names);
1320 return clone_localizedstring(This->data->names, names);
1323 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont2 *iface,
1324 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1326 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface)
1372 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1373 TRACE("(%p)\n", This);
1374 return This->data->simulations;
1377 static void WINAPI dwritefont_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS *metrics)
1379 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1381 TRACE("(%p)->(%p)\n", This, metrics);
1382 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1385 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont2 *iface, UINT32 value, BOOL *exists)
1387 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface, IDWriteFontFace **face)
1411 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface, DWRITE_FONT_METRICS1 *metrics)
1425 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1426 TRACE("(%p)->(%p)\n", This, metrics);
1427 *metrics = This->data->metrics;
1430 static void WINAPI dwritefont1_GetPanose(IDWriteFont2 *iface, DWRITE_PANOSE *panose)
1432 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1433 TRACE("(%p)->(%p)\n", This, panose);
1434 *panose = This->data->panose;
1437 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont2 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1439 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface)
1454 struct dwrite_font *This = impl_from_IDWriteFont2(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(IDWriteFont2 *iface)
1469 struct dwrite_font *This = impl_from_IDWriteFont2(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 const IDWriteFont2Vtbl dwritefontvtbl = {
1483 dwritefont_QueryInterface,
1484 dwritefont_AddRef,
1485 dwritefont_Release,
1486 dwritefont_GetFontFamily,
1487 dwritefont_GetWeight,
1488 dwritefont_GetStretch,
1489 dwritefont_GetStyle,
1490 dwritefont_IsSymbolFont,
1491 dwritefont_GetFaceNames,
1492 dwritefont_GetInformationalStrings,
1493 dwritefont_GetSimulations,
1494 dwritefont_GetMetrics,
1495 dwritefont_HasCharacter,
1496 dwritefont_CreateFontFace,
1497 dwritefont1_GetMetrics,
1498 dwritefont1_GetPanose,
1499 dwritefont1_GetUnicodeRanges,
1500 dwritefont1_IsMonospacedFont,
1501 dwritefont2_IsColorFont
1504 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily *family, IDWriteFont **font)
1506 struct dwrite_font *This;
1507 *font = NULL;
1509 This = heap_alloc(sizeof(struct dwrite_font));
1510 if (!This) return E_OUTOFMEMORY;
1512 This->IDWriteFont2_iface.lpVtbl = &dwritefontvtbl;
1513 This->ref = 1;
1514 This->family = family;
1515 IDWriteFontFamily_AddRef(family);
1516 This->style = data->style;
1517 This->data = data;
1518 InterlockedIncrement(&This->data->ref);
1520 *font = (IDWriteFont*)&This->IDWriteFont2_iface;
1522 return S_OK;
1525 /* IDWriteFontList */
1526 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList *iface, REFIID riid, void **obj)
1528 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1530 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1532 if (IsEqualIID(riid, &IID_IDWriteFontList) ||
1533 IsEqualIID(riid, &IID_IUnknown))
1535 *obj = iface;
1536 IDWriteFontList_AddRef(iface);
1537 return S_OK;
1540 *obj = NULL;
1541 return E_NOINTERFACE;
1544 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList *iface)
1546 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1547 ULONG ref = InterlockedIncrement(&This->ref);
1548 TRACE("(%p)->(%d)\n", This, ref);
1549 return ref;
1552 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList *iface)
1554 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1555 ULONG ref = InterlockedDecrement(&This->ref);
1557 TRACE("(%p)->(%d)\n", This, ref);
1559 if (!ref) {
1560 UINT32 i;
1562 for (i = 0; i < This->font_count; i++)
1563 release_font_data(This->fonts[i]);
1564 IDWriteFontFamily_Release(This->family);
1565 heap_free(This);
1568 return ref;
1571 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList *iface, IDWriteFontCollection **collection)
1573 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1574 return IDWriteFontFamily_GetFontCollection(This->family, collection);
1577 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList *iface)
1579 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1580 TRACE("(%p)\n", This);
1581 return This->font_count;
1584 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList *iface, UINT32 index, IDWriteFont **font)
1586 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1588 TRACE("(%p)->(%u %p)\n", This, index, font);
1590 *font = NULL;
1592 if (This->font_count == 0)
1593 return S_FALSE;
1595 if (index >= This->font_count)
1596 return E_INVALIDARG;
1598 return create_font(This->fonts[index], This->family, font);
1601 static const IDWriteFontListVtbl dwritefontlistvtbl = {
1602 dwritefontlist_QueryInterface,
1603 dwritefontlist_AddRef,
1604 dwritefontlist_Release,
1605 dwritefontlist_GetFontCollection,
1606 dwritefontlist_GetFontCount,
1607 dwritefontlist_GetFont
1610 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily *iface, REFIID riid, void **obj)
1612 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1613 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1615 if (IsEqualIID(riid, &IID_IUnknown) ||
1616 IsEqualIID(riid, &IID_IDWriteFontList) ||
1617 IsEqualIID(riid, &IID_IDWriteFontFamily))
1619 *obj = iface;
1620 IDWriteFontFamily_AddRef(iface);
1621 return S_OK;
1624 *obj = NULL;
1625 return E_NOINTERFACE;
1628 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily *iface)
1630 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1631 ULONG ref = InterlockedIncrement(&This->ref);
1632 TRACE("(%p)->(%d)\n", This, ref);
1633 return ref;
1636 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily *iface)
1638 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1639 ULONG ref = InterlockedDecrement(&This->ref);
1641 TRACE("(%p)->(%d)\n", This, ref);
1643 if (!ref)
1645 IDWriteFontCollection_Release(This->collection);
1646 release_fontfamily_data(This->data);
1647 heap_free(This);
1650 return ref;
1653 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily *iface, IDWriteFontCollection **collection)
1655 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1656 TRACE("(%p)->(%p)\n", This, collection);
1658 *collection = This->collection;
1659 IDWriteFontCollection_AddRef(This->collection);
1660 return S_OK;
1663 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily *iface)
1665 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1666 TRACE("(%p)\n", This);
1667 return This->data->font_count;
1670 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily *iface, UINT32 index, IDWriteFont **font)
1672 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1674 TRACE("(%p)->(%u %p)\n", This, index, font);
1676 *font = NULL;
1678 if (This->data->font_count == 0)
1679 return S_FALSE;
1681 if (index >= This->data->font_count)
1682 return E_INVALIDARG;
1684 return create_font(This->data->fonts[index], iface, font);
1687 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface, IDWriteLocalizedStrings **names)
1689 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1690 return clone_localizedstring(This->data->familyname, names);
1693 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1694 const struct dwrite_font_propvec *req)
1696 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1697 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1698 FLOAT cur_req_prod, next_req_prod;
1700 if (next_to_req < cur_to_req)
1701 return TRUE;
1703 if (next_to_req > cur_to_req)
1704 return FALSE;
1706 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1707 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1709 if (next_req_prod > cur_req_prod)
1710 return TRUE;
1712 if (next_req_prod < cur_req_prod)
1713 return FALSE;
1715 if (next->stretch > cur->stretch)
1716 return TRUE;
1717 if (next->stretch < cur->stretch)
1718 return FALSE;
1720 if (next->style > cur->style)
1721 return TRUE;
1722 if (next->style < cur->style)
1723 return FALSE;
1725 if (next->weight > cur->weight)
1726 return TRUE;
1727 if (next->weight < cur->weight)
1728 return FALSE;
1730 /* full match, no reason to prefer new variant */
1731 return FALSE;
1734 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1735 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1737 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1738 struct dwrite_font_propvec req;
1739 struct dwrite_font_data *match;
1740 UINT32 i;
1742 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1744 if (This->data->font_count == 0) {
1745 *font = NULL;
1746 return DWRITE_E_NOFONT;
1749 init_font_prop_vec(weight, stretch, style, &req);
1750 match = This->data->fonts[0];
1752 for (i = 1; i < This->data->font_count; i++) {
1753 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1754 match = This->data->fonts[i];
1757 return create_font(match, iface, font);
1760 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1762 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1764 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1767 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1769 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1772 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1774 UINT32 b = fonts->font_count - 1, j, t;
1776 while (1) {
1777 t = b;
1779 for (j = 0; j < b; j++) {
1780 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1781 struct dwrite_font_data *s = fonts->fonts[j];
1782 fonts->fonts[j] = fonts->fonts[j+1];
1783 fonts->fonts[j+1] = s;
1784 t = j;
1788 if (t == b)
1789 break;
1790 b = t;
1794 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1795 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1797 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1798 matching_filter_func func = NULL;
1799 struct dwrite_font_propvec req;
1800 struct dwrite_fontlist *fonts;
1801 UINT32 i;
1803 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1805 *ret = NULL;
1807 fonts = heap_alloc(sizeof(*fonts));
1808 if (!fonts)
1809 return E_OUTOFMEMORY;
1811 /* Allocate as many as family has, not all of them will be necessary used. */
1812 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1813 if (!fonts->fonts) {
1814 heap_free(fonts);
1815 return E_OUTOFMEMORY;
1818 fonts->IDWriteFontList_iface.lpVtbl = &dwritefontlistvtbl;
1819 fonts->ref = 1;
1820 fonts->family = iface;
1821 IDWriteFontFamily_AddRef(fonts->family);
1822 fonts->font_count = 0;
1824 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1825 if (style == DWRITE_FONT_STYLE_NORMAL) {
1826 if (This->data->has_normal_face || This->data->has_italic_face)
1827 func = is_font_acceptable_for_normal;
1829 else /* requested oblique or italic */ {
1830 if (This->data->has_oblique_face || This->data->has_italic_face)
1831 func = is_font_acceptable_for_oblique_italic;
1834 for (i = 0; i < This->data->font_count; i++) {
1835 if (!func || func(This->data->fonts[i])) {
1836 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1837 InterlockedIncrement(&This->data->fonts[i]->ref);
1838 fonts->font_count++;
1842 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1843 init_font_prop_vec(weight, stretch, style, &req);
1844 matchingfonts_sort(fonts, &req);
1846 *ret = &fonts->IDWriteFontList_iface;
1847 return S_OK;
1850 static const IDWriteFontFamilyVtbl fontfamilyvtbl = {
1851 dwritefontfamily_QueryInterface,
1852 dwritefontfamily_AddRef,
1853 dwritefontfamily_Release,
1854 dwritefontfamily_GetFontCollection,
1855 dwritefontfamily_GetFontCount,
1856 dwritefontfamily_GetFont,
1857 dwritefontfamily_GetFamilyNames,
1858 dwritefontfamily_GetFirstMatchingFont,
1859 dwritefontfamily_GetMatchingFonts
1862 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily **family)
1864 struct dwrite_fontfamily *This;
1866 *family = NULL;
1868 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1869 if (!This) return E_OUTOFMEMORY;
1871 This->IDWriteFontFamily_iface.lpVtbl = &fontfamilyvtbl;
1872 This->ref = 1;
1873 This->collection = collection;
1874 IDWriteFontCollection_AddRef(collection);
1875 This->data = data;
1876 InterlockedIncrement(&This->data->ref);
1878 *family = &This->IDWriteFontFamily_iface;
1880 return S_OK;
1883 BOOL is_system_collection(IDWriteFontCollection *collection)
1885 void *obj;
1886 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1889 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection *iface, REFIID riid, void **obj)
1891 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1892 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1894 if (IsEqualIID(riid, &IID_IUnknown) ||
1895 IsEqualIID(riid, &IID_IDWriteFontCollection))
1897 *obj = iface;
1898 IDWriteFontCollection_AddRef(iface);
1899 return S_OK;
1902 *obj = NULL;
1904 if (This->is_system && IsEqualIID(riid, &IID_issystemcollection))
1905 return S_OK;
1907 return E_NOINTERFACE;
1910 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection *iface)
1912 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1913 ULONG ref = InterlockedIncrement(&This->ref);
1914 TRACE("(%p)->(%d)\n", This, ref);
1915 return ref;
1918 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection *iface)
1920 unsigned int i;
1921 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1922 ULONG ref = InterlockedDecrement(&This->ref);
1923 TRACE("(%p)->(%d)\n", This, ref);
1925 if (!ref) {
1926 for (i = 0; i < This->family_count; i++)
1927 release_fontfamily_data(This->family_data[i]);
1928 heap_free(This->family_data);
1929 heap_free(This);
1932 return ref;
1935 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
1937 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1938 TRACE("(%p)\n", This);
1939 return This->family_count;
1942 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
1944 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1946 TRACE("(%p)->(%u %p)\n", This, index, family);
1948 if (index >= This->family_count) {
1949 *family = NULL;
1950 return E_FAIL;
1953 return create_fontfamily(This->family_data[index], iface, family);
1956 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
1958 UINT32 i;
1960 for (i = 0; i < collection->family_count; i++) {
1961 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
1962 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
1963 HRESULT hr;
1965 for (j = 0; j < count; j++) {
1966 WCHAR buffer[255];
1967 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
1968 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
1969 return i;
1973 return ~0u;
1976 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
1978 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1979 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
1980 *index = collection_find_family(This, name);
1981 *exists = *index != ~0u;
1982 return S_OK;
1985 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
1987 UINT32 left_key_size, right_key_size;
1988 const void *left_key, *right_key;
1989 HRESULT hr;
1991 if (left == right)
1992 return TRUE;
1994 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
1995 if (FAILED(hr))
1996 return FALSE;
1998 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
1999 if (FAILED(hr))
2000 return FALSE;
2002 if (left_key_size != right_key_size)
2003 return FALSE;
2005 return !memcmp(left_key, right_key, left_key_size);
2008 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
2010 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
2011 struct dwrite_fontfamily_data *found_family = NULL;
2012 struct dwrite_font_data *found_font = NULL;
2013 IDWriteFontFamily *family;
2014 UINT32 i, j, face_index;
2015 IDWriteFontFile *file;
2016 HRESULT hr;
2018 TRACE("(%p)->(%p %p)\n", This, face, font);
2020 *font = NULL;
2022 if (!face)
2023 return E_INVALIDARG;
2025 i = 1;
2026 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2027 if (FAILED(hr))
2028 return hr;
2029 face_index = IDWriteFontFace_GetIndex(face);
2031 for (i = 0; i < This->family_count; i++) {
2032 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2033 for (j = 0; j < family_data->font_count; j++) {
2034 struct dwrite_font_data *font_data = family_data->fonts[j];
2036 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2037 found_font = font_data;
2038 found_family = family_data;
2039 break;
2044 if (!found_font)
2045 return DWRITE_E_NOFONT;
2047 hr = create_fontfamily(found_family, iface, &family);
2048 if (FAILED(hr))
2049 return hr;
2051 hr = create_font(found_font, family, font);
2052 IDWriteFontFamily_Release(family);
2053 return hr;
2056 static const IDWriteFontCollectionVtbl fontcollectionvtbl = {
2057 dwritefontcollection_QueryInterface,
2058 dwritefontcollection_AddRef,
2059 dwritefontcollection_Release,
2060 dwritefontcollection_GetFontFamilyCount,
2061 dwritefontcollection_GetFontFamily,
2062 dwritefontcollection_FindFamilyName,
2063 dwritefontcollection_GetFontFromFontFace
2066 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2068 if (family_data->font_count + 1 >= family_data->font_alloc) {
2069 struct dwrite_font_data **new_list;
2070 UINT32 new_alloc;
2072 new_alloc = family_data->font_alloc * 2;
2073 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2074 if (!new_list)
2075 return E_OUTOFMEMORY;
2076 family_data->fonts = new_list;
2077 family_data->font_alloc = new_alloc;
2080 family_data->fonts[family_data->font_count] = font_data;
2081 family_data->font_count++;
2082 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2083 family_data->has_normal_face = 1;
2084 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2085 family_data->has_oblique_face = 1;
2086 else
2087 family_data->has_italic_face = 1;
2088 return S_OK;
2091 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2093 if (collection->family_alloc < collection->family_count + 1) {
2094 struct dwrite_fontfamily_data **new_list;
2095 UINT32 new_alloc;
2097 new_alloc = collection->family_alloc * 2;
2098 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2099 if (!new_list)
2100 return E_OUTOFMEMORY;
2102 collection->family_alloc = new_alloc;
2103 collection->family_data = new_list;
2106 collection->family_data[collection->family_count] = family;
2107 collection->family_count++;
2109 return S_OK;
2112 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2114 collection->IDWriteFontCollection_iface.lpVtbl = &fontcollectionvtbl;
2115 collection->ref = 1;
2116 collection->family_count = 0;
2117 collection->family_alloc = is_system ? 30 : 5;
2118 collection->is_system = is_system;
2120 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2121 if (!collection->family_data)
2122 return E_OUTOFMEMORY;
2124 return S_OK;
2127 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2129 IDWriteFontFileLoader *loader;
2130 const void *key;
2131 UINT32 key_size;
2132 HRESULT hr;
2134 *stream = NULL;
2136 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2137 if (FAILED(hr))
2138 return hr;
2140 hr = IDWriteFontFile_GetLoader(file, &loader);
2141 if (FAILED(hr))
2142 return hr;
2144 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2145 IDWriteFontFileLoader_Release(loader);
2146 if (FAILED(hr))
2147 return hr;
2149 return hr;
2152 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2154 BOOL exists = FALSE;
2155 UINT32 index;
2156 HRESULT hr;
2158 buffer[0] = 0;
2159 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2160 if (FAILED(hr) || !exists)
2161 return;
2163 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2166 static int trim_spaces(WCHAR *in, WCHAR *ret)
2168 int len;
2170 while (isspaceW(*in))
2171 in++;
2173 ret[0] = 0;
2174 if (!(len = strlenW(in)))
2175 return 0;
2177 while (isspaceW(in[len-1]))
2178 len--;
2180 memcpy(ret, in, len*sizeof(WCHAR));
2181 ret[len] = 0;
2183 return len;
2186 struct name_token {
2187 struct list entry;
2188 const WCHAR *ptr;
2189 INT len; /* token length */
2190 INT fulllen; /* full length including following separators */
2193 static inline BOOL is_name_separator_char(WCHAR ch)
2195 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2198 struct name_pattern {
2199 const WCHAR *part1; /* NULL indicates end of list */
2200 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2203 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2205 const struct name_pattern *pattern;
2206 struct name_token *token;
2207 int i = 0;
2209 while ((pattern = &patterns[i++])->part1) {
2210 int len_part1 = strlenW(pattern->part1);
2211 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2213 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2214 if (len_part2 == 0) {
2215 /* simple case with single part pattern */
2216 if (token->len != len_part1)
2217 continue;
2219 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2220 if (match) *match = *token;
2221 list_remove(&token->entry);
2222 heap_free(token);
2223 return TRUE;
2226 else {
2227 struct name_token *next_token;
2228 struct list *next_entry;
2230 /* pattern parts are stored in reading order, tokens list is reversed */
2231 if (token->len < len_part2)
2232 continue;
2234 /* it's possible to have combined string as a token, like ExtraCondensed */
2235 if (token->len == len_part1 + len_part2) {
2236 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2237 continue;
2239 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2240 continue;
2242 /* combined string match */
2243 if (match) *match = *token;
2244 list_remove(&token->entry);
2245 heap_free(token);
2246 return TRUE;
2249 /* now it's only possible to have two tokens matched to respective pattern parts */
2250 if (token->len != len_part2)
2251 continue;
2253 next_entry = list_next(tokens, &token->entry);
2254 if (next_entry) {
2255 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2256 if (next_token->len != len_part1)
2257 continue;
2259 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2260 continue;
2262 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2263 continue;
2265 /* both parts matched, remove tokens */
2266 if (match) {
2267 match->ptr = next_token->ptr;
2268 match->len = (token->ptr - next_token->ptr) + token->len;
2270 list_remove(&token->entry);
2271 list_remove(&next_token->entry);
2272 heap_free(next_token);
2273 heap_free(token);
2274 return TRUE;
2280 if (match) {
2281 match->ptr = NULL;
2282 match->len = 0;
2284 return FALSE;
2287 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2289 static const WCHAR itaW[] = {'i','t','a',0};
2290 static const WCHAR italW[] = {'i','t','a','l',0};
2291 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2292 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2294 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2295 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2296 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2297 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2299 static const struct name_pattern italic_patterns[] = {
2300 { itaW },
2301 { italW },
2302 { italicW },
2303 { cursiveW },
2304 { kursivW },
2305 { NULL }
2308 static const struct name_pattern oblique_patterns[] = {
2309 { inclinedW },
2310 { obliqueW },
2311 { backslantedW },
2312 { backslantW },
2313 { slantedW },
2314 { NULL }
2317 /* italic patterns first */
2318 if (match_pattern_list(tokens, italic_patterns, match))
2319 return DWRITE_FONT_STYLE_ITALIC;
2321 /* oblique patterns */
2322 if (match_pattern_list(tokens, oblique_patterns, match))
2323 return DWRITE_FONT_STYLE_OBLIQUE;
2325 return style;
2328 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2329 struct name_token *match)
2331 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2332 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2333 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2334 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2335 static const WCHAR wideW[] = {'w','i','d','e',0};
2336 static const WCHAR condW[] = {'c','o','n','d',0};
2338 static const struct name_pattern ultracondensed_patterns[] = {
2339 { extraW, compressedW },
2340 { extW, compressedW },
2341 { ultraW, compressedW },
2342 { ultraW, condensedW },
2343 { ultraW, condW },
2344 { NULL }
2347 static const struct name_pattern extracondensed_patterns[] = {
2348 { compressedW },
2349 { extraW, condensedW },
2350 { extW, condensedW },
2351 { extraW, condW },
2352 { extW, condW },
2353 { NULL }
2356 static const struct name_pattern semicondensed_patterns[] = {
2357 { narrowW },
2358 { compactW },
2359 { semiW, condensedW },
2360 { semiW, condW },
2361 { NULL }
2364 static const struct name_pattern semiexpanded_patterns[] = {
2365 { wideW },
2366 { semiW, expandedW },
2367 { semiW, extendedW },
2368 { NULL }
2371 static const struct name_pattern extraexpanded_patterns[] = {
2372 { extraW, expandedW },
2373 { extW, expandedW },
2374 { extraW, extendedW },
2375 { extW, extendedW },
2376 { NULL }
2379 static const struct name_pattern ultraexpanded_patterns[] = {
2380 { ultraW, expandedW },
2381 { ultraW, extendedW },
2382 { NULL }
2385 static const struct name_pattern condensed_patterns[] = {
2386 { condensedW },
2387 { condW },
2388 { NULL }
2391 static const struct name_pattern expanded_patterns[] = {
2392 { expandedW },
2393 { extendedW },
2394 { NULL }
2397 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2398 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2400 if (match_pattern_list(tokens, extracondensed_patterns, match))
2401 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2403 if (match_pattern_list(tokens, semicondensed_patterns, match))
2404 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2406 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2407 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2409 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2410 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2412 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2413 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2415 if (match_pattern_list(tokens, condensed_patterns, match))
2416 return DWRITE_FONT_STRETCH_CONDENSED;
2418 if (match_pattern_list(tokens, expanded_patterns, match))
2419 return DWRITE_FONT_STRETCH_EXPANDED;
2421 return stretch;
2424 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2425 struct name_token *match)
2427 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2428 static const WCHAR nordW[] = {'n','o','r','d',0};
2430 static const struct name_pattern thin_patterns[] = {
2431 { extraW, thinW },
2432 { extW, thinW },
2433 { ultraW, thinW },
2434 { NULL }
2437 static const struct name_pattern extralight_patterns[] = {
2438 { extraW, lightW },
2439 { extW, lightW },
2440 { ultraW, lightW },
2441 { NULL }
2444 static const struct name_pattern semilight_patterns[] = {
2445 { semiW, lightW },
2446 { NULL }
2449 static const struct name_pattern demibold_patterns[] = {
2450 { semiW, boldW },
2451 { demiW, boldW },
2452 { NULL }
2455 static const struct name_pattern extrabold_patterns[] = {
2456 { extraW, boldW },
2457 { extW, boldW },
2458 { ultraW, boldW },
2459 { NULL }
2462 static const struct name_pattern extrablack_patterns[] = {
2463 { extraW, blackW },
2464 { extW, blackW },
2465 { ultraW, blackW },
2466 { NULL }
2469 static const struct name_pattern bold_patterns[] = {
2470 { boldW },
2471 { NULL }
2474 static const struct name_pattern thin2_patterns[] = {
2475 { thinW },
2476 { NULL }
2479 static const struct name_pattern light_patterns[] = {
2480 { lightW },
2481 { NULL }
2484 static const struct name_pattern medium_patterns[] = {
2485 { mediumW },
2486 { NULL }
2489 static const struct name_pattern black_patterns[] = {
2490 { blackW },
2491 { heavyW },
2492 { nordW },
2493 { NULL }
2496 static const struct name_pattern demibold2_patterns[] = {
2497 { demiW },
2498 { NULL }
2501 static const struct name_pattern extrabold2_patterns[] = {
2502 { ultraW },
2503 { NULL }
2506 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2507 matching pattern. */
2509 if (match_pattern_list(tokens, thin_patterns, match))
2510 return DWRITE_FONT_WEIGHT_THIN;
2512 if (match_pattern_list(tokens, extralight_patterns, match))
2513 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2515 if (match_pattern_list(tokens, semilight_patterns, match))
2516 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2518 if (match_pattern_list(tokens, demibold_patterns, match))
2519 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2521 if (match_pattern_list(tokens, extrabold_patterns, match))
2522 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2524 if (match_pattern_list(tokens, extrablack_patterns, match))
2525 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2527 if (match_pattern_list(tokens, bold_patterns, match))
2528 return DWRITE_FONT_WEIGHT_BOLD;
2530 if (match_pattern_list(tokens, thin2_patterns, match))
2531 return DWRITE_FONT_WEIGHT_THIN;
2533 if (match_pattern_list(tokens, light_patterns, match))
2534 return DWRITE_FONT_WEIGHT_LIGHT;
2536 if (match_pattern_list(tokens, medium_patterns, match))
2537 return DWRITE_FONT_WEIGHT_MEDIUM;
2539 if (match_pattern_list(tokens, black_patterns, match))
2540 return DWRITE_FONT_WEIGHT_BLACK;
2542 if (match_pattern_list(tokens, black_patterns, match))
2543 return DWRITE_FONT_WEIGHT_BLACK;
2545 if (match_pattern_list(tokens, demibold2_patterns, match))
2546 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2548 if (match_pattern_list(tokens, extrabold2_patterns, match))
2549 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2551 /* FIXME: use abbreviated names to extract weight */
2553 return weight;
2556 struct knownweight_entry {
2557 const WCHAR *nameW;
2558 DWRITE_FONT_WEIGHT weight;
2561 static int compare_knownweights(const void *a, const void* b)
2563 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2564 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2565 int ret = 0;
2567 if (target > entry->weight)
2568 ret = 1;
2569 else if (target < entry->weight)
2570 ret = -1;
2572 return ret;
2575 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2577 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2578 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2579 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2580 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2581 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2582 const struct knownweight_entry *ptr;
2584 static const struct knownweight_entry knownweights[] = {
2585 { thinW, DWRITE_FONT_WEIGHT_THIN },
2586 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2587 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2588 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2589 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2590 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2591 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2592 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2593 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2594 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2597 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2598 compare_knownweights);
2599 if (!ptr) {
2600 nameW[0] = 0;
2601 return FALSE;
2604 strcpyW(nameW, ptr->nameW);
2605 return TRUE;
2608 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2610 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2611 strW[name->len] = 0;
2614 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2615 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2617 static const WCHAR bookW[] = {'B','o','o','k',0};
2618 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2619 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2620 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2621 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2623 static const WCHAR *regular_patterns[] = {
2624 bookW,
2625 normalW,
2626 regularW,
2627 romanW,
2628 uprightW,
2629 NULL
2632 const WCHAR *regular_ptr = NULL, *ptr;
2633 int i = 0;
2635 if (len == -1)
2636 len = strlenW(facenameW);
2638 /* remove rightmost regular variant from face name */
2639 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2640 int pattern_len = strlenW(ptr);
2641 WCHAR *src;
2643 if (pattern_len > len)
2644 continue;
2646 src = facenameW + len - pattern_len;
2647 while (src >= facenameW) {
2648 if (!strncmpiW(src, ptr, pattern_len)) {
2649 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2650 len = strlenW(facenameW);
2651 regular_ptr = ptr;
2652 break;
2654 else
2655 src--;
2659 return regular_ptr;
2662 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2664 const WCHAR *ptr;
2666 list_init(tokens);
2667 ptr = nameW;
2669 while (*ptr) {
2670 struct name_token *token = heap_alloc(sizeof(*token));
2671 token->ptr = ptr;
2672 token->len = 0;
2673 token->fulllen = 0;
2675 while (*ptr && !is_name_separator_char(*ptr)) {
2676 token->len++;
2677 token->fulllen++;
2678 ptr++;
2681 /* skip separators */
2682 while (is_name_separator_char(*ptr)) {
2683 token->fulllen++;
2684 ptr++;
2687 list_add_head(tokens, &token->entry);
2691 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2693 struct name_token *token, *token2;
2694 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2695 int len;
2697 list_remove(&token->entry);
2699 /* don't include last separator */
2700 len = list_empty(tokens) ? token->len : token->fulllen;
2701 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2702 nameW += len;
2704 heap_free(token);
2706 *nameW = 0;
2709 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2711 struct name_token stretch_name, weight_name, style_name;
2712 WCHAR familynameW[255], facenameW[255], finalW[255];
2713 WCHAR weightW[32], stretchW[32], styleW[32];
2714 const WCHAR *regular_ptr = NULL;
2715 DWRITE_FONT_STRETCH stretch;
2716 DWRITE_FONT_WEIGHT weight;
2717 struct list tokens;
2718 int len;
2720 /* remove leading and trailing spaces from family and face name */
2721 trim_spaces(familyW, familynameW);
2722 len = trim_spaces(faceW, facenameW);
2724 /* remove rightmost regular variant from face name */
2725 regular_ptr = facename_remove_regular_term(facenameW, len);
2727 /* append face name to family name, FIXME check if face name is a substring of family name */
2728 if (*facenameW) {
2729 strcatW(familynameW, spaceW);
2730 strcatW(familynameW, facenameW);
2733 /* tokenize with " .-_" */
2734 fontname_tokenize(&tokens, familynameW);
2736 /* extract and resolve style */
2737 font->style = font_extract_style(&tokens, font->style, &style_name);
2739 /* extract stretch */
2740 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2742 /* extract weight */
2743 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2745 /* resolve weight */
2746 if (weight != font->weight) {
2747 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2748 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2749 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2750 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2751 !(abs(weight - font->weight) <= 150 &&
2752 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2753 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2754 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2756 font->weight = weight;
2760 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2761 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2762 stretch itself is normal (extracted stretch is never normal). */
2763 if (stretch != font->stretch) {
2764 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2765 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2766 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2768 font->stretch = stretch;
2772 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2774 /* get final combined string from what's left in token list, list is released */
2775 fontname_tokens_to_str(&tokens, finalW);
2777 if (!strcmpW(familyW, finalW))
2778 return FALSE;
2780 /* construct face name */
2781 strcpyW(familyW, finalW);
2783 /* resolved weight name */
2784 if (weight_name.ptr)
2785 font_name_token_to_str(&weight_name, weightW);
2786 /* ignore normal weight */
2787 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2788 weightW[0] = 0;
2789 /* for known weight values use appropriate names */
2790 else if (is_known_weight_value(font->weight, weightW)) {
2792 /* use Wnnn format as a fallback in case weight is not one of known values */
2793 else {
2794 static const WCHAR fmtW[] = {'W','%','d',0};
2795 sprintfW(weightW, fmtW, font->weight);
2798 /* resolved stretch name */
2799 if (stretch_name.ptr)
2800 font_name_token_to_str(&stretch_name, stretchW);
2801 /* ignore normal stretch */
2802 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2803 stretchW[0] = 0;
2804 /* use predefined stretch names */
2805 else {
2806 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2807 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2808 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2809 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2810 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2811 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2813 static const WCHAR *stretchnamesW[] = {
2814 ultracondensedW,
2815 extracondensedW,
2816 condensedW,
2817 semicondensedW,
2818 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
2819 semiexpandedW,
2820 expandedW,
2821 extraexpandedW,
2822 ultraexpandedW
2824 strcpyW(stretchW, stretchnamesW[font->stretch]);
2827 /* resolved style name */
2828 if (style_name.ptr)
2829 font_name_token_to_str(&style_name, styleW);
2830 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
2831 styleW[0] = 0;
2832 /* use predefined names */
2833 else {
2834 if (font->style == DWRITE_FONT_STYLE_ITALIC)
2835 strcpyW(styleW, italicW);
2836 else
2837 strcpyW(styleW, obliqueW);
2840 /* use Regular match if it was found initially */
2841 if (!*weightW && !*stretchW && !*styleW)
2842 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
2843 else {
2844 faceW[0] = 0;
2845 if (*stretchW)
2846 strcpyW(faceW, stretchW);
2847 if (*weightW) {
2848 if (*faceW)
2849 strcatW(faceW, spaceW);
2850 strcatW(faceW, weightW);
2852 if (*styleW) {
2853 if (*faceW)
2854 strcatW(faceW, spaceW);
2855 strcatW(faceW, styleW);
2859 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
2860 return TRUE;
2863 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
2864 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
2866 struct dwrite_font_props props;
2867 struct dwrite_font_data *data;
2868 IDWriteFontFileStream *stream;
2869 WCHAR familyW[255], faceW[255];
2870 HRESULT hr;
2872 *ret = NULL;
2873 data = heap_alloc_zero(sizeof(*data));
2874 if (!data)
2875 return E_OUTOFMEMORY;
2877 hr = get_filestream_from_file(file, &stream);
2878 if (FAILED(hr)) {
2879 heap_free(data);
2880 return hr;
2883 data->ref = 1;
2884 data->factory = factory;
2885 data->file = file;
2886 data->face_index = face_index;
2887 data->face_type = face_type;
2888 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
2889 data->bold_sim_tested = 0;
2890 data->oblique_sim_tested = 0;
2891 IDWriteFontFile_AddRef(file);
2892 IDWriteFactory2_AddRef(factory);
2894 opentype_get_font_properties(stream, face_type, face_index, &props);
2895 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
2896 opentype_get_font_facename(stream, face_type, face_index, &data->names);
2898 /* get family name from font file */
2899 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
2900 IDWriteFontFileStream_Release(stream);
2901 if (FAILED(hr)) {
2902 WARN("unable to get family name from font\n");
2903 release_font_data(data);
2904 return hr;
2907 data->style = props.style;
2908 data->stretch = props.stretch;
2909 data->weight = props.weight;
2910 data->panose = props.panose;
2912 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
2913 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
2914 if (font_apply_differentiation_rules(data, familyW, faceW)) {
2915 set_en_localizedstring(*family_name, familyW);
2916 set_en_localizedstring(data->names, faceW);
2919 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2921 *ret = data;
2922 return S_OK;
2925 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
2926 struct dwrite_font_data **ret)
2928 struct dwrite_font_data *data;
2930 *ret = NULL;
2931 data = heap_alloc_zero(sizeof(*data));
2932 if (!data)
2933 return E_OUTOFMEMORY;
2935 *data = *src;
2936 data->ref = 1;
2937 data->simulations |= sim;
2938 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
2939 data->weight = DWRITE_FONT_WEIGHT_BOLD;
2940 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
2941 data->style = DWRITE_FONT_STYLE_OBLIQUE;
2942 memset(data->info_strings, 0, sizeof(data->info_strings));
2943 data->names = NULL;
2944 IDWriteFactory2_AddRef(data->factory);
2945 IDWriteFontFile_AddRef(data->file);
2947 create_localizedstrings(&data->names);
2948 add_localizedstring(data->names, enusW, facenameW);
2950 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2952 *ret = data;
2953 return S_OK;
2956 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
2958 struct dwrite_fontfamily_data *data;
2960 data = heap_alloc(sizeof(*data));
2961 if (!data)
2962 return E_OUTOFMEMORY;
2964 data->ref = 1;
2965 data->font_count = 0;
2966 data->font_alloc = 2;
2967 data->has_normal_face = 0;
2968 data->has_oblique_face = 0;
2969 data->has_italic_face = 0;
2971 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
2972 if (!data->fonts) {
2973 heap_free(data);
2974 return E_OUTOFMEMORY;
2977 data->familyname = familyname;
2978 IDWriteLocalizedStrings_AddRef(familyname);
2980 *ret = data;
2981 return S_OK;
2984 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
2986 UINT32 i, j, heaviest;
2988 for (i = 0; i < family->font_count; i++) {
2989 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
2990 heaviest = i;
2992 if (family->fonts[i]->bold_sim_tested)
2993 continue;
2995 family->fonts[i]->bold_sim_tested = 1;
2996 for (j = i; j < family->font_count; j++) {
2997 if (family->fonts[j]->bold_sim_tested)
2998 continue;
3000 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3001 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3002 if (family->fonts[j]->weight > weight) {
3003 weight = family->fonts[j]->weight;
3004 heaviest = j;
3006 family->fonts[j]->bold_sim_tested = 1;
3010 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3011 static const struct name_pattern weightsim_patterns[] = {
3012 { extraW, lightW },
3013 { extW, lightW },
3014 { ultraW, lightW },
3015 { semiW, lightW },
3016 { semiW, boldW },
3017 { demiW, boldW },
3018 { boldW },
3019 { thinW },
3020 { lightW },
3021 { mediumW },
3022 { demiW },
3023 { NULL }
3026 WCHAR facenameW[255], initialW[255];
3027 struct dwrite_font_data *boldface;
3028 struct list tokens;
3030 /* add Bold simulation based on heaviest face data */
3032 /* Simulated face name should only contain Bold as weight term,
3033 so remove existing regular and weight terms. */
3034 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3035 facename_remove_regular_term(initialW, -1);
3037 /* remove current weight pattern */
3038 fontname_tokenize(&tokens, initialW);
3039 match_pattern_list(&tokens, weightsim_patterns, NULL);
3040 fontname_tokens_to_str(&tokens, facenameW);
3042 /* Bold suffix for new name */
3043 if (*facenameW)
3044 strcatW(facenameW, spaceW);
3045 strcatW(facenameW, boldW);
3047 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3048 boldface->bold_sim_tested = 1;
3049 fontfamily_add_font(family, boldface);
3055 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3057 UINT32 i, j;
3059 for (i = 0; i < family->font_count; i++) {
3060 UINT32 regular = ~0u, oblique = ~0u;
3061 struct dwrite_font_data *obliqueface;
3062 WCHAR facenameW[255];
3064 if (family->fonts[i]->oblique_sim_tested)
3065 continue;
3067 family->fonts[i]->oblique_sim_tested = 1;
3068 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3069 regular = i;
3070 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3071 oblique = i;
3073 /* find regular style with same weight/stretch values */
3074 for (j = i; j < family->font_count; j++) {
3075 if (family->fonts[j]->oblique_sim_tested)
3076 continue;
3078 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3079 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3081 family->fonts[j]->oblique_sim_tested = 1;
3082 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3083 regular = j;
3085 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3086 oblique = j;
3089 if (regular != ~0u && oblique != ~0u)
3090 break;
3093 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3094 if (regular == ~0u)
3095 continue;
3097 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3098 if (oblique != ~0u)
3099 continue;
3101 /* add oblique simulation based on this regular face */
3103 /* remove regular term if any, append 'Oblique' */
3104 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3105 facename_remove_regular_term(facenameW, -1);
3107 if (*facenameW)
3108 strcatW(facenameW, spaceW);
3109 strcatW(facenameW, obliqueW);
3111 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3112 obliqueface->oblique_sim_tested = 1;
3113 fontfamily_add_font(family, obliqueface);
3118 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3119 const WCHAR *replacement_name)
3121 UINT32 i = collection_find_family(collection, replacement_name);
3122 struct dwrite_fontfamily_data *target;
3123 IDWriteLocalizedStrings *strings;
3124 HRESULT hr;
3126 /* replacement does not exist */
3127 if (i == ~0u)
3128 return FALSE;
3130 hr = create_localizedstrings(&strings);
3131 if (FAILED(hr))
3132 return FALSE;
3134 /* add a new family with target name, reuse font data from replacement */
3135 add_localizedstring(strings, enusW, target_name);
3136 hr = init_fontfamily_data(strings, &target);
3137 if (hr == S_OK) {
3138 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3139 WCHAR nameW[255];
3141 for (i = 0; i < replacement->font_count; i++)
3142 fontfamily_add_font(target, replacement->fonts[i]);
3144 fontcollection_add_family(collection, target);
3145 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3146 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3148 IDWriteLocalizedStrings_Release(strings);
3149 return TRUE;
3152 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3153 system font collections. */
3154 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3156 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3157 WCHAR *name;
3158 void *data;
3159 HKEY hkey;
3161 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3162 return;
3164 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3165 RegCloseKey(hkey);
3166 return;
3169 max_namelen++; /* returned value doesn't include room for '\0' */
3170 name = heap_alloc(max_namelen * sizeof(WCHAR));
3171 data = heap_alloc(max_datalen);
3173 datalen = max_datalen;
3174 namelen = max_namelen;
3175 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3176 if (collection_find_family(collection, name) == ~0u) {
3177 if (type == REG_MULTI_SZ) {
3178 WCHAR *replacement = data;
3179 while (*replacement) {
3180 if (fontcollection_add_replacement(collection, name, replacement))
3181 break;
3182 replacement += strlenW(replacement) + 1;
3185 else if (type == REG_SZ)
3186 fontcollection_add_replacement(collection, name, data);
3188 else
3189 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3191 datalen = max_datalen;
3192 namelen = max_namelen;
3195 heap_free(data);
3196 heap_free(name);
3197 RegCloseKey(hkey);
3200 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3202 struct fontfile_enum {
3203 struct list entry;
3204 IDWriteFontFile *file;
3206 struct fontfile_enum *fileenum, *fileenum2;
3207 struct dwrite_fontcollection *collection;
3208 struct list scannedfiles;
3209 BOOL current = FALSE;
3210 HRESULT hr = S_OK;
3211 UINT32 i;
3213 *ret = NULL;
3215 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3216 if (!collection) return E_OUTOFMEMORY;
3218 hr = init_font_collection(collection, is_system);
3219 if (FAILED(hr)) {
3220 heap_free(collection);
3221 return hr;
3224 *ret = &collection->IDWriteFontCollection_iface;
3226 TRACE("building font collection:\n");
3228 list_init(&scannedfiles);
3229 while (hr == S_OK) {
3230 DWRITE_FONT_FACE_TYPE face_type;
3231 DWRITE_FONT_FILE_TYPE file_type;
3232 BOOL supported, same = FALSE;
3233 IDWriteFontFile *file;
3234 UINT32 face_count;
3236 current = FALSE;
3237 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3238 if (FAILED(hr) || !current)
3239 break;
3241 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3242 if (FAILED(hr))
3243 break;
3245 /* check if we've scanned this file already */
3246 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3247 if ((same = is_same_fontfile(fileenum->file, file)))
3248 break;
3251 if (same) {
3252 IDWriteFontFile_Release(file);
3253 continue;
3256 /* failed font files are skipped */
3257 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3258 if (FAILED(hr) || !supported || face_count == 0) {
3259 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3260 IDWriteFontFile_Release(file);
3261 hr = S_OK;
3262 continue;
3265 /* add to scanned list */
3266 fileenum = heap_alloc(sizeof(*fileenum));
3267 fileenum->file = file;
3268 list_add_tail(&scannedfiles, &fileenum->entry);
3270 for (i = 0; i < face_count; i++) {
3271 IDWriteLocalizedStrings *family_name = NULL;
3272 struct dwrite_font_data *font_data;
3273 WCHAR familyW[255];
3274 UINT32 index;
3276 /* alloc and init new font data structure */
3277 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3278 if (FAILED(hr)) {
3279 /* move to next one */
3280 hr = S_OK;
3281 continue;
3284 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3286 index = collection_find_family(collection, familyW);
3287 if (index != ~0u)
3288 hr = fontfamily_add_font(collection->family_data[index], font_data);
3289 else {
3290 struct dwrite_fontfamily_data *family_data;
3292 /* create and init new family */
3293 hr = init_fontfamily_data(family_name, &family_data);
3294 if (hr == S_OK) {
3295 /* add font to family, family - to collection */
3296 hr = fontfamily_add_font(family_data, font_data);
3297 if (hr == S_OK)
3298 hr = fontcollection_add_family(collection, family_data);
3300 if (FAILED(hr))
3301 release_fontfamily_data(family_data);
3305 IDWriteLocalizedStrings_Release(family_name);
3307 if (FAILED(hr))
3308 break;
3312 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3313 IDWriteFontFile_Release(fileenum->file);
3314 list_remove(&fileenum->entry);
3315 heap_free(fileenum);
3318 for (i = 0; i < collection->family_count; i++) {
3319 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3320 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3323 if (is_system)
3324 fontcollection_add_replacements(collection);
3326 return hr;
3329 struct system_fontfile_enumerator
3331 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3332 LONG ref;
3334 IDWriteFactory2 *factory;
3335 HKEY hkey;
3336 int index;
3339 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3341 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3344 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3346 *obj = NULL;
3348 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3349 IDWriteFontFileEnumerator_AddRef(iface);
3350 *obj = iface;
3351 return S_OK;
3354 return E_NOINTERFACE;
3357 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3359 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3360 return InterlockedIncrement(&enumerator->ref);
3363 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3365 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3366 ULONG ref = InterlockedDecrement(&enumerator->ref);
3368 if (!ref) {
3369 IDWriteFactory2_Release(enumerator->factory);
3370 RegCloseKey(enumerator->hkey);
3371 heap_free(enumerator);
3374 return ref;
3377 static HRESULT create_local_file_reference(IDWriteFactory2 *factory, const WCHAR *filename, IDWriteFontFile **file)
3379 HRESULT hr;
3381 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3382 if (!strchrW(filename, '\\')) {
3383 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3384 WCHAR fullpathW[MAX_PATH];
3386 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3387 strcatW(fullpathW, fontsW);
3388 strcatW(fullpathW, filename);
3390 hr = IDWriteFactory2_CreateFontFileReference(factory, fullpathW, NULL, file);
3392 else
3393 hr = IDWriteFactory2_CreateFontFileReference(factory, filename, NULL, file);
3395 return hr;
3398 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3400 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3401 DWORD ret, type, val_count, count;
3402 WCHAR *value, *filename;
3403 HRESULT hr;
3405 *file = NULL;
3407 if (enumerator->index < 0)
3408 return E_FAIL;
3410 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3411 if (ret != ERROR_SUCCESS)
3412 return E_FAIL;
3414 val_count++;
3415 value = heap_alloc( val_count * sizeof(value[0]) );
3416 filename = heap_alloc(count);
3417 if (!value || !filename) {
3418 heap_free(value);
3419 heap_free(filename);
3420 return E_OUTOFMEMORY;
3423 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3424 if (ret) {
3425 heap_free(value);
3426 heap_free(filename);
3427 return E_FAIL;
3430 hr = create_local_file_reference(enumerator->factory, filename, file);
3432 heap_free(value);
3433 heap_free(filename);
3434 return hr;
3437 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3439 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3440 DWORD ret, max_val_count;
3441 WCHAR *value;
3443 *current = FALSE;
3444 enumerator->index++;
3446 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3447 if (ret != ERROR_SUCCESS)
3448 return E_FAIL;
3450 max_val_count++;
3451 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3452 return E_OUTOFMEMORY;
3454 /* iterate until we find next string value */
3455 while (1) {
3456 DWORD type = 0, count, val_count;
3457 val_count = max_val_count;
3458 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3459 break;
3460 if (type == REG_SZ) {
3461 *current = TRUE;
3462 break;
3464 enumerator->index++;
3467 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3468 heap_free(value);
3469 return S_OK;
3472 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3474 systemfontfileenumerator_QueryInterface,
3475 systemfontfileenumerator_AddRef,
3476 systemfontfileenumerator_Release,
3477 systemfontfileenumerator_MoveNext,
3478 systemfontfileenumerator_GetCurrentFontFile
3481 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
3483 struct system_fontfile_enumerator *enumerator;
3484 static const WCHAR fontslistW[] = {
3485 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3486 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3487 'F','o','n','t','s',0
3490 *ret = NULL;
3492 enumerator = heap_alloc(sizeof(*enumerator));
3493 if (!enumerator)
3494 return E_OUTOFMEMORY;
3496 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3497 enumerator->ref = 1;
3498 enumerator->factory = factory;
3499 enumerator->index = -1;
3500 IDWriteFactory2_AddRef(factory);
3502 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3503 ERR("failed to open fonts list key\n");
3504 IDWriteFactory2_Release(factory);
3505 heap_free(enumerator);
3506 return E_FAIL;
3509 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3511 return S_OK;
3514 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3516 IDWriteFontFileEnumerator *enumerator;
3517 HRESULT hr;
3519 *collection = NULL;
3521 hr = create_system_fontfile_enumerator(factory, &enumerator);
3522 if (FAILED(hr))
3523 return hr;
3525 TRACE("building system font collection for factory %p\n", factory);
3526 hr = create_font_collection(factory, enumerator, TRUE, collection);
3527 IDWriteFontFileEnumerator_Release(enumerator);
3528 return hr;
3531 static HRESULT eudc_collection_add_family(IDWriteFactory2 *factory, struct dwrite_fontcollection *collection,
3532 const WCHAR *keynameW, const WCHAR *pathW)
3534 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};
3535 static const WCHAR emptyW[] = {0};
3536 IDWriteLocalizedStrings *names;
3537 DWRITE_FONT_FACE_TYPE face_type;
3538 DWRITE_FONT_FILE_TYPE file_type;
3539 BOOL supported;
3540 UINT32 face_count, i;
3541 IDWriteFontFile *file;
3542 HRESULT hr;
3543 struct dwrite_fontfamily_data *family_data;
3545 /* create font file from this path */
3546 hr = create_local_file_reference(factory, pathW, &file);
3547 if (FAILED(hr))
3548 return S_FALSE;
3550 /* failed font files are skipped */
3551 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3552 if (FAILED(hr) || !supported || face_count == 0) {
3553 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3554 IDWriteFontFile_Release(file);
3555 return S_FALSE;
3558 /* create and init new family */
3560 /* Family names are added for non-specific locale, represented with empty string.
3561 Default family appears with empty family name. */
3562 create_localizedstrings(&names);
3563 if (!strcmpiW(keynameW, defaultfontW))
3564 add_localizedstring(names, emptyW, emptyW);
3565 else
3566 add_localizedstring(names, emptyW, keynameW);
3568 hr = init_fontfamily_data(names, &family_data);
3569 IDWriteLocalizedStrings_Release(names);
3570 if (hr != S_OK) {
3571 IDWriteFontFile_Release(file);
3572 return hr;
3575 /* fill with faces */
3576 for (i = 0; i < face_count; i++) {
3577 struct dwrite_font_data *font_data;
3579 /* alloc and init new font data structure */
3580 hr = init_font_data(factory, file, face_type, i, &names, &font_data);
3581 if (FAILED(hr))
3582 continue;
3584 IDWriteLocalizedStrings_Release(names);
3586 /* add font to family */
3587 hr = fontfamily_add_font(family_data, font_data);
3588 if (hr != S_OK)
3589 release_font_data(font_data);
3592 /* add family to collection */
3593 hr = fontcollection_add_family(collection, family_data);
3594 if (FAILED(hr))
3595 release_fontfamily_data(family_data);
3596 IDWriteFontFile_Release(file);
3598 return hr;
3601 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **ret)
3603 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3604 struct dwrite_fontcollection *collection;
3605 static const WCHAR emptyW[] = {0};
3606 WCHAR eudckeypathW[16];
3607 HKEY eudckey;
3608 DWORD index;
3609 BOOL exists;
3610 LONG retval;
3611 HRESULT hr;
3612 UINT32 i;
3614 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3616 *ret = NULL;
3618 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3619 if (!collection) return E_OUTOFMEMORY;
3621 hr = init_font_collection(collection, FALSE);
3622 if (FAILED(hr)) {
3623 heap_free(collection);
3624 return hr;
3627 *ret = &collection->IDWriteFontCollection_iface;
3629 /* return empty collection if EUDC fonts are not configured */
3630 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3631 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3632 return S_OK;
3634 retval = ERROR_SUCCESS;
3635 index = 0;
3636 while (retval != ERROR_NO_MORE_ITEMS) {
3637 WCHAR keynameW[64], pathW[MAX_PATH];
3638 DWORD type, path_len, name_len;
3640 path_len = sizeof(pathW)/sizeof(*pathW);
3641 name_len = sizeof(keynameW)/sizeof(*keynameW);
3642 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3643 if (retval || type != REG_SZ)
3644 continue;
3646 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3647 if (hr != S_OK)
3648 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3650 RegCloseKey(eudckey);
3652 /* try to add global default if not defined for specific codepage */
3653 exists = FALSE;
3654 hr = IDWriteFontCollection_FindFamilyName(&collection->IDWriteFontCollection_iface, emptyW,
3655 &index, &exists);
3656 if (FAILED(hr) || !exists) {
3657 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3658 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3659 if (hr != S_OK)
3660 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3663 /* EUDC collection offers simulated faces too */
3664 for (i = 0; i < collection->family_count; i++) {
3665 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3666 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3669 return S_OK;
3672 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3674 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3676 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3678 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3680 *obj = iface;
3681 IDWriteFontFile_AddRef(iface);
3682 return S_OK;
3685 *obj = NULL;
3686 return E_NOINTERFACE;
3689 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3691 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3692 ULONG ref = InterlockedIncrement(&This->ref);
3693 TRACE("(%p)->(%d)\n", This, ref);
3694 return ref;
3697 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3699 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3700 ULONG ref = InterlockedDecrement(&This->ref);
3702 TRACE("(%p)->(%d)\n", This, ref);
3704 if (!ref)
3706 IDWriteFontFileLoader_Release(This->loader);
3707 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3708 heap_free(This->reference_key);
3709 heap_free(This);
3712 return ref;
3715 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3717 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3718 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3719 *fontFileReferenceKey = This->reference_key;
3720 *fontFileReferenceKeySize = This->key_size;
3722 return S_OK;
3725 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3727 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3728 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3729 *fontFileLoader = This->loader;
3730 IDWriteFontFileLoader_AddRef(This->loader);
3732 return S_OK;
3735 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
3736 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3738 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3739 IDWriteFontFileStream *stream;
3740 HRESULT hr;
3742 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3744 *isSupportedFontType = FALSE;
3745 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3746 if (fontFaceType)
3747 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3748 *numberOfFaces = 0;
3750 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3751 if (FAILED(hr))
3752 return hr;
3754 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3756 /* TODO: Further Analysis */
3757 IDWriteFontFileStream_Release(stream);
3758 return S_OK;
3761 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3762 dwritefontfile_QueryInterface,
3763 dwritefontfile_AddRef,
3764 dwritefontfile_Release,
3765 dwritefontfile_GetReferenceKey,
3766 dwritefontfile_GetLoader,
3767 dwritefontfile_Analyze,
3770 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3772 struct dwrite_fontfile *This;
3774 This = heap_alloc(sizeof(struct dwrite_fontfile));
3775 if (!This) return E_OUTOFMEMORY;
3777 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3778 This->ref = 1;
3779 IDWriteFontFileLoader_AddRef(loader);
3780 This->loader = loader;
3781 This->stream = NULL;
3782 This->reference_key = heap_alloc(key_size);
3783 memcpy(This->reference_key, reference_key, key_size);
3784 This->key_size = key_size;
3786 *font_file = &This->IDWriteFontFile_iface;
3788 return S_OK;
3791 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3793 IDWriteFontFileLoader *loader;
3794 UINT32 key_size;
3795 const void *key;
3796 HRESULT hr;
3798 *stream = NULL;
3799 hr = IDWriteFontFile_GetLoader(file, &loader);
3800 if (FAILED(hr))
3801 return hr;
3803 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3804 if (FAILED(hr)) {
3805 IDWriteFontFileLoader_Release(loader);
3806 return hr;
3809 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3810 IDWriteFontFileLoader_Release(loader);
3812 return hr;
3815 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
3816 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
3818 struct dwrite_fontface *fontface;
3819 HRESULT hr = S_OK;
3820 int i;
3822 *ret = NULL;
3824 fontface = heap_alloc(sizeof(struct dwrite_fontface));
3825 if (!fontface)
3826 return E_OUTOFMEMORY;
3828 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
3829 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
3831 if (!fontface->files || !fontface->streams) {
3832 heap_free(fontface->files);
3833 heap_free(fontface->streams);
3834 heap_free(fontface);
3835 return E_OUTOFMEMORY;
3838 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
3839 fontface->ref = 1;
3840 fontface->type = facetype;
3841 fontface->file_count = files_number;
3842 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
3843 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
3844 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
3845 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
3846 memset(&fontface->colr, 0, sizeof(fontface->colr));
3847 fontface->cmap.exists = TRUE;
3848 fontface->vdmx.exists = TRUE;
3849 fontface->gasp.exists = TRUE;
3850 fontface->cpal.exists = TRUE;
3851 fontface->colr.exists = TRUE;
3852 fontface->index = index;
3853 fontface->simulations = simulations;
3854 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
3856 for (i = 0; i < fontface->file_count; i++) {
3857 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
3858 if (FAILED(hr)) {
3859 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
3860 return hr;
3863 fontface->files[i] = font_files[i];
3864 IDWriteFontFile_AddRef(font_files[i]);
3867 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
3868 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
3869 /* TODO: test what happens if caret is already slanted */
3870 if (fontface->caret.slopeRise == 1) {
3871 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
3872 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
3875 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &fontface->is_symbol);
3876 fontface->has_kerning_pairs = freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface);
3877 fontface->is_monospaced = freetype_is_monospaced(&fontface->IDWriteFontFace3_iface);
3879 *ret = &fontface->IDWriteFontFace3_iface;
3880 return S_OK;
3883 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3884 struct local_refkey
3886 FILETIME writetime;
3887 WCHAR name[1];
3890 struct local_cached_stream
3892 struct list entry;
3893 IDWriteFontFileStream *stream;
3894 struct local_refkey *key;
3895 UINT32 key_size;
3898 struct dwrite_localfontfilestream
3900 IDWriteFontFileStream IDWriteFontFileStream_iface;
3901 LONG ref;
3903 struct local_cached_stream *entry;
3904 const void *file_ptr;
3905 UINT64 size;
3908 struct dwrite_localfontfileloader {
3909 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
3910 LONG ref;
3912 struct list streams;
3915 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
3917 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
3920 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
3922 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
3925 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
3927 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3928 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3929 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
3931 *obj = iface;
3932 IDWriteFontFileStream_AddRef(iface);
3933 return S_OK;
3936 *obj = NULL;
3937 return E_NOINTERFACE;
3940 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
3942 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3943 ULONG ref = InterlockedIncrement(&This->ref);
3944 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
3945 return ref;
3948 static inline void release_cached_stream(struct local_cached_stream *stream)
3950 list_remove(&stream->entry);
3951 heap_free(stream->key);
3952 heap_free(stream);
3955 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
3957 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3958 ULONG ref = InterlockedDecrement(&This->ref);
3960 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
3962 if (!ref) {
3963 UnmapViewOfFile(This->file_ptr);
3964 release_cached_stream(This->entry);
3965 heap_free(This);
3968 return ref;
3971 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
3973 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3975 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
3976 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
3978 *fragment_context = NULL;
3980 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
3981 *fragment_start = NULL;
3982 return E_FAIL;
3985 *fragment_start = (char*)This->file_ptr + offset;
3986 return S_OK;
3989 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
3991 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3992 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
3995 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
3997 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3998 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
3999 *size = This->size;
4000 return S_OK;
4003 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4005 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4006 ULARGE_INTEGER li;
4008 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4010 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4011 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4012 *last_writetime = li.QuadPart;
4014 return S_OK;
4017 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4019 localfontfilestream_QueryInterface,
4020 localfontfilestream_AddRef,
4021 localfontfilestream_Release,
4022 localfontfilestream_ReadFileFragment,
4023 localfontfilestream_ReleaseFileFragment,
4024 localfontfilestream_GetFileSize,
4025 localfontfilestream_GetLastWriteTime
4028 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4030 struct dwrite_localfontfilestream *This;
4032 *ret = NULL;
4034 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4035 if (!This)
4036 return E_OUTOFMEMORY;
4038 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4039 This->ref = 1;
4041 This->file_ptr = file_ptr;
4042 This->size = size;
4043 This->entry = entry;
4045 *ret = &This->IDWriteFontFileStream_iface;
4046 return S_OK;
4049 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4051 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4053 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4055 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4057 *obj = iface;
4058 IDWriteLocalFontFileLoader_AddRef(iface);
4059 return S_OK;
4062 *obj = NULL;
4063 return E_NOINTERFACE;
4066 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4068 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4069 ULONG ref = InterlockedIncrement(&This->ref);
4070 TRACE("(%p)->(%d)\n", This, ref);
4071 return ref;
4074 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4076 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4077 ULONG ref = InterlockedDecrement(&This->ref);
4079 TRACE("(%p)->(%d)\n", This, ref);
4081 if (!ref) {
4082 struct local_cached_stream *stream, *stream2;
4084 /* This will detach all entries from cache. Entries are released together with streams,
4085 so stream controls cache entry lifetime. */
4086 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4087 list_init(&stream->entry);
4089 heap_free(This);
4092 return ref;
4095 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4097 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4098 const struct local_refkey *refkey = key;
4099 struct local_cached_stream *stream;
4100 IDWriteFontFileStream *filestream;
4101 HANDLE file, mapping;
4102 LARGE_INTEGER size;
4103 void *file_ptr;
4104 HRESULT hr;
4106 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4107 TRACE("name: %s\n", debugstr_w(refkey->name));
4109 /* search cache first */
4110 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4111 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4112 *ret = stream->stream;
4113 IDWriteFontFileStream_AddRef(*ret);
4114 return S_OK;
4118 *ret = NULL;
4120 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4121 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4122 if (file == INVALID_HANDLE_VALUE)
4123 return E_FAIL;
4125 GetFileSizeEx(file, &size);
4126 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4127 CloseHandle(file);
4128 if (!mapping)
4129 return E_FAIL;
4131 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4132 CloseHandle(mapping);
4134 stream = heap_alloc(sizeof(*stream));
4135 if (!stream) {
4136 UnmapViewOfFile(file_ptr);
4137 return E_OUTOFMEMORY;
4140 stream->key = heap_alloc(key_size);
4141 if (!stream->key) {
4142 UnmapViewOfFile(file_ptr);
4143 heap_free(stream);
4144 return E_OUTOFMEMORY;
4147 stream->key_size = key_size;
4148 memcpy(stream->key, key, key_size);
4150 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4151 if (FAILED(hr)) {
4152 UnmapViewOfFile(file_ptr);
4153 heap_free(stream->key);
4154 heap_free(stream);
4155 return hr;
4158 stream->stream = filestream;
4159 list_add_head(&This->streams, &stream->entry);
4161 *ret = stream->stream;
4163 return S_OK;
4166 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4168 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4169 const struct local_refkey *refkey = key;
4171 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4173 *length = strlenW(refkey->name);
4174 return S_OK;
4177 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4179 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4180 const struct local_refkey *refkey = key;
4182 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4184 if (length < strlenW(refkey->name))
4185 return E_INVALIDARG;
4187 strcpyW(path, refkey->name);
4188 return S_OK;
4191 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4193 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4194 const struct local_refkey *refkey = key;
4196 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4198 *writetime = refkey->writetime;
4199 return S_OK;
4202 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4203 localfontfileloader_QueryInterface,
4204 localfontfileloader_AddRef,
4205 localfontfileloader_Release,
4206 localfontfileloader_CreateStreamFromKey,
4207 localfontfileloader_GetFilePathLengthFromKey,
4208 localfontfileloader_GetFilePathFromKey,
4209 localfontfileloader_GetLastWriteTimeFromKey
4212 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4214 struct dwrite_localfontfileloader *This;
4216 *ret = NULL;
4218 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4219 if (!This)
4220 return E_OUTOFMEMORY;
4222 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4223 This->ref = 1;
4224 list_init(&This->streams);
4226 *ret = &This->IDWriteLocalFontFileLoader_iface;
4227 return S_OK;
4230 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4232 struct local_refkey *refkey;
4234 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4235 *key = NULL;
4237 refkey = heap_alloc(*size);
4238 if (!refkey)
4239 return E_OUTOFMEMORY;
4241 if (writetime)
4242 refkey->writetime = *writetime;
4243 else {
4244 WIN32_FILE_ATTRIBUTE_DATA info;
4246 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4247 refkey->writetime = info.ftLastWriteTime;
4248 else
4249 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4251 strcpyW(refkey->name, path);
4253 *key = refkey;
4255 return S_OK;
4258 /* IDWriteGlyphRunAnalysis */
4259 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4261 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4263 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4265 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4266 IsEqualIID(riid, &IID_IUnknown))
4268 *ppv = iface;
4269 IDWriteGlyphRunAnalysis_AddRef(iface);
4270 return S_OK;
4273 *ppv = NULL;
4274 return E_NOINTERFACE;
4277 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4279 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4280 ULONG ref = InterlockedIncrement(&This->ref);
4281 TRACE("(%p)->(%u)\n", This, ref);
4282 return ref;
4285 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4287 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4288 ULONG ref = InterlockedDecrement(&This->ref);
4290 TRACE("(%p)->(%u)\n", This, ref);
4292 if (!ref) {
4293 if (This->run.fontFace)
4294 IDWriteFontFace_Release(This->run.fontFace);
4295 heap_free(This->glyphs);
4296 heap_free(This->advances);
4297 heap_free(This->advanceoffsets);
4298 heap_free(This->ascenderoffsets);
4299 heap_free(This->bitmap);
4300 heap_free(This);
4303 return ref;
4306 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4308 struct dwrite_glyphbitmap glyph_bitmap;
4309 IDWriteFontFace3 *fontface3;
4310 D2D_POINT_2F origin;
4311 BOOL is_rtl;
4312 HRESULT hr;
4313 UINT32 i;
4315 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4316 *bounds = analysis->bounds;
4317 return;
4320 if (analysis->run.isSideways)
4321 FIXME("sideways runs are not supported.\n");
4323 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4324 if (FAILED(hr))
4325 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4327 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4328 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4329 for any non-zero glyph ascender */
4330 origin.x = origin.y = 0.0f;
4331 is_rtl = analysis->run.bidiLevel & 1;
4333 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4334 glyph_bitmap.fontface = fontface3;
4335 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4336 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4337 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4338 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4339 glyph_bitmap.m = &analysis->m;
4341 for (i = 0; i < analysis->run.glyphCount; i++) {
4342 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4343 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4344 const D2D_POINT_2F *advance = analysis->advances + i;
4345 RECT *bbox = &glyph_bitmap.bbox;
4347 glyph_bitmap.index = analysis->run.glyphIndices[i];
4348 freetype_get_glyph_bbox(&glyph_bitmap);
4350 if (is_rtl)
4351 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4352 else
4353 OffsetRect(bbox, origin.x, origin.y);
4355 if (advanceoffset)
4356 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4358 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4359 origin.x += advance->x;
4360 origin.y += advance->y;
4363 IDWriteFontFace3_Release(fontface3);
4365 /* translate to given run origin */
4366 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4367 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4368 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4370 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4371 *bounds = analysis->bounds;
4374 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4376 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4378 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4380 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4381 memset(bounds, 0, sizeof(*bounds));
4382 return E_INVALIDARG;
4385 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4386 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4387 memset(bounds, 0, sizeof(*bounds));
4388 return S_OK;
4391 glyphrunanalysis_get_texturebounds(This, bounds);
4392 return S_OK;
4395 static inline int get_dib_stride( int width, int bpp )
4397 return ((width * bpp + 31) >> 3) & ~3;
4400 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4402 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4403 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4404 (runbounds->left - bounds->left) * 3;
4405 else
4406 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4407 runbounds->left - bounds->left;
4410 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4412 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4413 struct dwrite_glyphbitmap glyph_bitmap;
4414 IDWriteFontFace3 *fontface2;
4415 D2D_POINT_2F origin;
4416 UINT32 i, size;
4417 BOOL is_rtl;
4418 HRESULT hr;
4419 RECT *bbox;
4421 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4422 if (FAILED(hr)) {
4423 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4424 return;
4427 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4428 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4429 size *= 3;
4430 analysis->bitmap = heap_alloc_zero(size);
4432 origin.x = origin.y = 0.0f;
4433 is_rtl = analysis->run.bidiLevel & 1;
4435 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4436 glyph_bitmap.fontface = fontface2;
4437 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4438 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4439 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4440 glyph_bitmap.type = type;
4441 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4442 glyph_bitmap.m = &analysis->m;
4443 bbox = &glyph_bitmap.bbox;
4445 for (i = 0; i < analysis->run.glyphCount; i++) {
4446 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4447 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4448 const D2D_POINT_2F *advance = analysis->advances + i;
4449 int x, y, width, height;
4450 BYTE *src, *dst;
4451 BOOL is_1bpp;
4453 glyph_bitmap.index = analysis->run.glyphIndices[i];
4454 freetype_get_glyph_bbox(&glyph_bitmap);
4456 if (IsRectEmpty(bbox)) {
4457 origin.x += advance->x;
4458 origin.y += advance->y;
4459 continue;
4462 width = bbox->right - bbox->left;
4463 height = bbox->bottom - bbox->top;
4465 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4466 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4467 else
4468 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4470 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4471 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4473 if (is_rtl)
4474 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4475 else
4476 OffsetRect(bbox, origin.x, origin.y);
4478 if (advanceoffset)
4479 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4481 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4482 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4483 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4485 /* blit to analysis bitmap */
4486 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4488 if (is_1bpp) {
4489 /* convert 1bpp to 8bpp/24bpp */
4490 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4491 for (y = 0; y < height; y++) {
4492 for (x = 0; x < width; x++)
4493 if (src[x / 8] & masks[x % 8])
4494 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4495 src += glyph_bitmap.pitch;
4496 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4499 else {
4500 for (y = 0; y < height; y++) {
4501 for (x = 0; x < width; x++)
4502 if (src[x / 8] & masks[x % 8])
4503 dst[x] = DWRITE_ALPHA_MAX;
4504 src += get_dib_stride(width, 1);
4505 dst += analysis->bounds.right - analysis->bounds.left;
4509 else {
4510 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4511 for (y = 0; y < height; y++) {
4512 for (x = 0; x < width; x++)
4513 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4514 src += glyph_bitmap.pitch;
4515 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4519 heap_free(glyph_bitmap.buf);
4521 origin.x += advance->x;
4522 origin.y += advance->y;
4525 IDWriteFontFace3_Release(fontface2);
4527 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4529 /* we don't need this anymore */
4530 heap_free(analysis->glyphs);
4531 heap_free(analysis->advances);
4532 heap_free(analysis->advanceoffsets);
4533 heap_free(analysis->ascenderoffsets);
4534 IDWriteFontFace_Release(analysis->run.fontFace);
4536 analysis->glyphs = NULL;
4537 analysis->advances = NULL;
4538 analysis->advanceoffsets = NULL;
4539 analysis->ascenderoffsets = NULL;
4540 analysis->run.glyphIndices = NULL;
4541 analysis->run.fontFace = NULL;
4544 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4545 RECT const *bounds, BYTE *bitmap, UINT32 size)
4547 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4548 UINT32 required;
4549 RECT runbounds;
4551 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4553 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4554 return E_INVALIDARG;
4556 /* make sure buffer is large enough for requested texture type */
4557 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4558 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4559 required *= 3;
4561 if (size < required)
4562 return E_NOT_SUFFICIENT_BUFFER;
4564 /* validate requested texture type with rendering mode */
4565 switch (This->rendering_mode)
4567 case DWRITE_RENDERING_MODE_ALIASED:
4568 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4569 return DWRITE_E_UNSUPPORTEDOPERATION;
4570 break;
4571 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4572 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4573 case DWRITE_RENDERING_MODE_NATURAL:
4574 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4575 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4576 return DWRITE_E_UNSUPPORTEDOPERATION;
4577 break;
4578 default:
4582 memset(bitmap, 0, size);
4583 glyphrunanalysis_get_texturebounds(This, &runbounds);
4584 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4585 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4586 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4587 int dst_width = (bounds->right - bounds->left) * pixel_size;
4588 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4589 BYTE *src, *dst;
4590 int y;
4592 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4593 glyphrunanalysis_render(This, type);
4595 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4596 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4598 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4599 memcpy(dst, src, draw_width);
4600 src += src_width;
4601 dst += dst_width;
4605 return S_OK;
4608 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4609 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4611 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4613 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4615 if (!params)
4616 return E_INVALIDARG;
4618 switch (This->rendering_mode)
4620 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4621 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4623 UINT value = 0;
4624 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4625 *gamma = (FLOAT)value / 1000.0f;
4626 *contrast = 0.0f;
4627 *cleartypelevel = 1.0f;
4628 break;
4630 case DWRITE_RENDERING_MODE_ALIASED:
4631 case DWRITE_RENDERING_MODE_NATURAL:
4632 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4633 *gamma = IDWriteRenderingParams_GetGamma(params);
4634 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4635 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4636 break;
4637 default:
4641 return S_OK;
4644 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4645 glyphrunanalysis_QueryInterface,
4646 glyphrunanalysis_AddRef,
4647 glyphrunanalysis_Release,
4648 glyphrunanalysis_GetAlphaTextureBounds,
4649 glyphrunanalysis_CreateAlphaTexture,
4650 glyphrunanalysis_GetAlphaBlendParams
4653 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4655 if (is_vertical) {
4656 vec->x = 0.0f;
4657 vec->y = length;
4659 else {
4660 vec->x = length;
4661 vec->y = 0.0f;
4665 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4667 D2D_POINT_2F ret;
4668 ret.x = vec->x * m->m11 + vec->y * m->m21;
4669 ret.y = vec->x * m->m12 + vec->y * m->m22;
4670 *vec = ret;
4673 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4674 FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
4675 FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4677 struct dwrite_glyphrunanalysis *analysis;
4678 FLOAT rtl_factor;
4679 UINT32 i;
4681 *ret = NULL;
4683 /* check for valid rendering mode */
4684 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4685 return E_INVALIDARG;
4687 analysis = heap_alloc(sizeof(*analysis));
4688 if (!analysis)
4689 return E_OUTOFMEMORY;
4691 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4692 analysis->ref = 1;
4693 analysis->rendering_mode = rendering_mode;
4694 analysis->flags = 0;
4695 analysis->bitmap = NULL;
4696 analysis->ppdip = ppdip;
4697 analysis->origin.x = originX * ppdip;
4698 analysis->origin.y = originY * ppdip;
4699 SetRectEmpty(&analysis->bounds);
4700 analysis->run = *run;
4701 IDWriteFontFace_AddRef(analysis->run.fontFace);
4702 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4703 analysis->advances = heap_alloc(run->glyphCount*sizeof(*analysis->advances));
4704 if (run->glyphOffsets) {
4705 analysis->advanceoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->advanceoffsets));
4706 analysis->ascenderoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->ascenderoffsets));
4708 else {
4709 analysis->advanceoffsets = NULL;
4710 analysis->ascenderoffsets = NULL;
4713 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && run->glyphOffsets)) {
4714 heap_free(analysis->glyphs);
4715 heap_free(analysis->advances);
4716 heap_free(analysis->advanceoffsets);
4717 heap_free(analysis->ascenderoffsets);
4719 analysis->glyphs = NULL;
4720 analysis->advances = NULL;
4721 analysis->advanceoffsets = NULL;
4722 analysis->ascenderoffsets = NULL;
4724 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4725 return E_OUTOFMEMORY;
4728 /* check if transform is usable */
4729 if (transform && memcmp(transform, &identity, sizeof(*transform))) {
4730 analysis->m = *transform;
4731 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4733 else
4734 memset(&analysis->m, 0, sizeof(analysis->m));
4736 analysis->run.glyphIndices = analysis->glyphs;
4737 analysis->run.glyphAdvances = NULL;
4738 analysis->run.glyphOffsets = NULL;
4740 rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f;
4742 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4743 transform_2d_vec(&analysis->origin, &analysis->m);
4745 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4747 if (run->glyphAdvances) {
4748 for (i = 0; i < run->glyphCount; i++) {
4749 init_2d_vec(analysis->advances + i, rtl_factor * run->glyphAdvances[i] * ppdip, run->isSideways);
4750 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4751 transform_2d_vec(analysis->advances + i, &analysis->m);
4754 else {
4755 DWRITE_FONT_METRICS metrics;
4756 IDWriteFontFace1 *fontface1;
4758 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4759 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4761 for (i = 0; i < run->glyphCount; i++) {
4762 HRESULT hr;
4763 INT32 a;
4765 switch (measuring_mode)
4767 case DWRITE_MEASURING_MODE_NATURAL:
4768 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4769 if (FAILED(hr))
4770 a = 0;
4771 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics) * ppdip,
4772 run->isSideways);
4773 break;
4774 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4775 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4776 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, transform,
4777 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4778 if (FAILED(hr))
4779 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4780 else
4781 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f),
4782 run->isSideways);
4783 break;
4784 default:
4788 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4789 transform_2d_vec(analysis->advances + i, &analysis->m);
4792 IDWriteFontFace1_Release(fontface1);
4795 if (run->glyphOffsets) {
4796 for (i = 0; i < run->glyphCount; i++) {
4797 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
4798 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4799 init_2d_vec(analysis->ascenderoffsets + i, -run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
4800 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
4801 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
4802 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
4807 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
4808 return S_OK;
4811 /* IDWriteColorGlyphRunEnumerator */
4812 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
4814 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4816 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4818 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
4819 IsEqualIID(riid, &IID_IUnknown))
4821 *ppv = iface;
4822 IDWriteColorGlyphRunEnumerator_AddRef(iface);
4823 return S_OK;
4826 *ppv = NULL;
4827 return E_NOINTERFACE;
4830 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
4832 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4833 ULONG ref = InterlockedIncrement(&This->ref);
4834 TRACE("(%p)->(%u)\n", This, ref);
4835 return ref;
4838 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
4840 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4841 ULONG ref = InterlockedDecrement(&This->ref);
4843 TRACE("(%p)->(%u)\n", This, ref);
4845 if (!ref) {
4846 heap_free(This->advances);
4847 heap_free(This->color_advances);
4848 heap_free(This->offsets);
4849 heap_free(This->color_offsets);
4850 heap_free(This->glyphindices);
4851 heap_free(This->glyphs);
4852 if (This->colr.context)
4853 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
4854 IDWriteFontFace3_Release(This->fontface);
4855 heap_free(This);
4858 return ref;
4861 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
4863 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
4864 FLOAT origin = 0.0f;
4866 if (g == 0)
4867 return 0.0f;
4869 while (g--)
4870 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
4871 return origin;
4874 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
4876 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
4877 FLOAT advance_adj = 0.0f;
4878 BOOL got_palette_index;
4879 UINT32 g;
4881 /* start with regular glyphs */
4882 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
4883 UINT32 first_glyph = 0;
4885 for (g = 0; g < glyphenum->run.glyphCount; g++) {
4886 if (glyphenum->glyphs[g].num_layers == 0) {
4887 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
4888 first_glyph = min(first_glyph, g);
4890 else
4891 glyphenum->glyphindices[g] = 1;
4892 glyphenum->color_advances[g] = glyphenum->advances[g];
4893 if (glyphenum->color_offsets)
4894 glyphenum->color_offsets[g] = glyphenum->offsets[g];
4897 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
4898 colorrun->baselineOriginY = glyphenum->origin_y;
4899 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
4900 colorrun->paletteIndex = 0xffff;
4901 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
4902 glyphenum->has_regular_glyphs = FALSE;
4903 return TRUE;
4905 else {
4906 colorrun->glyphRun.glyphCount = 0;
4907 got_palette_index = FALSE;
4910 advance_adj = 0.0f;
4911 for (g = 0; g < glyphenum->run.glyphCount; g++) {
4913 glyphenum->glyphindices[g] = 1;
4915 /* all glyph layers were returned */
4916 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
4917 advance_adj += glyphenum->advances[g];
4918 continue;
4921 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
4922 UINT32 index = colorrun->glyphRun.glyphCount;
4923 if (!got_palette_index) {
4924 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
4925 /* use foreground color or request one from the font */
4926 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
4927 if (colorrun->paletteIndex != 0xffff) {
4928 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
4929 1, &colorrun->runColor);
4930 if (FAILED(hr))
4931 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
4932 glyphenum->palette, colorrun->paletteIndex, hr);
4934 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
4935 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
4936 colorrun->baselineOriginY = glyphenum->origin_y;
4937 glyphenum->color_advances[index] = glyphenum->advances[g];
4938 got_palette_index = TRUE;
4941 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
4942 /* offsets are relative to glyph origin, nothing to fix up */
4943 if (glyphenum->color_offsets)
4944 glyphenum->color_offsets[index] = glyphenum->offsets[g];
4945 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
4946 if (index)
4947 glyphenum->color_advances[index-1] += advance_adj;
4948 colorrun->glyphRun.glyphCount++;
4949 advance_adj = 0.0f;
4951 else
4952 advance_adj += glyphenum->advances[g];
4955 /* reset last advance */
4956 if (colorrun->glyphRun.glyphCount)
4957 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
4959 return colorrun->glyphRun.glyphCount > 0;
4962 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
4964 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4966 TRACE("(%p)->(%p)\n", This, has_run);
4968 *has_run = FALSE;
4970 This->colorrun.glyphRun.glyphCount = 0;
4971 while (This->current_layer < This->max_layer_num) {
4972 if (colorglyphenum_build_color_run(This))
4973 break;
4974 else
4975 This->current_layer++;
4978 *has_run = This->colorrun.glyphRun.glyphCount > 0;
4980 return S_OK;
4983 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
4985 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4987 TRACE("(%p)->(%p)\n", This, run);
4989 if (This->colorrun.glyphRun.glyphCount == 0) {
4990 *run = NULL;
4991 return E_NOT_VALID_STATE;
4994 *run = &This->colorrun;
4995 return S_OK;
4998 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
4999 colorglyphenum_QueryInterface,
5000 colorglyphenum_AddRef,
5001 colorglyphenum_Release,
5002 colorglyphenum_MoveNext,
5003 colorglyphenum_GetCurrentRun
5006 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5007 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5009 struct dwrite_colorglyphenum *colorglyphenum;
5010 BOOL colorfont, has_colored_glyph;
5011 IDWriteFontFace3 *fontface3;
5012 HRESULT hr;
5013 UINT32 i;
5015 *ret = NULL;
5017 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5018 if (FAILED(hr)) {
5019 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5020 return hr;
5023 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5024 if (!colorfont) {
5025 hr = DWRITE_E_NOCOLOR;
5026 goto failed;
5029 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5030 if (!colorglyphenum) {
5031 hr = E_OUTOFMEMORY;
5032 goto failed;
5035 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5036 colorglyphenum->ref = 1;
5037 colorglyphenum->origin_x = originX;
5038 colorglyphenum->origin_y = originY;
5039 colorglyphenum->fontface = fontface3;
5040 colorglyphenum->glyphs = NULL;
5041 colorglyphenum->run = *run;
5042 colorglyphenum->run.glyphIndices = NULL;
5043 colorglyphenum->run.glyphAdvances = NULL;
5044 colorglyphenum->run.glyphOffsets = NULL;
5045 colorglyphenum->palette = palette;
5046 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5047 colorglyphenum->colr.exists = TRUE;
5048 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5049 colorglyphenum->current_layer = 0;
5050 colorglyphenum->max_layer_num = 0;
5052 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5054 has_colored_glyph = FALSE;
5055 colorglyphenum->has_regular_glyphs = FALSE;
5056 for (i = 0; i < run->glyphCount; i++) {
5057 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5058 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5059 has_colored_glyph = TRUE;
5061 if (colorglyphenum->glyphs[i].num_layers == 0)
5062 colorglyphenum->has_regular_glyphs = TRUE;
5065 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5066 is supposed to proceed normally, like if font had no color info at all. */
5067 if (!has_colored_glyph) {
5068 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5069 return DWRITE_E_NOCOLOR;
5072 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5073 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5074 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5075 if (run->glyphOffsets) {
5076 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5077 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5078 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5081 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5082 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5083 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5084 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5086 if (run->glyphAdvances)
5087 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5088 else {
5089 DWRITE_FONT_METRICS metrics;
5091 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5092 for (i = 0; i < run->glyphCount; i++) {
5093 HRESULT hr;
5094 INT32 a;
5096 switch (measuring_mode)
5098 case DWRITE_MEASURING_MODE_NATURAL:
5099 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5100 if (FAILED(hr))
5101 a = 0;
5102 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5103 break;
5104 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5105 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5106 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5107 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5108 if (FAILED(hr))
5109 colorglyphenum->advances[i] = 0.0f;
5110 else
5111 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5112 break;
5113 default:
5119 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5120 return S_OK;
5122 failed:
5123 IDWriteFontFace3_Release(fontface3);
5124 return hr;