ntdll: Translate signal to trap when trap code is 0 on ARM.
[wine.git] / dlls / dwrite / font.c
blob374236657b8b82b338e54887b5c8b8fd48cf7d7c
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2017 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <math.h>
26 #define COBJMACROS
28 #include "dwrite_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
31 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
33 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
34 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
42 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
44 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
45 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
46 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
48 static const WCHAR extraW[] = {'e','x','t','r','a',0};
49 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
50 static const WCHAR semiW[] = {'s','e','m','i',0};
51 static const WCHAR extW[] = {'e','x','t',0};
52 static const WCHAR thinW[] = {'t','h','i','n',0};
53 static const WCHAR lightW[] = {'l','i','g','h','t',0};
54 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
55 static const WCHAR blackW[] = {'b','l','a','c','k',0};
56 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
57 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
58 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
59 static const WCHAR boldW[] = {'B','o','l','d',0};
60 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
61 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
62 static const WCHAR demiW[] = {'d','e','m','i',0};
63 static const WCHAR spaceW[] = {' ',0};
64 static const WCHAR enusW[] = {'e','n','-','u','s',0};
66 struct dwrite_font_propvec {
67 FLOAT stretch;
68 FLOAT style;
69 FLOAT weight;
72 struct dwrite_font_data {
73 LONG ref;
75 DWRITE_FONT_STYLE style;
76 DWRITE_FONT_STRETCH stretch;
77 DWRITE_FONT_WEIGHT weight;
78 DWRITE_PANOSE panose;
79 FONTSIGNATURE fontsig;
80 struct dwrite_font_propvec propvec;
82 DWRITE_FONT_METRICS1 metrics;
83 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
84 IDWriteLocalizedStrings *names;
86 /* data needed to create fontface instance */
87 DWRITE_FONT_FACE_TYPE face_type;
88 IDWriteFontFile *file;
89 UINT32 face_index;
91 WCHAR *facename;
93 USHORT simulations;
95 LOGFONTW lf;
97 /* used to mark font as tested when scanning for simulation candidate */
98 BOOL bold_sim_tested : 1;
99 BOOL oblique_sim_tested : 1;
102 struct dwrite_fontfamily_data {
103 LONG ref;
105 IDWriteLocalizedStrings *familyname;
107 struct dwrite_font_data **fonts;
108 UINT32 font_count;
109 UINT32 font_alloc;
110 BOOL has_normal_face : 1;
111 BOOL has_oblique_face : 1;
112 BOOL has_italic_face : 1;
115 struct dwrite_fontcollection {
116 IDWriteFontCollection1 IDWriteFontCollection1_iface;
117 LONG ref;
119 IDWriteFactory5 *factory;
120 struct dwrite_fontfamily_data **family_data;
121 UINT32 family_count;
122 UINT32 family_alloc;
125 struct dwrite_fontfamily {
126 IDWriteFontFamily1 IDWriteFontFamily1_iface;
127 IDWriteFontList1 IDWriteFontList1_iface;
128 LONG ref;
130 struct dwrite_fontfamily_data *data;
131 struct dwrite_fontcollection *collection;
134 struct dwrite_fontlist {
135 IDWriteFontList1 IDWriteFontList1_iface;
136 LONG ref;
138 struct dwrite_font_data **fonts;
139 UINT32 font_count;
140 struct dwrite_fontfamily *family;
143 struct dwrite_font {
144 IDWriteFont3 IDWriteFont3_iface;
145 LONG ref;
147 DWRITE_FONT_STYLE style;
148 struct dwrite_font_data *data;
149 struct dwrite_fontfamily *family;
152 enum runanalysis_flags {
153 RUNANALYSIS_BOUNDS_READY = 1 << 0,
154 RUNANALYSIS_BITMAP_READY = 1 << 1,
155 RUNANALYSIS_USE_TRANSFORM = 1 << 2
158 struct dwrite_glyphrunanalysis {
159 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
160 LONG ref;
162 DWRITE_RENDERING_MODE1 rendering_mode;
163 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
164 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
165 DWRITE_MATRIX m;
166 UINT16 *glyphs;
167 D2D_POINT_2F *origins;
169 UINT8 flags;
170 RECT bounds;
171 BYTE *bitmap;
172 UINT32 max_glyph_bitmap_size;
175 struct dwrite_colorglyphenum {
176 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
177 LONG ref;
179 FLOAT origin_x; /* original run origin */
180 FLOAT origin_y;
182 IDWriteFontFace4 *fontface; /* for convenience */
183 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
184 DWRITE_GLYPH_RUN run; /* base run */
185 UINT32 palette; /* palette index to get layer color from */
186 FLOAT *advances; /* original or measured advances for base glyphs */
187 FLOAT *color_advances; /* returned color run points to this */
188 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
189 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
190 UINT16 *glyphindices; /* returned color run points to this */
191 struct dwrite_colorglyph *glyphs; /* current glyph color info */
192 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
193 UINT16 current_layer; /* enumerator position, updated with MoveNext */
194 UINT16 max_layer_num; /* max number of layers for this run */
195 struct dwrite_fonttable colr; /* used to access layers */
198 #define GLYPH_BLOCK_SHIFT 8
199 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
200 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
201 #define GLYPH_MAX 65536
203 enum fontface_flags {
204 FONTFACE_IS_SYMBOL = 1 << 0,
205 FONTFACE_IS_MONOSPACED = 1 << 1,
206 FONTFACE_HAS_KERNING_PAIRS = 1 << 2,
207 FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
210 struct dwrite_fontface {
211 IDWriteFontFace4 IDWriteFontFace4_iface;
212 LONG ref;
214 IDWriteFontFileStream *stream;
215 IDWriteFontFile **files;
216 UINT32 file_count;
217 UINT32 index;
219 IDWriteFactory5 *factory;
220 struct fontfacecached *cached;
222 USHORT simulations;
223 DWRITE_FONT_FACE_TYPE type;
224 DWRITE_FONT_METRICS1 metrics;
225 DWRITE_CARET_METRICS caret;
226 INT charmap;
227 UINT16 flags;
229 struct dwrite_fonttable cmap;
230 struct dwrite_fonttable vdmx;
231 struct dwrite_fonttable gasp;
232 struct dwrite_fonttable cpal;
233 struct dwrite_fonttable colr;
234 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
236 DWRITE_FONT_STYLE style;
237 DWRITE_FONT_STRETCH stretch;
238 DWRITE_FONT_WEIGHT weight;
239 DWRITE_PANOSE panose;
240 FONTSIGNATURE fontsig;
241 UINT32 glyph_image_formats;
243 struct scriptshaping_cache *shaping_cache;
245 LOGFONTW lf;
248 struct dwrite_fontfile {
249 IDWriteFontFile IDWriteFontFile_iface;
250 LONG ref;
252 IDWriteFontFileLoader *loader;
253 void *reference_key;
254 UINT32 key_size;
255 IDWriteFontFileStream *stream;
258 struct dwrite_fontfacereference {
259 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
260 LONG ref;
262 IDWriteFontFile *file;
263 UINT32 index;
264 USHORT simulations;
265 IDWriteFactory5 *factory;
268 static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
270 struct dwrite_fontface *fontface = context;
271 BOOL exists = FALSE;
273 if (FAILED(IDWriteFontFace4_TryGetFontTable(&fontface->IDWriteFontFace4_iface, table, (const void **)data,
274 size, data_context, &exists)) || !exists)
276 *data = NULL;
277 *size = 0;
278 *data_context = NULL;
282 static void dwrite_release_font_table(void *context, void *data_context)
284 struct dwrite_fontface *fontface = context;
285 IDWriteFontFace4_ReleaseFontTable(&fontface->IDWriteFontFace4_iface, data_context);
288 static UINT16 dwrite_get_font_upem(void *context)
290 struct dwrite_fontface *fontface = context;
291 return fontface->metrics.designUnitsPerEm;
294 static const struct shaping_font_ops dwrite_font_ops =
296 dwrite_grab_font_table,
297 dwrite_release_font_table,
298 dwrite_get_font_upem,
301 struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
303 if (fontface->shaping_cache)
304 return fontface->shaping_cache;
306 return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
309 static inline struct dwrite_fontface *impl_from_IDWriteFontFace4(IDWriteFontFace4 *iface)
311 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
314 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
316 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
319 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
321 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
324 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
326 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
329 static inline struct dwrite_fontfamily *impl_family_from_IDWriteFontList1(IDWriteFontList1 *iface)
331 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontList1_iface);
334 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
336 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
339 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
341 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
344 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
346 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
349 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
351 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
354 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
356 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
359 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
361 static const DWRITE_GLYPH_METRICS nil;
362 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
364 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
365 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
366 return S_OK;
369 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
371 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
373 if (!*block) {
374 /* start new block */
375 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
376 if (!*block)
377 return E_OUTOFMEMORY;
380 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
381 return S_OK;
384 const void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table)
386 HRESULT hr;
388 if (table->data || !table->exists)
389 return table->data;
391 table->exists = FALSE;
392 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
393 &table->exists);
394 if (FAILED(hr) || !table->exists) {
395 TRACE("Font does not have %s table\n", debugstr_tag(tag));
396 return NULL;
399 return table->data;
402 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
403 struct dwrite_font_propvec *vec)
405 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
406 vec->style = style * 7.0f;
407 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
410 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
412 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
415 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
417 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
420 static const struct dwrite_fonttable *get_fontface_vdmx(struct dwrite_fontface *fontface)
422 get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx);
423 return &fontface->vdmx;
426 static const struct dwrite_fonttable *get_fontface_gasp(struct dwrite_fontface *fontface)
428 get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp);
429 return &fontface->gasp;
432 static const struct dwrite_fonttable *get_fontface_cpal(struct dwrite_fontface *fontface)
434 get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal);
435 return &fontface->cpal;
438 static const void* get_fontface_colr(struct dwrite_fontface *fontface)
440 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &fontface->colr);
443 static void addref_font_data(struct dwrite_font_data *data)
445 InterlockedIncrement(&data->ref);
448 static void release_font_data(struct dwrite_font_data *data)
450 int i;
452 if (InterlockedDecrement(&data->ref) > 0)
453 return;
455 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < ARRAY_SIZE(data->info_strings); i++) {
456 if (data->info_strings[i])
457 IDWriteLocalizedStrings_Release(data->info_strings[i]);
459 if (data->names)
460 IDWriteLocalizedStrings_Release(data->names);
462 IDWriteFontFile_Release(data->file);
463 heap_free(data->facename);
464 heap_free(data);
467 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
469 int i;
471 if (InterlockedDecrement(&data->ref) > 0)
472 return;
474 for (i = 0; i < data->font_count; i++)
475 release_font_data(data->fonts[i]);
476 heap_free(data->fonts);
477 IDWriteLocalizedStrings_Release(data->familyname);
478 heap_free(data);
481 void fontface_detach_from_cache(IDWriteFontFace4 *iface)
483 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace4(iface);
484 fontface->cached = NULL;
487 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace4 *iface, REFIID riid, void **obj)
489 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
491 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
493 if (IsEqualIID(riid, &IID_IDWriteFontFace4) ||
494 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
495 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
496 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
497 IsEqualIID(riid, &IID_IDWriteFontFace) ||
498 IsEqualIID(riid, &IID_IUnknown))
500 *obj = iface;
501 if (InterlockedIncrement(&This->ref) == 1) {
502 InterlockedDecrement(&This->ref);
503 *obj = NULL;
504 return E_FAIL;
506 return S_OK;
509 WARN("%s not implemented.\n", debugstr_guid(riid));
511 *obj = NULL;
512 return E_NOINTERFACE;
515 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace4 *iface)
517 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
518 ULONG ref = InterlockedIncrement(&This->ref);
519 TRACE("(%p)->(%d)\n", This, ref);
520 return ref;
523 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
525 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
526 ULONG ref = InterlockedDecrement(&This->ref);
528 TRACE("(%p)->(%d)\n", This, ref);
530 if (!ref) {
531 UINT32 i;
533 if (This->cached) {
534 factory_lock(This->factory);
535 list_remove(&This->cached->entry);
536 factory_unlock(This->factory);
537 heap_free(This->cached);
539 release_scriptshaping_cache(This->shaping_cache);
540 if (This->cmap.context)
541 IDWriteFontFace4_ReleaseFontTable(iface, This->cmap.context);
542 if (This->vdmx.context)
543 IDWriteFontFace4_ReleaseFontTable(iface, This->vdmx.context);
544 if (This->gasp.context)
545 IDWriteFontFace4_ReleaseFontTable(iface, This->gasp.context);
546 if (This->cpal.context)
547 IDWriteFontFace4_ReleaseFontTable(iface, This->cpal.context);
548 if (This->colr.context)
549 IDWriteFontFace4_ReleaseFontTable(iface, This->colr.context);
550 for (i = 0; i < This->file_count; i++) {
551 if (This->files[i])
552 IDWriteFontFile_Release(This->files[i]);
554 if (This->stream)
555 IDWriteFontFileStream_Release(This->stream);
556 heap_free(This->files);
558 for (i = 0; i < ARRAY_SIZE(This->glyphs); i++)
559 heap_free(This->glyphs[i]);
561 freetype_notify_cacheremove(iface);
563 IDWriteFactory5_Release(This->factory);
564 heap_free(This);
567 return ref;
570 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace4 *iface)
572 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
573 TRACE("(%p)\n", This);
574 return This->type;
577 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace4 *iface, UINT32 *number_of_files,
578 IDWriteFontFile **fontfiles)
580 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
581 int i;
583 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
584 if (fontfiles == NULL)
586 *number_of_files = This->file_count;
587 return S_OK;
589 if (*number_of_files < This->file_count)
590 return E_INVALIDARG;
592 for (i = 0; i < This->file_count; i++)
594 IDWriteFontFile_AddRef(This->files[i]);
595 fontfiles[i] = This->files[i];
598 return S_OK;
601 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace4 *iface)
603 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
604 TRACE("(%p)\n", This);
605 return This->index;
608 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace4 *iface)
610 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
611 TRACE("(%p)\n", This);
612 return This->simulations;
615 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace4 *iface)
617 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
618 TRACE("(%p)\n", This);
619 return !!(This->flags & FONTFACE_IS_SYMBOL);
622 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS *metrics)
624 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
625 TRACE("(%p)->(%p)\n", This, metrics);
626 memcpy(metrics, &This->metrics, sizeof(*metrics));
629 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface)
631 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
632 TRACE("(%p)\n", This);
633 return freetype_get_glyphcount(iface);
636 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface,
637 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
639 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
640 HRESULT hr;
641 UINT32 i;
643 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
645 if (!glyphs)
646 return E_INVALIDARG;
648 if (is_sideways)
649 FIXME("sideways metrics are not supported.\n");
651 for (i = 0; i < glyph_count; i++) {
652 DWRITE_GLYPH_METRICS metrics;
654 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
655 if (hr != S_OK) {
656 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
657 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
658 if (FAILED(hr))
659 return hr;
661 ret[i] = metrics;
664 return S_OK;
667 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
668 UINT32 count, UINT16 *glyphs)
670 if (!glyphs)
671 return E_INVALIDARG;
673 if (!codepoints) {
674 memset(glyphs, 0, count * sizeof(*glyphs));
675 return E_INVALIDARG;
678 freetype_get_glyphs(&fontface->IDWriteFontFace4_iface, fontface->charmap, codepoints, count, glyphs);
679 return S_OK;
682 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace4 *iface, UINT32 const *codepoints,
683 UINT32 count, UINT16 *glyphs)
685 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
687 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyphs);
689 return fontface_get_glyphs(This, codepoints, count, glyphs);
692 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace4 *iface, UINT32 table_tag,
693 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
695 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
696 struct file_stream_desc stream_desc;
698 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
700 stream_desc.stream = This->stream;
701 stream_desc.face_type = This->type;
702 stream_desc.face_index = This->index;
703 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
706 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace4 *iface, void *table_context)
708 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
710 TRACE("(%p)->(%p)\n", This, table_context);
712 IDWriteFontFileStream_ReleaseFileFragment(This->stream, table_context);
715 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, FLOAT emSize,
716 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
717 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
719 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
721 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
722 count, is_sideways, is_rtl, sink);
724 if (!glyphs || !sink)
725 return E_INVALIDARG;
727 if (is_sideways)
728 FIXME("sideways mode is not supported.\n");
730 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
733 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
734 float ppem, unsigned int gasp)
736 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
738 switch (measuring)
740 case DWRITE_MEASURING_MODE_NATURAL:
742 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
743 mode = DWRITE_RENDERING_MODE_NATURAL;
744 else
745 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
746 break;
748 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
749 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
750 break;
751 case DWRITE_MEASURING_MODE_GDI_NATURAL:
752 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
753 break;
754 default:
758 return mode;
761 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
762 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
764 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
765 unsigned int flags;
766 FLOAT ppem;
768 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
770 if (!params) {
771 *mode = DWRITE_RENDERING_MODE_DEFAULT;
772 return E_INVALIDARG;
775 *mode = IDWriteRenderingParams_GetRenderingMode(params);
776 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
777 return S_OK;
779 ppem = emSize * ppdip;
781 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
782 *mode = DWRITE_RENDERING_MODE_OUTLINE;
783 return S_OK;
786 flags = opentype_get_gasp_flags(get_fontface_gasp(This), ppem);
787 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, flags);
788 return S_OK;
791 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT pixels_per_dip,
792 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
794 DWRITE_FONT_METRICS1 metrics1;
795 HRESULT hr = IDWriteFontFace4_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
796 memcpy(metrics, &metrics1, sizeof(*metrics));
797 return hr;
800 static inline int round_metric(FLOAT metric)
802 return (int)floorf(metric + 0.5f);
805 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
807 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
808 return 0;
810 return (fontface->metrics.designUnitsPerEm + 49) / 50;
813 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip,
814 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
815 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
817 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
818 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
819 DWRITE_MEASURING_MODE mode;
820 FLOAT scale, size;
821 HRESULT hr;
822 UINT32 i;
824 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
825 glyph_count, metrics, is_sideways);
827 if (m && memcmp(m, &identity, sizeof(*m)))
828 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
830 size = emSize * ppdip;
831 scale = size / This->metrics.designUnitsPerEm;
832 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
834 for (i = 0; i < glyph_count; i++) {
835 DWRITE_GLYPH_METRICS *ret = metrics + i;
836 DWRITE_GLYPH_METRICS design;
837 BOOL has_contours;
839 hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
840 if (FAILED(hr))
841 return hr;
843 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
844 if (has_contours)
845 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment);
846 else
847 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
849 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
850 SCALE_METRIC(leftSideBearing);
851 SCALE_METRIC(rightSideBearing);
852 SCALE_METRIC(topSideBearing);
853 SCALE_METRIC(advanceHeight);
854 SCALE_METRIC(bottomSideBearing);
855 SCALE_METRIC(verticalOriginY);
856 #undef SCALE_METRIC
859 return S_OK;
862 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS1 *metrics)
864 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
865 TRACE("(%p)->(%p)\n", This, metrics);
866 *metrics = This->metrics;
869 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT em_size, FLOAT pixels_per_dip,
870 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
872 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
873 const DWRITE_FONT_METRICS1 *design = &This->metrics;
874 UINT16 ascent, descent;
875 FLOAT scale;
877 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
879 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
880 memset(metrics, 0, sizeof(*metrics));
881 return E_INVALIDARG;
884 em_size *= pixels_per_dip;
885 if (m && m->m22 != 0.0f)
886 em_size *= fabs(m->m22);
888 scale = em_size / design->designUnitsPerEm;
889 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
890 ascent = round_metric(design->ascent * scale);
891 descent = round_metric(design->descent * scale);
894 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
895 metrics->designUnitsPerEm = design->designUnitsPerEm;
896 metrics->ascent = round_metric(ascent / scale);
897 metrics->descent = round_metric(descent / scale);
899 SCALE_METRIC(lineGap);
900 SCALE_METRIC(capHeight);
901 SCALE_METRIC(xHeight);
902 SCALE_METRIC(underlinePosition);
903 SCALE_METRIC(underlineThickness);
904 SCALE_METRIC(strikethroughPosition);
905 SCALE_METRIC(strikethroughThickness);
906 SCALE_METRIC(glyphBoxLeft);
907 SCALE_METRIC(glyphBoxTop);
908 SCALE_METRIC(glyphBoxRight);
909 SCALE_METRIC(glyphBoxBottom);
910 SCALE_METRIC(subscriptPositionX);
911 SCALE_METRIC(subscriptPositionY);
912 SCALE_METRIC(subscriptSizeX);
913 SCALE_METRIC(subscriptSizeY);
914 SCALE_METRIC(superscriptPositionX);
915 SCALE_METRIC(superscriptPositionY);
916 SCALE_METRIC(superscriptSizeX);
917 SCALE_METRIC(superscriptSizeY);
919 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
920 #undef SCALE_METRIC
922 return S_OK;
925 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace4 *iface, DWRITE_CARET_METRICS *metrics)
927 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
928 TRACE("(%p)->(%p)\n", This, metrics);
929 *metrics = This->caret;
932 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, UINT32 max_count,
933 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
935 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
937 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
939 *count = 0;
940 if (max_count && !ranges)
941 return E_INVALIDARG;
943 get_fontface_table(iface, MS_CMAP_TAG, &This->cmap);
944 return opentype_cmap_get_unicode_ranges(&This->cmap, max_count, ranges, count);
947 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface)
949 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
950 TRACE("(%p)\n", This);
951 return !!(This->flags & FONTFACE_IS_MONOSPACED);
954 static int fontface_get_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
955 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
957 unsigned int adjustment = fontface_get_horz_metric_adjustment(fontface);
958 BOOL has_contours;
959 int advance;
961 if (is_sideways)
962 FIXME("Sideways mode is not supported.\n");
964 switch (measuring_mode)
966 case DWRITE_MEASURING_MODE_NATURAL:
967 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace4_iface, fontface->metrics.designUnitsPerEm,
968 glyph, measuring_mode, &has_contours);
969 if (has_contours)
970 advance += adjustment;
972 return advance;
973 case DWRITE_MEASURING_MODE_GDI_NATURAL:
974 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
975 emsize *= ppdip;
976 if (emsize == 0.0f)
977 return 0.0f;
979 if (transform && memcmp(transform, &identity, sizeof(*transform)))
980 FIXME("Transform is not supported.\n");
982 advance = freetype_get_glyph_advance(&fontface->IDWriteFontFace4_iface, emsize, glyph, measuring_mode,
983 &has_contours);
984 if (has_contours)
985 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize + adjustment);
986 else
987 advance = round_metric(advance * fontface->metrics.designUnitsPerEm / emsize);
989 return advance;
990 default:
991 WARN("Unknown measuring mode %u.\n", measuring_mode);
992 return 0;
996 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *iface,
997 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
999 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1000 unsigned int i;
1002 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
1004 if (is_sideways)
1005 FIXME("sideways mode not supported\n");
1007 for (i = 0; i < glyph_count; ++i)
1009 advances[i] = fontface_get_design_advance(This, DWRITE_MEASURING_MODE_NATURAL, This->metrics.designUnitsPerEm,
1010 1.0f, NULL, glyphs[i], is_sideways);
1013 return S_OK;
1016 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4 *iface,
1017 float em_size, float ppdip, const DWRITE_MATRIX *transform, BOOL use_gdi_natural,
1018 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
1020 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1021 DWRITE_MEASURING_MODE measuring_mode;
1022 UINT32 i;
1024 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, transform,
1025 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
1027 if (em_size < 0.0f || ppdip <= 0.0f) {
1028 memset(advances, 0, sizeof(*advances) * glyph_count);
1029 return E_INVALIDARG;
1032 if (em_size == 0.0f) {
1033 memset(advances, 0, sizeof(*advances) * glyph_count);
1034 return S_OK;
1037 measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
1038 for (i = 0; i < glyph_count; ++i)
1040 advances[i] = fontface_get_design_advance(This, measuring_mode, em_size, ppdip, transform,
1041 glyphs[i], is_sideways);
1044 return S_OK;
1047 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace4 *iface, UINT32 count,
1048 const UINT16 *indices, INT32 *adjustments)
1050 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1051 UINT32 i;
1053 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
1055 if (!(indices || adjustments) || !count)
1056 return E_INVALIDARG;
1058 if (!indices || count == 1) {
1059 memset(adjustments, 0, count*sizeof(INT32));
1060 return E_INVALIDARG;
1063 if (!(This->flags & FONTFACE_HAS_KERNING_PAIRS)) {
1064 memset(adjustments, 0, count*sizeof(INT32));
1065 return S_OK;
1068 for (i = 0; i < count-1; i++)
1069 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1070 adjustments[count-1] = 0;
1072 return S_OK;
1075 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace4 *iface)
1077 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1078 TRACE("(%p)\n", This);
1079 return !!(This->flags & FONTFACE_HAS_KERNING_PAIRS);
1082 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace4 *iface,
1083 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1084 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1086 DWRITE_GRID_FIT_MODE gridfitmode;
1087 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1088 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1091 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace4 *iface, UINT32 glyph_count,
1092 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1094 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1095 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1096 return E_NOTIMPL;
1099 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace4 *iface)
1101 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1102 TRACE("(%p)\n", This);
1103 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1106 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace4 *iface)
1108 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1109 TRACE("(%p)\n", This);
1110 return get_fontface_cpal(This) && get_fontface_colr(This);
1113 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace4 *iface)
1115 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1116 TRACE("(%p)\n", This);
1117 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1120 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace4 *iface)
1122 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1123 TRACE("(%p)\n", This);
1124 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1127 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace4 *iface, UINT32 palette_index,
1128 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1130 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1131 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1132 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1135 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
1136 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1137 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1138 DWRITE_GRID_FIT_MODE *gridfitmode)
1140 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1141 unsigned int flags;
1142 FLOAT emthreshold;
1144 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1145 measuringmode, params, renderingmode, gridfitmode);
1147 if (m)
1148 FIXME("transform not supported %s\n", debugstr_matrix(m));
1150 if (is_sideways)
1151 FIXME("sideways mode not supported\n");
1153 emSize *= max(dpiX, dpiY) / 96.0f;
1155 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1156 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1157 if (params) {
1158 IDWriteRenderingParams2 *params2;
1159 HRESULT hr;
1161 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1162 if (hr == S_OK) {
1163 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1164 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1165 IDWriteRenderingParams2_Release(params2);
1167 else
1168 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1171 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1173 flags = opentype_get_gasp_flags(get_fontface_gasp(This), emSize);
1175 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1176 if (emSize >= emthreshold)
1177 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1178 else
1179 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, flags);
1182 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1183 if (emSize >= emthreshold)
1184 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1185 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1186 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1187 else
1188 *gridfitmode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1189 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1192 return S_OK;
1195 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace4 *iface, IDWriteFontFaceReference **ref)
1197 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1198 FIXME("(%p)->(%p): stub\n", This, ref);
1199 return E_NOTIMPL;
1202 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace4 *iface, DWRITE_PANOSE *panose)
1204 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1205 TRACE("(%p)->(%p)\n", This, panose);
1206 *panose = This->panose;
1209 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace4 *iface)
1211 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1212 TRACE("(%p)\n", This);
1213 return This->weight;
1216 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace4 *iface)
1218 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1219 TRACE("(%p)\n", This);
1220 return This->stretch;
1223 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace4 *iface)
1225 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1226 TRACE("(%p)\n", This);
1227 return This->style;
1230 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1232 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1233 FIXME("(%p)->(%p): stub\n", This, names);
1234 return E_NOTIMPL;
1237 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1239 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1240 FIXME("(%p)->(%p): stub\n", This, names);
1241 return E_NOTIMPL;
1244 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace4 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1245 IDWriteLocalizedStrings **strings, BOOL *exists)
1247 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1248 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1249 return E_NOTIMPL;
1252 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace4 *iface, UINT32 ch)
1254 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1255 UINT16 index;
1257 TRACE("(%p)->(%#x)\n", This, ch);
1259 index = 0;
1260 if (FAILED(fontface_get_glyphs(This, &ch, 1, &index)))
1261 return FALSE;
1263 return index != 0;
1266 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1267 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1268 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1270 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1271 unsigned int flags;
1272 FLOAT emthreshold;
1274 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1275 measuring_mode, params, rendering_mode, gridfit_mode);
1277 if (m)
1278 FIXME("transform not supported %s\n", debugstr_matrix(m));
1280 if (is_sideways)
1281 FIXME("sideways mode not supported\n");
1283 emSize *= max(dpiX, dpiY) / 96.0f;
1285 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1286 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1287 if (params) {
1288 IDWriteRenderingParams3 *params3;
1289 HRESULT hr;
1291 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1292 if (hr == S_OK) {
1293 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1294 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1295 IDWriteRenderingParams3_Release(params3);
1297 else
1298 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1301 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1303 flags = opentype_get_gasp_flags(get_fontface_gasp(This), emSize);
1305 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1306 if (emSize >= emthreshold)
1307 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1308 else
1309 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, flags);
1312 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1313 if (emSize >= emthreshold)
1314 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1315 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1316 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1317 else
1318 *gridfit_mode = flags & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT) ?
1319 DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1322 return S_OK;
1325 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace4 *iface, UINT32 ch)
1327 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1328 FIXME("(%p)->(0x%x): stub\n", This, ch);
1329 return FALSE;
1332 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace4 *iface, UINT16 glyph)
1334 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1335 FIXME("(%p)->(%u): stub\n", This, glyph);
1336 return FALSE;
1339 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace4 *iface, WCHAR const *text,
1340 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1342 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1343 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1344 return E_NOTIMPL;
1347 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace4 *iface, UINT16 const *glyphs,
1348 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1350 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1351 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1352 return E_NOTIMPL;
1355 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace4 *iface, UINT16 glyph,
1356 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1358 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1359 FIXME("(%p)->(%u %u %u %p): stub\n", This, glyph, ppem_first, ppem_last, formats);
1360 return E_NOTIMPL;
1363 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace4 *iface)
1365 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1367 TRACE("(%p)\n", This);
1369 return This->glyph_image_formats;
1372 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace4 *iface, UINT16 glyph,
1373 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1375 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1376 FIXME("(%p)->(%u %u %d %p %p): stub\n", This, glyph, ppem, format, data, context);
1377 return E_NOTIMPL;
1380 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace4 *iface, void *context)
1382 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1383 FIXME("(%p)->(%p): stub\n", This, context);
1386 static const IDWriteFontFace4Vtbl dwritefontfacevtbl = {
1387 dwritefontface_QueryInterface,
1388 dwritefontface_AddRef,
1389 dwritefontface_Release,
1390 dwritefontface_GetType,
1391 dwritefontface_GetFiles,
1392 dwritefontface_GetIndex,
1393 dwritefontface_GetSimulations,
1394 dwritefontface_IsSymbolFont,
1395 dwritefontface_GetMetrics,
1396 dwritefontface_GetGlyphCount,
1397 dwritefontface_GetDesignGlyphMetrics,
1398 dwritefontface_GetGlyphIndices,
1399 dwritefontface_TryGetFontTable,
1400 dwritefontface_ReleaseFontTable,
1401 dwritefontface_GetGlyphRunOutline,
1402 dwritefontface_GetRecommendedRenderingMode,
1403 dwritefontface_GetGdiCompatibleMetrics,
1404 dwritefontface_GetGdiCompatibleGlyphMetrics,
1405 dwritefontface1_GetMetrics,
1406 dwritefontface1_GetGdiCompatibleMetrics,
1407 dwritefontface1_GetCaretMetrics,
1408 dwritefontface1_GetUnicodeRanges,
1409 dwritefontface1_IsMonospacedFont,
1410 dwritefontface1_GetDesignGlyphAdvances,
1411 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1412 dwritefontface1_GetKerningPairAdjustments,
1413 dwritefontface1_HasKerningPairs,
1414 dwritefontface1_GetRecommendedRenderingMode,
1415 dwritefontface1_GetVerticalGlyphVariants,
1416 dwritefontface1_HasVerticalGlyphVariants,
1417 dwritefontface2_IsColorFont,
1418 dwritefontface2_GetColorPaletteCount,
1419 dwritefontface2_GetPaletteEntryCount,
1420 dwritefontface2_GetPaletteEntries,
1421 dwritefontface2_GetRecommendedRenderingMode,
1422 dwritefontface3_GetFontFaceReference,
1423 dwritefontface3_GetPanose,
1424 dwritefontface3_GetWeight,
1425 dwritefontface3_GetStretch,
1426 dwritefontface3_GetStyle,
1427 dwritefontface3_GetFamilyNames,
1428 dwritefontface3_GetFaceNames,
1429 dwritefontface3_GetInformationalStrings,
1430 dwritefontface3_HasCharacter,
1431 dwritefontface3_GetRecommendedRenderingMode,
1432 dwritefontface3_IsCharacterLocal,
1433 dwritefontface3_IsGlyphLocal,
1434 dwritefontface3_AreCharactersLocal,
1435 dwritefontface3_AreGlyphsLocal,
1436 dwritefontface4_GetGlyphImageFormats_,
1437 dwritefontface4_GetGlyphImageFormats,
1438 dwritefontface4_GetGlyphImageData,
1439 dwritefontface4_ReleaseGlyphImageData
1442 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace4 **fontface)
1444 struct dwrite_font_data *data = font->data;
1445 struct fontface_desc desc;
1446 struct list *cached_list;
1447 HRESULT hr;
1449 *fontface = NULL;
1451 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1452 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1453 if (hr == S_OK)
1454 return hr;
1456 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1457 return hr;
1459 desc.factory = font->family->collection->factory;
1460 desc.face_type = data->face_type;
1461 desc.files = &data->file;
1462 desc.files_number = 1;
1463 desc.index = data->face_index;
1464 desc.simulations = data->simulations;
1465 desc.font_data = data;
1466 hr = create_fontface(&desc, cached_list, fontface);
1468 IDWriteFontFileStream_Release(desc.stream);
1469 return hr;
1472 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1474 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1476 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1478 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1479 IsEqualIID(riid, &IID_IDWriteFont2) ||
1480 IsEqualIID(riid, &IID_IDWriteFont1) ||
1481 IsEqualIID(riid, &IID_IDWriteFont) ||
1482 IsEqualIID(riid, &IID_IUnknown))
1484 *obj = iface;
1485 IDWriteFont3_AddRef(iface);
1486 return S_OK;
1489 WARN("%s not implemented.\n", debugstr_guid(riid));
1491 *obj = NULL;
1492 return E_NOINTERFACE;
1495 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1497 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1498 ULONG ref = InterlockedIncrement(&This->ref);
1499 TRACE("(%p)->(%d)\n", This, ref);
1500 return ref;
1503 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1505 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1506 ULONG ref = InterlockedDecrement(&This->ref);
1508 TRACE("(%p)->(%d)\n", This, ref);
1510 if (!ref) {
1511 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1512 release_font_data(This->data);
1513 heap_free(This);
1516 return ref;
1519 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1521 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1522 TRACE("(%p)->(%p)\n", This, family);
1524 *family = (IDWriteFontFamily*)This->family;
1525 IDWriteFontFamily_AddRef(*family);
1526 return S_OK;
1529 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1531 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1532 TRACE("(%p)\n", This);
1533 return This->data->weight;
1536 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1538 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1539 TRACE("(%p)\n", This);
1540 return This->data->stretch;
1543 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1545 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1546 TRACE("(%p)\n", This);
1547 return This->style;
1550 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1552 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1553 IDWriteFontFace4 *fontface;
1554 HRESULT hr;
1555 BOOL ret;
1557 TRACE("(%p)\n", This);
1559 hr = get_fontface_from_font(This, &fontface);
1560 if (FAILED(hr))
1561 return FALSE;
1563 ret = IDWriteFontFace4_IsSymbolFont(fontface);
1564 IDWriteFontFace4_Release(fontface);
1565 return ret;
1568 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1570 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1571 TRACE("(%p)->(%p)\n", This, names);
1572 return clone_localizedstring(This->data->names, names);
1575 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1576 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1578 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1579 struct dwrite_font_data *data = This->data;
1580 HRESULT hr;
1582 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1584 *exists = FALSE;
1585 *strings = NULL;
1587 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1588 return S_OK;
1590 if (!data->info_strings[stringid]) {
1591 IDWriteFontFace4 *fontface;
1592 const void *table_data;
1593 BOOL table_exists;
1594 void *context;
1595 UINT32 size;
1597 hr = get_fontface_from_font(This, &fontface);
1598 if (FAILED(hr))
1599 return hr;
1601 table_exists = FALSE;
1602 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1603 if (FAILED(hr) || !table_exists)
1604 WARN("no NAME table found.\n");
1606 if (table_exists) {
1607 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1608 IDWriteFontFace4_ReleaseFontTable(fontface, context);
1609 if (FAILED(hr) || !data->info_strings[stringid])
1610 return hr;
1612 IDWriteFontFace4_Release(fontface);
1615 hr = clone_localizedstring(data->info_strings[stringid], strings);
1616 if (FAILED(hr))
1617 return hr;
1619 *exists = TRUE;
1620 return S_OK;
1623 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1625 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1626 TRACE("(%p)\n", This);
1627 return This->data->simulations;
1630 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1632 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1634 TRACE("(%p)->(%p)\n", This, metrics);
1635 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1638 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1640 IDWriteFontFace4 *fontface;
1641 UINT16 index;
1642 HRESULT hr;
1644 *exists = FALSE;
1646 hr = get_fontface_from_font(font, &fontface);
1647 if (FAILED(hr))
1648 return hr;
1650 index = 0;
1651 hr = IDWriteFontFace4_GetGlyphIndices(fontface, &ch, 1, &index);
1652 IDWriteFontFace4_Release(fontface);
1653 if (FAILED(hr))
1654 return hr;
1656 *exists = index != 0;
1657 return S_OK;
1660 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1662 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1664 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1666 return font_has_character(This, ch, exists);
1669 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1671 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1672 TRACE("(%p)->(%p)\n", This, fontface);
1673 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1676 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1678 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1679 TRACE("(%p)->(%p)\n", This, metrics);
1680 *metrics = This->data->metrics;
1683 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1685 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1686 TRACE("(%p)->(%p)\n", This, panose);
1687 *panose = This->data->panose;
1690 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1692 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1693 IDWriteFontFace4 *fontface;
1694 HRESULT hr;
1696 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1698 hr = get_fontface_from_font(This, &fontface);
1699 if (FAILED(hr))
1700 return hr;
1702 hr = IDWriteFontFace4_GetUnicodeRanges(fontface, max_count, ranges, count);
1703 IDWriteFontFace4_Release(fontface);
1704 return hr;
1707 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1709 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1710 IDWriteFontFace4 *fontface;
1711 HRESULT hr;
1712 BOOL ret;
1714 TRACE("(%p)\n", This);
1716 hr = get_fontface_from_font(This, &fontface);
1717 if (FAILED(hr))
1718 return FALSE;
1720 ret = IDWriteFontFace4_IsMonospacedFont(fontface);
1721 IDWriteFontFace4_Release(fontface);
1722 return ret;
1725 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1727 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1728 IDWriteFontFace4 *fontface;
1729 HRESULT hr;
1730 BOOL ret;
1732 TRACE("(%p)\n", This);
1734 hr = get_fontface_from_font(This, &fontface);
1735 if (FAILED(hr))
1736 return FALSE;
1738 ret = IDWriteFontFace4_IsColorFont(fontface);
1739 IDWriteFontFace4_Release(fontface);
1740 return ret;
1743 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1745 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1747 TRACE("(%p)->(%p)\n", This, fontface);
1749 return get_fontface_from_font(This, (IDWriteFontFace4 **)fontface);
1752 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1754 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1755 FIXME("(%p)->(%p): stub\n", This, font);
1756 return FALSE;
1759 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1761 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1763 TRACE("(%p)->(%p)\n", This, reference);
1765 return IDWriteFactory5_CreateFontFaceReference_(This->family->collection->factory, This->data->file,
1766 This->data->face_index, This->data->simulations, reference);
1769 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1771 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1772 BOOL ret;
1774 TRACE("(%p)->(%#x)\n", This, ch);
1776 return font_has_character(This, ch, &ret) == S_OK && ret;
1779 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1781 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1782 FIXME("(%p): stub\n", This);
1783 return DWRITE_LOCALITY_LOCAL;
1786 static const IDWriteFont3Vtbl dwritefontvtbl = {
1787 dwritefont_QueryInterface,
1788 dwritefont_AddRef,
1789 dwritefont_Release,
1790 dwritefont_GetFontFamily,
1791 dwritefont_GetWeight,
1792 dwritefont_GetStretch,
1793 dwritefont_GetStyle,
1794 dwritefont_IsSymbolFont,
1795 dwritefont_GetFaceNames,
1796 dwritefont_GetInformationalStrings,
1797 dwritefont_GetSimulations,
1798 dwritefont_GetMetrics,
1799 dwritefont_HasCharacter,
1800 dwritefont_CreateFontFace,
1801 dwritefont1_GetMetrics,
1802 dwritefont1_GetPanose,
1803 dwritefont1_GetUnicodeRanges,
1804 dwritefont1_IsMonospacedFont,
1805 dwritefont2_IsColorFont,
1806 dwritefont3_CreateFontFace,
1807 dwritefont3_Equals,
1808 dwritefont3_GetFontFaceReference,
1809 dwritefont3_HasCharacter,
1810 dwritefont3_GetLocality
1813 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1815 if (!iface)
1816 return NULL;
1817 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1818 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1821 struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1823 if (!iface)
1824 return NULL;
1825 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1826 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
1829 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1831 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1832 *lf = font->data->lf;
1835 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1837 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1838 *lf = fontface->lf;
1841 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
1843 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1844 *fontsig = font->data->fontsig;
1845 return S_OK;
1848 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
1850 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1851 *fontsig = fontface->fontsig;
1852 return S_OK;
1855 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1857 struct dwrite_font *This;
1859 *font = NULL;
1861 This = heap_alloc(sizeof(*This));
1862 if (!This)
1863 return E_OUTOFMEMORY;
1865 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1866 This->ref = 1;
1867 This->family = family;
1868 IDWriteFontFamily1_AddRef(&family->IDWriteFontFamily1_iface);
1869 This->data = family->data->fonts[index];
1870 This->style = This->data->style;
1871 addref_font_data(This->data);
1873 *font = &This->IDWriteFont3_iface;
1875 return S_OK;
1878 /* IDWriteFontList1 */
1879 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1881 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1883 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1885 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1886 IsEqualIID(riid, &IID_IDWriteFontList) ||
1887 IsEqualIID(riid, &IID_IUnknown))
1889 *obj = iface;
1890 IDWriteFontList1_AddRef(iface);
1891 return S_OK;
1894 WARN("%s not implemented.\n", debugstr_guid(riid));
1896 *obj = NULL;
1897 return E_NOINTERFACE;
1900 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1902 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1903 ULONG ref = InterlockedIncrement(&This->ref);
1904 TRACE("(%p)->(%d)\n", This, ref);
1905 return ref;
1908 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1910 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1911 ULONG ref = InterlockedDecrement(&This->ref);
1913 TRACE("(%p)->(%d)\n", This, ref);
1915 if (!ref) {
1916 UINT32 i;
1918 for (i = 0; i < This->font_count; i++)
1919 release_font_data(This->fonts[i]);
1920 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1921 heap_free(This->fonts);
1922 heap_free(This);
1925 return ref;
1928 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1930 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1931 return IDWriteFontFamily1_GetFontCollection(&This->family->IDWriteFontFamily1_iface, collection);
1934 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1936 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1937 TRACE("(%p)\n", This);
1938 return This->font_count;
1941 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1943 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1945 TRACE("(%p)->(%u %p)\n", This, index, font);
1947 *font = NULL;
1949 if (This->font_count == 0)
1950 return S_FALSE;
1952 if (index >= This->font_count)
1953 return E_INVALIDARG;
1955 return create_font(This->family, index, (IDWriteFont3 **)font);
1958 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1960 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1962 FIXME("(%p)->(%u): stub\n", This, index);
1964 return DWRITE_LOCALITY_LOCAL;
1967 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1969 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1971 TRACE("(%p)->(%u %p)\n", This, index, font);
1973 *font = NULL;
1975 if (This->font_count == 0)
1976 return S_FALSE;
1978 if (index >= This->font_count)
1979 return E_FAIL;
1981 return create_font(This->family, index, font);
1984 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1985 IDWriteFontFaceReference **reference)
1987 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1988 IDWriteFont3 *font;
1989 HRESULT hr;
1991 TRACE("(%p)->(%u %p)\n", This, index, reference);
1993 *reference = NULL;
1995 hr = IDWriteFontList1_GetFont(iface, index, &font);
1996 if (FAILED(hr))
1997 return hr;
1999 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2000 IDWriteFont3_Release(font);
2002 return hr;
2005 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
2006 dwritefontlist_QueryInterface,
2007 dwritefontlist_AddRef,
2008 dwritefontlist_Release,
2009 dwritefontlist_GetFontCollection,
2010 dwritefontlist_GetFontCount,
2011 dwritefontlist_GetFont,
2012 dwritefontlist1_GetFontLocality,
2013 dwritefontlist1_GetFont,
2014 dwritefontlist1_GetFontFaceReference
2017 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
2019 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2021 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2023 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
2024 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
2025 IsEqualIID(riid, &IID_IUnknown))
2027 *obj = iface;
2028 IDWriteFontFamily1_AddRef(iface);
2029 return S_OK;
2032 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
2033 IsEqualIID(riid, &IID_IDWriteFontList))
2035 *obj = &This->IDWriteFontList1_iface;
2036 IDWriteFontList1_AddRef(&This->IDWriteFontList1_iface);
2037 return S_OK;
2040 WARN("%s not implemented.\n", debugstr_guid(riid));
2042 *obj = NULL;
2043 return E_NOINTERFACE;
2046 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
2048 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2049 ULONG ref = InterlockedIncrement(&This->ref);
2050 TRACE("(%p)->(%d)\n", This, ref);
2051 return ref;
2054 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
2056 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2057 ULONG ref = InterlockedDecrement(&This->ref);
2059 TRACE("(%p)->(%d)\n", This, ref);
2061 if (!ref)
2063 IDWriteFontCollection1_Release(&This->collection->IDWriteFontCollection1_iface);
2064 release_fontfamily_data(This->data);
2065 heap_free(This);
2068 return ref;
2071 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
2073 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2075 TRACE("(%p)->(%p)\n", This, collection);
2077 *collection = (IDWriteFontCollection*)This->collection;
2078 IDWriteFontCollection_AddRef(*collection);
2079 return S_OK;
2082 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
2084 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2085 TRACE("(%p)\n", This);
2086 return This->data->font_count;
2089 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
2091 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2093 TRACE("(%p)->(%u %p)\n", This, index, font);
2095 *font = NULL;
2097 if (This->data->font_count == 0)
2098 return S_FALSE;
2100 if (index >= This->data->font_count)
2101 return E_INVALIDARG;
2103 return create_font(This, index, (IDWriteFont3 **)font);
2106 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
2108 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2109 return clone_localizedstring(This->data->familyname, names);
2112 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2113 const struct dwrite_font_propvec *req)
2115 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2116 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2117 FLOAT cur_req_prod, next_req_prod;
2119 if (next_to_req < cur_to_req)
2120 return TRUE;
2122 if (next_to_req > cur_to_req)
2123 return FALSE;
2125 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2126 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2128 if (next_req_prod > cur_req_prod)
2129 return TRUE;
2131 if (next_req_prod < cur_req_prod)
2132 return FALSE;
2134 if (next->stretch > cur->stretch)
2135 return TRUE;
2136 if (next->stretch < cur->stretch)
2137 return FALSE;
2139 if (next->style > cur->style)
2140 return TRUE;
2141 if (next->style < cur->style)
2142 return FALSE;
2144 if (next->weight > cur->weight)
2145 return TRUE;
2146 if (next->weight < cur->weight)
2147 return FALSE;
2149 /* full match, no reason to prefer new variant */
2150 return FALSE;
2153 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2154 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2156 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2157 struct dwrite_font_propvec req;
2158 UINT32 i, match;
2160 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
2162 if (This->data->font_count == 0) {
2163 *font = NULL;
2164 return DWRITE_E_NOFONT;
2167 init_font_prop_vec(weight, stretch, style, &req);
2168 match = 0;
2170 for (i = 1; i < This->data->font_count; i++) {
2171 if (is_better_font_match(&This->data->fonts[i]->propvec, &This->data->fonts[match]->propvec, &req))
2172 match = i;
2175 return create_font(This, match, (IDWriteFont3 **)font);
2178 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2180 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2182 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2185 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2187 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2190 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2192 UINT32 b = fonts->font_count - 1, j, t;
2194 while (1) {
2195 t = b;
2197 for (j = 0; j < b; j++) {
2198 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2199 struct dwrite_font_data *s = fonts->fonts[j];
2200 fonts->fonts[j] = fonts->fonts[j+1];
2201 fonts->fonts[j+1] = s;
2202 t = j;
2206 if (t == b)
2207 break;
2208 b = t;
2212 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2213 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2215 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2216 matching_filter_func func = NULL;
2217 struct dwrite_font_propvec req;
2218 struct dwrite_fontlist *fonts;
2219 UINT32 i;
2221 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
2223 *ret = NULL;
2225 fonts = heap_alloc(sizeof(*fonts));
2226 if (!fonts)
2227 return E_OUTOFMEMORY;
2229 /* Allocate as many as family has, not all of them will be necessary used. */
2230 fonts->fonts = heap_calloc(This->data->font_count, sizeof(*fonts->fonts));
2231 if (!fonts->fonts) {
2232 heap_free(fonts);
2233 return E_OUTOFMEMORY;
2236 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2237 fonts->ref = 1;
2238 fonts->family = This;
2239 IDWriteFontFamily1_AddRef(&fonts->family->IDWriteFontFamily1_iface);
2240 fonts->font_count = 0;
2242 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2243 if (style == DWRITE_FONT_STYLE_NORMAL) {
2244 if (This->data->has_normal_face || This->data->has_italic_face)
2245 func = is_font_acceptable_for_normal;
2247 else /* requested oblique or italic */ {
2248 if (This->data->has_oblique_face || This->data->has_italic_face)
2249 func = is_font_acceptable_for_oblique_italic;
2252 for (i = 0; i < This->data->font_count; i++) {
2253 if (!func || func(This->data->fonts[i])) {
2254 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2255 addref_font_data(This->data->fonts[i]);
2256 fonts->font_count++;
2260 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2261 init_font_prop_vec(weight, stretch, style, &req);
2262 matchingfonts_sort(fonts, &req);
2264 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2265 return S_OK;
2268 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2270 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2272 FIXME("(%p)->(%u): stub\n", This, index);
2274 return DWRITE_LOCALITY_LOCAL;
2277 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2279 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2281 TRACE("(%p)->(%u %p)\n", This, index, font);
2283 *font = NULL;
2285 if (This->data->font_count == 0)
2286 return S_FALSE;
2288 if (index >= This->data->font_count)
2289 return E_FAIL;
2291 return create_font(This, index, font);
2294 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2295 IDWriteFontFaceReference **reference)
2297 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2298 IDWriteFont3 *font;
2299 HRESULT hr;
2301 TRACE("(%p)->(%u %p)\n", This, index, reference);
2303 *reference = NULL;
2305 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2306 if (FAILED(hr))
2307 return hr;
2309 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2310 IDWriteFont3_Release(font);
2312 return hr;
2315 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2316 dwritefontfamily_QueryInterface,
2317 dwritefontfamily_AddRef,
2318 dwritefontfamily_Release,
2319 dwritefontfamily_GetFontCollection,
2320 dwritefontfamily_GetFontCount,
2321 dwritefontfamily_GetFont,
2322 dwritefontfamily_GetFamilyNames,
2323 dwritefontfamily_GetFirstMatchingFont,
2324 dwritefontfamily_GetMatchingFonts,
2325 dwritefontfamily1_GetFontLocality,
2326 dwritefontfamily1_GetFont,
2327 dwritefontfamily1_GetFontFaceReference
2330 static HRESULT WINAPI dwritefontfamilylist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
2332 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2333 return dwritefontfamily_QueryInterface(&This->IDWriteFontFamily1_iface, riid, obj);
2336 static ULONG WINAPI dwritefontfamilylist_AddRef(IDWriteFontList1 *iface)
2338 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2339 return dwritefontfamily_AddRef(&This->IDWriteFontFamily1_iface);
2342 static ULONG WINAPI dwritefontfamilylist_Release(IDWriteFontList1 *iface)
2344 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2345 return dwritefontfamily_Release(&This->IDWriteFontFamily1_iface);
2348 static HRESULT WINAPI dwritefontfamilylist_GetFontCollection(IDWriteFontList1 *iface,
2349 IDWriteFontCollection **collection)
2351 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2352 return dwritefontfamily_GetFontCollection(&This->IDWriteFontFamily1_iface, collection);
2355 static UINT32 WINAPI dwritefontfamilylist_GetFontCount(IDWriteFontList1 *iface)
2357 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2358 return dwritefontfamily_GetFontCount(&This->IDWriteFontFamily1_iface);
2361 static HRESULT WINAPI dwritefontfamilylist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
2363 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2364 return dwritefontfamily_GetFont(&This->IDWriteFontFamily1_iface, index, font);
2367 static DWRITE_LOCALITY WINAPI dwritefontfamilylist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
2369 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2370 return dwritefontfamily1_GetFontLocality(&This->IDWriteFontFamily1_iface, index);
2373 static HRESULT WINAPI dwritefontfamilylist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
2375 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2376 return dwritefontfamily1_GetFont(&This->IDWriteFontFamily1_iface, index, font);
2379 static HRESULT WINAPI dwritefontfamilylist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
2380 IDWriteFontFaceReference **reference)
2382 struct dwrite_fontfamily *This = impl_family_from_IDWriteFontList1(iface);
2383 return dwritefontfamily1_GetFontFaceReference(&This->IDWriteFontFamily1_iface, index, reference);
2386 static const IDWriteFontList1Vtbl fontfamilylistvtbl = {
2387 dwritefontfamilylist_QueryInterface,
2388 dwritefontfamilylist_AddRef,
2389 dwritefontfamilylist_Release,
2390 dwritefontfamilylist_GetFontCollection,
2391 dwritefontfamilylist_GetFontCount,
2392 dwritefontfamilylist_GetFont,
2393 dwritefontfamilylist1_GetFontLocality,
2394 dwritefontfamilylist1_GetFont,
2395 dwritefontfamilylist1_GetFontFaceReference,
2398 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index, IDWriteFontFamily1 **family)
2400 struct dwrite_fontfamily *This;
2402 *family = NULL;
2404 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2405 if (!This) return E_OUTOFMEMORY;
2407 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2408 This->IDWriteFontList1_iface.lpVtbl = &fontfamilylistvtbl;
2409 This->ref = 1;
2410 This->collection = collection;
2411 IDWriteFontCollection1_AddRef(&collection->IDWriteFontCollection1_iface);
2412 This->data = collection->family_data[index];
2413 InterlockedIncrement(&This->data->ref);
2415 *family = &This->IDWriteFontFamily1_iface;
2417 return S_OK;
2420 BOOL is_system_collection(IDWriteFontCollection *collection)
2422 void *obj;
2423 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, &obj) == S_OK;
2426 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2428 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2429 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2431 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2432 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2433 IsEqualIID(riid, &IID_IUnknown))
2435 *obj = iface;
2436 IDWriteFontCollection1_AddRef(iface);
2437 return S_OK;
2440 *obj = NULL;
2442 if (IsEqualIID(riid, &IID_issystemcollection))
2443 return S_OK;
2445 WARN("%s not implemented.\n", debugstr_guid(riid));
2447 return E_NOINTERFACE;
2450 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2452 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2453 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2455 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2456 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2457 IsEqualIID(riid, &IID_IUnknown))
2459 *obj = iface;
2460 IDWriteFontCollection1_AddRef(iface);
2461 return S_OK;
2464 WARN("%s not implemented.\n", debugstr_guid(riid));
2466 *obj = NULL;
2468 return E_NOINTERFACE;
2471 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2473 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2474 ULONG ref = InterlockedIncrement(&This->ref);
2475 TRACE("(%p)->(%d)\n", This, ref);
2476 return ref;
2479 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2481 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2482 ULONG ref = InterlockedDecrement(&This->ref);
2484 TRACE("(%p)->(%d)\n", This, ref);
2486 if (!ref) {
2487 int i;
2489 factory_detach_fontcollection(This->factory, iface);
2490 for (i = 0; i < This->family_count; i++)
2491 release_fontfamily_data(This->family_data[i]);
2492 heap_free(This->family_data);
2493 heap_free(This);
2496 return ref;
2499 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2501 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2502 TRACE("(%p)\n", This);
2503 return This->family_count;
2506 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2508 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2510 TRACE("(%p)->(%u %p)\n", This, index, family);
2512 if (index >= This->family_count) {
2513 *family = NULL;
2514 return E_FAIL;
2517 return create_fontfamily(This, index, (IDWriteFontFamily1 **)family);
2520 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2522 UINT32 i;
2524 for (i = 0; i < collection->family_count; i++) {
2525 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2526 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2527 HRESULT hr;
2529 for (j = 0; j < count; j++) {
2530 WCHAR buffer[255];
2531 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2532 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2533 return i;
2537 return ~0u;
2540 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2542 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2543 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2544 *index = collection_find_family(This, name);
2545 *exists = *index != ~0u;
2546 return S_OK;
2549 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2551 UINT32 left_key_size, right_key_size;
2552 const void *left_key, *right_key;
2553 HRESULT hr;
2555 if (left == right)
2556 return TRUE;
2558 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2559 if (FAILED(hr))
2560 return FALSE;
2562 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2563 if (FAILED(hr))
2564 return FALSE;
2566 if (left_key_size != right_key_size)
2567 return FALSE;
2569 return !memcmp(left_key, right_key, left_key_size);
2572 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2574 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2575 IDWriteFontFamily1 *family;
2576 UINT32 i, j, face_index;
2577 BOOL found_font = FALSE;
2578 IDWriteFontFile *file;
2579 HRESULT hr;
2581 TRACE("(%p)->(%p %p)\n", This, face, font);
2583 *font = NULL;
2585 if (!face)
2586 return E_INVALIDARG;
2588 i = 1;
2589 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2590 if (FAILED(hr))
2591 return hr;
2592 face_index = IDWriteFontFace_GetIndex(face);
2594 found_font = FALSE;
2595 for (i = 0; i < This->family_count; i++) {
2596 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2598 for (j = 0; j < family_data->font_count; j++) {
2599 struct dwrite_font_data *font_data = family_data->fonts[j];
2601 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2602 found_font = TRUE;
2603 break;
2607 if (found_font)
2608 break;
2610 IDWriteFontFile_Release(file);
2612 if (!found_font)
2613 return DWRITE_E_NOFONT;
2615 hr = create_fontfamily(This, i, &family);
2616 if (FAILED(hr))
2617 return hr;
2619 hr = create_font(impl_from_IDWriteFontFamily1(family), j, (IDWriteFont3 **)font);
2620 IDWriteFontFamily1_Release(family);
2621 return hr;
2624 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2626 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2628 FIXME("(%p)->(%p): stub\n", This, fontset);
2630 return E_NOTIMPL;
2633 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2635 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2637 TRACE("(%p)->(%u %p)\n", This, index, family);
2639 if (index >= This->family_count) {
2640 *family = NULL;
2641 return E_FAIL;
2644 return create_fontfamily(This, index, family);
2647 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2648 dwritefontcollection_QueryInterface,
2649 dwritefontcollection_AddRef,
2650 dwritefontcollection_Release,
2651 dwritefontcollection_GetFontFamilyCount,
2652 dwritefontcollection_GetFontFamily,
2653 dwritefontcollection_FindFamilyName,
2654 dwritefontcollection_GetFontFromFontFace,
2655 dwritefontcollection1_GetFontSet,
2656 dwritefontcollection1_GetFontFamily
2659 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2660 dwritesystemfontcollection_QueryInterface,
2661 dwritefontcollection_AddRef,
2662 dwritefontcollection_Release,
2663 dwritefontcollection_GetFontFamilyCount,
2664 dwritefontcollection_GetFontFamily,
2665 dwritefontcollection_FindFamilyName,
2666 dwritefontcollection_GetFontFromFontFace,
2667 dwritefontcollection1_GetFontSet,
2668 dwritefontcollection1_GetFontFamily
2671 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2673 if (family_data->font_count + 1 >= family_data->font_alloc) {
2674 struct dwrite_font_data **new_list;
2675 UINT32 new_alloc;
2677 new_alloc = family_data->font_alloc * 2;
2678 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2679 if (!new_list)
2680 return E_OUTOFMEMORY;
2681 family_data->fonts = new_list;
2682 family_data->font_alloc = new_alloc;
2685 family_data->fonts[family_data->font_count] = font_data;
2686 family_data->font_count++;
2687 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2688 family_data->has_normal_face = 1;
2689 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2690 family_data->has_oblique_face = 1;
2691 else
2692 family_data->has_italic_face = 1;
2693 return S_OK;
2696 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2698 if (collection->family_alloc < collection->family_count + 1) {
2699 struct dwrite_fontfamily_data **new_list;
2700 UINT32 new_alloc;
2702 new_alloc = collection->family_alloc * 2;
2703 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2704 if (!new_list)
2705 return E_OUTOFMEMORY;
2707 collection->family_alloc = new_alloc;
2708 collection->family_data = new_list;
2711 collection->family_data[collection->family_count++] = family;
2712 return S_OK;
2715 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2717 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2718 collection->ref = 1;
2719 collection->family_count = 0;
2720 collection->family_alloc = is_system ? 30 : 5;
2721 collection->family_data = heap_calloc(collection->family_alloc, sizeof(*collection->family_data));
2722 if (!collection->family_data)
2723 return E_OUTOFMEMORY;
2725 return S_OK;
2728 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2730 IDWriteFontFileLoader *loader;
2731 const void *key;
2732 UINT32 key_size;
2733 HRESULT hr;
2735 *stream = NULL;
2737 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2738 if (FAILED(hr))
2739 return hr;
2741 hr = IDWriteFontFile_GetLoader(file, &loader);
2742 if (FAILED(hr))
2743 return hr;
2745 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2746 IDWriteFontFileLoader_Release(loader);
2747 if (FAILED(hr))
2748 return hr;
2750 return hr;
2753 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2755 BOOL exists = FALSE;
2756 UINT32 index;
2757 HRESULT hr;
2759 buffer[0] = 0;
2760 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2761 if (FAILED(hr) || !exists)
2762 return;
2764 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2767 static int trim_spaces(WCHAR *in, WCHAR *ret)
2769 int len;
2771 while (isspaceW(*in))
2772 in++;
2774 ret[0] = 0;
2775 if (!(len = strlenW(in)))
2776 return 0;
2778 while (isspaceW(in[len-1]))
2779 len--;
2781 memcpy(ret, in, len*sizeof(WCHAR));
2782 ret[len] = 0;
2784 return len;
2787 struct name_token {
2788 struct list entry;
2789 const WCHAR *ptr;
2790 INT len; /* token length */
2791 INT fulllen; /* full length including following separators */
2794 static inline BOOL is_name_separator_char(WCHAR ch)
2796 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2799 struct name_pattern {
2800 const WCHAR *part1; /* NULL indicates end of list */
2801 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2804 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2806 const struct name_pattern *pattern;
2807 struct name_token *token;
2808 int i = 0;
2810 while ((pattern = &patterns[i++])->part1) {
2811 int len_part1 = strlenW(pattern->part1);
2812 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2814 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2815 if (len_part2 == 0) {
2816 /* simple case with single part pattern */
2817 if (token->len != len_part1)
2818 continue;
2820 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2821 if (match) *match = *token;
2822 list_remove(&token->entry);
2823 heap_free(token);
2824 return TRUE;
2827 else {
2828 struct name_token *next_token;
2829 struct list *next_entry;
2831 /* pattern parts are stored in reading order, tokens list is reversed */
2832 if (token->len < len_part2)
2833 continue;
2835 /* it's possible to have combined string as a token, like ExtraCondensed */
2836 if (token->len == len_part1 + len_part2) {
2837 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2838 continue;
2840 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2841 continue;
2843 /* combined string match */
2844 if (match) *match = *token;
2845 list_remove(&token->entry);
2846 heap_free(token);
2847 return TRUE;
2850 /* now it's only possible to have two tokens matched to respective pattern parts */
2851 if (token->len != len_part2)
2852 continue;
2854 next_entry = list_next(tokens, &token->entry);
2855 if (next_entry) {
2856 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2857 if (next_token->len != len_part1)
2858 continue;
2860 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2861 continue;
2863 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2864 continue;
2866 /* both parts matched, remove tokens */
2867 if (match) {
2868 match->ptr = next_token->ptr;
2869 match->len = (token->ptr - next_token->ptr) + token->len;
2871 list_remove(&token->entry);
2872 list_remove(&next_token->entry);
2873 heap_free(next_token);
2874 heap_free(token);
2875 return TRUE;
2881 if (match) {
2882 match->ptr = NULL;
2883 match->len = 0;
2885 return FALSE;
2888 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2890 static const WCHAR itaW[] = {'i','t','a',0};
2891 static const WCHAR italW[] = {'i','t','a','l',0};
2892 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2893 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2895 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2896 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2897 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2898 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2900 static const struct name_pattern italic_patterns[] = {
2901 { itaW },
2902 { italW },
2903 { italicW },
2904 { cursiveW },
2905 { kursivW },
2906 { NULL }
2909 static const struct name_pattern oblique_patterns[] = {
2910 { inclinedW },
2911 { obliqueW },
2912 { backslantedW },
2913 { backslantW },
2914 { slantedW },
2915 { NULL }
2918 /* italic patterns first */
2919 if (match_pattern_list(tokens, italic_patterns, match))
2920 return DWRITE_FONT_STYLE_ITALIC;
2922 /* oblique patterns */
2923 if (match_pattern_list(tokens, oblique_patterns, match))
2924 return DWRITE_FONT_STYLE_OBLIQUE;
2926 return style;
2929 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2930 struct name_token *match)
2932 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2933 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2934 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2935 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2936 static const WCHAR wideW[] = {'w','i','d','e',0};
2937 static const WCHAR condW[] = {'c','o','n','d',0};
2939 static const struct name_pattern ultracondensed_patterns[] = {
2940 { extraW, compressedW },
2941 { extW, compressedW },
2942 { ultraW, compressedW },
2943 { ultraW, condensedW },
2944 { ultraW, condW },
2945 { NULL }
2948 static const struct name_pattern extracondensed_patterns[] = {
2949 { compressedW },
2950 { extraW, condensedW },
2951 { extW, condensedW },
2952 { extraW, condW },
2953 { extW, condW },
2954 { NULL }
2957 static const struct name_pattern semicondensed_patterns[] = {
2958 { narrowW },
2959 { compactW },
2960 { semiW, condensedW },
2961 { semiW, condW },
2962 { NULL }
2965 static const struct name_pattern semiexpanded_patterns[] = {
2966 { wideW },
2967 { semiW, expandedW },
2968 { semiW, extendedW },
2969 { NULL }
2972 static const struct name_pattern extraexpanded_patterns[] = {
2973 { extraW, expandedW },
2974 { extW, expandedW },
2975 { extraW, extendedW },
2976 { extW, extendedW },
2977 { NULL }
2980 static const struct name_pattern ultraexpanded_patterns[] = {
2981 { ultraW, expandedW },
2982 { ultraW, extendedW },
2983 { NULL }
2986 static const struct name_pattern condensed_patterns[] = {
2987 { condensedW },
2988 { condW },
2989 { NULL }
2992 static const struct name_pattern expanded_patterns[] = {
2993 { expandedW },
2994 { extendedW },
2995 { NULL }
2998 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2999 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
3001 if (match_pattern_list(tokens, extracondensed_patterns, match))
3002 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
3004 if (match_pattern_list(tokens, semicondensed_patterns, match))
3005 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
3007 if (match_pattern_list(tokens, semiexpanded_patterns, match))
3008 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
3010 if (match_pattern_list(tokens, extraexpanded_patterns, match))
3011 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
3013 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
3014 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
3016 if (match_pattern_list(tokens, condensed_patterns, match))
3017 return DWRITE_FONT_STRETCH_CONDENSED;
3019 if (match_pattern_list(tokens, expanded_patterns, match))
3020 return DWRITE_FONT_STRETCH_EXPANDED;
3022 return stretch;
3025 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
3026 struct name_token *match)
3028 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
3029 static const WCHAR nordW[] = {'n','o','r','d',0};
3031 static const struct name_pattern thin_patterns[] = {
3032 { extraW, thinW },
3033 { extW, thinW },
3034 { ultraW, thinW },
3035 { NULL }
3038 static const struct name_pattern extralight_patterns[] = {
3039 { extraW, lightW },
3040 { extW, lightW },
3041 { ultraW, lightW },
3042 { NULL }
3045 static const struct name_pattern semilight_patterns[] = {
3046 { semiW, lightW },
3047 { NULL }
3050 static const struct name_pattern demibold_patterns[] = {
3051 { semiW, boldW },
3052 { demiW, boldW },
3053 { NULL }
3056 static const struct name_pattern extrabold_patterns[] = {
3057 { extraW, boldW },
3058 { extW, boldW },
3059 { ultraW, boldW },
3060 { NULL }
3063 static const struct name_pattern extrablack_patterns[] = {
3064 { extraW, blackW },
3065 { extW, blackW },
3066 { ultraW, blackW },
3067 { NULL }
3070 static const struct name_pattern bold_patterns[] = {
3071 { boldW },
3072 { NULL }
3075 static const struct name_pattern thin2_patterns[] = {
3076 { thinW },
3077 { NULL }
3080 static const struct name_pattern light_patterns[] = {
3081 { lightW },
3082 { NULL }
3085 static const struct name_pattern medium_patterns[] = {
3086 { mediumW },
3087 { NULL }
3090 static const struct name_pattern black_patterns[] = {
3091 { blackW },
3092 { heavyW },
3093 { nordW },
3094 { NULL }
3097 static const struct name_pattern demibold2_patterns[] = {
3098 { demiW },
3099 { NULL }
3102 static const struct name_pattern extrabold2_patterns[] = {
3103 { ultraW },
3104 { NULL }
3107 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
3108 matching pattern. */
3110 if (match_pattern_list(tokens, thin_patterns, match))
3111 return DWRITE_FONT_WEIGHT_THIN;
3113 if (match_pattern_list(tokens, extralight_patterns, match))
3114 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
3116 if (match_pattern_list(tokens, semilight_patterns, match))
3117 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
3119 if (match_pattern_list(tokens, demibold_patterns, match))
3120 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3122 if (match_pattern_list(tokens, extrabold_patterns, match))
3123 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3125 if (match_pattern_list(tokens, extrablack_patterns, match))
3126 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
3128 if (match_pattern_list(tokens, bold_patterns, match))
3129 return DWRITE_FONT_WEIGHT_BOLD;
3131 if (match_pattern_list(tokens, thin2_patterns, match))
3132 return DWRITE_FONT_WEIGHT_THIN;
3134 if (match_pattern_list(tokens, light_patterns, match))
3135 return DWRITE_FONT_WEIGHT_LIGHT;
3137 if (match_pattern_list(tokens, medium_patterns, match))
3138 return DWRITE_FONT_WEIGHT_MEDIUM;
3140 if (match_pattern_list(tokens, black_patterns, match))
3141 return DWRITE_FONT_WEIGHT_BLACK;
3143 if (match_pattern_list(tokens, black_patterns, match))
3144 return DWRITE_FONT_WEIGHT_BLACK;
3146 if (match_pattern_list(tokens, demibold2_patterns, match))
3147 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3149 if (match_pattern_list(tokens, extrabold2_patterns, match))
3150 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3152 /* FIXME: use abbreviated names to extract weight */
3154 return weight;
3157 struct knownweight_entry {
3158 const WCHAR *nameW;
3159 DWRITE_FONT_WEIGHT weight;
3162 static int compare_knownweights(const void *a, const void* b)
3164 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3165 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3166 int ret = 0;
3168 if (target > entry->weight)
3169 ret = 1;
3170 else if (target < entry->weight)
3171 ret = -1;
3173 return ret;
3176 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3178 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3179 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3180 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3181 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3182 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3183 const struct knownweight_entry *ptr;
3185 static const struct knownweight_entry knownweights[] = {
3186 { thinW, DWRITE_FONT_WEIGHT_THIN },
3187 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3188 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3189 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3190 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3191 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3192 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3193 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3194 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3195 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3198 ptr = bsearch(&weight, knownweights, ARRAY_SIZE(knownweights), sizeof(knownweights[0]),
3199 compare_knownweights);
3200 if (!ptr) {
3201 nameW[0] = 0;
3202 return FALSE;
3205 strcpyW(nameW, ptr->nameW);
3206 return TRUE;
3209 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3211 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3212 strW[name->len] = 0;
3215 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3216 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3218 static const WCHAR bookW[] = {'B','o','o','k',0};
3219 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3220 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3221 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3222 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3224 static const WCHAR *regular_patterns[] = {
3225 bookW,
3226 normalW,
3227 regularW,
3228 romanW,
3229 uprightW,
3230 NULL
3233 const WCHAR *regular_ptr = NULL, *ptr;
3234 int i = 0;
3236 if (len == -1)
3237 len = strlenW(facenameW);
3239 /* remove rightmost regular variant from face name */
3240 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3241 int pattern_len = strlenW(ptr);
3242 WCHAR *src;
3244 if (pattern_len > len)
3245 continue;
3247 src = facenameW + len - pattern_len;
3248 while (src >= facenameW) {
3249 if (!strncmpiW(src, ptr, pattern_len)) {
3250 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3251 len = strlenW(facenameW);
3252 regular_ptr = ptr;
3253 break;
3255 else
3256 src--;
3260 return regular_ptr;
3263 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3265 const WCHAR *ptr;
3267 list_init(tokens);
3268 ptr = nameW;
3270 while (*ptr) {
3271 struct name_token *token = heap_alloc(sizeof(*token));
3272 token->ptr = ptr;
3273 token->len = 0;
3274 token->fulllen = 0;
3276 while (*ptr && !is_name_separator_char(*ptr)) {
3277 token->len++;
3278 token->fulllen++;
3279 ptr++;
3282 /* skip separators */
3283 while (is_name_separator_char(*ptr)) {
3284 token->fulllen++;
3285 ptr++;
3288 list_add_head(tokens, &token->entry);
3292 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3294 struct name_token *token, *token2;
3295 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3296 int len;
3298 list_remove(&token->entry);
3300 /* don't include last separator */
3301 len = list_empty(tokens) ? token->len : token->fulllen;
3302 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3303 nameW += len;
3305 heap_free(token);
3307 *nameW = 0;
3310 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3312 struct name_token stretch_name, weight_name, style_name;
3313 WCHAR familynameW[255], facenameW[255], finalW[255];
3314 WCHAR weightW[32], stretchW[32], styleW[32];
3315 const WCHAR *regular_ptr = NULL;
3316 DWRITE_FONT_STRETCH stretch;
3317 DWRITE_FONT_WEIGHT weight;
3318 struct list tokens;
3319 int len;
3321 /* remove leading and trailing spaces from family and face name */
3322 trim_spaces(familyW, familynameW);
3323 len = trim_spaces(faceW, facenameW);
3325 /* remove rightmost regular variant from face name */
3326 regular_ptr = facename_remove_regular_term(facenameW, len);
3328 /* append face name to family name, FIXME check if face name is a substring of family name */
3329 if (*facenameW) {
3330 strcatW(familynameW, spaceW);
3331 strcatW(familynameW, facenameW);
3334 /* tokenize with " .-_" */
3335 fontname_tokenize(&tokens, familynameW);
3337 /* extract and resolve style */
3338 font->style = font_extract_style(&tokens, font->style, &style_name);
3340 /* extract stretch */
3341 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3343 /* extract weight */
3344 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3346 /* resolve weight */
3347 if (weight != font->weight) {
3348 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3349 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3350 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3351 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3352 !(abs(weight - font->weight) <= 150 &&
3353 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3354 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3355 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3357 font->weight = weight;
3361 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3362 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3363 stretch itself is normal (extracted stretch is never normal). */
3364 if (stretch != font->stretch) {
3365 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3366 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3367 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3369 font->stretch = stretch;
3373 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3375 /* get final combined string from what's left in token list, list is released */
3376 fontname_tokens_to_str(&tokens, finalW);
3378 if (!strcmpW(familyW, finalW))
3379 return FALSE;
3381 /* construct face name */
3382 strcpyW(familyW, finalW);
3384 /* resolved weight name */
3385 if (weight_name.ptr)
3386 font_name_token_to_str(&weight_name, weightW);
3387 /* ignore normal weight */
3388 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3389 weightW[0] = 0;
3390 /* for known weight values use appropriate names */
3391 else if (is_known_weight_value(font->weight, weightW)) {
3393 /* use Wnnn format as a fallback in case weight is not one of known values */
3394 else {
3395 static const WCHAR fmtW[] = {'W','%','d',0};
3396 sprintfW(weightW, fmtW, font->weight);
3399 /* resolved stretch name */
3400 if (stretch_name.ptr)
3401 font_name_token_to_str(&stretch_name, stretchW);
3402 /* ignore normal stretch */
3403 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3404 stretchW[0] = 0;
3405 /* use predefined stretch names */
3406 else {
3407 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3408 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3409 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3410 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3411 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3412 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3414 static const WCHAR *stretchnamesW[] = {
3415 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3416 ultracondensedW,
3417 extracondensedW,
3418 condensedW,
3419 semicondensedW,
3420 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3421 semiexpandedW,
3422 expandedW,
3423 extraexpandedW,
3424 ultraexpandedW
3426 strcpyW(stretchW, stretchnamesW[font->stretch]);
3429 /* resolved style name */
3430 if (style_name.ptr)
3431 font_name_token_to_str(&style_name, styleW);
3432 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3433 styleW[0] = 0;
3434 /* use predefined names */
3435 else {
3436 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3437 strcpyW(styleW, italicW);
3438 else
3439 strcpyW(styleW, obliqueW);
3442 /* use Regular match if it was found initially */
3443 if (!*weightW && !*stretchW && !*styleW)
3444 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3445 else {
3446 faceW[0] = 0;
3447 if (*stretchW)
3448 strcpyW(faceW, stretchW);
3449 if (*weightW) {
3450 if (*faceW)
3451 strcatW(faceW, spaceW);
3452 strcatW(faceW, weightW);
3454 if (*styleW) {
3455 if (*faceW)
3456 strcatW(faceW, spaceW);
3457 strcatW(faceW, styleW);
3461 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3462 return TRUE;
3465 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name,
3466 struct dwrite_font_data **ret)
3468 struct file_stream_desc stream_desc;
3469 struct dwrite_font_props props;
3470 struct dwrite_font_data *data;
3471 WCHAR familyW[255], faceW[255];
3472 HRESULT hr;
3474 *ret = NULL;
3476 data = heap_alloc_zero(sizeof(*data));
3477 if (!data)
3478 return E_OUTOFMEMORY;
3480 data->ref = 1;
3481 data->file = desc->files[0];
3482 data->face_index = desc->index;
3483 data->face_type = desc->face_type;
3484 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3485 data->bold_sim_tested = 0;
3486 data->oblique_sim_tested = 0;
3487 IDWriteFontFile_AddRef(data->file);
3489 stream_desc.stream = desc->stream;
3490 stream_desc.face_type = desc->face_type;
3491 stream_desc.face_index = desc->index;
3492 opentype_get_font_properties(&stream_desc, &props);
3493 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3494 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3496 /* get family name from font file */
3497 hr = opentype_get_font_familyname(&stream_desc, family_name);
3498 if (FAILED(hr)) {
3499 WARN("unable to get family name from font\n");
3500 release_font_data(data);
3501 return hr;
3504 data->style = props.style;
3505 data->stretch = props.stretch;
3506 data->weight = props.weight;
3507 data->panose = props.panose;
3508 data->fontsig = props.fontsig;
3509 data->lf = props.lf;
3511 fontstrings_get_en_string(*family_name, familyW, ARRAY_SIZE(familyW));
3512 fontstrings_get_en_string(data->names, faceW, ARRAY_SIZE(faceW));
3513 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3514 set_en_localizedstring(*family_name, familyW);
3515 set_en_localizedstring(data->names, faceW);
3518 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3520 *ret = data;
3521 return S_OK;
3524 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3525 const WCHAR *facenameW, struct dwrite_font_data **ret)
3527 struct dwrite_font_data *data;
3529 *ret = NULL;
3531 data = heap_alloc_zero(sizeof(*data));
3532 if (!data)
3533 return E_OUTOFMEMORY;
3535 *data = *src;
3536 data->ref = 1;
3537 data->simulations |= sim;
3538 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3539 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3540 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3541 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3542 memset(data->info_strings, 0, sizeof(data->info_strings));
3543 data->names = NULL;
3544 IDWriteFontFile_AddRef(data->file);
3546 create_localizedstrings(&data->names);
3547 add_localizedstring(data->names, enusW, facenameW);
3549 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3551 *ret = data;
3552 return S_OK;
3555 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3557 struct dwrite_fontfamily_data *data;
3559 data = heap_alloc(sizeof(*data));
3560 if (!data)
3561 return E_OUTOFMEMORY;
3563 data->ref = 1;
3564 data->font_count = 0;
3565 data->font_alloc = 2;
3566 data->has_normal_face = 0;
3567 data->has_oblique_face = 0;
3568 data->has_italic_face = 0;
3570 data->fonts = heap_calloc(data->font_alloc, sizeof(*data->fonts));
3571 if (!data->fonts) {
3572 heap_free(data);
3573 return E_OUTOFMEMORY;
3576 data->familyname = familyname;
3577 IDWriteLocalizedStrings_AddRef(familyname);
3579 *ret = data;
3580 return S_OK;
3583 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3585 UINT32 i, j, heaviest;
3587 for (i = 0; i < family->font_count; i++) {
3588 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3589 heaviest = i;
3591 if (family->fonts[i]->bold_sim_tested)
3592 continue;
3594 family->fonts[i]->bold_sim_tested = 1;
3595 for (j = i; j < family->font_count; j++) {
3596 if (family->fonts[j]->bold_sim_tested)
3597 continue;
3599 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3600 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3601 if (family->fonts[j]->weight > weight) {
3602 weight = family->fonts[j]->weight;
3603 heaviest = j;
3605 family->fonts[j]->bold_sim_tested = 1;
3609 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3610 static const struct name_pattern weightsim_patterns[] = {
3611 { extraW, lightW },
3612 { extW, lightW },
3613 { ultraW, lightW },
3614 { semiW, lightW },
3615 { semiW, boldW },
3616 { demiW, boldW },
3617 { boldW },
3618 { thinW },
3619 { lightW },
3620 { mediumW },
3621 { demiW },
3622 { NULL }
3625 WCHAR facenameW[255], initialW[255];
3626 struct dwrite_font_data *boldface;
3627 struct list tokens;
3629 /* add Bold simulation based on heaviest face data */
3631 /* Simulated face name should only contain Bold as weight term,
3632 so remove existing regular and weight terms. */
3633 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, ARRAY_SIZE(initialW));
3634 facename_remove_regular_term(initialW, -1);
3636 /* remove current weight pattern */
3637 fontname_tokenize(&tokens, initialW);
3638 match_pattern_list(&tokens, weightsim_patterns, NULL);
3639 fontname_tokens_to_str(&tokens, facenameW);
3641 /* Bold suffix for new name */
3642 if (*facenameW)
3643 strcatW(facenameW, spaceW);
3644 strcatW(facenameW, boldW);
3646 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3647 boldface->bold_sim_tested = 1;
3648 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3649 fontfamily_add_font(family, boldface);
3655 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3657 UINT32 i, j;
3659 for (i = 0; i < family->font_count; i++) {
3660 UINT32 regular = ~0u, oblique = ~0u;
3661 struct dwrite_font_data *obliqueface;
3662 WCHAR facenameW[255];
3664 if (family->fonts[i]->oblique_sim_tested)
3665 continue;
3667 family->fonts[i]->oblique_sim_tested = 1;
3668 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3669 regular = i;
3670 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3671 oblique = i;
3673 /* find regular style with same weight/stretch values */
3674 for (j = i; j < family->font_count; j++) {
3675 if (family->fonts[j]->oblique_sim_tested)
3676 continue;
3678 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3679 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3681 family->fonts[j]->oblique_sim_tested = 1;
3682 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3683 regular = j;
3685 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3686 oblique = j;
3689 if (regular != ~0u && oblique != ~0u)
3690 break;
3693 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3694 if (regular == ~0u)
3695 continue;
3697 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3698 if (oblique != ~0u)
3699 continue;
3701 /* add oblique simulation based on this regular face */
3703 /* remove regular term if any, append 'Oblique' */
3704 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, ARRAY_SIZE(facenameW));
3705 facename_remove_regular_term(facenameW, -1);
3707 if (*facenameW)
3708 strcatW(facenameW, spaceW);
3709 strcatW(facenameW, obliqueW);
3711 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3712 obliqueface->oblique_sim_tested = 1;
3713 obliqueface->lf.lfItalic = 1;
3714 fontfamily_add_font(family, obliqueface);
3719 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3720 const WCHAR *replacement_name)
3722 UINT32 i = collection_find_family(collection, replacement_name);
3723 struct dwrite_fontfamily_data *target;
3724 IDWriteLocalizedStrings *strings;
3725 HRESULT hr;
3727 /* replacement does not exist */
3728 if (i == ~0u)
3729 return FALSE;
3731 hr = create_localizedstrings(&strings);
3732 if (FAILED(hr))
3733 return FALSE;
3735 /* add a new family with target name, reuse font data from replacement */
3736 add_localizedstring(strings, enusW, target_name);
3737 hr = init_fontfamily_data(strings, &target);
3738 if (hr == S_OK) {
3739 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3740 WCHAR nameW[255];
3742 for (i = 0; i < replacement->font_count; i++) {
3743 fontfamily_add_font(target, replacement->fonts[i]);
3744 addref_font_data(replacement->fonts[i]);
3747 fontcollection_add_family(collection, target);
3748 fontstrings_get_en_string(replacement->familyname, nameW, ARRAY_SIZE(nameW));
3749 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3751 IDWriteLocalizedStrings_Release(strings);
3752 return TRUE;
3755 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3756 system font collections. */
3757 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3759 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3760 WCHAR *name;
3761 void *data;
3762 HKEY hkey;
3764 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3765 return;
3767 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3768 RegCloseKey(hkey);
3769 return;
3772 max_namelen++; /* returned value doesn't include room for '\0' */
3773 name = heap_alloc(max_namelen * sizeof(WCHAR));
3774 data = heap_alloc(max_datalen);
3776 datalen = max_datalen;
3777 namelen = max_namelen;
3778 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3779 if (collection_find_family(collection, name) == ~0u) {
3780 if (type == REG_MULTI_SZ) {
3781 WCHAR *replacement = data;
3782 while (*replacement) {
3783 if (fontcollection_add_replacement(collection, name, replacement))
3784 break;
3785 replacement += strlenW(replacement) + 1;
3788 else if (type == REG_SZ)
3789 fontcollection_add_replacement(collection, name, data);
3791 else
3792 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3794 datalen = max_datalen;
3795 namelen = max_namelen;
3798 heap_free(data);
3799 heap_free(name);
3800 RegCloseKey(hkey);
3803 HRESULT create_font_collection(IDWriteFactory5 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3804 IDWriteFontCollection1 **ret)
3806 struct fontfile_enum {
3807 struct list entry;
3808 IDWriteFontFile *file;
3810 struct fontfile_enum *fileenum, *fileenum2;
3811 struct dwrite_fontcollection *collection;
3812 struct list scannedfiles;
3813 BOOL current = FALSE;
3814 HRESULT hr = S_OK;
3815 UINT32 i;
3817 *ret = NULL;
3819 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3820 if (!collection) return E_OUTOFMEMORY;
3822 hr = init_font_collection(collection, is_system);
3823 if (FAILED(hr)) {
3824 heap_free(collection);
3825 return hr;
3828 *ret = &collection->IDWriteFontCollection1_iface;
3830 TRACE("building font collection:\n");
3832 list_init(&scannedfiles);
3833 while (hr == S_OK) {
3834 DWRITE_FONT_FACE_TYPE face_type;
3835 DWRITE_FONT_FILE_TYPE file_type;
3836 BOOL supported, same = FALSE;
3837 IDWriteFontFileStream *stream;
3838 IDWriteFontFile *file;
3839 UINT32 face_count;
3841 current = FALSE;
3842 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3843 if (FAILED(hr) || !current)
3844 break;
3846 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3847 if (FAILED(hr))
3848 break;
3850 /* check if we've scanned this file already */
3851 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3852 if ((same = is_same_fontfile(fileenum->file, file)))
3853 break;
3856 if (same) {
3857 IDWriteFontFile_Release(file);
3858 continue;
3861 if (FAILED(get_filestream_from_file(file, &stream))) {
3862 IDWriteFontFile_Release(file);
3863 continue;
3866 /* Unsupported formats are skipped. */
3867 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
3868 if (FAILED(hr) || !supported || face_count == 0) {
3869 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3870 IDWriteFontFileStream_Release(stream);
3871 IDWriteFontFile_Release(file);
3872 hr = S_OK;
3873 continue;
3876 /* add to scanned list */
3877 fileenum = heap_alloc(sizeof(*fileenum));
3878 fileenum->file = file;
3879 list_add_tail(&scannedfiles, &fileenum->entry);
3881 for (i = 0; i < face_count; i++) {
3882 IDWriteLocalizedStrings *family_name = NULL;
3883 struct dwrite_font_data *font_data;
3884 struct fontface_desc desc;
3885 WCHAR familyW[255];
3886 UINT32 index;
3888 desc.factory = factory;
3889 desc.face_type = face_type;
3890 desc.files = &file;
3891 desc.stream = stream;
3892 desc.files_number = 1;
3893 desc.index = i;
3894 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3895 desc.font_data = NULL;
3897 /* alloc and init new font data structure */
3898 hr = init_font_data(&desc, &family_name, &font_data);
3899 if (FAILED(hr)) {
3900 /* move to next one */
3901 hr = S_OK;
3902 continue;
3905 fontstrings_get_en_string(family_name, familyW, ARRAY_SIZE(familyW));
3907 /* ignore dot named faces */
3908 if (familyW[0] == '.') {
3909 WARN("Ignoring face %s\n", debugstr_w(familyW));
3910 IDWriteLocalizedStrings_Release(family_name);
3911 release_font_data(font_data);
3912 continue;
3915 index = collection_find_family(collection, familyW);
3916 if (index != ~0u)
3917 hr = fontfamily_add_font(collection->family_data[index], font_data);
3918 else {
3919 struct dwrite_fontfamily_data *family_data;
3921 /* create and init new family */
3922 hr = init_fontfamily_data(family_name, &family_data);
3923 if (hr == S_OK) {
3924 /* add font to family, family - to collection */
3925 hr = fontfamily_add_font(family_data, font_data);
3926 if (hr == S_OK)
3927 hr = fontcollection_add_family(collection, family_data);
3929 if (FAILED(hr))
3930 release_fontfamily_data(family_data);
3934 IDWriteLocalizedStrings_Release(family_name);
3936 if (FAILED(hr))
3937 break;
3940 IDWriteFontFileStream_Release(stream);
3943 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3944 IDWriteFontFile_Release(fileenum->file);
3945 list_remove(&fileenum->entry);
3946 heap_free(fileenum);
3949 for (i = 0; i < collection->family_count; i++) {
3950 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3951 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3954 if (is_system)
3955 fontcollection_add_replacements(collection);
3957 collection->factory = factory;
3958 IDWriteFactory5_AddRef(factory);
3960 return hr;
3963 struct system_fontfile_enumerator
3965 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3966 LONG ref;
3968 IDWriteFactory5 *factory;
3969 HKEY hkey;
3970 int index;
3972 WCHAR *filename;
3973 DWORD filename_size;
3976 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3978 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3981 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3983 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3984 IDWriteFontFileEnumerator_AddRef(iface);
3985 *obj = iface;
3986 return S_OK;
3989 WARN("%s not implemented.\n", debugstr_guid(riid));
3991 *obj = NULL;
3993 return E_NOINTERFACE;
3996 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3998 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3999 return InterlockedIncrement(&enumerator->ref);
4002 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
4004 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4005 ULONG ref = InterlockedDecrement(&enumerator->ref);
4007 if (!ref) {
4008 IDWriteFactory5_Release(enumerator->factory);
4009 RegCloseKey(enumerator->hkey);
4010 heap_free(enumerator->filename);
4011 heap_free(enumerator);
4014 return ref;
4017 static HRESULT create_local_file_reference(IDWriteFactory5 *factory, const WCHAR *filename, IDWriteFontFile **file)
4019 HRESULT hr;
4021 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
4022 if (!strchrW(filename, '\\')) {
4023 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
4024 WCHAR fullpathW[MAX_PATH];
4026 GetWindowsDirectoryW(fullpathW, ARRAY_SIZE(fullpathW));
4027 strcatW(fullpathW, fontsW);
4028 strcatW(fullpathW, filename);
4030 hr = IDWriteFactory5_CreateFontFileReference(factory, fullpathW, NULL, file);
4032 else
4033 hr = IDWriteFactory5_CreateFontFileReference(factory, filename, NULL, file);
4035 return hr;
4038 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
4040 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4042 *file = NULL;
4044 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
4045 return E_FAIL;
4047 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
4050 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
4052 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
4053 WCHAR name_buf[256], *name = name_buf;
4054 DWORD name_count, max_name_count = ARRAY_SIZE(name_buf), type, data_size;
4055 HRESULT hr = S_OK;
4056 LONG r;
4058 *current = FALSE;
4059 enumerator->index++;
4061 /* iterate until we find next string value */
4062 for (;;) {
4063 do {
4064 name_count = max_name_count;
4065 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
4067 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
4068 NULL, &type, (BYTE *)enumerator->filename, &data_size);
4069 if (r == ERROR_MORE_DATA) {
4070 if (name_count >= max_name_count) {
4071 if (name != name_buf) heap_free(name);
4072 max_name_count *= 2;
4073 name = heap_alloc(max_name_count * sizeof(*name));
4074 if (!name) return E_OUTOFMEMORY;
4076 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
4077 heap_free(enumerator->filename);
4078 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
4079 enumerator->filename = heap_alloc(enumerator->filename_size);
4080 if (!enumerator->filename) {
4081 hr = E_OUTOFMEMORY;
4082 goto err;
4086 } while (r == ERROR_MORE_DATA);
4088 if (r != ERROR_SUCCESS) {
4089 enumerator->filename[0] = 0;
4090 break;
4092 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
4093 if (type == REG_SZ && *name != '@') {
4094 *current = TRUE;
4095 break;
4097 enumerator->index++;
4099 TRACE("index = %d, current = %d\n", enumerator->index, *current);
4101 err:
4102 if (name != name_buf) heap_free(name);
4103 return hr;
4106 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
4108 systemfontfileenumerator_QueryInterface,
4109 systemfontfileenumerator_AddRef,
4110 systemfontfileenumerator_Release,
4111 systemfontfileenumerator_MoveNext,
4112 systemfontfileenumerator_GetCurrentFontFile
4115 static HRESULT create_system_fontfile_enumerator(IDWriteFactory5 *factory, IDWriteFontFileEnumerator **ret)
4117 struct system_fontfile_enumerator *enumerator;
4118 static const WCHAR fontslistW[] = {
4119 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
4120 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4121 'F','o','n','t','s',0
4124 *ret = NULL;
4126 enumerator = heap_alloc(sizeof(*enumerator));
4127 if (!enumerator)
4128 return E_OUTOFMEMORY;
4130 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
4131 enumerator->ref = 1;
4132 enumerator->factory = factory;
4133 enumerator->index = -1;
4134 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
4135 enumerator->filename = heap_alloc(enumerator->filename_size);
4136 if (!enumerator->filename) {
4137 heap_free(enumerator);
4138 return E_OUTOFMEMORY;
4141 IDWriteFactory5_AddRef(factory);
4143 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
4144 ERR("failed to open fonts list key\n");
4145 IDWriteFactory5_Release(factory);
4146 heap_free(enumerator->filename);
4147 heap_free(enumerator);
4148 return E_FAIL;
4151 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4153 return S_OK;
4156 HRESULT get_system_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **collection)
4158 IDWriteFontFileEnumerator *enumerator;
4159 HRESULT hr;
4161 *collection = NULL;
4163 hr = create_system_fontfile_enumerator(factory, &enumerator);
4164 if (FAILED(hr))
4165 return hr;
4167 TRACE("building system font collection for factory %p\n", factory);
4168 hr = create_font_collection(factory, enumerator, TRUE, collection);
4169 IDWriteFontFileEnumerator_Release(enumerator);
4170 return hr;
4173 static HRESULT eudc_collection_add_family(IDWriteFactory5 *factory, struct dwrite_fontcollection *collection,
4174 const WCHAR *keynameW, const WCHAR *pathW)
4176 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};
4177 static const WCHAR emptyW[] = {0};
4178 struct dwrite_fontfamily_data *family_data;
4179 IDWriteLocalizedStrings *names;
4180 DWRITE_FONT_FACE_TYPE face_type;
4181 DWRITE_FONT_FILE_TYPE file_type;
4182 IDWriteFontFileStream *stream;
4183 IDWriteFontFile *file;
4184 UINT32 face_count, i;
4185 BOOL supported;
4186 HRESULT hr;
4188 /* create font file from this path */
4189 hr = create_local_file_reference(factory, pathW, &file);
4190 if (FAILED(hr))
4191 return S_FALSE;
4193 if (FAILED(get_filestream_from_file(file, &stream))) {
4194 IDWriteFontFile_Release(file);
4195 return S_FALSE;
4198 /* Unsupported formats are skipped. */
4199 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4200 if (FAILED(hr) || !supported || face_count == 0) {
4201 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4202 IDWriteFontFileStream_Release(stream);
4203 IDWriteFontFile_Release(file);
4204 return S_FALSE;
4207 /* create and init new family */
4209 /* Family names are added for non-specific locale, represented with empty string.
4210 Default family appears with empty family name. */
4211 create_localizedstrings(&names);
4212 if (!strcmpiW(keynameW, defaultfontW))
4213 add_localizedstring(names, emptyW, emptyW);
4214 else
4215 add_localizedstring(names, emptyW, keynameW);
4217 hr = init_fontfamily_data(names, &family_data);
4218 IDWriteLocalizedStrings_Release(names);
4219 if (hr != S_OK) {
4220 IDWriteFontFile_Release(file);
4221 return hr;
4224 /* fill with faces */
4225 for (i = 0; i < face_count; i++) {
4226 struct dwrite_font_data *font_data;
4227 struct fontface_desc desc;
4229 /* alloc and init new font data structure */
4230 desc.factory = factory;
4231 desc.face_type = face_type;
4232 desc.index = i;
4233 desc.files = &file;
4234 desc.stream = stream;
4235 desc.files_number = 1;
4236 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4237 desc.font_data = NULL;
4239 hr = init_font_data(&desc, &names, &font_data);
4240 if (FAILED(hr))
4241 continue;
4243 IDWriteLocalizedStrings_Release(names);
4245 /* add font to family */
4246 hr = fontfamily_add_font(family_data, font_data);
4247 if (hr != S_OK)
4248 release_font_data(font_data);
4251 /* add family to collection */
4252 hr = fontcollection_add_family(collection, family_data);
4253 if (FAILED(hr))
4254 release_fontfamily_data(family_data);
4255 IDWriteFontFileStream_Release(stream);
4256 IDWriteFontFile_Release(file);
4258 return hr;
4261 HRESULT get_eudc_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **ret)
4263 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4264 struct dwrite_fontcollection *collection;
4265 static const WCHAR emptyW[] = {0};
4266 WCHAR eudckeypathW[16];
4267 HKEY eudckey;
4268 DWORD index;
4269 BOOL exists;
4270 LONG retval;
4271 HRESULT hr;
4272 UINT32 i;
4274 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4276 *ret = NULL;
4278 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4279 if (!collection) return E_OUTOFMEMORY;
4281 hr = init_font_collection(collection, FALSE);
4282 if (FAILED(hr)) {
4283 heap_free(collection);
4284 return hr;
4287 *ret = &collection->IDWriteFontCollection1_iface;
4288 collection->factory = factory;
4289 IDWriteFactory5_AddRef(factory);
4291 /* return empty collection if EUDC fonts are not configured */
4292 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4293 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4294 return S_OK;
4296 retval = ERROR_SUCCESS;
4297 index = 0;
4298 while (retval != ERROR_NO_MORE_ITEMS) {
4299 WCHAR keynameW[64], pathW[MAX_PATH];
4300 DWORD type, path_len, name_len;
4302 path_len = ARRAY_SIZE(pathW);
4303 name_len = ARRAY_SIZE(keynameW);
4304 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4305 if (retval || type != REG_SZ)
4306 continue;
4308 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4309 if (hr != S_OK)
4310 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4312 RegCloseKey(eudckey);
4314 /* try to add global default if not defined for specific codepage */
4315 exists = FALSE;
4316 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
4317 &index, &exists);
4318 if (FAILED(hr) || !exists) {
4319 static const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4320 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4321 if (hr != S_OK)
4322 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4325 /* EUDC collection offers simulated faces too */
4326 for (i = 0; i < collection->family_count; i++) {
4327 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4328 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4331 return S_OK;
4334 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4336 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4338 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4340 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4342 *obj = iface;
4343 IDWriteFontFile_AddRef(iface);
4344 return S_OK;
4347 WARN("%s not implemented.\n", debugstr_guid(riid));
4349 *obj = NULL;
4350 return E_NOINTERFACE;
4353 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4355 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4356 ULONG ref = InterlockedIncrement(&This->ref);
4357 TRACE("(%p)->(%d)\n", This, ref);
4358 return ref;
4361 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4363 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4364 ULONG ref = InterlockedDecrement(&This->ref);
4366 TRACE("(%p)->(%d)\n", This, ref);
4368 if (!ref)
4370 IDWriteFontFileLoader_Release(This->loader);
4371 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4372 heap_free(This->reference_key);
4373 heap_free(This);
4376 return ref;
4379 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4381 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4382 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4383 *fontFileReferenceKey = This->reference_key;
4384 *fontFileReferenceKeySize = This->key_size;
4386 return S_OK;
4389 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4391 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4392 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4393 *fontFileLoader = This->loader;
4394 IDWriteFontFileLoader_AddRef(This->loader);
4396 return S_OK;
4399 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4400 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4402 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4403 IDWriteFontFileStream *stream;
4404 HRESULT hr;
4406 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4408 *is_supported = FALSE;
4409 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4410 if (face_type)
4411 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4412 *face_count = 0;
4414 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4415 if (FAILED(hr))
4416 return hr;
4418 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4420 /* TODO: Further Analysis */
4421 IDWriteFontFileStream_Release(stream);
4422 return S_OK;
4425 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4426 dwritefontfile_QueryInterface,
4427 dwritefontfile_AddRef,
4428 dwritefontfile_Release,
4429 dwritefontfile_GetReferenceKey,
4430 dwritefontfile_GetLoader,
4431 dwritefontfile_Analyze,
4434 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4435 IDWriteFontFile **ret)
4437 struct dwrite_fontfile *file;
4438 void *key;
4440 *ret = NULL;
4442 file = heap_alloc(sizeof(*file));
4443 key = heap_alloc(key_size);
4444 if (!file || !key) {
4445 heap_free(file);
4446 heap_free(key);
4447 return E_OUTOFMEMORY;
4450 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4451 file->ref = 1;
4452 IDWriteFontFileLoader_AddRef(loader);
4453 file->loader = loader;
4454 file->stream = NULL;
4455 file->reference_key = key;
4456 memcpy(file->reference_key, reference_key, key_size);
4457 file->key_size = key_size;
4459 *ret = &file->IDWriteFontFile_iface;
4461 return S_OK;
4464 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace4 **ret)
4466 struct file_stream_desc stream_desc;
4467 struct dwrite_fontface *fontface;
4468 HRESULT hr = S_OK;
4469 BOOL is_symbol;
4470 int i;
4472 *ret = NULL;
4474 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4475 if (!fontface)
4476 return E_OUTOFMEMORY;
4478 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4479 if (!fontface->files) {
4480 heap_free(fontface);
4481 return E_OUTOFMEMORY;
4484 fontface->IDWriteFontFace4_iface.lpVtbl = &dwritefontfacevtbl;
4485 fontface->ref = 1;
4486 fontface->type = desc->face_type;
4487 fontface->file_count = desc->files_number;
4488 fontface->cmap.exists = TRUE;
4489 fontface->vdmx.exists = TRUE;
4490 fontface->gasp.exists = TRUE;
4491 fontface->cpal.exists = TRUE;
4492 fontface->colr.exists = TRUE;
4493 fontface->index = desc->index;
4494 fontface->simulations = desc->simulations;
4495 IDWriteFactory5_AddRef(fontface->factory = desc->factory);
4497 for (i = 0; i < fontface->file_count; i++) {
4498 fontface->files[i] = desc->files[i];
4499 IDWriteFontFile_AddRef(fontface->files[i]);
4501 fontface->stream = desc->stream;
4502 IDWriteFontFileStream_AddRef(fontface->stream);
4504 stream_desc.stream = fontface->stream;
4505 stream_desc.face_type = desc->face_type;
4506 stream_desc.face_index = desc->index;
4507 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4508 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4509 /* TODO: test what happens if caret is already slanted */
4510 if (fontface->caret.slopeRise == 1) {
4511 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4512 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4516 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace4_iface, &is_symbol);
4517 if (is_symbol)
4518 fontface->flags |= FONTFACE_IS_SYMBOL;
4519 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace4_iface))
4520 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4521 if (freetype_is_monospaced(&fontface->IDWriteFontFace4_iface))
4522 fontface->flags |= FONTFACE_IS_MONOSPACED;
4523 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace4_iface))
4524 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4525 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace4_iface);
4527 /* Font properties are reused from font object when 'normal' face creation path is used:
4528 collection -> family -> matching font -> fontface.
4530 If face is created directly from factory we have to go through properties resolution.
4532 if (desc->font_data) {
4533 fontface->weight = desc->font_data->weight;
4534 fontface->style = desc->font_data->style;
4535 fontface->stretch = desc->font_data->stretch;
4536 fontface->panose = desc->font_data->panose;
4537 fontface->fontsig = desc->font_data->fontsig;
4538 fontface->lf = desc->font_data->lf;
4540 else {
4541 IDWriteLocalizedStrings *names;
4542 struct dwrite_font_data *data;
4544 hr = init_font_data(desc, &names, &data);
4545 if (FAILED(hr)) {
4546 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4547 return hr;
4550 fontface->weight = data->weight;
4551 fontface->style = data->style;
4552 fontface->stretch = data->stretch;
4553 fontface->panose = data->panose;
4554 fontface->fontsig = data->fontsig;
4555 fontface->lf = data->lf;
4557 IDWriteLocalizedStrings_Release(names);
4558 release_font_data(data);
4561 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace4_iface);
4563 *ret = &fontface->IDWriteFontFace4_iface;
4564 return S_OK;
4567 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4568 struct local_refkey
4570 FILETIME writetime;
4571 WCHAR name[1];
4574 struct local_cached_stream
4576 struct list entry;
4577 IDWriteFontFileStream *stream;
4578 struct local_refkey *key;
4579 UINT32 key_size;
4582 struct dwrite_localfontfilestream
4584 IDWriteFontFileStream IDWriteFontFileStream_iface;
4585 LONG ref;
4587 struct local_cached_stream *entry;
4588 const void *file_ptr;
4589 UINT64 size;
4592 struct dwrite_localfontfileloader {
4593 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4594 LONG ref;
4596 struct list streams;
4597 CRITICAL_SECTION cs;
4600 static struct dwrite_localfontfileloader local_fontfile_loader;
4602 struct dwrite_inmemory_stream_data
4604 LONG ref;
4605 IUnknown *owner;
4606 void *data;
4607 UINT32 size;
4610 struct dwrite_inmemory_filestream
4612 IDWriteFontFileStream IDWriteFontFileStream_iface;
4613 LONG ref;
4615 struct dwrite_inmemory_stream_data *data;
4618 struct dwrite_inmemory_fileloader
4620 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
4621 LONG ref;
4623 struct dwrite_inmemory_stream_data **streams;
4624 UINT32 filecount;
4625 UINT32 capacity;
4628 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4630 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4633 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4635 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4638 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
4640 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
4643 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4645 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
4648 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
4650 if (InterlockedDecrement(&stream->ref) == 0) {
4651 if (stream->owner)
4652 IUnknown_Release(stream->owner);
4653 else
4654 heap_free(stream->data);
4655 heap_free(stream);
4659 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4661 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4663 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4665 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
4666 IsEqualIID(riid, &IID_IUnknown))
4668 *obj = iface;
4669 if (InterlockedIncrement(&This->ref) == 1) {
4670 InterlockedDecrement(&This->ref);
4671 *obj = NULL;
4672 return E_FAIL;
4674 return S_OK;
4677 WARN("%s not implemented.\n", debugstr_guid(riid));
4679 *obj = NULL;
4680 return E_NOINTERFACE;
4683 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4685 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4686 ULONG ref = InterlockedIncrement(&This->ref);
4687 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4688 return ref;
4691 static inline void release_cached_stream(struct local_cached_stream *stream)
4693 list_remove(&stream->entry);
4694 heap_free(stream->key);
4695 heap_free(stream);
4698 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4700 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4701 ULONG ref = InterlockedDecrement(&This->ref);
4703 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4705 if (!ref) {
4706 UnmapViewOfFile(This->file_ptr);
4708 EnterCriticalSection(&local_fontfile_loader.cs);
4709 release_cached_stream(This->entry);
4710 LeaveCriticalSection(&local_fontfile_loader.cs);
4712 heap_free(This);
4715 return ref;
4718 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4719 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4721 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4723 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4724 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4726 *fragment_context = NULL;
4728 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4729 *fragment_start = NULL;
4730 return E_FAIL;
4733 *fragment_start = (char*)This->file_ptr + offset;
4734 return S_OK;
4737 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4739 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4740 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4743 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4745 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4746 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4747 *size = This->size;
4748 return S_OK;
4751 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4753 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4754 ULARGE_INTEGER li;
4756 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4758 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4759 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4760 *last_writetime = li.QuadPart;
4762 return S_OK;
4765 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4767 localfontfilestream_QueryInterface,
4768 localfontfilestream_AddRef,
4769 localfontfilestream_Release,
4770 localfontfilestream_ReadFileFragment,
4771 localfontfilestream_ReleaseFileFragment,
4772 localfontfilestream_GetFileSize,
4773 localfontfilestream_GetLastWriteTime
4776 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4778 struct dwrite_localfontfilestream *This;
4780 *ret = NULL;
4782 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4783 if (!This)
4784 return E_OUTOFMEMORY;
4786 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4787 This->ref = 1;
4789 This->file_ptr = file_ptr;
4790 This->size = size;
4791 This->entry = entry;
4793 *ret = &This->IDWriteFontFileStream_iface;
4794 return S_OK;
4797 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4799 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4801 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4803 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
4804 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
4805 IsEqualIID(riid, &IID_IUnknown))
4807 *obj = iface;
4808 IDWriteLocalFontFileLoader_AddRef(iface);
4809 return S_OK;
4812 WARN("%s not implemented.\n", debugstr_guid(riid));
4814 *obj = NULL;
4815 return E_NOINTERFACE;
4818 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4820 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4821 ULONG ref = InterlockedIncrement(&This->ref);
4822 TRACE("(%p)->(%d)\n", This, ref);
4823 return ref;
4826 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4828 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4829 ULONG ref = InterlockedDecrement(&This->ref);
4831 TRACE("(%p)->(%d)\n", This, ref);
4833 return ref;
4836 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
4838 const struct local_refkey *refkey = key;
4839 struct local_cached_stream *stream;
4840 IDWriteFontFileStream *filestream;
4841 HANDLE file, mapping;
4842 LARGE_INTEGER size;
4843 void *file_ptr;
4844 HRESULT hr = S_OK;
4846 *ret = NULL;
4848 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4849 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4850 if (file == INVALID_HANDLE_VALUE) {
4851 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
4852 return E_FAIL;
4855 GetFileSizeEx(file, &size);
4856 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4857 CloseHandle(file);
4858 if (!mapping)
4859 return E_FAIL;
4861 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4862 CloseHandle(mapping);
4863 if (!file_ptr) {
4864 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4865 return E_FAIL;
4868 stream = heap_alloc(sizeof(*stream));
4869 if (!stream) {
4870 UnmapViewOfFile(file_ptr);
4871 return E_OUTOFMEMORY;
4874 stream->key = heap_alloc(key_size);
4875 if (!stream->key) {
4876 UnmapViewOfFile(file_ptr);
4877 heap_free(stream);
4878 return E_OUTOFMEMORY;
4881 stream->key_size = key_size;
4882 memcpy(stream->key, key, key_size);
4884 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4885 if (FAILED(hr)) {
4886 UnmapViewOfFile(file_ptr);
4887 heap_free(stream->key);
4888 heap_free(stream);
4889 return hr;
4892 stream->stream = filestream;
4894 *ret = stream;
4896 return S_OK;
4899 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
4900 UINT32 key_size, IDWriteFontFileStream **ret)
4902 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4903 const struct local_refkey *refkey = key;
4904 struct local_cached_stream *stream;
4905 HRESULT hr = S_OK;
4907 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
4908 TRACE("name: %s\n", debugstr_w(refkey->name));
4910 EnterCriticalSection(&This->cs);
4912 *ret = NULL;
4914 /* search cache first */
4915 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4916 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4917 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
4918 break;
4922 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
4923 list_add_head(&This->streams, &stream->entry);
4924 *ret = stream->stream;
4927 LeaveCriticalSection(&This->cs);
4929 return hr;
4932 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4934 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4935 const struct local_refkey *refkey = key;
4937 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4939 *length = strlenW(refkey->name);
4940 return S_OK;
4943 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4945 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4946 const struct local_refkey *refkey = key;
4948 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4950 if (length < strlenW(refkey->name))
4951 return E_INVALIDARG;
4953 strcpyW(path, refkey->name);
4954 return S_OK;
4957 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
4958 UINT32 key_size, FILETIME *writetime)
4960 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4961 const struct local_refkey *refkey = key;
4963 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
4965 *writetime = refkey->writetime;
4966 return S_OK;
4969 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4970 localfontfileloader_QueryInterface,
4971 localfontfileloader_AddRef,
4972 localfontfileloader_Release,
4973 localfontfileloader_CreateStreamFromKey,
4974 localfontfileloader_GetFilePathLengthFromKey,
4975 localfontfileloader_GetFilePathFromKey,
4976 localfontfileloader_GetLastWriteTimeFromKey
4979 void init_local_fontfile_loader(void)
4981 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4982 local_fontfile_loader.ref = 1;
4983 list_init(&local_fontfile_loader.streams);
4984 InitializeCriticalSection(&local_fontfile_loader.cs);
4985 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
4988 IDWriteFontFileLoader *get_local_fontfile_loader(void)
4990 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
4993 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4995 struct local_refkey *refkey;
4997 if (!path)
4998 return E_INVALIDARG;
5000 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
5001 *key = NULL;
5003 refkey = heap_alloc(*size);
5004 if (!refkey)
5005 return E_OUTOFMEMORY;
5007 if (writetime)
5008 refkey->writetime = *writetime;
5009 else {
5010 WIN32_FILE_ATTRIBUTE_DATA info;
5012 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
5013 refkey->writetime = info.ftLastWriteTime;
5014 else
5015 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
5017 strcpyW(refkey->name, path);
5019 *key = refkey;
5021 return S_OK;
5024 /* IDWriteGlyphRunAnalysis */
5025 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
5027 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5029 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5031 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
5032 IsEqualIID(riid, &IID_IUnknown))
5034 *ppv = iface;
5035 IDWriteGlyphRunAnalysis_AddRef(iface);
5036 return S_OK;
5039 WARN("%s not implemented.\n", debugstr_guid(riid));
5041 *ppv = NULL;
5042 return E_NOINTERFACE;
5045 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
5047 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5048 ULONG ref = InterlockedIncrement(&This->ref);
5049 TRACE("(%p)->(%u)\n", This, ref);
5050 return ref;
5053 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
5055 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5056 ULONG ref = InterlockedDecrement(&This->ref);
5058 TRACE("(%p)->(%u)\n", This, ref);
5060 if (!ref) {
5061 if (This->run.fontFace)
5062 IDWriteFontFace_Release(This->run.fontFace);
5063 heap_free(This->glyphs);
5064 heap_free(This->origins);
5065 heap_free(This->bitmap);
5066 heap_free(This);
5069 return ref;
5072 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
5074 switch (mode)
5076 case DWRITE_RENDERING_MODE1_NATURAL:
5077 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5078 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5079 return TRUE;
5080 default:
5081 return FALSE;
5085 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
5087 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
5090 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
5092 struct dwrite_glyphbitmap glyph_bitmap;
5093 IDWriteFontFace4 *fontface;
5094 HRESULT hr;
5095 UINT32 i;
5097 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
5098 *bounds = analysis->bounds;
5099 return;
5102 if (analysis->run.isSideways)
5103 FIXME("sideways runs are not supported.\n");
5105 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5106 if (FAILED(hr))
5107 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5109 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5110 glyph_bitmap.fontface = fontface;
5111 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5112 glyph_bitmap.emsize = analysis->run.fontEmSize;
5113 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5114 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5115 glyph_bitmap.m = &analysis->m;
5117 for (i = 0; i < analysis->run.glyphCount; i++) {
5118 RECT *bbox = &glyph_bitmap.bbox;
5119 UINT32 bitmap_size;
5121 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5122 freetype_get_glyph_bbox(&glyph_bitmap);
5124 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5125 (bbox->bottom - bbox->top);
5126 if (bitmap_size > analysis->max_glyph_bitmap_size)
5127 analysis->max_glyph_bitmap_size = bitmap_size;
5129 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5130 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5133 IDWriteFontFace4_Release(fontface);
5135 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5136 *bounds = analysis->bounds;
5139 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5141 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5143 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5145 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5146 SetRectEmpty(bounds);
5147 return E_INVALIDARG;
5150 if (type != This->texture_type) {
5151 SetRectEmpty(bounds);
5152 return S_OK;
5155 glyphrunanalysis_get_texturebounds(This, bounds);
5156 return S_OK;
5159 static inline int get_dib_stride( int width, int bpp )
5161 return ((width * bpp + 31) >> 3) & ~3;
5164 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5166 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5167 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5168 (runbounds->left - bounds->left) * 3;
5169 else
5170 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5171 runbounds->left - bounds->left;
5174 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5176 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5177 struct dwrite_glyphbitmap glyph_bitmap;
5178 IDWriteFontFace4 *fontface;
5179 D2D_POINT_2F origin;
5180 UINT32 i, size;
5181 HRESULT hr;
5182 RECT *bbox;
5184 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5185 if (FAILED(hr)) {
5186 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5187 return hr;
5190 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5191 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5192 size *= 3;
5193 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5194 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5195 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5196 IDWriteFontFace4_Release(fontface);
5197 return E_OUTOFMEMORY;
5200 origin.x = origin.y = 0.0f;
5202 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5203 glyph_bitmap.fontface = fontface;
5204 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5205 glyph_bitmap.emsize = analysis->run.fontEmSize;
5206 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5207 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5208 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5209 glyph_bitmap.m = &analysis->m;
5210 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5211 IDWriteFontFace4_Release(fontface);
5212 return E_OUTOFMEMORY;
5215 bbox = &glyph_bitmap.bbox;
5217 for (i = 0; i < analysis->run.glyphCount; i++) {
5218 BYTE *src = glyph_bitmap.buf, *dst;
5219 int x, y, width, height;
5220 BOOL is_1bpp;
5222 glyph_bitmap.glyph = analysis->run.glyphIndices[i];
5223 freetype_get_glyph_bbox(&glyph_bitmap);
5225 if (IsRectEmpty(bbox))
5226 continue;
5228 width = bbox->right - bbox->left;
5229 height = bbox->bottom - bbox->top;
5231 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5232 memset(src, 0, height * glyph_bitmap.pitch);
5233 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5235 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5237 /* blit to analysis bitmap */
5238 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5240 if (is_1bpp) {
5241 /* convert 1bpp to 8bpp/24bpp */
5242 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5243 for (y = 0; y < height; y++) {
5244 for (x = 0; x < width; x++)
5245 if (src[x / 8] & masks[x % 8])
5246 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5247 src += glyph_bitmap.pitch;
5248 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5251 else {
5252 for (y = 0; y < height; y++) {
5253 for (x = 0; x < width; x++)
5254 if (src[x / 8] & masks[x % 8])
5255 dst[x] = DWRITE_ALPHA_MAX;
5256 src += glyph_bitmap.pitch;
5257 dst += analysis->bounds.right - analysis->bounds.left;
5261 else {
5262 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5263 for (y = 0; y < height; y++) {
5264 for (x = 0; x < width; x++)
5265 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5266 src += glyph_bitmap.pitch;
5267 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5270 else {
5271 for (y = 0; y < height; y++) {
5272 for (x = 0; x < width; x++)
5273 dst[x] |= src[x];
5274 src += glyph_bitmap.pitch;
5275 dst += analysis->bounds.right - analysis->bounds.left;
5280 heap_free(glyph_bitmap.buf);
5282 IDWriteFontFace4_Release(fontface);
5284 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5286 /* we don't need this anymore */
5287 heap_free(analysis->glyphs);
5288 heap_free(analysis->origins);
5289 IDWriteFontFace_Release(analysis->run.fontFace);
5291 analysis->glyphs = NULL;
5292 analysis->origins = NULL;
5293 analysis->run.glyphIndices = NULL;
5294 analysis->run.fontFace = NULL;
5296 return S_OK;
5299 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5300 RECT const *bounds, BYTE *bitmap, UINT32 size)
5302 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5303 UINT32 required;
5304 RECT runbounds;
5306 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5308 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5309 return E_INVALIDARG;
5311 /* make sure buffer is large enough for requested texture type */
5312 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5313 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5314 required *= 3;
5316 if (size < required)
5317 return E_NOT_SUFFICIENT_BUFFER;
5319 /* validate requested texture type */
5320 if (This->texture_type != type)
5321 return DWRITE_E_UNSUPPORTEDOPERATION;
5323 memset(bitmap, 0, size);
5324 glyphrunanalysis_get_texturebounds(This, &runbounds);
5325 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5326 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5327 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5328 int dst_width = (bounds->right - bounds->left) * pixel_size;
5329 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5330 BYTE *src, *dst;
5331 int y;
5333 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5334 HRESULT hr;
5336 if (FAILED(hr = glyphrunanalysis_render(This)))
5337 return hr;
5340 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5341 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5343 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5344 memcpy(dst, src, draw_width);
5345 src += src_width;
5346 dst += dst_width;
5350 return S_OK;
5353 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5354 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5356 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5358 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5360 if (!params)
5361 return E_INVALIDARG;
5363 switch (This->rendering_mode)
5365 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5366 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5368 UINT value = 0;
5369 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5370 *gamma = (FLOAT)value / 1000.0f;
5371 *contrast = 0.0f;
5372 *cleartypelevel = 1.0f;
5373 break;
5375 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5376 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5377 /* fallthrough */
5378 case DWRITE_RENDERING_MODE1_ALIASED:
5379 case DWRITE_RENDERING_MODE1_NATURAL:
5380 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5381 *gamma = IDWriteRenderingParams_GetGamma(params);
5382 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5383 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5384 break;
5385 default:
5389 return S_OK;
5392 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5393 glyphrunanalysis_QueryInterface,
5394 glyphrunanalysis_AddRef,
5395 glyphrunanalysis_Release,
5396 glyphrunanalysis_GetAlphaTextureBounds,
5397 glyphrunanalysis_CreateAlphaTexture,
5398 glyphrunanalysis_GetAlphaBlendParams
5401 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5403 D2D_POINT_2F ret;
5404 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5405 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5406 *point = ret;
5409 float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
5410 float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
5412 unsigned int upem = fontface->metrics.designUnitsPerEm;
5413 int advance;
5415 if (is_sideways)
5416 FIXME("Sideways mode is not supported.\n");
5418 advance = fontface_get_design_advance(fontface, measuring_mode, emsize, ppdip, transform, glyph, is_sideways);
5420 switch (measuring_mode)
5422 case DWRITE_MEASURING_MODE_NATURAL:
5423 return (float)advance * emsize / (float)upem;
5424 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5425 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5426 return ppdip > 0.0f ? floorf(advance * emsize * ppdip / upem + 0.5f) / ppdip : 0.0f;
5427 default:
5428 WARN("Unknown measuring mode %u.\n", measuring_mode);
5429 return 0.0f;
5433 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5435 struct dwrite_glyphrunanalysis *analysis;
5436 struct dwrite_fontface *fontface;
5437 D2D_POINT_2F origin;
5438 FLOAT rtl_factor;
5439 UINT32 i;
5441 *ret = NULL;
5443 /* Check rendering, antialising, measuring, and grid fitting modes. */
5444 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5445 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5446 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5447 return E_INVALIDARG;
5449 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5450 return E_INVALIDARG;
5452 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5453 return E_INVALIDARG;
5455 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5456 return E_INVALIDARG;
5458 analysis = heap_alloc(sizeof(*analysis));
5459 if (!analysis)
5460 return E_OUTOFMEMORY;
5462 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5463 analysis->ref = 1;
5464 analysis->rendering_mode = desc->rendering_mode;
5466 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5467 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5468 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5469 else
5470 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5472 analysis->flags = 0;
5473 analysis->bitmap = NULL;
5474 analysis->max_glyph_bitmap_size = 0;
5475 SetRectEmpty(&analysis->bounds);
5476 analysis->run = *desc->run;
5477 IDWriteFontFace_AddRef(analysis->run.fontFace);
5478 analysis->glyphs = heap_calloc(desc->run->glyphCount, sizeof(*analysis->glyphs));
5479 analysis->origins = heap_calloc(desc->run->glyphCount, sizeof(*analysis->origins));
5481 if (!analysis->glyphs || !analysis->origins) {
5482 heap_free(analysis->glyphs);
5483 heap_free(analysis->origins);
5485 analysis->glyphs = NULL;
5486 analysis->origins = NULL;
5488 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5489 return E_OUTOFMEMORY;
5492 /* check if transform is usable */
5493 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5494 analysis->m = *desc->transform;
5495 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5497 else
5498 memset(&analysis->m, 0, sizeof(analysis->m));
5500 analysis->run.glyphIndices = analysis->glyphs;
5501 analysis->run.glyphAdvances = NULL;
5502 analysis->run.glyphOffsets = NULL;
5504 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5506 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5508 fontface = unsafe_impl_from_IDWriteFontFace(desc->run->fontFace);
5510 origin.x = desc->origin.x;
5511 origin.y = desc->origin.y;
5512 for (i = 0; i < desc->run->glyphCount; ++i)
5514 float advance;
5516 /* Use nominal advances if not provided by caller. */
5517 if (desc->run->glyphAdvances)
5518 advance = rtl_factor * desc->run->glyphAdvances[i];
5519 else
5520 advance = rtl_factor * fontface_get_scaled_design_advance(fontface, desc->measuring_mode,
5521 desc->run->fontEmSize, 1.0f, desc->transform, desc->run->glyphIndices[i], desc->run->isSideways);
5523 analysis->origins[i] = origin;
5524 if (desc->run->bidiLevel & 1)
5526 if (desc->run->isSideways)
5527 analysis->origins[i].y += advance;
5528 else
5529 analysis->origins[i].x += advance;
5532 /* Offsets are optional, appled to pre-transformed origin. */
5533 if (desc->run->glyphOffsets) {
5534 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset;
5535 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset;
5537 if (desc->run->isSideways) {
5538 analysis->origins[i].x += ascenderoffset;
5539 analysis->origins[i].y += advanceoffset;
5541 else {
5542 analysis->origins[i].x += advanceoffset;
5543 analysis->origins[i].y += ascenderoffset;
5547 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5548 transform_point(analysis->origins + i, &analysis->m);
5550 if (desc->run->isSideways)
5551 origin.y += advance;
5552 else
5553 origin.x += advance;
5556 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5557 return S_OK;
5560 /* IDWriteColorGlyphRunEnumerator */
5561 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5563 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5565 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5567 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5568 IsEqualIID(riid, &IID_IUnknown))
5570 *ppv = iface;
5571 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5572 return S_OK;
5575 WARN("%s not implemented.\n", debugstr_guid(riid));
5577 *ppv = NULL;
5578 return E_NOINTERFACE;
5581 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5583 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5584 ULONG ref = InterlockedIncrement(&This->ref);
5585 TRACE("(%p)->(%u)\n", This, ref);
5586 return ref;
5589 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5591 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5592 ULONG ref = InterlockedDecrement(&This->ref);
5594 TRACE("(%p)->(%u)\n", This, ref);
5596 if (!ref) {
5597 heap_free(This->advances);
5598 heap_free(This->color_advances);
5599 heap_free(This->offsets);
5600 heap_free(This->color_offsets);
5601 heap_free(This->glyphindices);
5602 heap_free(This->glyphs);
5603 if (This->colr.context)
5604 IDWriteFontFace4_ReleaseFontTable(This->fontface, This->colr.context);
5605 IDWriteFontFace4_Release(This->fontface);
5606 heap_free(This);
5609 return ref;
5612 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5614 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5615 FLOAT origin = 0.0f;
5617 if (g == 0)
5618 return 0.0f;
5620 while (g--)
5621 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5622 return origin;
5625 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5627 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5628 FLOAT advance_adj = 0.0f;
5629 BOOL got_palette_index;
5630 UINT32 g;
5632 /* start with regular glyphs */
5633 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5634 UINT32 first_glyph = 0;
5636 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5637 if (glyphenum->glyphs[g].num_layers == 0) {
5638 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5639 first_glyph = min(first_glyph, g);
5641 else
5642 glyphenum->glyphindices[g] = 1;
5643 glyphenum->color_advances[g] = glyphenum->advances[g];
5644 if (glyphenum->color_offsets)
5645 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5648 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5649 colorrun->baselineOriginY = glyphenum->origin_y;
5650 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5651 colorrun->paletteIndex = 0xffff;
5652 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5653 glyphenum->has_regular_glyphs = FALSE;
5654 return TRUE;
5656 else {
5657 colorrun->glyphRun.glyphCount = 0;
5658 got_palette_index = FALSE;
5661 advance_adj = 0.0f;
5662 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5664 glyphenum->glyphindices[g] = 1;
5666 /* all glyph layers were returned */
5667 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5668 advance_adj += glyphenum->advances[g];
5669 continue;
5672 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5673 UINT32 index = colorrun->glyphRun.glyphCount;
5674 if (!got_palette_index) {
5675 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5676 /* use foreground color or request one from the font */
5677 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5678 if (colorrun->paletteIndex != 0xffff) {
5679 HRESULT hr = IDWriteFontFace4_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5680 1, &colorrun->runColor);
5681 if (FAILED(hr))
5682 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5683 glyphenum->palette, colorrun->paletteIndex, hr);
5685 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5686 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5687 colorrun->baselineOriginY = glyphenum->origin_y;
5688 glyphenum->color_advances[index] = glyphenum->advances[g];
5689 got_palette_index = TRUE;
5692 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5693 /* offsets are relative to glyph origin, nothing to fix up */
5694 if (glyphenum->color_offsets)
5695 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5696 opentype_colr_next_glyph(&glyphenum->colr, glyphenum->glyphs + g);
5697 if (index)
5698 glyphenum->color_advances[index-1] += advance_adj;
5699 colorrun->glyphRun.glyphCount++;
5700 advance_adj = 0.0f;
5702 else
5703 advance_adj += glyphenum->advances[g];
5706 /* reset last advance */
5707 if (colorrun->glyphRun.glyphCount)
5708 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5710 return colorrun->glyphRun.glyphCount > 0;
5713 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5715 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5717 TRACE("(%p)->(%p)\n", This, has_run);
5719 *has_run = FALSE;
5721 This->colorrun.glyphRun.glyphCount = 0;
5722 while (This->current_layer < This->max_layer_num) {
5723 if (colorglyphenum_build_color_run(This))
5724 break;
5725 else
5726 This->current_layer++;
5729 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5731 return S_OK;
5734 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5736 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5738 TRACE("(%p)->(%p)\n", This, run);
5740 if (This->colorrun.glyphRun.glyphCount == 0) {
5741 *run = NULL;
5742 return E_NOT_VALID_STATE;
5745 *run = &This->colorrun;
5746 return S_OK;
5749 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5750 colorglyphenum_QueryInterface,
5751 colorglyphenum_AddRef,
5752 colorglyphenum_Release,
5753 colorglyphenum_MoveNext,
5754 colorglyphenum_GetCurrentRun
5757 HRESULT create_colorglyphenum(float originX, float originY, const DWRITE_GLYPH_RUN *run,
5758 const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr, DWRITE_MEASURING_MODE measuring_mode,
5759 const DWRITE_MATRIX *transform, unsigned int palette, IDWriteColorGlyphRunEnumerator **ret)
5761 struct dwrite_colorglyphenum *colorglyphenum;
5762 BOOL colorfont, has_colored_glyph;
5763 struct dwrite_fontface *fontface;
5764 unsigned int i;
5766 *ret = NULL;
5768 fontface = unsafe_impl_from_IDWriteFontFace(run->fontFace);
5770 colorfont = IDWriteFontFace4_IsColorFont(&fontface->IDWriteFontFace4_iface) &&
5771 IDWriteFontFace4_GetColorPaletteCount(&fontface->IDWriteFontFace4_iface) > palette;
5772 if (!colorfont)
5773 return DWRITE_E_NOCOLOR;
5775 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5776 if (!colorglyphenum)
5777 return E_OUTOFMEMORY;
5779 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5780 colorglyphenum->ref = 1;
5781 colorglyphenum->origin_x = originX;
5782 colorglyphenum->origin_y = originY;
5783 colorglyphenum->fontface = &fontface->IDWriteFontFace4_iface;
5784 IDWriteFontFace4_AddRef(colorglyphenum->fontface);
5785 colorglyphenum->glyphs = NULL;
5786 colorglyphenum->run = *run;
5787 colorglyphenum->run.glyphIndices = NULL;
5788 colorglyphenum->run.glyphAdvances = NULL;
5789 colorglyphenum->run.glyphOffsets = NULL;
5790 colorglyphenum->palette = palette;
5791 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5792 colorglyphenum->colr.exists = TRUE;
5793 get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &colorglyphenum->colr);
5794 colorglyphenum->current_layer = 0;
5795 colorglyphenum->max_layer_num = 0;
5797 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5799 has_colored_glyph = FALSE;
5800 colorglyphenum->has_regular_glyphs = FALSE;
5801 for (i = 0; i < run->glyphCount; i++) {
5802 if (opentype_get_colr_glyph(&colorglyphenum->colr, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5803 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5804 has_colored_glyph = TRUE;
5806 if (colorglyphenum->glyphs[i].num_layers == 0)
5807 colorglyphenum->has_regular_glyphs = TRUE;
5810 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5811 is supposed to proceed normally, like if font had no color info at all. */
5812 if (!has_colored_glyph) {
5813 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5814 return DWRITE_E_NOCOLOR;
5817 colorglyphenum->advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->advances));
5818 colorglyphenum->color_advances = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_advances));
5819 colorglyphenum->glyphindices = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->glyphindices));
5820 if (run->glyphOffsets) {
5821 colorglyphenum->offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->offsets));
5822 colorglyphenum->color_offsets = heap_calloc(run->glyphCount, sizeof(*colorglyphenum->color_offsets));
5823 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5826 colorglyphenum->colorrun.glyphRun.fontFace = run->fontFace;
5827 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
5828 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5829 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5830 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5831 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5833 if (run->glyphAdvances)
5834 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5835 else
5837 for (i = 0; i < run->glyphCount; ++i)
5838 colorglyphenum->advances[i] = fontface_get_scaled_design_advance(fontface, measuring_mode,
5839 run->fontEmSize, 1.0f, transform, run->glyphIndices[i], run->isSideways);
5842 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5844 return S_OK;
5847 /* IDWriteFontFaceReference */
5848 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5850 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5852 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5854 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5855 *obj = iface;
5856 IDWriteFontFaceReference_AddRef(iface);
5857 return S_OK;
5860 WARN("%s not implemented.\n", debugstr_guid(riid));
5862 *obj = NULL;
5864 return E_NOINTERFACE;
5867 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5869 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5870 ULONG ref = InterlockedIncrement(&This->ref);
5871 TRACE("(%p)->(%u)\n", This, ref);
5872 return ref;
5875 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5877 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5878 ULONG ref = InterlockedDecrement(&This->ref);
5880 TRACE("(%p)->(%u)\n", This, ref);
5882 if (!ref) {
5883 IDWriteFontFile_Release(This->file);
5884 IDWriteFactory5_Release(This->factory);
5885 heap_free(This);
5888 return ref;
5891 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5893 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5895 TRACE("(%p)->(%p)\n", This, fontface);
5897 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5900 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5901 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5903 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5904 DWRITE_FONT_FILE_TYPE file_type;
5905 DWRITE_FONT_FACE_TYPE face_type;
5906 IDWriteFontFace *fontface;
5907 BOOL is_supported;
5908 UINT32 face_num;
5909 HRESULT hr;
5911 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5913 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5914 if (FAILED(hr))
5915 return hr;
5917 hr = IDWriteFactory5_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5918 if (SUCCEEDED(hr)) {
5919 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
5920 IDWriteFontFace_Release(fontface);
5923 return hr;
5926 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5928 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5929 IDWriteFontFile *file;
5930 BOOL ret;
5932 TRACE("(%p)->(%p)\n", This, ref);
5934 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5935 return FALSE;
5937 ret = is_same_fontfile(This->file, file) &&
5938 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5939 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5940 IDWriteFontFile_Release(file);
5942 return ret;
5945 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5947 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5949 TRACE("(%p)\n", This);
5951 return This->index;
5954 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5956 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5958 TRACE("(%p)\n", This);
5960 return This->simulations;
5963 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5965 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5966 IDWriteFontFileLoader *loader;
5967 const void *key;
5968 UINT32 key_size;
5969 HRESULT hr;
5971 TRACE("(%p)->(%p)\n", This, file);
5973 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5974 if (FAILED(hr))
5975 return hr;
5977 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5978 if (FAILED(hr))
5979 return hr;
5981 hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5982 IDWriteFontFileLoader_Release(loader);
5984 return hr;
5987 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5989 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5991 FIXME("(%p): stub\n", This);
5993 return 0;
5996 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5998 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6000 FIXME("(%p): stub\n", This);
6002 return 0;
6005 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
6007 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6009 FIXME("(%p)->(%p): stub\n", This, writetime);
6011 return E_NOTIMPL;
6014 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
6016 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6018 FIXME("(%p): stub\n", This);
6020 return DWRITE_LOCALITY_LOCAL;
6023 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
6025 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6027 FIXME("(%p): stub\n", This);
6029 return E_NOTIMPL;
6032 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
6033 UINT32 count)
6035 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6037 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
6039 return E_NOTIMPL;
6042 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
6043 UINT32 count)
6045 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6047 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
6049 return E_NOTIMPL;
6052 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
6053 UINT64 offset, UINT64 size)
6055 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
6057 FIXME("(%p)->(0x%s 0x%s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
6059 return E_NOTIMPL;
6062 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
6063 fontfacereference_QueryInterface,
6064 fontfacereference_AddRef,
6065 fontfacereference_Release,
6066 fontfacereference_CreateFontFace,
6067 fontfacereference_CreateFontFaceWithSimulations,
6068 fontfacereference_Equals,
6069 fontfacereference_GetFontFaceIndex,
6070 fontfacereference_GetSimulations,
6071 fontfacereference_GetFontFile,
6072 fontfacereference_GetLocalFileSize,
6073 fontfacereference_GetFileSize,
6074 fontfacereference_GetFileTime,
6075 fontfacereference_GetLocality,
6076 fontfacereference_EnqueueFontDownloadRequest,
6077 fontfacereference_EnqueueCharacterDownloadRequest,
6078 fontfacereference_EnqueueGlyphDownloadRequest,
6079 fontfacereference_EnqueueFileFragmentDownloadRequest
6082 HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file, UINT32 index,
6083 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
6085 struct dwrite_fontfacereference *ref;
6087 *ret = NULL;
6089 if (!is_simulation_valid(simulations))
6090 return E_INVALIDARG;
6092 ref = heap_alloc(sizeof(*ref));
6093 if (!ref)
6094 return E_OUTOFMEMORY;
6096 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
6097 ref->ref = 1;
6099 ref->factory = factory;
6100 IDWriteFactory5_AddRef(ref->factory);
6101 ref->file = file;
6102 IDWriteFontFile_AddRef(ref->file);
6103 ref->index = index;
6104 ref->simulations = simulations;
6105 *ret = &ref->IDWriteFontFaceReference_iface;
6107 return S_OK;
6110 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6112 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6114 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6116 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6117 *obj = iface;
6118 IDWriteFontFileStream_AddRef(iface);
6119 return S_OK;
6122 *obj = NULL;
6124 WARN("%s not implemented.\n", debugstr_guid(riid));
6125 return E_NOINTERFACE;
6128 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6130 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6131 ULONG ref = InterlockedIncrement(&stream->ref);
6132 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6133 return ref;
6136 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6138 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6139 ULONG ref = InterlockedDecrement(&stream->ref);
6141 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6143 if (!ref) {
6144 release_inmemory_stream(stream->data);
6145 heap_free(stream);
6148 return ref;
6151 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6152 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6154 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6156 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6157 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6159 *fragment_context = NULL;
6161 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6162 *fragment_start = NULL;
6163 return E_FAIL;
6166 *fragment_start = (char *)stream->data->data + offset;
6167 return S_OK;
6170 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6172 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6174 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6177 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6179 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6181 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6183 *size = stream->data->size;
6185 return S_OK;
6188 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6190 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6192 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6194 *last_writetime = 0;
6196 return E_NOTIMPL;
6199 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6200 inmemoryfilestream_QueryInterface,
6201 inmemoryfilestream_AddRef,
6202 inmemoryfilestream_Release,
6203 inmemoryfilestream_ReadFileFragment,
6204 inmemoryfilestream_ReleaseFileFragment,
6205 inmemoryfilestream_GetFileSize,
6206 inmemoryfilestream_GetLastWriteTime,
6209 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6210 REFIID riid, void **obj)
6212 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6214 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6216 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6217 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6218 IsEqualIID(riid, &IID_IUnknown))
6220 *obj = iface;
6221 IDWriteInMemoryFontFileLoader_AddRef(iface);
6222 return S_OK;
6225 WARN("%s not implemented.\n", debugstr_guid(riid));
6227 *obj = NULL;
6229 return E_NOINTERFACE;
6232 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6234 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6235 ULONG ref = InterlockedIncrement(&loader->ref);
6236 TRACE("(%p)->(%u)\n", loader, ref);
6237 return ref;
6240 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6242 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6243 ULONG ref = InterlockedDecrement(&loader->ref);
6245 TRACE("(%p)->(%u)\n", loader, ref);
6247 if (!ref) {
6248 UINT32 i;
6250 for (i = 0; i < loader->filecount; i++)
6251 release_inmemory_stream(loader->streams[i]);
6252 heap_free(loader->streams);
6253 heap_free(loader);
6256 return ref;
6259 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6260 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6262 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6263 struct dwrite_inmemory_filestream *stream;
6264 DWORD index;
6266 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6268 *ret = NULL;
6270 if (key_size != sizeof(DWORD))
6271 return E_INVALIDARG;
6273 index = *(DWORD *)key;
6275 if (index >= loader->filecount)
6276 return E_INVALIDARG;
6278 if (!(stream = heap_alloc(sizeof(*stream))))
6279 return E_OUTOFMEMORY;
6281 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6282 stream->ref = 1;
6283 stream->data = loader->streams[index];
6284 InterlockedIncrement(&stream->data->ref);
6286 *ret = &stream->IDWriteFontFileStream_iface;
6288 return S_OK;
6291 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6292 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6294 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6295 struct dwrite_inmemory_stream_data *stream;
6296 DWORD key;
6298 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6300 *fontfile = NULL;
6302 if (loader->filecount == loader->capacity) {
6303 if (loader->streams) {
6304 struct dwrite_inmemory_stream_data **ptr;
6306 if (!(ptr = heap_realloc(loader->streams, 2 * loader->capacity * sizeof(*loader->streams))))
6307 return E_OUTOFMEMORY;
6309 loader->streams = ptr;
6310 loader->capacity *= 2;
6312 else {
6313 loader->capacity = 16;
6314 loader->streams = heap_calloc(loader->capacity, sizeof(*loader->streams));
6318 if (!(stream = heap_alloc(sizeof(*stream))))
6319 return E_OUTOFMEMORY;
6321 stream->ref = 1;
6322 stream->size = data_size;
6323 stream->owner = owner;
6324 if (stream->owner) {
6325 IUnknown_AddRef(stream->owner);
6326 stream->data = (void *)data;
6328 else {
6329 if (!(stream->data = heap_alloc(data_size))) {
6330 heap_free(stream);
6331 return E_OUTOFMEMORY;
6333 memcpy(stream->data, data, data_size);
6336 key = loader->filecount;
6337 loader->streams[loader->filecount++] = stream;
6339 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6340 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6343 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6345 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6347 TRACE("(%p)\n", loader);
6349 return loader->filecount;
6352 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6354 inmemoryfontfileloader_QueryInterface,
6355 inmemoryfontfileloader_AddRef,
6356 inmemoryfontfileloader_Release,
6357 inmemoryfontfileloader_CreateStreamFromKey,
6358 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6359 inmemoryfontfileloader_GetFileCount,
6362 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6364 struct dwrite_inmemory_fileloader *loader;
6366 *ret = NULL;
6368 loader = heap_alloc_zero(sizeof(*loader));
6369 if (!loader)
6370 return E_OUTOFMEMORY;
6372 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6373 loader->ref = 1;
6375 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6377 return S_OK;