gphoto2.ds: Set supported groups.
[wine.git] / dlls / dwrite / font.c
blobc545f09c0ab16088f1d0ebfff75e8e92160fe799
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 LONG ref;
129 struct dwrite_fontfamily_data *data;
130 struct dwrite_fontcollection *collection;
133 struct dwrite_fontlist {
134 IDWriteFontList1 IDWriteFontList1_iface;
135 LONG ref;
137 struct dwrite_font_data **fonts;
138 UINT32 font_count;
139 struct dwrite_fontfamily *family;
142 struct dwrite_font {
143 IDWriteFont3 IDWriteFont3_iface;
144 LONG ref;
146 DWRITE_FONT_STYLE style;
147 struct dwrite_font_data *data;
148 struct dwrite_fontfamily *family;
151 struct dwrite_fonttable {
152 void *data;
153 void *context;
154 UINT32 size;
155 BOOL exists;
158 enum runanalysis_flags {
159 RUNANALYSIS_BOUNDS_READY = 1 << 0,
160 RUNANALYSIS_BITMAP_READY = 1 << 1,
161 RUNANALYSIS_USE_TRANSFORM = 1 << 2
164 struct dwrite_glyphrunanalysis {
165 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
166 LONG ref;
168 DWRITE_RENDERING_MODE1 rendering_mode;
169 DWRITE_TEXTURE_TYPE texture_type; /* derived from rendering mode specified on creation */
170 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
171 DWRITE_MATRIX m;
172 UINT16 *glyphs;
173 D2D_POINT_2F *origins;
175 UINT8 flags;
176 RECT bounds;
177 BYTE *bitmap;
178 UINT32 max_glyph_bitmap_size;
181 struct dwrite_colorglyphenum {
182 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
183 LONG ref;
185 FLOAT origin_x; /* original run origin */
186 FLOAT origin_y;
188 IDWriteFontFace4 *fontface; /* for convenience */
189 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
190 DWRITE_GLYPH_RUN run; /* base run */
191 UINT32 palette; /* palette index to get layer color from */
192 FLOAT *advances; /* original or measured advances for base glyphs */
193 FLOAT *color_advances; /* returned color run points to this */
194 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
195 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
196 UINT16 *glyphindices; /* returned color run points to this */
197 struct dwrite_colorglyph *glyphs; /* current glyph color info */
198 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
199 UINT16 current_layer; /* enumerator position, updated with MoveNext */
200 UINT16 max_layer_num; /* max number of layers for this run */
201 struct dwrite_fonttable colr; /* used to access layers */
204 #define GLYPH_BLOCK_SHIFT 8
205 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
206 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
207 #define GLYPH_MAX 65536
209 enum fontface_flags {
210 FONTFACE_IS_SYMBOL = 1 << 0,
211 FONTFACE_IS_MONOSPACED = 1 << 1,
212 FONTFACE_HAS_KERNING_PAIRS = 1 << 2,
213 FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
216 struct dwrite_fontface {
217 IDWriteFontFace4 IDWriteFontFace4_iface;
218 LONG ref;
220 IDWriteFontFileStream *stream;
221 IDWriteFontFile **files;
222 UINT32 file_count;
223 UINT32 index;
225 IDWriteFactory5 *factory;
226 struct fontfacecached *cached;
228 USHORT simulations;
229 DWRITE_FONT_FACE_TYPE type;
230 DWRITE_FONT_METRICS1 metrics;
231 DWRITE_CARET_METRICS caret;
232 INT charmap;
233 UINT16 flags;
235 struct dwrite_fonttable cmap;
236 struct dwrite_fonttable vdmx;
237 struct dwrite_fonttable gasp;
238 struct dwrite_fonttable cpal;
239 struct dwrite_fonttable colr;
240 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
242 DWRITE_FONT_STYLE style;
243 DWRITE_FONT_STRETCH stretch;
244 DWRITE_FONT_WEIGHT weight;
245 DWRITE_PANOSE panose;
246 FONTSIGNATURE fontsig;
247 UINT32 glyph_image_formats;
249 LOGFONTW lf;
252 struct dwrite_fontfile {
253 IDWriteFontFile IDWriteFontFile_iface;
254 LONG ref;
256 IDWriteFontFileLoader *loader;
257 void *reference_key;
258 UINT32 key_size;
259 IDWriteFontFileStream *stream;
262 struct dwrite_fontfacereference {
263 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
264 LONG ref;
266 IDWriteFontFile *file;
267 UINT32 index;
268 USHORT simulations;
269 IDWriteFactory5 *factory;
272 static inline struct dwrite_fontface *impl_from_IDWriteFontFace4(IDWriteFontFace4 *iface)
274 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
277 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
279 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
282 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
284 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
287 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
289 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
292 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
294 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
297 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
299 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
302 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
304 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
307 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
309 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
312 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
314 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
317 static inline const char *debugstr_tag(UINT32 tag)
319 return debugstr_an((char*)&tag, 4);
322 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
324 static const DWRITE_GLYPH_METRICS nil;
325 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
327 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
328 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
329 return S_OK;
332 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
334 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
336 if (!*block) {
337 /* start new block */
338 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
339 if (!*block)
340 return E_OUTOFMEMORY;
343 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
344 return S_OK;
347 static void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table)
349 HRESULT hr;
351 if (table->data || !table->exists)
352 return table->data;
354 table->exists = FALSE;
355 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
356 &table->exists);
357 if (FAILED(hr) || !table->exists) {
358 TRACE("Font does not have %s table\n", debugstr_tag(tag));
359 return NULL;
362 return table->data;
365 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
366 struct dwrite_font_propvec *vec)
368 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
369 vec->style = style * 7.0f;
370 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
373 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
375 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
378 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
380 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
383 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
385 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CMAP_TAG, &fontface->cmap);
388 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
390 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_VDMX_TAG, &fontface->vdmx);
393 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
395 void *ptr = get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_GASP_TAG, &fontface->gasp);
396 *size = fontface->gasp.size;
397 return ptr;
400 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
402 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_CPAL_TAG, &fontface->cpal);
405 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
407 return get_fontface_table(&fontface->IDWriteFontFace4_iface, MS_COLR_TAG, &fontface->colr);
410 static void addref_font_data(struct dwrite_font_data *data)
412 InterlockedIncrement(&data->ref);
415 static void release_font_data(struct dwrite_font_data *data)
417 int i;
419 if (InterlockedDecrement(&data->ref) > 0)
420 return;
422 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
423 if (data->info_strings[i])
424 IDWriteLocalizedStrings_Release(data->info_strings[i]);
426 if (data->names)
427 IDWriteLocalizedStrings_Release(data->names);
429 IDWriteFontFile_Release(data->file);
430 heap_free(data->facename);
431 heap_free(data);
434 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
436 int i;
438 if (InterlockedDecrement(&data->ref) > 0)
439 return;
441 for (i = 0; i < data->font_count; i++)
442 release_font_data(data->fonts[i]);
443 heap_free(data->fonts);
444 IDWriteLocalizedStrings_Release(data->familyname);
445 heap_free(data);
448 void fontface_detach_from_cache(IDWriteFontFace4 *iface)
450 struct dwrite_fontface *fontface = impl_from_IDWriteFontFace4(iface);
451 fontface->cached = NULL;
454 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace4 *iface, REFIID riid, void **obj)
456 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
458 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
460 if (IsEqualIID(riid, &IID_IDWriteFontFace4) ||
461 IsEqualIID(riid, &IID_IDWriteFontFace3) ||
462 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
463 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
464 IsEqualIID(riid, &IID_IDWriteFontFace) ||
465 IsEqualIID(riid, &IID_IUnknown))
467 *obj = iface;
468 if (InterlockedIncrement(&This->ref) == 1) {
469 InterlockedDecrement(&This->ref);
470 *obj = NULL;
471 return E_FAIL;
473 return S_OK;
476 WARN("%s not implemented.\n", debugstr_guid(riid));
478 *obj = NULL;
479 return E_NOINTERFACE;
482 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace4 *iface)
484 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
485 ULONG ref = InterlockedIncrement(&This->ref);
486 TRACE("(%p)->(%d)\n", This, ref);
487 return ref;
490 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
492 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
493 ULONG ref = InterlockedDecrement(&This->ref);
495 TRACE("(%p)->(%d)\n", This, ref);
497 if (!ref) {
498 UINT32 i;
500 if (This->cached) {
501 factory_lock(This->factory);
502 list_remove(&This->cached->entry);
503 factory_unlock(This->factory);
504 heap_free(This->cached);
507 if (This->cmap.context)
508 IDWriteFontFace4_ReleaseFontTable(iface, This->cmap.context);
509 if (This->vdmx.context)
510 IDWriteFontFace4_ReleaseFontTable(iface, This->vdmx.context);
511 if (This->gasp.context)
512 IDWriteFontFace4_ReleaseFontTable(iface, This->gasp.context);
513 if (This->cpal.context)
514 IDWriteFontFace4_ReleaseFontTable(iface, This->cpal.context);
515 if (This->colr.context)
516 IDWriteFontFace4_ReleaseFontTable(iface, This->colr.context);
517 for (i = 0; i < This->file_count; i++) {
518 if (This->files[i])
519 IDWriteFontFile_Release(This->files[i]);
521 if (This->stream)
522 IDWriteFontFileStream_Release(This->stream);
523 heap_free(This->files);
525 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
526 heap_free(This->glyphs[i]);
528 freetype_notify_cacheremove(iface);
530 IDWriteFactory5_Release(This->factory);
531 heap_free(This);
534 return ref;
537 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace4 *iface)
539 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
540 TRACE("(%p)\n", This);
541 return This->type;
544 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace4 *iface, UINT32 *number_of_files,
545 IDWriteFontFile **fontfiles)
547 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
548 int i;
550 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
551 if (fontfiles == NULL)
553 *number_of_files = This->file_count;
554 return S_OK;
556 if (*number_of_files < This->file_count)
557 return E_INVALIDARG;
559 for (i = 0; i < This->file_count; i++)
561 IDWriteFontFile_AddRef(This->files[i]);
562 fontfiles[i] = This->files[i];
565 return S_OK;
568 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace4 *iface)
570 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
571 TRACE("(%p)\n", This);
572 return This->index;
575 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace4 *iface)
577 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
578 TRACE("(%p)\n", This);
579 return This->simulations;
582 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace4 *iface)
584 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
585 TRACE("(%p)\n", This);
586 return !!(This->flags & FONTFACE_IS_SYMBOL);
589 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS *metrics)
591 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
592 TRACE("(%p)->(%p)\n", This, metrics);
593 memcpy(metrics, &This->metrics, sizeof(*metrics));
596 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface)
598 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
599 TRACE("(%p)\n", This);
600 return freetype_get_glyphcount(iface);
603 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface,
604 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
606 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
607 HRESULT hr;
608 UINT32 i;
610 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
612 if (!glyphs)
613 return E_INVALIDARG;
615 if (is_sideways)
616 FIXME("sideways metrics are not supported.\n");
618 for (i = 0; i < glyph_count; i++) {
619 DWRITE_GLYPH_METRICS metrics;
621 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
622 if (hr != S_OK) {
623 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
624 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
625 if (FAILED(hr))
626 return hr;
628 ret[i] = metrics;
631 return S_OK;
634 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
635 UINT32 count, UINT16 *glyphs)
637 if (!glyphs)
638 return E_INVALIDARG;
640 if (!codepoints) {
641 memset(glyphs, 0, count * sizeof(*glyphs));
642 return E_INVALIDARG;
645 freetype_get_glyphs(&fontface->IDWriteFontFace4_iface, fontface->charmap, codepoints, count, glyphs);
646 return S_OK;
649 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace4 *iface, UINT32 const *codepoints,
650 UINT32 count, UINT16 *glyphs)
652 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
654 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyphs);
656 return fontface_get_glyphs(This, codepoints, count, glyphs);
659 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace4 *iface, UINT32 table_tag,
660 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
662 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
663 struct file_stream_desc stream_desc;
665 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
667 stream_desc.stream = This->stream;
668 stream_desc.face_type = This->type;
669 stream_desc.face_index = This->index;
670 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
673 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace4 *iface, void *table_context)
675 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
677 TRACE("(%p)->(%p)\n", This, table_context);
679 IDWriteFontFileStream_ReleaseFileFragment(This->stream, table_context);
682 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, FLOAT emSize,
683 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
684 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
686 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
688 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
689 count, is_sideways, is_rtl, sink);
691 if (!glyphs || !sink)
692 return E_INVALIDARG;
694 if (is_sideways)
695 FIXME("sideways mode is not supported.\n");
697 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
700 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
701 FLOAT ppem, WORD gasp)
703 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
705 switch (measuring)
707 case DWRITE_MEASURING_MODE_NATURAL:
709 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
710 mode = DWRITE_RENDERING_MODE_NATURAL;
711 else
712 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
713 break;
715 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
716 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
717 break;
718 case DWRITE_MEASURING_MODE_GDI_NATURAL:
719 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
720 break;
721 default:
725 return mode;
728 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
729 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
731 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
732 WORD gasp, *ptr;
733 UINT32 size;
734 FLOAT ppem;
736 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
738 if (!params) {
739 *mode = DWRITE_RENDERING_MODE_DEFAULT;
740 return E_INVALIDARG;
743 *mode = IDWriteRenderingParams_GetRenderingMode(params);
744 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
745 return S_OK;
747 ppem = emSize * ppdip;
749 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
750 *mode = DWRITE_RENDERING_MODE_OUTLINE;
751 return S_OK;
754 ptr = get_fontface_gasp(This, &size);
755 gasp = opentype_get_gasp_flags(ptr, size, ppem);
756 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
757 return S_OK;
760 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT pixels_per_dip,
761 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
763 DWRITE_FONT_METRICS1 metrics1;
764 HRESULT hr = IDWriteFontFace4_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
765 memcpy(metrics, &metrics1, sizeof(*metrics));
766 return hr;
769 static inline int round_metric(FLOAT metric)
771 return (int)floorf(metric + 0.5f);
774 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
776 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
777 return 0;
779 return (fontface->metrics.designUnitsPerEm + 49) / 50;
782 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip,
783 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
784 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
786 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
787 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
788 DWRITE_MEASURING_MODE mode;
789 FLOAT scale, size;
790 HRESULT hr;
791 UINT32 i;
793 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
794 glyph_count, metrics, is_sideways);
796 if (m && memcmp(m, &identity, sizeof(*m)))
797 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
799 size = emSize * ppdip;
800 scale = size / This->metrics.designUnitsPerEm;
801 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
803 for (i = 0; i < glyph_count; i++) {
804 DWRITE_GLYPH_METRICS *ret = metrics + i;
805 DWRITE_GLYPH_METRICS design;
806 BOOL has_contours;
808 hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
809 if (FAILED(hr))
810 return hr;
812 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
813 if (has_contours)
814 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment);
815 else
816 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
818 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
819 SCALE_METRIC(leftSideBearing);
820 SCALE_METRIC(rightSideBearing);
821 SCALE_METRIC(topSideBearing);
822 SCALE_METRIC(advanceHeight);
823 SCALE_METRIC(bottomSideBearing);
824 SCALE_METRIC(verticalOriginY);
825 #undef SCALE_METRIC
828 return S_OK;
831 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS1 *metrics)
833 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
834 TRACE("(%p)->(%p)\n", This, metrics);
835 *metrics = This->metrics;
838 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT em_size, FLOAT pixels_per_dip,
839 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
841 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
842 const DWRITE_FONT_METRICS1 *design = &This->metrics;
843 UINT16 ascent, descent;
844 FLOAT scale;
846 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
848 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
849 memset(metrics, 0, sizeof(*metrics));
850 return E_INVALIDARG;
853 em_size *= pixels_per_dip;
854 if (m && m->m22 != 0.0f)
855 em_size *= fabs(m->m22);
857 scale = em_size / design->designUnitsPerEm;
858 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
859 ascent = round_metric(design->ascent * scale);
860 descent = round_metric(design->descent * scale);
863 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
864 metrics->designUnitsPerEm = design->designUnitsPerEm;
865 metrics->ascent = round_metric(ascent / scale);
866 metrics->descent = round_metric(descent / scale);
868 SCALE_METRIC(lineGap);
869 SCALE_METRIC(capHeight);
870 SCALE_METRIC(xHeight);
871 SCALE_METRIC(underlinePosition);
872 SCALE_METRIC(underlineThickness);
873 SCALE_METRIC(strikethroughPosition);
874 SCALE_METRIC(strikethroughThickness);
875 SCALE_METRIC(glyphBoxLeft);
876 SCALE_METRIC(glyphBoxTop);
877 SCALE_METRIC(glyphBoxRight);
878 SCALE_METRIC(glyphBoxBottom);
879 SCALE_METRIC(subscriptPositionX);
880 SCALE_METRIC(subscriptPositionY);
881 SCALE_METRIC(subscriptSizeX);
882 SCALE_METRIC(subscriptSizeY);
883 SCALE_METRIC(superscriptPositionX);
884 SCALE_METRIC(superscriptPositionY);
885 SCALE_METRIC(superscriptSizeX);
886 SCALE_METRIC(superscriptSizeY);
888 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
889 #undef SCALE_METRIC
891 return S_OK;
894 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace4 *iface, DWRITE_CARET_METRICS *metrics)
896 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
897 TRACE("(%p)->(%p)\n", This, metrics);
898 *metrics = This->caret;
901 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, UINT32 max_count,
902 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
904 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
906 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
908 *count = 0;
909 if (max_count && !ranges)
910 return E_INVALIDARG;
912 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
915 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface)
917 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
918 TRACE("(%p)\n", This);
919 return !!(This->flags & FONTFACE_IS_MONOSPACED);
922 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *iface,
923 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
925 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
926 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
927 UINT32 i;
929 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
931 if (is_sideways)
932 FIXME("sideways mode not supported\n");
934 for (i = 0; i < glyph_count; i++) {
935 BOOL has_contours;
937 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i],
938 DWRITE_MEASURING_MODE_NATURAL, &has_contours);
939 if (has_contours)
940 advances[i] += adjustment;
943 return S_OK;
946 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4 *iface,
947 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
948 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
950 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
951 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
952 DWRITE_MEASURING_MODE mode;
953 UINT32 i;
955 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
956 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
958 if (em_size < 0.0f || ppdip <= 0.0f) {
959 memset(advances, 0, sizeof(*advances) * glyph_count);
960 return E_INVALIDARG;
963 em_size *= ppdip;
964 if (em_size == 0.0f) {
965 memset(advances, 0, sizeof(*advances) * glyph_count);
966 return S_OK;
969 if (m && memcmp(m, &identity, sizeof(*m)))
970 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
972 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
973 for (i = 0; i < glyph_count; i++) {
974 BOOL has_contours;
976 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode, &has_contours);
977 if (has_contours)
978 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size + adjustment);
979 else
980 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
983 return S_OK;
986 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace4 *iface, UINT32 count,
987 const UINT16 *indices, INT32 *adjustments)
989 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
990 UINT32 i;
992 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
994 if (!(indices || adjustments) || !count)
995 return E_INVALIDARG;
997 if (!indices || count == 1) {
998 memset(adjustments, 0, count*sizeof(INT32));
999 return E_INVALIDARG;
1002 if (!(This->flags & FONTFACE_HAS_KERNING_PAIRS)) {
1003 memset(adjustments, 0, count*sizeof(INT32));
1004 return S_OK;
1007 for (i = 0; i < count-1; i++)
1008 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1009 adjustments[count-1] = 0;
1011 return S_OK;
1014 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace4 *iface)
1016 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1017 TRACE("(%p)\n", This);
1018 return !!(This->flags & FONTFACE_HAS_KERNING_PAIRS);
1021 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace4 *iface,
1022 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1023 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1025 DWRITE_GRID_FIT_MODE gridfitmode;
1026 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1027 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1030 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace4 *iface, UINT32 glyph_count,
1031 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1033 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1034 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1035 return E_NOTIMPL;
1038 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace4 *iface)
1040 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1041 TRACE("(%p)\n", This);
1042 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1045 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace4 *iface)
1047 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1048 TRACE("(%p)\n", This);
1049 return get_fontface_cpal(This) && get_fontface_colr(This);
1052 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace4 *iface)
1054 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1055 TRACE("(%p)\n", This);
1056 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1059 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace4 *iface)
1061 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1062 TRACE("(%p)\n", This);
1063 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1066 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace4 *iface, UINT32 palette_index,
1067 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1069 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1070 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1071 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1074 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
1075 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1076 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1077 DWRITE_GRID_FIT_MODE *gridfitmode)
1079 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1080 FLOAT emthreshold;
1081 WORD gasp, *ptr;
1082 UINT32 size;
1084 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1085 measuringmode, params, renderingmode, gridfitmode);
1087 if (m)
1088 FIXME("transform not supported %s\n", debugstr_matrix(m));
1090 if (is_sideways)
1091 FIXME("sideways mode not supported\n");
1093 emSize *= max(dpiX, dpiY) / 96.0f;
1095 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1096 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1097 if (params) {
1098 IDWriteRenderingParams2 *params2;
1099 HRESULT hr;
1101 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1102 if (hr == S_OK) {
1103 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1104 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1105 IDWriteRenderingParams2_Release(params2);
1107 else
1108 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1111 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1113 ptr = get_fontface_gasp(This, &size);
1114 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1116 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1117 if (emSize >= emthreshold)
1118 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1119 else
1120 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1123 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1124 if (emSize >= emthreshold)
1125 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1126 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1127 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1128 else
1129 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1132 return S_OK;
1135 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace4 *iface, IDWriteFontFaceReference **ref)
1137 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1138 FIXME("(%p)->(%p): stub\n", This, ref);
1139 return E_NOTIMPL;
1142 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace4 *iface, DWRITE_PANOSE *panose)
1144 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1145 TRACE("(%p)->(%p)\n", This, panose);
1146 *panose = This->panose;
1149 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace4 *iface)
1151 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1152 TRACE("(%p)\n", This);
1153 return This->weight;
1156 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace4 *iface)
1158 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1159 TRACE("(%p)\n", This);
1160 return This->stretch;
1163 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace4 *iface)
1165 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1166 TRACE("(%p)\n", This);
1167 return This->style;
1170 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1172 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1173 FIXME("(%p)->(%p): stub\n", This, names);
1174 return E_NOTIMPL;
1177 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1179 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1180 FIXME("(%p)->(%p): stub\n", This, names);
1181 return E_NOTIMPL;
1184 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace4 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1185 IDWriteLocalizedStrings **strings, BOOL *exists)
1187 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1188 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1189 return E_NOTIMPL;
1192 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace4 *iface, UINT32 ch)
1194 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1195 UINT16 index;
1197 TRACE("(%p)->(%#x)\n", This, ch);
1199 index = 0;
1200 if (FAILED(fontface_get_glyphs(This, &ch, 1, &index)))
1201 return FALSE;
1203 return index != 0;
1206 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1207 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1208 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1210 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1211 FLOAT emthreshold;
1212 WORD gasp, *ptr;
1213 UINT32 size;
1215 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1216 measuring_mode, params, rendering_mode, gridfit_mode);
1218 if (m)
1219 FIXME("transform not supported %s\n", debugstr_matrix(m));
1221 if (is_sideways)
1222 FIXME("sideways mode not supported\n");
1224 emSize *= max(dpiX, dpiY) / 96.0f;
1226 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1227 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1228 if (params) {
1229 IDWriteRenderingParams3 *params3;
1230 HRESULT hr;
1232 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1233 if (hr == S_OK) {
1234 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1235 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1236 IDWriteRenderingParams3_Release(params3);
1238 else
1239 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1242 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1244 ptr = get_fontface_gasp(This, &size);
1245 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1247 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1248 if (emSize >= emthreshold)
1249 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1250 else
1251 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp);
1254 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1255 if (emSize >= emthreshold)
1256 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1257 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1258 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1259 else
1260 *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1263 return S_OK;
1266 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace4 *iface, UINT32 ch)
1268 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1269 FIXME("(%p)->(0x%x): stub\n", This, ch);
1270 return FALSE;
1273 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace4 *iface, UINT16 glyph)
1275 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1276 FIXME("(%p)->(%u): stub\n", This, glyph);
1277 return FALSE;
1280 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace4 *iface, WCHAR const *text,
1281 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1283 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1284 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1285 return E_NOTIMPL;
1288 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace4 *iface, UINT16 const *glyphs,
1289 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1291 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1292 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1293 return E_NOTIMPL;
1296 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace4 *iface, UINT16 glyph,
1297 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1299 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1300 FIXME("(%p)->(%u %u %u %p): stub\n", This, glyph, ppem_first, ppem_last, formats);
1301 return E_NOTIMPL;
1304 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace4 *iface)
1306 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1308 TRACE("(%p)\n", This);
1310 return This->glyph_image_formats;
1313 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace4 *iface, UINT16 glyph,
1314 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1316 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1317 FIXME("(%p)->(%u %u %d %p %p): stub\n", This, glyph, ppem, format, data, context);
1318 return E_NOTIMPL;
1321 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace4 *iface, void *context)
1323 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1324 FIXME("(%p)->(%p): stub\n", This, context);
1327 static const IDWriteFontFace4Vtbl dwritefontfacevtbl = {
1328 dwritefontface_QueryInterface,
1329 dwritefontface_AddRef,
1330 dwritefontface_Release,
1331 dwritefontface_GetType,
1332 dwritefontface_GetFiles,
1333 dwritefontface_GetIndex,
1334 dwritefontface_GetSimulations,
1335 dwritefontface_IsSymbolFont,
1336 dwritefontface_GetMetrics,
1337 dwritefontface_GetGlyphCount,
1338 dwritefontface_GetDesignGlyphMetrics,
1339 dwritefontface_GetGlyphIndices,
1340 dwritefontface_TryGetFontTable,
1341 dwritefontface_ReleaseFontTable,
1342 dwritefontface_GetGlyphRunOutline,
1343 dwritefontface_GetRecommendedRenderingMode,
1344 dwritefontface_GetGdiCompatibleMetrics,
1345 dwritefontface_GetGdiCompatibleGlyphMetrics,
1346 dwritefontface1_GetMetrics,
1347 dwritefontface1_GetGdiCompatibleMetrics,
1348 dwritefontface1_GetCaretMetrics,
1349 dwritefontface1_GetUnicodeRanges,
1350 dwritefontface1_IsMonospacedFont,
1351 dwritefontface1_GetDesignGlyphAdvances,
1352 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1353 dwritefontface1_GetKerningPairAdjustments,
1354 dwritefontface1_HasKerningPairs,
1355 dwritefontface1_GetRecommendedRenderingMode,
1356 dwritefontface1_GetVerticalGlyphVariants,
1357 dwritefontface1_HasVerticalGlyphVariants,
1358 dwritefontface2_IsColorFont,
1359 dwritefontface2_GetColorPaletteCount,
1360 dwritefontface2_GetPaletteEntryCount,
1361 dwritefontface2_GetPaletteEntries,
1362 dwritefontface2_GetRecommendedRenderingMode,
1363 dwritefontface3_GetFontFaceReference,
1364 dwritefontface3_GetPanose,
1365 dwritefontface3_GetWeight,
1366 dwritefontface3_GetStretch,
1367 dwritefontface3_GetStyle,
1368 dwritefontface3_GetFamilyNames,
1369 dwritefontface3_GetFaceNames,
1370 dwritefontface3_GetInformationalStrings,
1371 dwritefontface3_HasCharacter,
1372 dwritefontface3_GetRecommendedRenderingMode,
1373 dwritefontface3_IsCharacterLocal,
1374 dwritefontface3_IsGlyphLocal,
1375 dwritefontface3_AreCharactersLocal,
1376 dwritefontface3_AreGlyphsLocal,
1377 dwritefontface4_GetGlyphImageFormats_,
1378 dwritefontface4_GetGlyphImageFormats,
1379 dwritefontface4_GetGlyphImageData,
1380 dwritefontface4_ReleaseGlyphImageData
1383 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace4 **fontface)
1385 struct dwrite_font_data *data = font->data;
1386 struct fontface_desc desc;
1387 struct list *cached_list;
1388 HRESULT hr;
1390 *fontface = NULL;
1392 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1393 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1394 if (hr == S_OK)
1395 return hr;
1397 if (FAILED(hr = get_filestream_from_file(data->file, &desc.stream)))
1398 return hr;
1400 desc.factory = font->family->collection->factory;
1401 desc.face_type = data->face_type;
1402 desc.files = &data->file;
1403 desc.files_number = 1;
1404 desc.index = data->face_index;
1405 desc.simulations = data->simulations;
1406 desc.font_data = data;
1407 hr = create_fontface(&desc, cached_list, fontface);
1409 IDWriteFontFileStream_Release(desc.stream);
1410 return hr;
1413 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1415 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1417 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1419 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1420 IsEqualIID(riid, &IID_IDWriteFont2) ||
1421 IsEqualIID(riid, &IID_IDWriteFont1) ||
1422 IsEqualIID(riid, &IID_IDWriteFont) ||
1423 IsEqualIID(riid, &IID_IUnknown))
1425 *obj = iface;
1426 IDWriteFont3_AddRef(iface);
1427 return S_OK;
1430 WARN("%s not implemented.\n", debugstr_guid(riid));
1432 *obj = NULL;
1433 return E_NOINTERFACE;
1436 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1438 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1439 ULONG ref = InterlockedIncrement(&This->ref);
1440 TRACE("(%p)->(%d)\n", This, ref);
1441 return ref;
1444 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1446 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1447 ULONG ref = InterlockedDecrement(&This->ref);
1449 TRACE("(%p)->(%d)\n", This, ref);
1451 if (!ref) {
1452 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1453 release_font_data(This->data);
1454 heap_free(This);
1457 return ref;
1460 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1462 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1463 TRACE("(%p)->(%p)\n", This, family);
1465 *family = (IDWriteFontFamily*)This->family;
1466 IDWriteFontFamily_AddRef(*family);
1467 return S_OK;
1470 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1472 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1473 TRACE("(%p)\n", This);
1474 return This->data->weight;
1477 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1479 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1480 TRACE("(%p)\n", This);
1481 return This->data->stretch;
1484 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1486 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1487 TRACE("(%p)\n", This);
1488 return This->style;
1491 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1493 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1494 IDWriteFontFace4 *fontface;
1495 HRESULT hr;
1496 BOOL ret;
1498 TRACE("(%p)\n", This);
1500 hr = get_fontface_from_font(This, &fontface);
1501 if (FAILED(hr))
1502 return FALSE;
1504 ret = IDWriteFontFace4_IsSymbolFont(fontface);
1505 IDWriteFontFace4_Release(fontface);
1506 return ret;
1509 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1511 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1512 TRACE("(%p)->(%p)\n", This, names);
1513 return clone_localizedstring(This->data->names, names);
1516 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1517 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1519 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1520 struct dwrite_font_data *data = This->data;
1521 HRESULT hr;
1523 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1525 *exists = FALSE;
1526 *strings = NULL;
1528 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1529 return S_OK;
1531 if (!data->info_strings[stringid]) {
1532 IDWriteFontFace4 *fontface;
1533 const void *table_data;
1534 BOOL table_exists;
1535 void *context;
1536 UINT32 size;
1538 hr = get_fontface_from_font(This, &fontface);
1539 if (FAILED(hr))
1540 return hr;
1542 table_exists = FALSE;
1543 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1544 if (FAILED(hr) || !table_exists)
1545 WARN("no NAME table found.\n");
1547 if (table_exists) {
1548 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1549 IDWriteFontFace4_ReleaseFontTable(fontface, context);
1550 if (FAILED(hr) || !data->info_strings[stringid])
1551 return hr;
1553 IDWriteFontFace4_Release(fontface);
1556 hr = clone_localizedstring(data->info_strings[stringid], strings);
1557 if (FAILED(hr))
1558 return hr;
1560 *exists = TRUE;
1561 return S_OK;
1564 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1566 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1567 TRACE("(%p)\n", This);
1568 return This->data->simulations;
1571 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1573 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1575 TRACE("(%p)->(%p)\n", This, metrics);
1576 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1579 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1581 IDWriteFontFace4 *fontface;
1582 UINT16 index;
1583 HRESULT hr;
1585 *exists = FALSE;
1587 hr = get_fontface_from_font(font, &fontface);
1588 if (FAILED(hr))
1589 return hr;
1591 index = 0;
1592 hr = IDWriteFontFace4_GetGlyphIndices(fontface, &ch, 1, &index);
1593 IDWriteFontFace4_Release(fontface);
1594 if (FAILED(hr))
1595 return hr;
1597 *exists = index != 0;
1598 return S_OK;
1601 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1603 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1605 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1607 return font_has_character(This, ch, exists);
1610 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1612 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1613 TRACE("(%p)->(%p)\n", This, fontface);
1614 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1617 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1619 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1620 TRACE("(%p)->(%p)\n", This, metrics);
1621 *metrics = This->data->metrics;
1624 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1626 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1627 TRACE("(%p)->(%p)\n", This, panose);
1628 *panose = This->data->panose;
1631 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1633 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1634 IDWriteFontFace4 *fontface;
1635 HRESULT hr;
1637 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1639 hr = get_fontface_from_font(This, &fontface);
1640 if (FAILED(hr))
1641 return hr;
1643 hr = IDWriteFontFace4_GetUnicodeRanges(fontface, max_count, ranges, count);
1644 IDWriteFontFace4_Release(fontface);
1645 return hr;
1648 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1650 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1651 IDWriteFontFace4 *fontface;
1652 HRESULT hr;
1653 BOOL ret;
1655 TRACE("(%p)\n", This);
1657 hr = get_fontface_from_font(This, &fontface);
1658 if (FAILED(hr))
1659 return FALSE;
1661 ret = IDWriteFontFace4_IsMonospacedFont(fontface);
1662 IDWriteFontFace4_Release(fontface);
1663 return ret;
1666 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1668 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1669 IDWriteFontFace4 *fontface;
1670 HRESULT hr;
1671 BOOL ret;
1673 TRACE("(%p)\n", This);
1675 hr = get_fontface_from_font(This, &fontface);
1676 if (FAILED(hr))
1677 return FALSE;
1679 ret = IDWriteFontFace4_IsColorFont(fontface);
1680 IDWriteFontFace4_Release(fontface);
1681 return ret;
1684 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1686 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1688 TRACE("(%p)->(%p)\n", This, fontface);
1690 return get_fontface_from_font(This, (IDWriteFontFace4 **)fontface);
1693 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1695 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1696 FIXME("(%p)->(%p): stub\n", This, font);
1697 return FALSE;
1700 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1702 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1704 TRACE("(%p)->(%p)\n", This, reference);
1706 return IDWriteFactory5_CreateFontFaceReference_(This->family->collection->factory, This->data->file,
1707 This->data->face_index, This->data->simulations, reference);
1710 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1712 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1713 BOOL ret;
1715 TRACE("(%p)->(%#x)\n", This, ch);
1717 return font_has_character(This, ch, &ret) == S_OK && ret;
1720 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1722 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1723 FIXME("(%p): stub\n", This);
1724 return DWRITE_LOCALITY_LOCAL;
1727 static const IDWriteFont3Vtbl dwritefontvtbl = {
1728 dwritefont_QueryInterface,
1729 dwritefont_AddRef,
1730 dwritefont_Release,
1731 dwritefont_GetFontFamily,
1732 dwritefont_GetWeight,
1733 dwritefont_GetStretch,
1734 dwritefont_GetStyle,
1735 dwritefont_IsSymbolFont,
1736 dwritefont_GetFaceNames,
1737 dwritefont_GetInformationalStrings,
1738 dwritefont_GetSimulations,
1739 dwritefont_GetMetrics,
1740 dwritefont_HasCharacter,
1741 dwritefont_CreateFontFace,
1742 dwritefont1_GetMetrics,
1743 dwritefont1_GetPanose,
1744 dwritefont1_GetUnicodeRanges,
1745 dwritefont1_IsMonospacedFont,
1746 dwritefont2_IsColorFont,
1747 dwritefont3_CreateFontFace,
1748 dwritefont3_Equals,
1749 dwritefont3_GetFontFaceReference,
1750 dwritefont3_HasCharacter,
1751 dwritefont3_GetLocality
1754 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1756 if (!iface)
1757 return NULL;
1758 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1759 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1762 static struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1764 if (!iface)
1765 return NULL;
1766 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1767 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
1770 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1772 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1773 *lf = font->data->lf;
1776 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1778 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1779 *lf = fontface->lf;
1782 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
1784 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1785 *fontsig = font->data->fontsig;
1786 return S_OK;
1789 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
1791 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1792 *fontsig = fontface->fontsig;
1793 return S_OK;
1796 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1798 struct dwrite_font *This;
1800 *font = NULL;
1802 This = heap_alloc(sizeof(*This));
1803 if (!This)
1804 return E_OUTOFMEMORY;
1806 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1807 This->ref = 1;
1808 This->family = family;
1809 IDWriteFontFamily1_AddRef(&family->IDWriteFontFamily1_iface);
1810 This->data = family->data->fonts[index];
1811 This->style = This->data->style;
1812 addref_font_data(This->data);
1814 *font = &This->IDWriteFont3_iface;
1816 return S_OK;
1819 /* IDWriteFontList1 */
1820 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1822 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1824 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1826 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1827 IsEqualIID(riid, &IID_IDWriteFontList) ||
1828 IsEqualIID(riid, &IID_IUnknown))
1830 *obj = iface;
1831 IDWriteFontList1_AddRef(iface);
1832 return S_OK;
1835 WARN("%s not implemented.\n", debugstr_guid(riid));
1837 *obj = NULL;
1838 return E_NOINTERFACE;
1841 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1843 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1844 ULONG ref = InterlockedIncrement(&This->ref);
1845 TRACE("(%p)->(%d)\n", This, ref);
1846 return ref;
1849 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1851 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1852 ULONG ref = InterlockedDecrement(&This->ref);
1854 TRACE("(%p)->(%d)\n", This, ref);
1856 if (!ref) {
1857 UINT32 i;
1859 for (i = 0; i < This->font_count; i++)
1860 release_font_data(This->fonts[i]);
1861 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1862 heap_free(This->fonts);
1863 heap_free(This);
1866 return ref;
1869 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1871 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1872 return IDWriteFontFamily1_GetFontCollection(&This->family->IDWriteFontFamily1_iface, collection);
1875 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1877 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1878 TRACE("(%p)\n", This);
1879 return This->font_count;
1882 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1884 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1886 TRACE("(%p)->(%u %p)\n", This, index, font);
1888 *font = NULL;
1890 if (This->font_count == 0)
1891 return S_FALSE;
1893 if (index >= This->font_count)
1894 return E_INVALIDARG;
1896 return create_font(This->family, index, (IDWriteFont3 **)font);
1899 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1901 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1903 FIXME("(%p)->(%u): stub\n", This, index);
1905 return DWRITE_LOCALITY_LOCAL;
1908 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1910 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1912 TRACE("(%p)->(%u %p)\n", This, index, font);
1914 *font = NULL;
1916 if (This->font_count == 0)
1917 return S_FALSE;
1919 if (index >= This->font_count)
1920 return E_FAIL;
1922 return create_font(This->family, index, font);
1925 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1926 IDWriteFontFaceReference **reference)
1928 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1929 IDWriteFont3 *font;
1930 HRESULT hr;
1932 TRACE("(%p)->(%u %p)\n", This, index, reference);
1934 *reference = NULL;
1936 hr = IDWriteFontList1_GetFont(iface, index, &font);
1937 if (FAILED(hr))
1938 return hr;
1940 hr = IDWriteFont3_GetFontFaceReference(font, reference);
1941 IDWriteFont3_Release(font);
1943 return hr;
1946 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1947 dwritefontlist_QueryInterface,
1948 dwritefontlist_AddRef,
1949 dwritefontlist_Release,
1950 dwritefontlist_GetFontCollection,
1951 dwritefontlist_GetFontCount,
1952 dwritefontlist_GetFont,
1953 dwritefontlist1_GetFontLocality,
1954 dwritefontlist1_GetFont,
1955 dwritefontlist1_GetFontFaceReference
1958 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1960 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1962 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1964 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1965 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1966 IsEqualIID(riid, &IID_IDWriteFontList) ||
1967 IsEqualIID(riid, &IID_IUnknown))
1969 *obj = iface;
1970 IDWriteFontFamily1_AddRef(iface);
1971 return S_OK;
1974 WARN("%s not implemented.\n", debugstr_guid(riid));
1976 *obj = NULL;
1977 return E_NOINTERFACE;
1980 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1982 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1983 ULONG ref = InterlockedIncrement(&This->ref);
1984 TRACE("(%p)->(%d)\n", This, ref);
1985 return ref;
1988 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1990 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1991 ULONG ref = InterlockedDecrement(&This->ref);
1993 TRACE("(%p)->(%d)\n", This, ref);
1995 if (!ref)
1997 IDWriteFontCollection1_Release(&This->collection->IDWriteFontCollection1_iface);
1998 release_fontfamily_data(This->data);
1999 heap_free(This);
2002 return ref;
2005 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
2007 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2009 TRACE("(%p)->(%p)\n", This, collection);
2011 *collection = (IDWriteFontCollection*)This->collection;
2012 IDWriteFontCollection_AddRef(*collection);
2013 return S_OK;
2016 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
2018 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2019 TRACE("(%p)\n", This);
2020 return This->data->font_count;
2023 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
2025 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2027 TRACE("(%p)->(%u %p)\n", This, index, font);
2029 *font = NULL;
2031 if (This->data->font_count == 0)
2032 return S_FALSE;
2034 if (index >= This->data->font_count)
2035 return E_INVALIDARG;
2037 return create_font(This, index, (IDWriteFont3 **)font);
2040 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
2042 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2043 return clone_localizedstring(This->data->familyname, names);
2046 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2047 const struct dwrite_font_propvec *req)
2049 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2050 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2051 FLOAT cur_req_prod, next_req_prod;
2053 if (next_to_req < cur_to_req)
2054 return TRUE;
2056 if (next_to_req > cur_to_req)
2057 return FALSE;
2059 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2060 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2062 if (next_req_prod > cur_req_prod)
2063 return TRUE;
2065 if (next_req_prod < cur_req_prod)
2066 return FALSE;
2068 if (next->stretch > cur->stretch)
2069 return TRUE;
2070 if (next->stretch < cur->stretch)
2071 return FALSE;
2073 if (next->style > cur->style)
2074 return TRUE;
2075 if (next->style < cur->style)
2076 return FALSE;
2078 if (next->weight > cur->weight)
2079 return TRUE;
2080 if (next->weight < cur->weight)
2081 return FALSE;
2083 /* full match, no reason to prefer new variant */
2084 return FALSE;
2087 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2088 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2090 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2091 struct dwrite_font_propvec req;
2092 UINT32 i, match;
2094 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
2096 if (This->data->font_count == 0) {
2097 *font = NULL;
2098 return DWRITE_E_NOFONT;
2101 init_font_prop_vec(weight, stretch, style, &req);
2102 match = 0;
2104 for (i = 1; i < This->data->font_count; i++) {
2105 if (is_better_font_match(&This->data->fonts[i]->propvec, &This->data->fonts[match]->propvec, &req))
2106 match = i;
2109 return create_font(This, match, (IDWriteFont3 **)font);
2112 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2114 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2116 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2119 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2121 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2124 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2126 UINT32 b = fonts->font_count - 1, j, t;
2128 while (1) {
2129 t = b;
2131 for (j = 0; j < b; j++) {
2132 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2133 struct dwrite_font_data *s = fonts->fonts[j];
2134 fonts->fonts[j] = fonts->fonts[j+1];
2135 fonts->fonts[j+1] = s;
2136 t = j;
2140 if (t == b)
2141 break;
2142 b = t;
2146 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2147 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2149 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2150 matching_filter_func func = NULL;
2151 struct dwrite_font_propvec req;
2152 struct dwrite_fontlist *fonts;
2153 UINT32 i;
2155 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
2157 *ret = NULL;
2159 fonts = heap_alloc(sizeof(*fonts));
2160 if (!fonts)
2161 return E_OUTOFMEMORY;
2163 /* Allocate as many as family has, not all of them will be necessary used. */
2164 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
2165 if (!fonts->fonts) {
2166 heap_free(fonts);
2167 return E_OUTOFMEMORY;
2170 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2171 fonts->ref = 1;
2172 fonts->family = This;
2173 IDWriteFontFamily1_AddRef(&fonts->family->IDWriteFontFamily1_iface);
2174 fonts->font_count = 0;
2176 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2177 if (style == DWRITE_FONT_STYLE_NORMAL) {
2178 if (This->data->has_normal_face || This->data->has_italic_face)
2179 func = is_font_acceptable_for_normal;
2181 else /* requested oblique or italic */ {
2182 if (This->data->has_oblique_face || This->data->has_italic_face)
2183 func = is_font_acceptable_for_oblique_italic;
2186 for (i = 0; i < This->data->font_count; i++) {
2187 if (!func || func(This->data->fonts[i])) {
2188 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2189 addref_font_data(This->data->fonts[i]);
2190 fonts->font_count++;
2194 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2195 init_font_prop_vec(weight, stretch, style, &req);
2196 matchingfonts_sort(fonts, &req);
2198 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2199 return S_OK;
2202 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2204 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2206 FIXME("(%p)->(%u): stub\n", This, index);
2208 return DWRITE_LOCALITY_LOCAL;
2211 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2213 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2215 TRACE("(%p)->(%u %p)\n", This, index, font);
2217 *font = NULL;
2219 if (This->data->font_count == 0)
2220 return S_FALSE;
2222 if (index >= This->data->font_count)
2223 return E_FAIL;
2225 return create_font(This, index, font);
2228 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2229 IDWriteFontFaceReference **reference)
2231 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2232 IDWriteFont3 *font;
2233 HRESULT hr;
2235 TRACE("(%p)->(%u %p)\n", This, index, reference);
2237 *reference = NULL;
2239 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2240 if (FAILED(hr))
2241 return hr;
2243 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2244 IDWriteFont3_Release(font);
2246 return hr;
2249 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2250 dwritefontfamily_QueryInterface,
2251 dwritefontfamily_AddRef,
2252 dwritefontfamily_Release,
2253 dwritefontfamily_GetFontCollection,
2254 dwritefontfamily_GetFontCount,
2255 dwritefontfamily_GetFont,
2256 dwritefontfamily_GetFamilyNames,
2257 dwritefontfamily_GetFirstMatchingFont,
2258 dwritefontfamily_GetMatchingFonts,
2259 dwritefontfamily1_GetFontLocality,
2260 dwritefontfamily1_GetFont,
2261 dwritefontfamily1_GetFontFaceReference
2264 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index, IDWriteFontFamily1 **family)
2266 struct dwrite_fontfamily *This;
2268 *family = NULL;
2270 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2271 if (!This) return E_OUTOFMEMORY;
2273 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2274 This->ref = 1;
2275 This->collection = collection;
2276 IDWriteFontCollection1_AddRef(&collection->IDWriteFontCollection1_iface);
2277 This->data = collection->family_data[index];
2278 InterlockedIncrement(&This->data->ref);
2280 *family = &This->IDWriteFontFamily1_iface;
2282 return S_OK;
2285 BOOL is_system_collection(IDWriteFontCollection *collection)
2287 void *obj;
2288 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2291 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2293 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2294 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2296 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2297 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2298 IsEqualIID(riid, &IID_IUnknown))
2300 *obj = iface;
2301 IDWriteFontCollection1_AddRef(iface);
2302 return S_OK;
2305 *obj = NULL;
2307 if (IsEqualIID(riid, &IID_issystemcollection))
2308 return S_OK;
2310 WARN("%s not implemented.\n", debugstr_guid(riid));
2312 return E_NOINTERFACE;
2315 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2317 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2318 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2320 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2321 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2322 IsEqualIID(riid, &IID_IUnknown))
2324 *obj = iface;
2325 IDWriteFontCollection1_AddRef(iface);
2326 return S_OK;
2329 WARN("%s not implemented.\n", debugstr_guid(riid));
2331 *obj = NULL;
2333 return E_NOINTERFACE;
2336 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2338 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2339 ULONG ref = InterlockedIncrement(&This->ref);
2340 TRACE("(%p)->(%d)\n", This, ref);
2341 return ref;
2344 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2346 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2347 ULONG ref = InterlockedDecrement(&This->ref);
2349 TRACE("(%p)->(%d)\n", This, ref);
2351 if (!ref) {
2352 int i;
2354 factory_detach_fontcollection(This->factory, iface);
2355 for (i = 0; i < This->family_count; i++)
2356 release_fontfamily_data(This->family_data[i]);
2357 heap_free(This->family_data);
2358 heap_free(This);
2361 return ref;
2364 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2366 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2367 TRACE("(%p)\n", This);
2368 return This->family_count;
2371 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2373 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2375 TRACE("(%p)->(%u %p)\n", This, index, family);
2377 if (index >= This->family_count) {
2378 *family = NULL;
2379 return E_FAIL;
2382 return create_fontfamily(This, index, (IDWriteFontFamily1 **)family);
2385 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2387 UINT32 i;
2389 for (i = 0; i < collection->family_count; i++) {
2390 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2391 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2392 HRESULT hr;
2394 for (j = 0; j < count; j++) {
2395 WCHAR buffer[255];
2396 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2397 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2398 return i;
2402 return ~0u;
2405 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2407 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2408 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2409 *index = collection_find_family(This, name);
2410 *exists = *index != ~0u;
2411 return S_OK;
2414 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2416 UINT32 left_key_size, right_key_size;
2417 const void *left_key, *right_key;
2418 HRESULT hr;
2420 if (left == right)
2421 return TRUE;
2423 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2424 if (FAILED(hr))
2425 return FALSE;
2427 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2428 if (FAILED(hr))
2429 return FALSE;
2431 if (left_key_size != right_key_size)
2432 return FALSE;
2434 return !memcmp(left_key, right_key, left_key_size);
2437 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2439 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2440 IDWriteFontFamily1 *family;
2441 UINT32 i, j, face_index;
2442 BOOL found_font = FALSE;
2443 IDWriteFontFile *file;
2444 HRESULT hr;
2446 TRACE("(%p)->(%p %p)\n", This, face, font);
2448 *font = NULL;
2450 if (!face)
2451 return E_INVALIDARG;
2453 i = 1;
2454 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2455 if (FAILED(hr))
2456 return hr;
2457 face_index = IDWriteFontFace_GetIndex(face);
2459 found_font = FALSE;
2460 for (i = 0; i < This->family_count; i++) {
2461 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2463 for (j = 0; j < family_data->font_count; j++) {
2464 struct dwrite_font_data *font_data = family_data->fonts[j];
2466 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2467 found_font = TRUE;
2468 break;
2472 if (found_font)
2473 break;
2475 IDWriteFontFile_Release(file);
2477 if (!found_font)
2478 return DWRITE_E_NOFONT;
2480 hr = create_fontfamily(This, i, &family);
2481 if (FAILED(hr))
2482 return hr;
2484 hr = create_font(impl_from_IDWriteFontFamily1(family), j, (IDWriteFont3 **)font);
2485 IDWriteFontFamily1_Release(family);
2486 return hr;
2489 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2491 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2493 FIXME("(%p)->(%p): stub\n", This, fontset);
2495 return E_NOTIMPL;
2498 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2500 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2502 TRACE("(%p)->(%u %p)\n", This, index, family);
2504 if (index >= This->family_count) {
2505 *family = NULL;
2506 return E_FAIL;
2509 return create_fontfamily(This, index, family);
2512 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2513 dwritefontcollection_QueryInterface,
2514 dwritefontcollection_AddRef,
2515 dwritefontcollection_Release,
2516 dwritefontcollection_GetFontFamilyCount,
2517 dwritefontcollection_GetFontFamily,
2518 dwritefontcollection_FindFamilyName,
2519 dwritefontcollection_GetFontFromFontFace,
2520 dwritefontcollection1_GetFontSet,
2521 dwritefontcollection1_GetFontFamily
2524 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2525 dwritesystemfontcollection_QueryInterface,
2526 dwritefontcollection_AddRef,
2527 dwritefontcollection_Release,
2528 dwritefontcollection_GetFontFamilyCount,
2529 dwritefontcollection_GetFontFamily,
2530 dwritefontcollection_FindFamilyName,
2531 dwritefontcollection_GetFontFromFontFace,
2532 dwritefontcollection1_GetFontSet,
2533 dwritefontcollection1_GetFontFamily
2536 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2538 if (family_data->font_count + 1 >= family_data->font_alloc) {
2539 struct dwrite_font_data **new_list;
2540 UINT32 new_alloc;
2542 new_alloc = family_data->font_alloc * 2;
2543 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2544 if (!new_list)
2545 return E_OUTOFMEMORY;
2546 family_data->fonts = new_list;
2547 family_data->font_alloc = new_alloc;
2550 family_data->fonts[family_data->font_count] = font_data;
2551 family_data->font_count++;
2552 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2553 family_data->has_normal_face = 1;
2554 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2555 family_data->has_oblique_face = 1;
2556 else
2557 family_data->has_italic_face = 1;
2558 return S_OK;
2561 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2563 if (collection->family_alloc < collection->family_count + 1) {
2564 struct dwrite_fontfamily_data **new_list;
2565 UINT32 new_alloc;
2567 new_alloc = collection->family_alloc * 2;
2568 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2569 if (!new_list)
2570 return E_OUTOFMEMORY;
2572 collection->family_alloc = new_alloc;
2573 collection->family_data = new_list;
2576 collection->family_data[collection->family_count++] = family;
2577 return S_OK;
2580 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2582 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2583 collection->ref = 1;
2584 collection->family_count = 0;
2585 collection->family_alloc = is_system ? 30 : 5;
2586 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2587 if (!collection->family_data)
2588 return E_OUTOFMEMORY;
2590 return S_OK;
2593 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2595 IDWriteFontFileLoader *loader;
2596 const void *key;
2597 UINT32 key_size;
2598 HRESULT hr;
2600 *stream = NULL;
2602 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2603 if (FAILED(hr))
2604 return hr;
2606 hr = IDWriteFontFile_GetLoader(file, &loader);
2607 if (FAILED(hr))
2608 return hr;
2610 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2611 IDWriteFontFileLoader_Release(loader);
2612 if (FAILED(hr))
2613 return hr;
2615 return hr;
2618 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2620 BOOL exists = FALSE;
2621 UINT32 index;
2622 HRESULT hr;
2624 buffer[0] = 0;
2625 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2626 if (FAILED(hr) || !exists)
2627 return;
2629 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2632 static int trim_spaces(WCHAR *in, WCHAR *ret)
2634 int len;
2636 while (isspaceW(*in))
2637 in++;
2639 ret[0] = 0;
2640 if (!(len = strlenW(in)))
2641 return 0;
2643 while (isspaceW(in[len-1]))
2644 len--;
2646 memcpy(ret, in, len*sizeof(WCHAR));
2647 ret[len] = 0;
2649 return len;
2652 struct name_token {
2653 struct list entry;
2654 const WCHAR *ptr;
2655 INT len; /* token length */
2656 INT fulllen; /* full length including following separators */
2659 static inline BOOL is_name_separator_char(WCHAR ch)
2661 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2664 struct name_pattern {
2665 const WCHAR *part1; /* NULL indicates end of list */
2666 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2669 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2671 const struct name_pattern *pattern;
2672 struct name_token *token;
2673 int i = 0;
2675 while ((pattern = &patterns[i++])->part1) {
2676 int len_part1 = strlenW(pattern->part1);
2677 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2679 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2680 if (len_part2 == 0) {
2681 /* simple case with single part pattern */
2682 if (token->len != len_part1)
2683 continue;
2685 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2686 if (match) *match = *token;
2687 list_remove(&token->entry);
2688 heap_free(token);
2689 return TRUE;
2692 else {
2693 struct name_token *next_token;
2694 struct list *next_entry;
2696 /* pattern parts are stored in reading order, tokens list is reversed */
2697 if (token->len < len_part2)
2698 continue;
2700 /* it's possible to have combined string as a token, like ExtraCondensed */
2701 if (token->len == len_part1 + len_part2) {
2702 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2703 continue;
2705 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2706 continue;
2708 /* combined string match */
2709 if (match) *match = *token;
2710 list_remove(&token->entry);
2711 heap_free(token);
2712 return TRUE;
2715 /* now it's only possible to have two tokens matched to respective pattern parts */
2716 if (token->len != len_part2)
2717 continue;
2719 next_entry = list_next(tokens, &token->entry);
2720 if (next_entry) {
2721 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2722 if (next_token->len != len_part1)
2723 continue;
2725 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2726 continue;
2728 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2729 continue;
2731 /* both parts matched, remove tokens */
2732 if (match) {
2733 match->ptr = next_token->ptr;
2734 match->len = (token->ptr - next_token->ptr) + token->len;
2736 list_remove(&token->entry);
2737 list_remove(&next_token->entry);
2738 heap_free(next_token);
2739 heap_free(token);
2740 return TRUE;
2746 if (match) {
2747 match->ptr = NULL;
2748 match->len = 0;
2750 return FALSE;
2753 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2755 static const WCHAR itaW[] = {'i','t','a',0};
2756 static const WCHAR italW[] = {'i','t','a','l',0};
2757 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2758 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2760 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2761 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2762 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2763 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2765 static const struct name_pattern italic_patterns[] = {
2766 { itaW },
2767 { italW },
2768 { italicW },
2769 { cursiveW },
2770 { kursivW },
2771 { NULL }
2774 static const struct name_pattern oblique_patterns[] = {
2775 { inclinedW },
2776 { obliqueW },
2777 { backslantedW },
2778 { backslantW },
2779 { slantedW },
2780 { NULL }
2783 /* italic patterns first */
2784 if (match_pattern_list(tokens, italic_patterns, match))
2785 return DWRITE_FONT_STYLE_ITALIC;
2787 /* oblique patterns */
2788 if (match_pattern_list(tokens, oblique_patterns, match))
2789 return DWRITE_FONT_STYLE_OBLIQUE;
2791 return style;
2794 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2795 struct name_token *match)
2797 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2798 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2799 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2800 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2801 static const WCHAR wideW[] = {'w','i','d','e',0};
2802 static const WCHAR condW[] = {'c','o','n','d',0};
2804 static const struct name_pattern ultracondensed_patterns[] = {
2805 { extraW, compressedW },
2806 { extW, compressedW },
2807 { ultraW, compressedW },
2808 { ultraW, condensedW },
2809 { ultraW, condW },
2810 { NULL }
2813 static const struct name_pattern extracondensed_patterns[] = {
2814 { compressedW },
2815 { extraW, condensedW },
2816 { extW, condensedW },
2817 { extraW, condW },
2818 { extW, condW },
2819 { NULL }
2822 static const struct name_pattern semicondensed_patterns[] = {
2823 { narrowW },
2824 { compactW },
2825 { semiW, condensedW },
2826 { semiW, condW },
2827 { NULL }
2830 static const struct name_pattern semiexpanded_patterns[] = {
2831 { wideW },
2832 { semiW, expandedW },
2833 { semiW, extendedW },
2834 { NULL }
2837 static const struct name_pattern extraexpanded_patterns[] = {
2838 { extraW, expandedW },
2839 { extW, expandedW },
2840 { extraW, extendedW },
2841 { extW, extendedW },
2842 { NULL }
2845 static const struct name_pattern ultraexpanded_patterns[] = {
2846 { ultraW, expandedW },
2847 { ultraW, extendedW },
2848 { NULL }
2851 static const struct name_pattern condensed_patterns[] = {
2852 { condensedW },
2853 { condW },
2854 { NULL }
2857 static const struct name_pattern expanded_patterns[] = {
2858 { expandedW },
2859 { extendedW },
2860 { NULL }
2863 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2864 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2866 if (match_pattern_list(tokens, extracondensed_patterns, match))
2867 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2869 if (match_pattern_list(tokens, semicondensed_patterns, match))
2870 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2872 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2873 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2875 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2876 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2878 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2879 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2881 if (match_pattern_list(tokens, condensed_patterns, match))
2882 return DWRITE_FONT_STRETCH_CONDENSED;
2884 if (match_pattern_list(tokens, expanded_patterns, match))
2885 return DWRITE_FONT_STRETCH_EXPANDED;
2887 return stretch;
2890 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2891 struct name_token *match)
2893 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2894 static const WCHAR nordW[] = {'n','o','r','d',0};
2896 static const struct name_pattern thin_patterns[] = {
2897 { extraW, thinW },
2898 { extW, thinW },
2899 { ultraW, thinW },
2900 { NULL }
2903 static const struct name_pattern extralight_patterns[] = {
2904 { extraW, lightW },
2905 { extW, lightW },
2906 { ultraW, lightW },
2907 { NULL }
2910 static const struct name_pattern semilight_patterns[] = {
2911 { semiW, lightW },
2912 { NULL }
2915 static const struct name_pattern demibold_patterns[] = {
2916 { semiW, boldW },
2917 { demiW, boldW },
2918 { NULL }
2921 static const struct name_pattern extrabold_patterns[] = {
2922 { extraW, boldW },
2923 { extW, boldW },
2924 { ultraW, boldW },
2925 { NULL }
2928 static const struct name_pattern extrablack_patterns[] = {
2929 { extraW, blackW },
2930 { extW, blackW },
2931 { ultraW, blackW },
2932 { NULL }
2935 static const struct name_pattern bold_patterns[] = {
2936 { boldW },
2937 { NULL }
2940 static const struct name_pattern thin2_patterns[] = {
2941 { thinW },
2942 { NULL }
2945 static const struct name_pattern light_patterns[] = {
2946 { lightW },
2947 { NULL }
2950 static const struct name_pattern medium_patterns[] = {
2951 { mediumW },
2952 { NULL }
2955 static const struct name_pattern black_patterns[] = {
2956 { blackW },
2957 { heavyW },
2958 { nordW },
2959 { NULL }
2962 static const struct name_pattern demibold2_patterns[] = {
2963 { demiW },
2964 { NULL }
2967 static const struct name_pattern extrabold2_patterns[] = {
2968 { ultraW },
2969 { NULL }
2972 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2973 matching pattern. */
2975 if (match_pattern_list(tokens, thin_patterns, match))
2976 return DWRITE_FONT_WEIGHT_THIN;
2978 if (match_pattern_list(tokens, extralight_patterns, match))
2979 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2981 if (match_pattern_list(tokens, semilight_patterns, match))
2982 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2984 if (match_pattern_list(tokens, demibold_patterns, match))
2985 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2987 if (match_pattern_list(tokens, extrabold_patterns, match))
2988 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2990 if (match_pattern_list(tokens, extrablack_patterns, match))
2991 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2993 if (match_pattern_list(tokens, bold_patterns, match))
2994 return DWRITE_FONT_WEIGHT_BOLD;
2996 if (match_pattern_list(tokens, thin2_patterns, match))
2997 return DWRITE_FONT_WEIGHT_THIN;
2999 if (match_pattern_list(tokens, light_patterns, match))
3000 return DWRITE_FONT_WEIGHT_LIGHT;
3002 if (match_pattern_list(tokens, medium_patterns, match))
3003 return DWRITE_FONT_WEIGHT_MEDIUM;
3005 if (match_pattern_list(tokens, black_patterns, match))
3006 return DWRITE_FONT_WEIGHT_BLACK;
3008 if (match_pattern_list(tokens, black_patterns, match))
3009 return DWRITE_FONT_WEIGHT_BLACK;
3011 if (match_pattern_list(tokens, demibold2_patterns, match))
3012 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3014 if (match_pattern_list(tokens, extrabold2_patterns, match))
3015 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3017 /* FIXME: use abbreviated names to extract weight */
3019 return weight;
3022 struct knownweight_entry {
3023 const WCHAR *nameW;
3024 DWRITE_FONT_WEIGHT weight;
3027 static int compare_knownweights(const void *a, const void* b)
3029 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3030 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3031 int ret = 0;
3033 if (target > entry->weight)
3034 ret = 1;
3035 else if (target < entry->weight)
3036 ret = -1;
3038 return ret;
3041 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3043 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3044 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3045 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3046 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3047 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3048 const struct knownweight_entry *ptr;
3050 static const struct knownweight_entry knownweights[] = {
3051 { thinW, DWRITE_FONT_WEIGHT_THIN },
3052 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3053 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3054 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3055 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3056 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3057 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3058 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3059 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3060 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3063 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
3064 compare_knownweights);
3065 if (!ptr) {
3066 nameW[0] = 0;
3067 return FALSE;
3070 strcpyW(nameW, ptr->nameW);
3071 return TRUE;
3074 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3076 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3077 strW[name->len] = 0;
3080 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3081 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3083 static const WCHAR bookW[] = {'B','o','o','k',0};
3084 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3085 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3086 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3087 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3089 static const WCHAR *regular_patterns[] = {
3090 bookW,
3091 normalW,
3092 regularW,
3093 romanW,
3094 uprightW,
3095 NULL
3098 const WCHAR *regular_ptr = NULL, *ptr;
3099 int i = 0;
3101 if (len == -1)
3102 len = strlenW(facenameW);
3104 /* remove rightmost regular variant from face name */
3105 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3106 int pattern_len = strlenW(ptr);
3107 WCHAR *src;
3109 if (pattern_len > len)
3110 continue;
3112 src = facenameW + len - pattern_len;
3113 while (src >= facenameW) {
3114 if (!strncmpiW(src, ptr, pattern_len)) {
3115 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3116 len = strlenW(facenameW);
3117 regular_ptr = ptr;
3118 break;
3120 else
3121 src--;
3125 return regular_ptr;
3128 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3130 const WCHAR *ptr;
3132 list_init(tokens);
3133 ptr = nameW;
3135 while (*ptr) {
3136 struct name_token *token = heap_alloc(sizeof(*token));
3137 token->ptr = ptr;
3138 token->len = 0;
3139 token->fulllen = 0;
3141 while (*ptr && !is_name_separator_char(*ptr)) {
3142 token->len++;
3143 token->fulllen++;
3144 ptr++;
3147 /* skip separators */
3148 while (is_name_separator_char(*ptr)) {
3149 token->fulllen++;
3150 ptr++;
3153 list_add_head(tokens, &token->entry);
3157 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3159 struct name_token *token, *token2;
3160 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3161 int len;
3163 list_remove(&token->entry);
3165 /* don't include last separator */
3166 len = list_empty(tokens) ? token->len : token->fulllen;
3167 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3168 nameW += len;
3170 heap_free(token);
3172 *nameW = 0;
3175 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3177 struct name_token stretch_name, weight_name, style_name;
3178 WCHAR familynameW[255], facenameW[255], finalW[255];
3179 WCHAR weightW[32], stretchW[32], styleW[32];
3180 const WCHAR *regular_ptr = NULL;
3181 DWRITE_FONT_STRETCH stretch;
3182 DWRITE_FONT_WEIGHT weight;
3183 struct list tokens;
3184 int len;
3186 /* remove leading and trailing spaces from family and face name */
3187 trim_spaces(familyW, familynameW);
3188 len = trim_spaces(faceW, facenameW);
3190 /* remove rightmost regular variant from face name */
3191 regular_ptr = facename_remove_regular_term(facenameW, len);
3193 /* append face name to family name, FIXME check if face name is a substring of family name */
3194 if (*facenameW) {
3195 strcatW(familynameW, spaceW);
3196 strcatW(familynameW, facenameW);
3199 /* tokenize with " .-_" */
3200 fontname_tokenize(&tokens, familynameW);
3202 /* extract and resolve style */
3203 font->style = font_extract_style(&tokens, font->style, &style_name);
3205 /* extract stretch */
3206 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3208 /* extract weight */
3209 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3211 /* resolve weight */
3212 if (weight != font->weight) {
3213 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3214 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3215 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3216 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3217 !(abs(weight - font->weight) <= 150 &&
3218 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3219 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3220 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3222 font->weight = weight;
3226 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3227 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3228 stretch itself is normal (extracted stretch is never normal). */
3229 if (stretch != font->stretch) {
3230 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3231 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3232 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3234 font->stretch = stretch;
3238 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3240 /* get final combined string from what's left in token list, list is released */
3241 fontname_tokens_to_str(&tokens, finalW);
3243 if (!strcmpW(familyW, finalW))
3244 return FALSE;
3246 /* construct face name */
3247 strcpyW(familyW, finalW);
3249 /* resolved weight name */
3250 if (weight_name.ptr)
3251 font_name_token_to_str(&weight_name, weightW);
3252 /* ignore normal weight */
3253 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3254 weightW[0] = 0;
3255 /* for known weight values use appropriate names */
3256 else if (is_known_weight_value(font->weight, weightW)) {
3258 /* use Wnnn format as a fallback in case weight is not one of known values */
3259 else {
3260 static const WCHAR fmtW[] = {'W','%','d',0};
3261 sprintfW(weightW, fmtW, font->weight);
3264 /* resolved stretch name */
3265 if (stretch_name.ptr)
3266 font_name_token_to_str(&stretch_name, stretchW);
3267 /* ignore normal stretch */
3268 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3269 stretchW[0] = 0;
3270 /* use predefined stretch names */
3271 else {
3272 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3273 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3274 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3275 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3276 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3277 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3279 static const WCHAR *stretchnamesW[] = {
3280 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3281 ultracondensedW,
3282 extracondensedW,
3283 condensedW,
3284 semicondensedW,
3285 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3286 semiexpandedW,
3287 expandedW,
3288 extraexpandedW,
3289 ultraexpandedW
3291 strcpyW(stretchW, stretchnamesW[font->stretch]);
3294 /* resolved style name */
3295 if (style_name.ptr)
3296 font_name_token_to_str(&style_name, styleW);
3297 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3298 styleW[0] = 0;
3299 /* use predefined names */
3300 else {
3301 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3302 strcpyW(styleW, italicW);
3303 else
3304 strcpyW(styleW, obliqueW);
3307 /* use Regular match if it was found initially */
3308 if (!*weightW && !*stretchW && !*styleW)
3309 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3310 else {
3311 faceW[0] = 0;
3312 if (*stretchW)
3313 strcpyW(faceW, stretchW);
3314 if (*weightW) {
3315 if (*faceW)
3316 strcatW(faceW, spaceW);
3317 strcatW(faceW, weightW);
3319 if (*styleW) {
3320 if (*faceW)
3321 strcatW(faceW, spaceW);
3322 strcatW(faceW, styleW);
3326 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3327 return TRUE;
3330 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name,
3331 struct dwrite_font_data **ret)
3333 struct file_stream_desc stream_desc;
3334 struct dwrite_font_props props;
3335 struct dwrite_font_data *data;
3336 WCHAR familyW[255], faceW[255];
3337 HRESULT hr;
3339 *ret = NULL;
3341 data = heap_alloc_zero(sizeof(*data));
3342 if (!data)
3343 return E_OUTOFMEMORY;
3345 data->ref = 1;
3346 data->file = desc->files[0];
3347 data->face_index = desc->index;
3348 data->face_type = desc->face_type;
3349 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3350 data->bold_sim_tested = 0;
3351 data->oblique_sim_tested = 0;
3352 IDWriteFontFile_AddRef(data->file);
3354 stream_desc.stream = desc->stream;
3355 stream_desc.face_type = desc->face_type;
3356 stream_desc.face_index = desc->index;
3357 opentype_get_font_properties(&stream_desc, &props);
3358 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3359 opentype_get_font_facename(&stream_desc, props.lf.lfFaceName, &data->names);
3361 /* get family name from font file */
3362 hr = opentype_get_font_familyname(&stream_desc, family_name);
3363 if (FAILED(hr)) {
3364 WARN("unable to get family name from font\n");
3365 release_font_data(data);
3366 return hr;
3369 data->style = props.style;
3370 data->stretch = props.stretch;
3371 data->weight = props.weight;
3372 data->panose = props.panose;
3373 data->fontsig = props.fontsig;
3374 data->lf = props.lf;
3376 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3377 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3378 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3379 set_en_localizedstring(*family_name, familyW);
3380 set_en_localizedstring(data->names, faceW);
3383 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3385 *ret = data;
3386 return S_OK;
3389 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3390 const WCHAR *facenameW, struct dwrite_font_data **ret)
3392 struct dwrite_font_data *data;
3394 *ret = NULL;
3396 data = heap_alloc_zero(sizeof(*data));
3397 if (!data)
3398 return E_OUTOFMEMORY;
3400 *data = *src;
3401 data->ref = 1;
3402 data->simulations |= sim;
3403 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3404 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3405 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3406 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3407 memset(data->info_strings, 0, sizeof(data->info_strings));
3408 data->names = NULL;
3409 IDWriteFontFile_AddRef(data->file);
3411 create_localizedstrings(&data->names);
3412 add_localizedstring(data->names, enusW, facenameW);
3414 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3416 *ret = data;
3417 return S_OK;
3420 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3422 struct dwrite_fontfamily_data *data;
3424 data = heap_alloc(sizeof(*data));
3425 if (!data)
3426 return E_OUTOFMEMORY;
3428 data->ref = 1;
3429 data->font_count = 0;
3430 data->font_alloc = 2;
3431 data->has_normal_face = 0;
3432 data->has_oblique_face = 0;
3433 data->has_italic_face = 0;
3435 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3436 if (!data->fonts) {
3437 heap_free(data);
3438 return E_OUTOFMEMORY;
3441 data->familyname = familyname;
3442 IDWriteLocalizedStrings_AddRef(familyname);
3444 *ret = data;
3445 return S_OK;
3448 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3450 UINT32 i, j, heaviest;
3452 for (i = 0; i < family->font_count; i++) {
3453 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3454 heaviest = i;
3456 if (family->fonts[i]->bold_sim_tested)
3457 continue;
3459 family->fonts[i]->bold_sim_tested = 1;
3460 for (j = i; j < family->font_count; j++) {
3461 if (family->fonts[j]->bold_sim_tested)
3462 continue;
3464 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3465 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3466 if (family->fonts[j]->weight > weight) {
3467 weight = family->fonts[j]->weight;
3468 heaviest = j;
3470 family->fonts[j]->bold_sim_tested = 1;
3474 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3475 static const struct name_pattern weightsim_patterns[] = {
3476 { extraW, lightW },
3477 { extW, lightW },
3478 { ultraW, lightW },
3479 { semiW, lightW },
3480 { semiW, boldW },
3481 { demiW, boldW },
3482 { boldW },
3483 { thinW },
3484 { lightW },
3485 { mediumW },
3486 { demiW },
3487 { NULL }
3490 WCHAR facenameW[255], initialW[255];
3491 struct dwrite_font_data *boldface;
3492 struct list tokens;
3494 /* add Bold simulation based on heaviest face data */
3496 /* Simulated face name should only contain Bold as weight term,
3497 so remove existing regular and weight terms. */
3498 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3499 facename_remove_regular_term(initialW, -1);
3501 /* remove current weight pattern */
3502 fontname_tokenize(&tokens, initialW);
3503 match_pattern_list(&tokens, weightsim_patterns, NULL);
3504 fontname_tokens_to_str(&tokens, facenameW);
3506 /* Bold suffix for new name */
3507 if (*facenameW)
3508 strcatW(facenameW, spaceW);
3509 strcatW(facenameW, boldW);
3511 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3512 boldface->bold_sim_tested = 1;
3513 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3514 fontfamily_add_font(family, boldface);
3520 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3522 UINT32 i, j;
3524 for (i = 0; i < family->font_count; i++) {
3525 UINT32 regular = ~0u, oblique = ~0u;
3526 struct dwrite_font_data *obliqueface;
3527 WCHAR facenameW[255];
3529 if (family->fonts[i]->oblique_sim_tested)
3530 continue;
3532 family->fonts[i]->oblique_sim_tested = 1;
3533 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3534 regular = i;
3535 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3536 oblique = i;
3538 /* find regular style with same weight/stretch values */
3539 for (j = i; j < family->font_count; j++) {
3540 if (family->fonts[j]->oblique_sim_tested)
3541 continue;
3543 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3544 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3546 family->fonts[j]->oblique_sim_tested = 1;
3547 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3548 regular = j;
3550 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3551 oblique = j;
3554 if (regular != ~0u && oblique != ~0u)
3555 break;
3558 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3559 if (regular == ~0u)
3560 continue;
3562 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3563 if (oblique != ~0u)
3564 continue;
3566 /* add oblique simulation based on this regular face */
3568 /* remove regular term if any, append 'Oblique' */
3569 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3570 facename_remove_regular_term(facenameW, -1);
3572 if (*facenameW)
3573 strcatW(facenameW, spaceW);
3574 strcatW(facenameW, obliqueW);
3576 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3577 obliqueface->oblique_sim_tested = 1;
3578 obliqueface->lf.lfItalic = 1;
3579 fontfamily_add_font(family, obliqueface);
3584 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3585 const WCHAR *replacement_name)
3587 UINT32 i = collection_find_family(collection, replacement_name);
3588 struct dwrite_fontfamily_data *target;
3589 IDWriteLocalizedStrings *strings;
3590 HRESULT hr;
3592 /* replacement does not exist */
3593 if (i == ~0u)
3594 return FALSE;
3596 hr = create_localizedstrings(&strings);
3597 if (FAILED(hr))
3598 return FALSE;
3600 /* add a new family with target name, reuse font data from replacement */
3601 add_localizedstring(strings, enusW, target_name);
3602 hr = init_fontfamily_data(strings, &target);
3603 if (hr == S_OK) {
3604 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3605 WCHAR nameW[255];
3607 for (i = 0; i < replacement->font_count; i++) {
3608 fontfamily_add_font(target, replacement->fonts[i]);
3609 addref_font_data(replacement->fonts[i]);
3612 fontcollection_add_family(collection, target);
3613 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3614 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3616 IDWriteLocalizedStrings_Release(strings);
3617 return TRUE;
3620 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3621 system font collections. */
3622 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3624 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3625 WCHAR *name;
3626 void *data;
3627 HKEY hkey;
3629 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3630 return;
3632 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3633 RegCloseKey(hkey);
3634 return;
3637 max_namelen++; /* returned value doesn't include room for '\0' */
3638 name = heap_alloc(max_namelen * sizeof(WCHAR));
3639 data = heap_alloc(max_datalen);
3641 datalen = max_datalen;
3642 namelen = max_namelen;
3643 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3644 if (collection_find_family(collection, name) == ~0u) {
3645 if (type == REG_MULTI_SZ) {
3646 WCHAR *replacement = data;
3647 while (*replacement) {
3648 if (fontcollection_add_replacement(collection, name, replacement))
3649 break;
3650 replacement += strlenW(replacement) + 1;
3653 else if (type == REG_SZ)
3654 fontcollection_add_replacement(collection, name, data);
3656 else
3657 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3659 datalen = max_datalen;
3660 namelen = max_namelen;
3663 heap_free(data);
3664 heap_free(name);
3665 RegCloseKey(hkey);
3668 HRESULT create_font_collection(IDWriteFactory5 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3669 IDWriteFontCollection1 **ret)
3671 struct fontfile_enum {
3672 struct list entry;
3673 IDWriteFontFile *file;
3675 struct fontfile_enum *fileenum, *fileenum2;
3676 struct dwrite_fontcollection *collection;
3677 struct list scannedfiles;
3678 BOOL current = FALSE;
3679 HRESULT hr = S_OK;
3680 UINT32 i;
3682 *ret = NULL;
3684 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3685 if (!collection) return E_OUTOFMEMORY;
3687 hr = init_font_collection(collection, is_system);
3688 if (FAILED(hr)) {
3689 heap_free(collection);
3690 return hr;
3693 *ret = &collection->IDWriteFontCollection1_iface;
3695 TRACE("building font collection:\n");
3697 list_init(&scannedfiles);
3698 while (hr == S_OK) {
3699 DWRITE_FONT_FACE_TYPE face_type;
3700 DWRITE_FONT_FILE_TYPE file_type;
3701 BOOL supported, same = FALSE;
3702 IDWriteFontFileStream *stream;
3703 IDWriteFontFile *file;
3704 UINT32 face_count;
3706 current = FALSE;
3707 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3708 if (FAILED(hr) || !current)
3709 break;
3711 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3712 if (FAILED(hr))
3713 break;
3715 /* check if we've scanned this file already */
3716 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3717 if ((same = is_same_fontfile(fileenum->file, file)))
3718 break;
3721 if (same) {
3722 IDWriteFontFile_Release(file);
3723 continue;
3726 if (FAILED(get_filestream_from_file(file, &stream))) {
3727 IDWriteFontFile_Release(file);
3728 continue;
3731 /* Unsupported formats are skipped. */
3732 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
3733 if (FAILED(hr) || !supported || face_count == 0) {
3734 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3735 IDWriteFontFileStream_Release(stream);
3736 IDWriteFontFile_Release(file);
3737 hr = S_OK;
3738 continue;
3741 /* add to scanned list */
3742 fileenum = heap_alloc(sizeof(*fileenum));
3743 fileenum->file = file;
3744 list_add_tail(&scannedfiles, &fileenum->entry);
3746 for (i = 0; i < face_count; i++) {
3747 IDWriteLocalizedStrings *family_name = NULL;
3748 struct dwrite_font_data *font_data;
3749 struct fontface_desc desc;
3750 WCHAR familyW[255];
3751 UINT32 index;
3753 desc.factory = factory;
3754 desc.face_type = face_type;
3755 desc.files = &file;
3756 desc.stream = stream;
3757 desc.files_number = 1;
3758 desc.index = i;
3759 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3760 desc.font_data = NULL;
3762 /* alloc and init new font data structure */
3763 hr = init_font_data(&desc, &family_name, &font_data);
3764 if (FAILED(hr)) {
3765 /* move to next one */
3766 hr = S_OK;
3767 continue;
3770 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3772 /* ignore dot named faces */
3773 if (familyW[0] == '.') {
3774 WARN("Ignoring face %s\n", debugstr_w(familyW));
3775 IDWriteLocalizedStrings_Release(family_name);
3776 release_font_data(font_data);
3777 continue;
3780 index = collection_find_family(collection, familyW);
3781 if (index != ~0u)
3782 hr = fontfamily_add_font(collection->family_data[index], font_data);
3783 else {
3784 struct dwrite_fontfamily_data *family_data;
3786 /* create and init new family */
3787 hr = init_fontfamily_data(family_name, &family_data);
3788 if (hr == S_OK) {
3789 /* add font to family, family - to collection */
3790 hr = fontfamily_add_font(family_data, font_data);
3791 if (hr == S_OK)
3792 hr = fontcollection_add_family(collection, family_data);
3794 if (FAILED(hr))
3795 release_fontfamily_data(family_data);
3799 IDWriteLocalizedStrings_Release(family_name);
3801 if (FAILED(hr))
3802 break;
3806 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3807 IDWriteFontFile_Release(fileenum->file);
3808 list_remove(&fileenum->entry);
3809 heap_free(fileenum);
3812 for (i = 0; i < collection->family_count; i++) {
3813 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3814 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3817 if (is_system)
3818 fontcollection_add_replacements(collection);
3820 collection->factory = factory;
3821 IDWriteFactory5_AddRef(factory);
3823 return hr;
3826 struct system_fontfile_enumerator
3828 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3829 LONG ref;
3831 IDWriteFactory5 *factory;
3832 HKEY hkey;
3833 int index;
3835 WCHAR *filename;
3836 DWORD filename_size;
3839 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3841 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3844 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3846 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3847 IDWriteFontFileEnumerator_AddRef(iface);
3848 *obj = iface;
3849 return S_OK;
3852 WARN("%s not implemented.\n", debugstr_guid(riid));
3854 *obj = NULL;
3856 return E_NOINTERFACE;
3859 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3861 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3862 return InterlockedIncrement(&enumerator->ref);
3865 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3867 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3868 ULONG ref = InterlockedDecrement(&enumerator->ref);
3870 if (!ref) {
3871 IDWriteFactory5_Release(enumerator->factory);
3872 RegCloseKey(enumerator->hkey);
3873 heap_free(enumerator->filename);
3874 heap_free(enumerator);
3877 return ref;
3880 static HRESULT create_local_file_reference(IDWriteFactory5 *factory, const WCHAR *filename, IDWriteFontFile **file)
3882 HRESULT hr;
3884 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3885 if (!strchrW(filename, '\\')) {
3886 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3887 WCHAR fullpathW[MAX_PATH];
3889 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3890 strcatW(fullpathW, fontsW);
3891 strcatW(fullpathW, filename);
3893 hr = IDWriteFactory5_CreateFontFileReference(factory, fullpathW, NULL, file);
3895 else
3896 hr = IDWriteFactory5_CreateFontFileReference(factory, filename, NULL, file);
3898 return hr;
3901 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3903 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3905 *file = NULL;
3907 if (enumerator->index < 0 || !enumerator->filename || !*enumerator->filename)
3908 return E_FAIL;
3910 return create_local_file_reference(enumerator->factory, enumerator->filename, file);
3913 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3915 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3916 WCHAR name_buf[256], *name = name_buf;
3917 DWORD name_count, max_name_count = sizeof(name_buf) / sizeof(*name_buf), type, data_size;
3918 HRESULT hr = S_OK;
3919 LONG r;
3921 *current = FALSE;
3922 enumerator->index++;
3924 /* iterate until we find next string value */
3925 for (;;) {
3926 do {
3927 name_count = max_name_count;
3928 data_size = enumerator->filename_size - sizeof(*enumerator->filename);
3930 r = RegEnumValueW(enumerator->hkey, enumerator->index, name, &name_count,
3931 NULL, &type, (BYTE *)enumerator->filename, &data_size);
3932 if (r == ERROR_MORE_DATA) {
3933 if (name_count >= max_name_count) {
3934 if (name != name_buf) heap_free(name);
3935 max_name_count *= 2;
3936 name = heap_alloc(max_name_count * sizeof(*name));
3937 if (!name) return E_OUTOFMEMORY;
3939 if (data_size > enumerator->filename_size - sizeof(*enumerator->filename)) {
3940 heap_free(enumerator->filename);
3941 enumerator->filename_size = max(data_size + sizeof(*enumerator->filename), enumerator->filename_size * 2);
3942 enumerator->filename = heap_alloc(enumerator->filename_size);
3943 if (!enumerator->filename) {
3944 hr = E_OUTOFMEMORY;
3945 goto err;
3949 } while (r == ERROR_MORE_DATA);
3951 if (r != ERROR_SUCCESS) {
3952 enumerator->filename[0] = 0;
3953 break;
3955 enumerator->filename[data_size / sizeof(*enumerator->filename)] = 0;
3956 if (type == REG_SZ && *name != '@') {
3957 *current = TRUE;
3958 break;
3960 enumerator->index++;
3962 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3964 err:
3965 if (name != name_buf) heap_free(name);
3966 return hr;
3969 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3971 systemfontfileenumerator_QueryInterface,
3972 systemfontfileenumerator_AddRef,
3973 systemfontfileenumerator_Release,
3974 systemfontfileenumerator_MoveNext,
3975 systemfontfileenumerator_GetCurrentFontFile
3978 static HRESULT create_system_fontfile_enumerator(IDWriteFactory5 *factory, IDWriteFontFileEnumerator **ret)
3980 struct system_fontfile_enumerator *enumerator;
3981 static const WCHAR fontslistW[] = {
3982 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3983 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3984 'F','o','n','t','s',0
3987 *ret = NULL;
3989 enumerator = heap_alloc(sizeof(*enumerator));
3990 if (!enumerator)
3991 return E_OUTOFMEMORY;
3993 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3994 enumerator->ref = 1;
3995 enumerator->factory = factory;
3996 enumerator->index = -1;
3997 enumerator->filename_size = MAX_PATH * sizeof(*enumerator->filename);
3998 enumerator->filename = heap_alloc(enumerator->filename_size);
3999 if (!enumerator->filename) {
4000 heap_free(enumerator);
4001 return E_OUTOFMEMORY;
4004 IDWriteFactory5_AddRef(factory);
4006 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
4007 ERR("failed to open fonts list key\n");
4008 IDWriteFactory5_Release(factory);
4009 heap_free(enumerator->filename);
4010 heap_free(enumerator);
4011 return E_FAIL;
4014 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4016 return S_OK;
4019 HRESULT get_system_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **collection)
4021 IDWriteFontFileEnumerator *enumerator;
4022 HRESULT hr;
4024 *collection = NULL;
4026 hr = create_system_fontfile_enumerator(factory, &enumerator);
4027 if (FAILED(hr))
4028 return hr;
4030 TRACE("building system font collection for factory %p\n", factory);
4031 hr = create_font_collection(factory, enumerator, TRUE, collection);
4032 IDWriteFontFileEnumerator_Release(enumerator);
4033 return hr;
4036 static HRESULT eudc_collection_add_family(IDWriteFactory5 *factory, struct dwrite_fontcollection *collection,
4037 const WCHAR *keynameW, const WCHAR *pathW)
4039 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};
4040 static const WCHAR emptyW[] = {0};
4041 struct dwrite_fontfamily_data *family_data;
4042 IDWriteLocalizedStrings *names;
4043 DWRITE_FONT_FACE_TYPE face_type;
4044 DWRITE_FONT_FILE_TYPE file_type;
4045 IDWriteFontFileStream *stream;
4046 IDWriteFontFile *file;
4047 UINT32 face_count, i;
4048 BOOL supported;
4049 HRESULT hr;
4051 /* create font file from this path */
4052 hr = create_local_file_reference(factory, pathW, &file);
4053 if (FAILED(hr))
4054 return S_FALSE;
4056 if (FAILED(get_filestream_from_file(file, &stream))) {
4057 IDWriteFontFile_Release(file);
4058 return S_FALSE;
4061 /* Unsupported formats are skipped. */
4062 hr = opentype_analyze_font(stream, &supported, &file_type, &face_type, &face_count);
4063 if (FAILED(hr) || !supported || face_count == 0) {
4064 TRACE("Unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4065 IDWriteFontFileStream_Release(stream);
4066 IDWriteFontFile_Release(file);
4067 return S_FALSE;
4070 /* create and init new family */
4072 /* Family names are added for non-specific locale, represented with empty string.
4073 Default family appears with empty family name. */
4074 create_localizedstrings(&names);
4075 if (!strcmpiW(keynameW, defaultfontW))
4076 add_localizedstring(names, emptyW, emptyW);
4077 else
4078 add_localizedstring(names, emptyW, keynameW);
4080 hr = init_fontfamily_data(names, &family_data);
4081 IDWriteLocalizedStrings_Release(names);
4082 if (hr != S_OK) {
4083 IDWriteFontFile_Release(file);
4084 return hr;
4087 /* fill with faces */
4088 for (i = 0; i < face_count; i++) {
4089 struct dwrite_font_data *font_data;
4090 struct fontface_desc desc;
4092 /* alloc and init new font data structure */
4093 desc.factory = factory;
4094 desc.face_type = face_type;
4095 desc.index = i;
4096 desc.files = &file;
4097 desc.stream = stream;
4098 desc.files_number = 1;
4099 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4100 desc.font_data = NULL;
4102 hr = init_font_data(&desc, &names, &font_data);
4103 if (FAILED(hr))
4104 continue;
4106 IDWriteLocalizedStrings_Release(names);
4108 /* add font to family */
4109 hr = fontfamily_add_font(family_data, font_data);
4110 if (hr != S_OK)
4111 release_font_data(font_data);
4114 /* add family to collection */
4115 hr = fontcollection_add_family(collection, family_data);
4116 if (FAILED(hr))
4117 release_fontfamily_data(family_data);
4118 IDWriteFontFileStream_Release(stream);
4119 IDWriteFontFile_Release(file);
4121 return hr;
4124 HRESULT get_eudc_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **ret)
4126 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4127 struct dwrite_fontcollection *collection;
4128 static const WCHAR emptyW[] = {0};
4129 WCHAR eudckeypathW[16];
4130 HKEY eudckey;
4131 DWORD index;
4132 BOOL exists;
4133 LONG retval;
4134 HRESULT hr;
4135 UINT32 i;
4137 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4139 *ret = NULL;
4141 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4142 if (!collection) return E_OUTOFMEMORY;
4144 hr = init_font_collection(collection, FALSE);
4145 if (FAILED(hr)) {
4146 heap_free(collection);
4147 return hr;
4150 *ret = &collection->IDWriteFontCollection1_iface;
4151 collection->factory = factory;
4152 IDWriteFactory5_AddRef(factory);
4154 /* return empty collection if EUDC fonts are not configured */
4155 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4156 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4157 return S_OK;
4159 retval = ERROR_SUCCESS;
4160 index = 0;
4161 while (retval != ERROR_NO_MORE_ITEMS) {
4162 WCHAR keynameW[64], pathW[MAX_PATH];
4163 DWORD type, path_len, name_len;
4165 path_len = sizeof(pathW)/sizeof(*pathW);
4166 name_len = sizeof(keynameW)/sizeof(*keynameW);
4167 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4168 if (retval || type != REG_SZ)
4169 continue;
4171 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4172 if (hr != S_OK)
4173 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4175 RegCloseKey(eudckey);
4177 /* try to add global default if not defined for specific codepage */
4178 exists = FALSE;
4179 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
4180 &index, &exists);
4181 if (FAILED(hr) || !exists) {
4182 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4183 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4184 if (hr != S_OK)
4185 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4188 /* EUDC collection offers simulated faces too */
4189 for (i = 0; i < collection->family_count; i++) {
4190 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4191 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4194 return S_OK;
4197 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4199 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4201 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4203 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4205 *obj = iface;
4206 IDWriteFontFile_AddRef(iface);
4207 return S_OK;
4210 WARN("%s not implemented.\n", debugstr_guid(riid));
4212 *obj = NULL;
4213 return E_NOINTERFACE;
4216 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4218 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4219 ULONG ref = InterlockedIncrement(&This->ref);
4220 TRACE("(%p)->(%d)\n", This, ref);
4221 return ref;
4224 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4226 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4227 ULONG ref = InterlockedDecrement(&This->ref);
4229 TRACE("(%p)->(%d)\n", This, ref);
4231 if (!ref)
4233 IDWriteFontFileLoader_Release(This->loader);
4234 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4235 heap_free(This->reference_key);
4236 heap_free(This);
4239 return ref;
4242 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4244 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4245 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4246 *fontFileReferenceKey = This->reference_key;
4247 *fontFileReferenceKeySize = This->key_size;
4249 return S_OK;
4252 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4254 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4255 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4256 *fontFileLoader = This->loader;
4257 IDWriteFontFileLoader_AddRef(This->loader);
4259 return S_OK;
4262 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *is_supported, DWRITE_FONT_FILE_TYPE *file_type,
4263 DWRITE_FONT_FACE_TYPE *face_type, UINT32 *face_count)
4265 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4266 IDWriteFontFileStream *stream;
4267 HRESULT hr;
4269 TRACE("(%p)->(%p, %p, %p, %p)\n", This, is_supported, file_type, face_type, face_count);
4271 *is_supported = FALSE;
4272 *file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4273 if (face_type)
4274 *face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4275 *face_count = 0;
4277 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4278 if (FAILED(hr))
4279 return hr;
4281 hr = opentype_analyze_font(stream, is_supported, file_type, face_type, face_count);
4283 /* TODO: Further Analysis */
4284 IDWriteFontFileStream_Release(stream);
4285 return S_OK;
4288 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4289 dwritefontfile_QueryInterface,
4290 dwritefontfile_AddRef,
4291 dwritefontfile_Release,
4292 dwritefontfile_GetReferenceKey,
4293 dwritefontfile_GetLoader,
4294 dwritefontfile_Analyze,
4297 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4298 IDWriteFontFile **ret)
4300 struct dwrite_fontfile *file;
4301 void *key;
4303 *ret = NULL;
4305 file = heap_alloc(sizeof(*file));
4306 key = heap_alloc(key_size);
4307 if (!file || !key) {
4308 heap_free(file);
4309 heap_free(key);
4310 return E_OUTOFMEMORY;
4313 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4314 file->ref = 1;
4315 IDWriteFontFileLoader_AddRef(loader);
4316 file->loader = loader;
4317 file->stream = NULL;
4318 file->reference_key = key;
4319 memcpy(file->reference_key, reference_key, key_size);
4320 file->key_size = key_size;
4322 *ret = &file->IDWriteFontFile_iface;
4324 return S_OK;
4327 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace4 **ret)
4329 struct file_stream_desc stream_desc;
4330 struct dwrite_fontface *fontface;
4331 HRESULT hr = S_OK;
4332 BOOL is_symbol;
4333 int i;
4335 *ret = NULL;
4337 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4338 if (!fontface)
4339 return E_OUTOFMEMORY;
4341 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4342 if (!fontface->files) {
4343 heap_free(fontface);
4344 return E_OUTOFMEMORY;
4347 fontface->IDWriteFontFace4_iface.lpVtbl = &dwritefontfacevtbl;
4348 fontface->ref = 1;
4349 fontface->type = desc->face_type;
4350 fontface->file_count = desc->files_number;
4351 fontface->cmap.exists = TRUE;
4352 fontface->vdmx.exists = TRUE;
4353 fontface->gasp.exists = TRUE;
4354 fontface->cpal.exists = TRUE;
4355 fontface->colr.exists = TRUE;
4356 fontface->index = desc->index;
4357 fontface->simulations = desc->simulations;
4358 IDWriteFactory5_AddRef(fontface->factory = desc->factory);
4360 for (i = 0; i < fontface->file_count; i++) {
4361 fontface->files[i] = desc->files[i];
4362 IDWriteFontFile_AddRef(fontface->files[i]);
4364 fontface->stream = desc->stream;
4365 IDWriteFontFileStream_AddRef(fontface->stream);
4367 stream_desc.stream = fontface->stream;
4368 stream_desc.face_type = desc->face_type;
4369 stream_desc.face_index = desc->index;
4370 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4371 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4372 /* TODO: test what happens if caret is already slanted */
4373 if (fontface->caret.slopeRise == 1) {
4374 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4375 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4379 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace4_iface, &is_symbol);
4380 if (is_symbol)
4381 fontface->flags |= FONTFACE_IS_SYMBOL;
4382 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace4_iface))
4383 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4384 if (freetype_is_monospaced(&fontface->IDWriteFontFace4_iface))
4385 fontface->flags |= FONTFACE_IS_MONOSPACED;
4386 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace4_iface))
4387 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4388 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace4_iface);
4390 /* Font properties are reused from font object when 'normal' face creation path is used:
4391 collection -> family -> matching font -> fontface.
4393 If face is created directly from factory we have to go through properties resolution.
4395 if (desc->font_data) {
4396 fontface->weight = desc->font_data->weight;
4397 fontface->style = desc->font_data->style;
4398 fontface->stretch = desc->font_data->stretch;
4399 fontface->panose = desc->font_data->panose;
4400 fontface->fontsig = desc->font_data->fontsig;
4401 fontface->lf = desc->font_data->lf;
4403 else {
4404 IDWriteLocalizedStrings *names;
4405 struct dwrite_font_data *data;
4407 hr = init_font_data(desc, &names, &data);
4408 if (FAILED(hr)) {
4409 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4410 return hr;
4413 fontface->weight = data->weight;
4414 fontface->style = data->style;
4415 fontface->stretch = data->stretch;
4416 fontface->panose = data->panose;
4417 fontface->fontsig = data->fontsig;
4418 fontface->lf = data->lf;
4420 IDWriteLocalizedStrings_Release(names);
4421 release_font_data(data);
4424 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace4_iface);
4426 *ret = &fontface->IDWriteFontFace4_iface;
4427 return S_OK;
4430 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4431 struct local_refkey
4433 FILETIME writetime;
4434 WCHAR name[1];
4437 struct local_cached_stream
4439 struct list entry;
4440 IDWriteFontFileStream *stream;
4441 struct local_refkey *key;
4442 UINT32 key_size;
4445 struct dwrite_localfontfilestream
4447 IDWriteFontFileStream IDWriteFontFileStream_iface;
4448 LONG ref;
4450 struct local_cached_stream *entry;
4451 const void *file_ptr;
4452 UINT64 size;
4455 struct dwrite_localfontfileloader {
4456 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4457 LONG ref;
4459 struct list streams;
4460 CRITICAL_SECTION cs;
4463 static struct dwrite_localfontfileloader local_fontfile_loader;
4465 struct dwrite_inmemory_stream_data
4467 LONG ref;
4468 IUnknown *owner;
4469 void *data;
4470 UINT32 size;
4473 struct dwrite_inmemory_filestream
4475 IDWriteFontFileStream IDWriteFontFileStream_iface;
4476 LONG ref;
4478 struct dwrite_inmemory_stream_data *data;
4481 struct dwrite_inmemory_fileloader
4483 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
4484 LONG ref;
4486 struct dwrite_inmemory_stream_data **streams;
4487 UINT32 filecount;
4488 UINT32 capacity;
4491 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4493 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4496 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4498 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4501 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
4503 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
4506 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4508 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
4511 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
4513 if (InterlockedDecrement(&stream->ref) == 0) {
4514 if (stream->owner)
4515 IUnknown_Release(stream->owner);
4516 else
4517 heap_free(stream->data);
4518 heap_free(stream);
4522 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4524 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4526 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4528 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
4529 IsEqualIID(riid, &IID_IUnknown))
4531 *obj = iface;
4532 if (InterlockedIncrement(&This->ref) == 1) {
4533 InterlockedDecrement(&This->ref);
4534 *obj = NULL;
4535 return E_FAIL;
4537 return S_OK;
4540 WARN("%s not implemented.\n", debugstr_guid(riid));
4542 *obj = NULL;
4543 return E_NOINTERFACE;
4546 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4548 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4549 ULONG ref = InterlockedIncrement(&This->ref);
4550 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4551 return ref;
4554 static inline void release_cached_stream(struct local_cached_stream *stream)
4556 list_remove(&stream->entry);
4557 heap_free(stream->key);
4558 heap_free(stream);
4561 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4563 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4564 ULONG ref = InterlockedDecrement(&This->ref);
4566 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4568 if (!ref) {
4569 UnmapViewOfFile(This->file_ptr);
4571 EnterCriticalSection(&local_fontfile_loader.cs);
4572 release_cached_stream(This->entry);
4573 LeaveCriticalSection(&local_fontfile_loader.cs);
4575 heap_free(This);
4578 return ref;
4581 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4582 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4584 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4586 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4587 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4589 *fragment_context = NULL;
4591 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4592 *fragment_start = NULL;
4593 return E_FAIL;
4596 *fragment_start = (char*)This->file_ptr + offset;
4597 return S_OK;
4600 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4602 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4603 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4606 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4608 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4609 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4610 *size = This->size;
4611 return S_OK;
4614 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4616 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4617 ULARGE_INTEGER li;
4619 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4621 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4622 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4623 *last_writetime = li.QuadPart;
4625 return S_OK;
4628 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4630 localfontfilestream_QueryInterface,
4631 localfontfilestream_AddRef,
4632 localfontfilestream_Release,
4633 localfontfilestream_ReadFileFragment,
4634 localfontfilestream_ReleaseFileFragment,
4635 localfontfilestream_GetFileSize,
4636 localfontfilestream_GetLastWriteTime
4639 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4641 struct dwrite_localfontfilestream *This;
4643 *ret = NULL;
4645 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4646 if (!This)
4647 return E_OUTOFMEMORY;
4649 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4650 This->ref = 1;
4652 This->file_ptr = file_ptr;
4653 This->size = size;
4654 This->entry = entry;
4656 *ret = &This->IDWriteFontFileStream_iface;
4657 return S_OK;
4660 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4662 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4664 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4666 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
4667 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
4668 IsEqualIID(riid, &IID_IUnknown))
4670 *obj = iface;
4671 IDWriteLocalFontFileLoader_AddRef(iface);
4672 return S_OK;
4675 WARN("%s not implemented.\n", debugstr_guid(riid));
4677 *obj = NULL;
4678 return E_NOINTERFACE;
4681 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4683 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4684 ULONG ref = InterlockedIncrement(&This->ref);
4685 TRACE("(%p)->(%d)\n", This, ref);
4686 return ref;
4689 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4691 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4692 ULONG ref = InterlockedDecrement(&This->ref);
4694 TRACE("(%p)->(%d)\n", This, ref);
4696 return ref;
4699 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
4701 const struct local_refkey *refkey = key;
4702 struct local_cached_stream *stream;
4703 IDWriteFontFileStream *filestream;
4704 HANDLE file, mapping;
4705 LARGE_INTEGER size;
4706 void *file_ptr;
4707 HRESULT hr = S_OK;
4709 *ret = NULL;
4711 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4712 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4713 if (file == INVALID_HANDLE_VALUE) {
4714 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
4715 return E_FAIL;
4718 GetFileSizeEx(file, &size);
4719 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4720 CloseHandle(file);
4721 if (!mapping)
4722 return E_FAIL;
4724 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4725 CloseHandle(mapping);
4726 if (!file_ptr) {
4727 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4728 return E_FAIL;
4731 stream = heap_alloc(sizeof(*stream));
4732 if (!stream) {
4733 UnmapViewOfFile(file_ptr);
4734 return E_OUTOFMEMORY;
4737 stream->key = heap_alloc(key_size);
4738 if (!stream->key) {
4739 UnmapViewOfFile(file_ptr);
4740 heap_free(stream);
4741 return E_OUTOFMEMORY;
4744 stream->key_size = key_size;
4745 memcpy(stream->key, key, key_size);
4747 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4748 if (FAILED(hr)) {
4749 UnmapViewOfFile(file_ptr);
4750 heap_free(stream->key);
4751 heap_free(stream);
4752 return hr;
4755 stream->stream = filestream;
4757 *ret = stream;
4759 return S_OK;
4762 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
4763 UINT32 key_size, IDWriteFontFileStream **ret)
4765 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4766 const struct local_refkey *refkey = key;
4767 struct local_cached_stream *stream;
4768 HRESULT hr = S_OK;
4770 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
4771 TRACE("name: %s\n", debugstr_w(refkey->name));
4773 EnterCriticalSection(&This->cs);
4775 *ret = NULL;
4777 /* search cache first */
4778 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4779 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4780 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
4781 break;
4785 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
4786 list_add_head(&This->streams, &stream->entry);
4787 *ret = stream->stream;
4790 LeaveCriticalSection(&This->cs);
4792 return hr;
4795 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4797 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4798 const struct local_refkey *refkey = key;
4800 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4802 *length = strlenW(refkey->name);
4803 return S_OK;
4806 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4808 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4809 const struct local_refkey *refkey = key;
4811 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4813 if (length < strlenW(refkey->name))
4814 return E_INVALIDARG;
4816 strcpyW(path, refkey->name);
4817 return S_OK;
4820 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
4821 UINT32 key_size, FILETIME *writetime)
4823 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4824 const struct local_refkey *refkey = key;
4826 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
4828 *writetime = refkey->writetime;
4829 return S_OK;
4832 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4833 localfontfileloader_QueryInterface,
4834 localfontfileloader_AddRef,
4835 localfontfileloader_Release,
4836 localfontfileloader_CreateStreamFromKey,
4837 localfontfileloader_GetFilePathLengthFromKey,
4838 localfontfileloader_GetFilePathFromKey,
4839 localfontfileloader_GetLastWriteTimeFromKey
4842 void init_local_fontfile_loader(void)
4844 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4845 local_fontfile_loader.ref = 1;
4846 list_init(&local_fontfile_loader.streams);
4847 InitializeCriticalSection(&local_fontfile_loader.cs);
4848 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
4851 IDWriteFontFileLoader *get_local_fontfile_loader(void)
4853 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
4856 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4858 struct local_refkey *refkey;
4860 if (!path)
4861 return E_INVALIDARG;
4863 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4864 *key = NULL;
4866 refkey = heap_alloc(*size);
4867 if (!refkey)
4868 return E_OUTOFMEMORY;
4870 if (writetime)
4871 refkey->writetime = *writetime;
4872 else {
4873 WIN32_FILE_ATTRIBUTE_DATA info;
4875 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4876 refkey->writetime = info.ftLastWriteTime;
4877 else
4878 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4880 strcpyW(refkey->name, path);
4882 *key = refkey;
4884 return S_OK;
4887 /* IDWriteGlyphRunAnalysis */
4888 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4890 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4892 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4894 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4895 IsEqualIID(riid, &IID_IUnknown))
4897 *ppv = iface;
4898 IDWriteGlyphRunAnalysis_AddRef(iface);
4899 return S_OK;
4902 WARN("%s not implemented.\n", debugstr_guid(riid));
4904 *ppv = NULL;
4905 return E_NOINTERFACE;
4908 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4910 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4911 ULONG ref = InterlockedIncrement(&This->ref);
4912 TRACE("(%p)->(%u)\n", This, ref);
4913 return ref;
4916 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4918 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4919 ULONG ref = InterlockedDecrement(&This->ref);
4921 TRACE("(%p)->(%u)\n", This, ref);
4923 if (!ref) {
4924 if (This->run.fontFace)
4925 IDWriteFontFace_Release(This->run.fontFace);
4926 heap_free(This->glyphs);
4927 heap_free(This->origins);
4928 heap_free(This->bitmap);
4929 heap_free(This);
4932 return ref;
4935 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
4937 switch (mode)
4939 case DWRITE_RENDERING_MODE1_NATURAL:
4940 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
4941 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
4942 return TRUE;
4943 default:
4944 return FALSE;
4948 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
4950 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
4953 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4955 struct dwrite_glyphbitmap glyph_bitmap;
4956 IDWriteFontFace4 *fontface;
4957 HRESULT hr;
4958 UINT32 i;
4960 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4961 *bounds = analysis->bounds;
4962 return;
4965 if (analysis->run.isSideways)
4966 FIXME("sideways runs are not supported.\n");
4968 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
4969 if (FAILED(hr))
4970 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
4972 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4973 glyph_bitmap.fontface = fontface;
4974 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
4975 glyph_bitmap.emsize = analysis->run.fontEmSize;
4976 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
4977 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4978 glyph_bitmap.m = &analysis->m;
4980 for (i = 0; i < analysis->run.glyphCount; i++) {
4981 RECT *bbox = &glyph_bitmap.bbox;
4982 UINT32 bitmap_size;
4984 glyph_bitmap.index = analysis->run.glyphIndices[i];
4985 freetype_get_glyph_bbox(&glyph_bitmap);
4987 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
4988 (bbox->bottom - bbox->top);
4989 if (bitmap_size > analysis->max_glyph_bitmap_size)
4990 analysis->max_glyph_bitmap_size = bitmap_size;
4992 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
4993 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4996 IDWriteFontFace4_Release(fontface);
4998 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4999 *bounds = analysis->bounds;
5002 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5004 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5006 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5008 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5009 SetRectEmpty(bounds);
5010 return E_INVALIDARG;
5013 if (type != This->texture_type) {
5014 SetRectEmpty(bounds);
5015 return S_OK;
5018 glyphrunanalysis_get_texturebounds(This, bounds);
5019 return S_OK;
5022 static inline int get_dib_stride( int width, int bpp )
5024 return ((width * bpp + 31) >> 3) & ~3;
5027 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5029 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5030 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5031 (runbounds->left - bounds->left) * 3;
5032 else
5033 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5034 runbounds->left - bounds->left;
5037 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5039 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5040 struct dwrite_glyphbitmap glyph_bitmap;
5041 IDWriteFontFace4 *fontface;
5042 D2D_POINT_2F origin;
5043 UINT32 i, size;
5044 HRESULT hr;
5045 RECT *bbox;
5047 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5048 if (FAILED(hr)) {
5049 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5050 return hr;
5053 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5054 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5055 size *= 3;
5056 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5057 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5058 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5059 IDWriteFontFace4_Release(fontface);
5060 return E_OUTOFMEMORY;
5063 origin.x = origin.y = 0.0f;
5065 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5066 glyph_bitmap.fontface = fontface;
5067 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5068 glyph_bitmap.emsize = analysis->run.fontEmSize;
5069 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5070 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5071 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5072 glyph_bitmap.m = &analysis->m;
5073 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5074 IDWriteFontFace4_Release(fontface);
5075 return E_OUTOFMEMORY;
5078 bbox = &glyph_bitmap.bbox;
5080 for (i = 0; i < analysis->run.glyphCount; i++) {
5081 BYTE *src = glyph_bitmap.buf, *dst;
5082 int x, y, width, height;
5083 BOOL is_1bpp;
5085 glyph_bitmap.index = analysis->run.glyphIndices[i];
5086 freetype_get_glyph_bbox(&glyph_bitmap);
5088 if (IsRectEmpty(bbox))
5089 continue;
5091 width = bbox->right - bbox->left;
5092 height = bbox->bottom - bbox->top;
5094 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5095 memset(src, 0, height * glyph_bitmap.pitch);
5096 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5098 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5100 /* blit to analysis bitmap */
5101 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5103 if (is_1bpp) {
5104 /* convert 1bpp to 8bpp/24bpp */
5105 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5106 for (y = 0; y < height; y++) {
5107 for (x = 0; x < width; x++)
5108 if (src[x / 8] & masks[x % 8])
5109 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5110 src += glyph_bitmap.pitch;
5111 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5114 else {
5115 for (y = 0; y < height; y++) {
5116 for (x = 0; x < width; x++)
5117 if (src[x / 8] & masks[x % 8])
5118 dst[x] = DWRITE_ALPHA_MAX;
5119 src += glyph_bitmap.pitch;
5120 dst += analysis->bounds.right - analysis->bounds.left;
5124 else {
5125 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5126 for (y = 0; y < height; y++) {
5127 for (x = 0; x < width; x++)
5128 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5129 src += glyph_bitmap.pitch;
5130 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5133 else {
5134 for (y = 0; y < height; y++) {
5135 for (x = 0; x < width; x++)
5136 dst[x] |= src[x];
5137 src += glyph_bitmap.pitch;
5138 dst += analysis->bounds.right - analysis->bounds.left;
5143 heap_free(glyph_bitmap.buf);
5145 IDWriteFontFace4_Release(fontface);
5147 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5149 /* we don't need this anymore */
5150 heap_free(analysis->glyphs);
5151 heap_free(analysis->origins);
5152 IDWriteFontFace_Release(analysis->run.fontFace);
5154 analysis->glyphs = NULL;
5155 analysis->origins = NULL;
5156 analysis->run.glyphIndices = NULL;
5157 analysis->run.fontFace = NULL;
5159 return S_OK;
5162 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5163 RECT const *bounds, BYTE *bitmap, UINT32 size)
5165 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5166 UINT32 required;
5167 RECT runbounds;
5169 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5171 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5172 return E_INVALIDARG;
5174 /* make sure buffer is large enough for requested texture type */
5175 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5176 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5177 required *= 3;
5179 if (size < required)
5180 return E_NOT_SUFFICIENT_BUFFER;
5182 /* validate requested texture type */
5183 if (This->texture_type != type)
5184 return DWRITE_E_UNSUPPORTEDOPERATION;
5186 memset(bitmap, 0, size);
5187 glyphrunanalysis_get_texturebounds(This, &runbounds);
5188 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5189 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5190 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5191 int dst_width = (bounds->right - bounds->left) * pixel_size;
5192 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5193 BYTE *src, *dst;
5194 int y;
5196 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5197 HRESULT hr;
5199 if (FAILED(hr = glyphrunanalysis_render(This)))
5200 return hr;
5203 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5204 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5206 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5207 memcpy(dst, src, draw_width);
5208 src += src_width;
5209 dst += dst_width;
5213 return S_OK;
5216 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5217 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5219 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5221 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5223 if (!params)
5224 return E_INVALIDARG;
5226 switch (This->rendering_mode)
5228 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5229 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5231 UINT value = 0;
5232 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5233 *gamma = (FLOAT)value / 1000.0f;
5234 *contrast = 0.0f;
5235 *cleartypelevel = 1.0f;
5236 break;
5238 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5239 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5240 /* fallthrough */
5241 case DWRITE_RENDERING_MODE1_ALIASED:
5242 case DWRITE_RENDERING_MODE1_NATURAL:
5243 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5244 *gamma = IDWriteRenderingParams_GetGamma(params);
5245 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5246 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5247 break;
5248 default:
5252 return S_OK;
5255 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5256 glyphrunanalysis_QueryInterface,
5257 glyphrunanalysis_AddRef,
5258 glyphrunanalysis_Release,
5259 glyphrunanalysis_GetAlphaTextureBounds,
5260 glyphrunanalysis_CreateAlphaTexture,
5261 glyphrunanalysis_GetAlphaBlendParams
5264 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5266 D2D_POINT_2F ret;
5267 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5268 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5269 *point = ret;
5272 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5274 struct dwrite_glyphrunanalysis *analysis;
5275 DWRITE_FONT_METRICS metrics;
5276 IDWriteFontFace1 *fontface1;
5277 D2D_POINT_2F origin;
5278 FLOAT rtl_factor;
5279 HRESULT hr;
5280 UINT32 i;
5282 *ret = NULL;
5284 /* Check rendering, antialising, measuring, and grid fitting modes. */
5285 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5286 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5287 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5288 return E_INVALIDARG;
5290 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5291 return E_INVALIDARG;
5293 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5294 return E_INVALIDARG;
5296 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5297 return E_INVALIDARG;
5299 analysis = heap_alloc(sizeof(*analysis));
5300 if (!analysis)
5301 return E_OUTOFMEMORY;
5303 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5304 analysis->ref = 1;
5305 analysis->rendering_mode = desc->rendering_mode;
5307 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5308 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5309 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5310 else
5311 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5313 analysis->flags = 0;
5314 analysis->bitmap = NULL;
5315 analysis->max_glyph_bitmap_size = 0;
5316 SetRectEmpty(&analysis->bounds);
5317 analysis->run = *desc->run;
5318 analysis->run.fontEmSize *= desc->ppdip;
5319 IDWriteFontFace_AddRef(analysis->run.fontFace);
5320 analysis->glyphs = heap_alloc(desc->run->glyphCount * sizeof(*analysis->glyphs));
5321 analysis->origins = heap_alloc(desc->run->glyphCount * sizeof(*analysis->origins));
5323 if (!analysis->glyphs || !analysis->origins) {
5324 heap_free(analysis->glyphs);
5325 heap_free(analysis->origins);
5327 analysis->glyphs = NULL;
5328 analysis->origins = NULL;
5330 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5331 return E_OUTOFMEMORY;
5334 /* check if transform is usable */
5335 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5336 analysis->m = *desc->transform;
5337 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5339 else
5340 memset(&analysis->m, 0, sizeof(analysis->m));
5342 analysis->run.glyphIndices = analysis->glyphs;
5343 analysis->run.glyphAdvances = NULL;
5344 analysis->run.glyphOffsets = NULL;
5346 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5348 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5350 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
5351 if (FAILED(hr = IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1)))
5352 WARN("Failed to get IDWriteFontFace1, %#x.\n", hr);
5354 origin.x = desc->origin_x * desc->ppdip;
5355 origin.y = desc->origin_y * desc->ppdip;
5356 for (i = 0; i < desc->run->glyphCount; i++) {
5357 FLOAT advance;
5359 /* Use nominal advances if not provided by caller. */
5360 if (desc->run->glyphAdvances)
5361 advance = rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip;
5362 else {
5363 INT32 a;
5365 advance = 0.0f;
5366 switch (desc->measuring_mode)
5368 case DWRITE_MEASURING_MODE_NATURAL:
5369 if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a,
5370 desc->run->isSideways)))
5371 advance = rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip;
5372 break;
5373 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5374 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5375 if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize,
5376 desc->ppdip, desc->transform, desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL,
5377 desc->run->isSideways, 1, desc->run->glyphIndices + i, &a)))
5378 advance = rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f);
5379 break;
5380 default:
5385 analysis->origins[i] = origin;
5387 /* Offsets are optional, appled to pre-transformed origin. */
5388 if (desc->run->glyphOffsets) {
5389 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip;
5390 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip;
5392 if (desc->run->isSideways) {
5393 analysis->origins[i].x += ascenderoffset;
5394 analysis->origins[i].y += advanceoffset;
5396 else {
5397 analysis->origins[i].x += advanceoffset;
5398 analysis->origins[i].y += ascenderoffset;
5402 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5403 transform_point(analysis->origins + i, &analysis->m);
5405 if (desc->run->isSideways)
5406 origin.y += advance;
5407 else
5408 origin.x += advance;
5411 IDWriteFontFace1_Release(fontface1);
5413 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5414 return S_OK;
5417 /* IDWriteColorGlyphRunEnumerator */
5418 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5420 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5422 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5424 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5425 IsEqualIID(riid, &IID_IUnknown))
5427 *ppv = iface;
5428 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5429 return S_OK;
5432 WARN("%s not implemented.\n", debugstr_guid(riid));
5434 *ppv = NULL;
5435 return E_NOINTERFACE;
5438 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5440 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5441 ULONG ref = InterlockedIncrement(&This->ref);
5442 TRACE("(%p)->(%u)\n", This, ref);
5443 return ref;
5446 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5448 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5449 ULONG ref = InterlockedDecrement(&This->ref);
5451 TRACE("(%p)->(%u)\n", This, ref);
5453 if (!ref) {
5454 heap_free(This->advances);
5455 heap_free(This->color_advances);
5456 heap_free(This->offsets);
5457 heap_free(This->color_offsets);
5458 heap_free(This->glyphindices);
5459 heap_free(This->glyphs);
5460 if (This->colr.context)
5461 IDWriteFontFace4_ReleaseFontTable(This->fontface, This->colr.context);
5462 IDWriteFontFace4_Release(This->fontface);
5463 heap_free(This);
5466 return ref;
5469 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5471 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5472 FLOAT origin = 0.0f;
5474 if (g == 0)
5475 return 0.0f;
5477 while (g--)
5478 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5479 return origin;
5482 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5484 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5485 FLOAT advance_adj = 0.0f;
5486 BOOL got_palette_index;
5487 UINT32 g;
5489 /* start with regular glyphs */
5490 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5491 UINT32 first_glyph = 0;
5493 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5494 if (glyphenum->glyphs[g].num_layers == 0) {
5495 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5496 first_glyph = min(first_glyph, g);
5498 else
5499 glyphenum->glyphindices[g] = 1;
5500 glyphenum->color_advances[g] = glyphenum->advances[g];
5501 if (glyphenum->color_offsets)
5502 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5505 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5506 colorrun->baselineOriginY = glyphenum->origin_y;
5507 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5508 colorrun->paletteIndex = 0xffff;
5509 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5510 glyphenum->has_regular_glyphs = FALSE;
5511 return TRUE;
5513 else {
5514 colorrun->glyphRun.glyphCount = 0;
5515 got_palette_index = FALSE;
5518 advance_adj = 0.0f;
5519 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5521 glyphenum->glyphindices[g] = 1;
5523 /* all glyph layers were returned */
5524 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5525 advance_adj += glyphenum->advances[g];
5526 continue;
5529 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5530 UINT32 index = colorrun->glyphRun.glyphCount;
5531 if (!got_palette_index) {
5532 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5533 /* use foreground color or request one from the font */
5534 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5535 if (colorrun->paletteIndex != 0xffff) {
5536 HRESULT hr = IDWriteFontFace4_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5537 1, &colorrun->runColor);
5538 if (FAILED(hr))
5539 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5540 glyphenum->palette, colorrun->paletteIndex, hr);
5542 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5543 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5544 colorrun->baselineOriginY = glyphenum->origin_y;
5545 glyphenum->color_advances[index] = glyphenum->advances[g];
5546 got_palette_index = TRUE;
5549 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5550 /* offsets are relative to glyph origin, nothing to fix up */
5551 if (glyphenum->color_offsets)
5552 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5553 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5554 if (index)
5555 glyphenum->color_advances[index-1] += advance_adj;
5556 colorrun->glyphRun.glyphCount++;
5557 advance_adj = 0.0f;
5559 else
5560 advance_adj += glyphenum->advances[g];
5563 /* reset last advance */
5564 if (colorrun->glyphRun.glyphCount)
5565 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5567 return colorrun->glyphRun.glyphCount > 0;
5570 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5572 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5574 TRACE("(%p)->(%p)\n", This, has_run);
5576 *has_run = FALSE;
5578 This->colorrun.glyphRun.glyphCount = 0;
5579 while (This->current_layer < This->max_layer_num) {
5580 if (colorglyphenum_build_color_run(This))
5581 break;
5582 else
5583 This->current_layer++;
5586 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5588 return S_OK;
5591 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5593 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5595 TRACE("(%p)->(%p)\n", This, run);
5597 if (This->colorrun.glyphRun.glyphCount == 0) {
5598 *run = NULL;
5599 return E_NOT_VALID_STATE;
5602 *run = &This->colorrun;
5603 return S_OK;
5606 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5607 colorglyphenum_QueryInterface,
5608 colorglyphenum_AddRef,
5609 colorglyphenum_Release,
5610 colorglyphenum_MoveNext,
5611 colorglyphenum_GetCurrentRun
5614 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5615 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5617 struct dwrite_colorglyphenum *colorglyphenum;
5618 BOOL colorfont, has_colored_glyph;
5619 IDWriteFontFace4 *fontface;
5620 HRESULT hr;
5621 UINT32 i;
5623 *ret = NULL;
5625 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace4, (void**)&fontface);
5626 if (FAILED(hr)) {
5627 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5628 return hr;
5631 colorfont = IDWriteFontFace4_IsColorFont(fontface) && IDWriteFontFace4_GetColorPaletteCount(fontface) > palette;
5632 if (!colorfont) {
5633 hr = DWRITE_E_NOCOLOR;
5634 goto failed;
5637 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5638 if (!colorglyphenum) {
5639 hr = E_OUTOFMEMORY;
5640 goto failed;
5643 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5644 colorglyphenum->ref = 1;
5645 colorglyphenum->origin_x = originX;
5646 colorglyphenum->origin_y = originY;
5647 colorglyphenum->fontface = fontface;
5648 colorglyphenum->glyphs = NULL;
5649 colorglyphenum->run = *run;
5650 colorglyphenum->run.glyphIndices = NULL;
5651 colorglyphenum->run.glyphAdvances = NULL;
5652 colorglyphenum->run.glyphOffsets = NULL;
5653 colorglyphenum->palette = palette;
5654 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5655 colorglyphenum->colr.exists = TRUE;
5656 get_fontface_table(fontface, MS_COLR_TAG, &colorglyphenum->colr);
5657 colorglyphenum->current_layer = 0;
5658 colorglyphenum->max_layer_num = 0;
5660 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5662 has_colored_glyph = FALSE;
5663 colorglyphenum->has_regular_glyphs = FALSE;
5664 for (i = 0; i < run->glyphCount; i++) {
5665 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5666 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5667 has_colored_glyph = TRUE;
5669 if (colorglyphenum->glyphs[i].num_layers == 0)
5670 colorglyphenum->has_regular_glyphs = TRUE;
5673 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5674 is supposed to proceed normally, like if font had no color info at all. */
5675 if (!has_colored_glyph) {
5676 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5677 return DWRITE_E_NOCOLOR;
5680 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5681 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5682 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5683 if (run->glyphOffsets) {
5684 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5685 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5686 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5689 colorglyphenum->colorrun.glyphRun.fontFace = (IDWriteFontFace*)fontface;
5690 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
5691 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5692 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5693 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5694 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5696 if (run->glyphAdvances)
5697 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5698 else {
5699 DWRITE_FONT_METRICS metrics;
5701 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5702 for (i = 0; i < run->glyphCount; i++) {
5703 HRESULT hr;
5704 INT32 a;
5706 switch (measuring_mode)
5708 case DWRITE_MEASURING_MODE_NATURAL:
5709 hr = IDWriteFontFace4_GetDesignGlyphAdvances(fontface, 1, run->glyphIndices + i, &a, run->isSideways);
5710 if (FAILED(hr))
5711 a = 0;
5712 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5713 break;
5714 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5715 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5716 hr = IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(fontface, run->fontEmSize, 1.0f, transform,
5717 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5718 if (FAILED(hr))
5719 colorglyphenum->advances[i] = 0.0f;
5720 else
5721 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5722 break;
5723 default:
5729 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5730 return S_OK;
5732 failed:
5733 IDWriteFontFace4_Release(fontface);
5734 return hr;
5737 /* IDWriteFontFaceReference */
5738 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5740 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5742 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5744 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5745 *obj = iface;
5746 IDWriteFontFaceReference_AddRef(iface);
5747 return S_OK;
5750 WARN("%s not implemented.\n", debugstr_guid(riid));
5752 *obj = NULL;
5754 return E_NOINTERFACE;
5757 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5759 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5760 ULONG ref = InterlockedIncrement(&This->ref);
5761 TRACE("(%p)->(%u)\n", This, ref);
5762 return ref;
5765 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5767 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5768 ULONG ref = InterlockedDecrement(&This->ref);
5770 TRACE("(%p)->(%u)\n", This, ref);
5772 if (!ref) {
5773 IDWriteFontFile_Release(This->file);
5774 IDWriteFactory5_Release(This->factory);
5775 heap_free(This);
5778 return ref;
5781 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5783 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5785 TRACE("(%p)->(%p)\n", This, fontface);
5787 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5790 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5791 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5793 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5794 DWRITE_FONT_FILE_TYPE file_type;
5795 DWRITE_FONT_FACE_TYPE face_type;
5796 IDWriteFontFace *fontface;
5797 BOOL is_supported;
5798 UINT32 face_num;
5799 HRESULT hr;
5801 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5803 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5804 if (FAILED(hr))
5805 return hr;
5807 hr = IDWriteFactory5_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5808 if (SUCCEEDED(hr)) {
5809 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
5810 IDWriteFontFace_Release(fontface);
5813 return hr;
5816 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5818 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5819 IDWriteFontFile *file;
5820 BOOL ret;
5822 TRACE("(%p)->(%p)\n", This, ref);
5824 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5825 return FALSE;
5827 ret = is_same_fontfile(This->file, file) &&
5828 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5829 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5830 IDWriteFontFile_Release(file);
5832 return ret;
5835 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5837 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5839 TRACE("(%p)\n", This);
5841 return This->index;
5844 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5846 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5848 TRACE("(%p)\n", This);
5850 return This->simulations;
5853 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5855 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5856 IDWriteFontFileLoader *loader;
5857 const void *key;
5858 UINT32 key_size;
5859 HRESULT hr;
5861 TRACE("(%p)->(%p)\n", This, file);
5863 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5864 if (FAILED(hr))
5865 return hr;
5867 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5868 if (FAILED(hr))
5869 return hr;
5871 hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5872 IDWriteFontFileLoader_Release(loader);
5874 return hr;
5877 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5879 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5881 FIXME("(%p): stub\n", This);
5883 return 0;
5886 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5888 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5890 FIXME("(%p): stub\n", This);
5892 return 0;
5895 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5897 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5899 FIXME("(%p)->(%p): stub\n", This, writetime);
5901 return E_NOTIMPL;
5904 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5906 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5908 FIXME("(%p): stub\n", This);
5910 return DWRITE_LOCALITY_LOCAL;
5913 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5915 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5917 FIXME("(%p): stub\n", This);
5919 return E_NOTIMPL;
5922 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5923 UINT32 count)
5925 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5927 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5929 return E_NOTIMPL;
5932 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5933 UINT32 count)
5935 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5937 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5939 return E_NOTIMPL;
5942 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5943 UINT64 offset, UINT64 size)
5945 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5947 FIXME("(%p)->(0x%s 0x%s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5949 return E_NOTIMPL;
5952 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5953 fontfacereference_QueryInterface,
5954 fontfacereference_AddRef,
5955 fontfacereference_Release,
5956 fontfacereference_CreateFontFace,
5957 fontfacereference_CreateFontFaceWithSimulations,
5958 fontfacereference_Equals,
5959 fontfacereference_GetFontFaceIndex,
5960 fontfacereference_GetSimulations,
5961 fontfacereference_GetFontFile,
5962 fontfacereference_GetLocalFileSize,
5963 fontfacereference_GetFileSize,
5964 fontfacereference_GetFileTime,
5965 fontfacereference_GetLocality,
5966 fontfacereference_EnqueueFontDownloadRequest,
5967 fontfacereference_EnqueueCharacterDownloadRequest,
5968 fontfacereference_EnqueueGlyphDownloadRequest,
5969 fontfacereference_EnqueueFileFragmentDownloadRequest
5972 HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file, UINT32 index,
5973 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5975 struct dwrite_fontfacereference *ref;
5977 *ret = NULL;
5979 if (!is_simulation_valid(simulations))
5980 return E_INVALIDARG;
5982 ref = heap_alloc(sizeof(*ref));
5983 if (!ref)
5984 return E_OUTOFMEMORY;
5986 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
5987 ref->ref = 1;
5989 ref->factory = factory;
5990 IDWriteFactory5_AddRef(ref->factory);
5991 ref->file = file;
5992 IDWriteFontFile_AddRef(ref->file);
5993 ref->index = index;
5994 ref->simulations = simulations;
5995 *ret = &ref->IDWriteFontFaceReference_iface;
5997 return S_OK;
6000 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6002 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6004 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6006 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6007 *obj = iface;
6008 IDWriteFontFileStream_AddRef(iface);
6009 return S_OK;
6012 *obj = NULL;
6014 WARN("%s not implemented.\n", debugstr_guid(riid));
6015 return E_NOINTERFACE;
6018 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6020 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6021 ULONG ref = InterlockedIncrement(&stream->ref);
6022 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6023 return ref;
6026 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6028 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6029 ULONG ref = InterlockedDecrement(&stream->ref);
6031 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6033 if (!ref) {
6034 release_inmemory_stream(stream->data);
6035 heap_free(stream);
6038 return ref;
6041 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6042 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6044 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6046 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6047 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6049 *fragment_context = NULL;
6051 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6052 *fragment_start = NULL;
6053 return E_FAIL;
6056 *fragment_start = (char *)stream->data->data + offset;
6057 return S_OK;
6060 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6062 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6064 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6067 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6069 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6071 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6073 *size = stream->data->size;
6075 return S_OK;
6078 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6080 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6082 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6084 *last_writetime = 0;
6086 return E_NOTIMPL;
6089 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6090 inmemoryfilestream_QueryInterface,
6091 inmemoryfilestream_AddRef,
6092 inmemoryfilestream_Release,
6093 inmemoryfilestream_ReadFileFragment,
6094 inmemoryfilestream_ReleaseFileFragment,
6095 inmemoryfilestream_GetFileSize,
6096 inmemoryfilestream_GetLastWriteTime,
6099 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6100 REFIID riid, void **obj)
6102 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6104 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6106 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6107 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6108 IsEqualIID(riid, &IID_IUnknown))
6110 *obj = iface;
6111 IDWriteInMemoryFontFileLoader_AddRef(iface);
6112 return S_OK;
6115 WARN("%s not implemented.\n", debugstr_guid(riid));
6117 *obj = NULL;
6119 return E_NOINTERFACE;
6122 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6124 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6125 ULONG ref = InterlockedIncrement(&loader->ref);
6126 TRACE("(%p)->(%u)\n", loader, ref);
6127 return ref;
6130 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6132 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6133 ULONG ref = InterlockedDecrement(&loader->ref);
6135 TRACE("(%p)->(%u)\n", loader, ref);
6137 if (!ref) {
6138 UINT32 i;
6140 for (i = 0; i < loader->filecount; i++)
6141 release_inmemory_stream(loader->streams[i]);
6142 heap_free(loader->streams);
6143 heap_free(loader);
6146 return ref;
6149 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6150 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6152 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6153 struct dwrite_inmemory_filestream *stream;
6154 DWORD index;
6156 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6158 *ret = NULL;
6160 if (key_size != sizeof(DWORD))
6161 return E_INVALIDARG;
6163 index = *(DWORD *)key;
6165 if (index >= loader->filecount)
6166 return E_INVALIDARG;
6168 if (!(stream = heap_alloc(sizeof(*stream))))
6169 return E_OUTOFMEMORY;
6171 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6172 stream->ref = 1;
6173 stream->data = loader->streams[index];
6174 InterlockedIncrement(&stream->data->ref);
6176 *ret = &stream->IDWriteFontFileStream_iface;
6178 return S_OK;
6181 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6182 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6184 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6185 struct dwrite_inmemory_stream_data *stream;
6186 DWORD key;
6188 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6190 *fontfile = NULL;
6192 if (loader->filecount == loader->capacity) {
6193 if (loader->streams) {
6194 struct dwrite_inmemory_stream_data **ptr;
6196 if (!(ptr = heap_realloc(loader->streams, 2 * loader->capacity * sizeof(*loader->streams))))
6197 return E_OUTOFMEMORY;
6199 loader->streams = ptr;
6200 loader->capacity *= 2;
6202 else {
6203 loader->capacity = 16;
6204 loader->streams = heap_alloc(loader->capacity * sizeof(*loader->streams));
6208 if (!(stream = heap_alloc(sizeof(*stream))))
6209 return E_OUTOFMEMORY;
6211 stream->ref = 1;
6212 stream->size = data_size;
6213 stream->owner = owner;
6214 if (stream->owner) {
6215 IUnknown_AddRef(stream->owner);
6216 stream->data = (void *)data;
6218 else {
6219 if (!(stream->data = heap_alloc(data_size))) {
6220 heap_free(stream);
6221 return E_OUTOFMEMORY;
6223 memcpy(stream->data, data, data_size);
6226 key = loader->filecount;
6227 loader->streams[loader->filecount++] = stream;
6229 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6230 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6233 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6235 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6237 TRACE("(%p)\n", loader);
6239 return loader->filecount;
6242 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6244 inmemoryfontfileloader_QueryInterface,
6245 inmemoryfontfileloader_AddRef,
6246 inmemoryfontfileloader_Release,
6247 inmemoryfontfileloader_CreateStreamFromKey,
6248 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6249 inmemoryfontfileloader_GetFileCount,
6252 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6254 struct dwrite_inmemory_fileloader *loader;
6256 *ret = NULL;
6258 loader = heap_alloc_zero(sizeof(*loader));
6259 if (!loader)
6260 return E_OUTOFMEMORY;
6262 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6263 loader->ref = 1;
6265 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6267 return S_OK;