gdiplus/metafile: Support playback for EmfPlusRecordTypeSetAntiAliasMode.
[wine.git] / dlls / dwrite / font.c
blob1916bf22fc94cf1783f3cdacae0f6442ab4904e6
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 **streams;
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->streams[i])
519 IDWriteFontFileStream_Release(This->streams[i]);
520 if (This->files[i])
521 IDWriteFontFile_Release(This->files[i]);
523 heap_free(This->streams);
524 heap_free(This->files);
526 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
527 heap_free(This->glyphs[i]);
529 freetype_notify_cacheremove(iface);
531 IDWriteFactory5_Release(This->factory);
532 heap_free(This);
535 return ref;
538 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace4 *iface)
540 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
541 TRACE("(%p)\n", This);
542 return This->type;
545 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace4 *iface, UINT32 *number_of_files,
546 IDWriteFontFile **fontfiles)
548 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
549 int i;
551 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
552 if (fontfiles == NULL)
554 *number_of_files = This->file_count;
555 return S_OK;
557 if (*number_of_files < This->file_count)
558 return E_INVALIDARG;
560 for (i = 0; i < This->file_count; i++)
562 IDWriteFontFile_AddRef(This->files[i]);
563 fontfiles[i] = This->files[i];
566 return S_OK;
569 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace4 *iface)
571 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
572 TRACE("(%p)\n", This);
573 return This->index;
576 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace4 *iface)
578 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
579 TRACE("(%p)\n", This);
580 return This->simulations;
583 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace4 *iface)
585 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
586 TRACE("(%p)\n", This);
587 return !!(This->flags & FONTFACE_IS_SYMBOL);
590 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS *metrics)
592 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
593 TRACE("(%p)->(%p)\n", This, metrics);
594 memcpy(metrics, &This->metrics, sizeof(*metrics));
597 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface)
599 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
600 TRACE("(%p)\n", This);
601 return freetype_get_glyphcount(iface);
604 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface,
605 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
607 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
608 HRESULT hr;
609 UINT32 i;
611 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
613 if (!glyphs)
614 return E_INVALIDARG;
616 if (is_sideways)
617 FIXME("sideways metrics are not supported.\n");
619 for (i = 0; i < glyph_count; i++) {
620 DWRITE_GLYPH_METRICS metrics;
622 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
623 if (hr != S_OK) {
624 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
625 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
626 if (FAILED(hr))
627 return hr;
629 ret[i] = metrics;
632 return S_OK;
635 static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints,
636 UINT32 count, UINT16 *glyphs)
638 if (!glyphs)
639 return E_INVALIDARG;
641 if (!codepoints) {
642 memset(glyphs, 0, count * sizeof(*glyphs));
643 return E_INVALIDARG;
646 freetype_get_glyphs(&fontface->IDWriteFontFace4_iface, fontface->charmap, codepoints, count, glyphs);
647 return S_OK;
650 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace4 *iface, UINT32 const *codepoints,
651 UINT32 count, UINT16 *glyphs)
653 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
655 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyphs);
657 return fontface_get_glyphs(This, codepoints, count, glyphs);
660 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace4 *iface, UINT32 table_tag,
661 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
663 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
664 struct file_stream_desc stream_desc;
666 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
668 stream_desc.stream = This->streams[0];
669 stream_desc.face_type = This->type;
670 stream_desc.face_index = This->index;
671 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
674 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace4 *iface, void *table_context)
676 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
678 TRACE("(%p)->(%p)\n", This, table_context);
680 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
683 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace4 *iface, FLOAT emSize,
684 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
685 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
687 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
689 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
690 count, is_sideways, is_rtl, sink);
692 if (!glyphs || !sink)
693 return E_INVALIDARG;
695 if (is_sideways)
696 FIXME("sideways mode is not supported.\n");
698 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
701 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
702 FLOAT ppem, WORD gasp)
704 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
706 switch (measuring)
708 case DWRITE_MEASURING_MODE_NATURAL:
710 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
711 mode = DWRITE_RENDERING_MODE_NATURAL;
712 else
713 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
714 break;
716 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
717 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
718 break;
719 case DWRITE_MEASURING_MODE_GDI_NATURAL:
720 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
721 break;
722 default:
726 return mode;
729 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
730 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
732 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
733 WORD gasp, *ptr;
734 UINT32 size;
735 FLOAT ppem;
737 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
739 if (!params) {
740 *mode = DWRITE_RENDERING_MODE_DEFAULT;
741 return E_INVALIDARG;
744 *mode = IDWriteRenderingParams_GetRenderingMode(params);
745 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
746 return S_OK;
748 ppem = emSize * ppdip;
750 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
751 *mode = DWRITE_RENDERING_MODE_OUTLINE;
752 return S_OK;
755 ptr = get_fontface_gasp(This, &size);
756 gasp = opentype_get_gasp_flags(ptr, size, ppem);
757 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
758 return S_OK;
761 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT pixels_per_dip,
762 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
764 DWRITE_FONT_METRICS1 metrics1;
765 HRESULT hr = IDWriteFontFace4_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
766 memcpy(metrics, &metrics1, sizeof(*metrics));
767 return hr;
770 static inline int round_metric(FLOAT metric)
772 return (int)floorf(metric + 0.5f);
775 static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface)
777 if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD))
778 return 0;
780 return (fontface->metrics.designUnitsPerEm + 49) / 50;
783 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip,
784 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
785 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
787 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
788 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
789 DWRITE_MEASURING_MODE mode;
790 FLOAT scale, size;
791 HRESULT hr;
792 UINT32 i;
794 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
795 glyph_count, metrics, is_sideways);
797 if (m && memcmp(m, &identity, sizeof(*m)))
798 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
800 size = emSize * ppdip;
801 scale = size / This->metrics.designUnitsPerEm;
802 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
804 for (i = 0; i < glyph_count; i++) {
805 DWRITE_GLYPH_METRICS *ret = metrics + i;
806 DWRITE_GLYPH_METRICS design;
807 BOOL has_contours;
809 hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
810 if (FAILED(hr))
811 return hr;
813 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours);
814 if (has_contours)
815 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment);
816 else
817 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
819 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
820 SCALE_METRIC(leftSideBearing);
821 SCALE_METRIC(rightSideBearing);
822 SCALE_METRIC(topSideBearing);
823 SCALE_METRIC(advanceHeight);
824 SCALE_METRIC(bottomSideBearing);
825 SCALE_METRIC(verticalOriginY);
826 #undef SCALE_METRIC
829 return S_OK;
832 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace4 *iface, DWRITE_FONT_METRICS1 *metrics)
834 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
835 TRACE("(%p)->(%p)\n", This, metrics);
836 *metrics = This->metrics;
839 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace4 *iface, FLOAT em_size, FLOAT pixels_per_dip,
840 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
842 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
843 const DWRITE_FONT_METRICS1 *design = &This->metrics;
844 UINT16 ascent, descent;
845 FLOAT scale;
847 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
849 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
850 memset(metrics, 0, sizeof(*metrics));
851 return E_INVALIDARG;
854 em_size *= pixels_per_dip;
855 if (m && m->m22 != 0.0f)
856 em_size *= fabs(m->m22);
858 scale = em_size / design->designUnitsPerEm;
859 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
860 ascent = round_metric(design->ascent * scale);
861 descent = round_metric(design->descent * scale);
864 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
865 metrics->designUnitsPerEm = design->designUnitsPerEm;
866 metrics->ascent = round_metric(ascent / scale);
867 metrics->descent = round_metric(descent / scale);
869 SCALE_METRIC(lineGap);
870 SCALE_METRIC(capHeight);
871 SCALE_METRIC(xHeight);
872 SCALE_METRIC(underlinePosition);
873 SCALE_METRIC(underlineThickness);
874 SCALE_METRIC(strikethroughPosition);
875 SCALE_METRIC(strikethroughThickness);
876 SCALE_METRIC(glyphBoxLeft);
877 SCALE_METRIC(glyphBoxTop);
878 SCALE_METRIC(glyphBoxRight);
879 SCALE_METRIC(glyphBoxBottom);
880 SCALE_METRIC(subscriptPositionX);
881 SCALE_METRIC(subscriptPositionY);
882 SCALE_METRIC(subscriptSizeX);
883 SCALE_METRIC(subscriptSizeY);
884 SCALE_METRIC(superscriptPositionX);
885 SCALE_METRIC(superscriptPositionY);
886 SCALE_METRIC(superscriptSizeX);
887 SCALE_METRIC(superscriptSizeY);
889 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
890 #undef SCALE_METRIC
892 return S_OK;
895 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace4 *iface, DWRITE_CARET_METRICS *metrics)
897 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
898 TRACE("(%p)->(%p)\n", This, metrics);
899 *metrics = This->caret;
902 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace4 *iface, UINT32 max_count,
903 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
905 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
907 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
909 *count = 0;
910 if (max_count && !ranges)
911 return E_INVALIDARG;
913 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
916 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace4 *iface)
918 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
919 TRACE("(%p)\n", This);
920 return !!(This->flags & FONTFACE_IS_MONOSPACED);
923 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *iface,
924 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
926 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
927 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
928 UINT32 i;
930 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
932 if (is_sideways)
933 FIXME("sideways mode not supported\n");
935 for (i = 0; i < glyph_count; i++) {
936 BOOL has_contours;
938 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i],
939 DWRITE_MEASURING_MODE_NATURAL, &has_contours);
940 if (has_contours)
941 advances[i] += adjustment;
944 return S_OK;
947 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace4 *iface,
948 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
949 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
951 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
952 UINT32 adjustment = fontface_get_horz_metric_adjustment(This);
953 DWRITE_MEASURING_MODE mode;
954 UINT32 i;
956 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
957 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
959 if (em_size < 0.0f || ppdip <= 0.0f) {
960 memset(advances, 0, sizeof(*advances) * glyph_count);
961 return E_INVALIDARG;
964 em_size *= ppdip;
965 if (em_size == 0.0f) {
966 memset(advances, 0, sizeof(*advances) * glyph_count);
967 return S_OK;
970 if (m && memcmp(m, &identity, sizeof(*m)))
971 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
973 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
974 for (i = 0; i < glyph_count; i++) {
975 BOOL has_contours;
977 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode, &has_contours);
978 if (has_contours)
979 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size + adjustment);
980 else
981 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
984 return S_OK;
987 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace4 *iface, UINT32 count,
988 const UINT16 *indices, INT32 *adjustments)
990 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
991 UINT32 i;
993 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
995 if (!(indices || adjustments) || !count)
996 return E_INVALIDARG;
998 if (!indices || count == 1) {
999 memset(adjustments, 0, count*sizeof(INT32));
1000 return E_INVALIDARG;
1003 if (!(This->flags & FONTFACE_HAS_KERNING_PAIRS)) {
1004 memset(adjustments, 0, count*sizeof(INT32));
1005 return S_OK;
1008 for (i = 0; i < count-1; i++)
1009 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
1010 adjustments[count-1] = 0;
1012 return S_OK;
1015 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace4 *iface)
1017 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1018 TRACE("(%p)\n", This);
1019 return !!(This->flags & FONTFACE_HAS_KERNING_PAIRS);
1022 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace4 *iface,
1023 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1024 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1026 DWRITE_GRID_FIT_MODE gridfitmode;
1027 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1028 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1031 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace4 *iface, UINT32 glyph_count,
1032 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1034 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1035 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1036 return E_NOTIMPL;
1039 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace4 *iface)
1041 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1042 TRACE("(%p)\n", This);
1043 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
1046 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace4 *iface)
1048 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1049 TRACE("(%p)\n", This);
1050 return get_fontface_cpal(This) && get_fontface_colr(This);
1053 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace4 *iface)
1055 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1056 TRACE("(%p)\n", This);
1057 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1060 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace4 *iface)
1062 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1063 TRACE("(%p)\n", This);
1064 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1067 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace4 *iface, UINT32 palette_index,
1068 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1070 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1071 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1072 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1075 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize,
1076 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1077 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1078 DWRITE_GRID_FIT_MODE *gridfitmode)
1080 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1081 FLOAT emthreshold;
1082 WORD gasp, *ptr;
1083 UINT32 size;
1085 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1086 measuringmode, params, renderingmode, gridfitmode);
1088 if (m)
1089 FIXME("transform not supported %s\n", debugstr_matrix(m));
1091 if (is_sideways)
1092 FIXME("sideways mode not supported\n");
1094 emSize *= max(dpiX, dpiY) / 96.0f;
1096 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1097 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1098 if (params) {
1099 IDWriteRenderingParams2 *params2;
1100 HRESULT hr;
1102 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1103 if (hr == S_OK) {
1104 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1105 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1106 IDWriteRenderingParams2_Release(params2);
1108 else
1109 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1112 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1114 ptr = get_fontface_gasp(This, &size);
1115 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1117 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1118 if (emSize >= emthreshold)
1119 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1120 else
1121 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1124 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1125 if (emSize >= emthreshold)
1126 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1127 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1128 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1129 else
1130 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1133 return S_OK;
1136 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace4 *iface, IDWriteFontFaceReference **ref)
1138 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1139 FIXME("(%p)->(%p): stub\n", This, ref);
1140 return E_NOTIMPL;
1143 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace4 *iface, DWRITE_PANOSE *panose)
1145 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1146 TRACE("(%p)->(%p)\n", This, panose);
1147 *panose = This->panose;
1150 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace4 *iface)
1152 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1153 TRACE("(%p)\n", This);
1154 return This->weight;
1157 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace4 *iface)
1159 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1160 TRACE("(%p)\n", This);
1161 return This->stretch;
1164 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace4 *iface)
1166 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1167 TRACE("(%p)\n", This);
1168 return This->style;
1171 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1173 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1174 FIXME("(%p)->(%p): stub\n", This, names);
1175 return E_NOTIMPL;
1178 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace4 *iface, IDWriteLocalizedStrings **names)
1180 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1181 FIXME("(%p)->(%p): stub\n", This, names);
1182 return E_NOTIMPL;
1185 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace4 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1186 IDWriteLocalizedStrings **strings, BOOL *exists)
1188 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1189 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1190 return E_NOTIMPL;
1193 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace4 *iface, UINT32 ch)
1195 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1196 UINT16 index;
1198 TRACE("(%p)->(%#x)\n", This, ch);
1200 index = 0;
1201 if (FAILED(fontface_get_glyphs(This, &ch, 1, &index)))
1202 return FALSE;
1204 return index != 0;
1207 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1208 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1209 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1211 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1212 FLOAT emthreshold;
1213 WORD gasp, *ptr;
1214 UINT32 size;
1216 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1217 measuring_mode, params, rendering_mode, gridfit_mode);
1219 if (m)
1220 FIXME("transform not supported %s\n", debugstr_matrix(m));
1222 if (is_sideways)
1223 FIXME("sideways mode not supported\n");
1225 emSize *= max(dpiX, dpiY) / 96.0f;
1227 *rendering_mode = DWRITE_RENDERING_MODE1_DEFAULT;
1228 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1229 if (params) {
1230 IDWriteRenderingParams3 *params3;
1231 HRESULT hr;
1233 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1234 if (hr == S_OK) {
1235 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1236 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1237 IDWriteRenderingParams3_Release(params3);
1239 else
1240 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1243 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1245 ptr = get_fontface_gasp(This, &size);
1246 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1248 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1249 if (emSize >= emthreshold)
1250 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1251 else
1252 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp);
1255 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1256 if (emSize >= emthreshold)
1257 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1258 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1259 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1260 else
1261 *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1264 return S_OK;
1267 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace4 *iface, UINT32 ch)
1269 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1270 FIXME("(%p)->(0x%x): stub\n", This, ch);
1271 return FALSE;
1274 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace4 *iface, UINT16 glyph)
1276 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1277 FIXME("(%p)->(%u): stub\n", This, glyph);
1278 return FALSE;
1281 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace4 *iface, WCHAR const *text,
1282 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1284 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1285 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1286 return E_NOTIMPL;
1289 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace4 *iface, UINT16 const *glyphs,
1290 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1292 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1293 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1294 return E_NOTIMPL;
1297 static HRESULT WINAPI dwritefontface4_GetGlyphImageFormats_(IDWriteFontFace4 *iface, UINT16 glyph,
1298 UINT32 ppem_first, UINT32 ppem_last, DWRITE_GLYPH_IMAGE_FORMATS *formats)
1300 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1301 FIXME("(%p)->(%u %u %u %p): stub\n", This, glyph, ppem_first, ppem_last, formats);
1302 return E_NOTIMPL;
1305 static DWRITE_GLYPH_IMAGE_FORMATS WINAPI dwritefontface4_GetGlyphImageFormats(IDWriteFontFace4 *iface)
1307 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1309 TRACE("(%p)\n", This);
1311 return This->glyph_image_formats;
1314 static HRESULT WINAPI dwritefontface4_GetGlyphImageData(IDWriteFontFace4 *iface, UINT16 glyph,
1315 UINT32 ppem, DWRITE_GLYPH_IMAGE_FORMATS format, DWRITE_GLYPH_IMAGE_DATA *data, void **context)
1317 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1318 FIXME("(%p)->(%u %u %d %p %p): stub\n", This, glyph, ppem, format, data, context);
1319 return E_NOTIMPL;
1322 static void WINAPI dwritefontface4_ReleaseGlyphImageData(IDWriteFontFace4 *iface, void *context)
1324 struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface);
1325 FIXME("(%p)->(%p): stub\n", This, context);
1328 static const IDWriteFontFace4Vtbl dwritefontfacevtbl = {
1329 dwritefontface_QueryInterface,
1330 dwritefontface_AddRef,
1331 dwritefontface_Release,
1332 dwritefontface_GetType,
1333 dwritefontface_GetFiles,
1334 dwritefontface_GetIndex,
1335 dwritefontface_GetSimulations,
1336 dwritefontface_IsSymbolFont,
1337 dwritefontface_GetMetrics,
1338 dwritefontface_GetGlyphCount,
1339 dwritefontface_GetDesignGlyphMetrics,
1340 dwritefontface_GetGlyphIndices,
1341 dwritefontface_TryGetFontTable,
1342 dwritefontface_ReleaseFontTable,
1343 dwritefontface_GetGlyphRunOutline,
1344 dwritefontface_GetRecommendedRenderingMode,
1345 dwritefontface_GetGdiCompatibleMetrics,
1346 dwritefontface_GetGdiCompatibleGlyphMetrics,
1347 dwritefontface1_GetMetrics,
1348 dwritefontface1_GetGdiCompatibleMetrics,
1349 dwritefontface1_GetCaretMetrics,
1350 dwritefontface1_GetUnicodeRanges,
1351 dwritefontface1_IsMonospacedFont,
1352 dwritefontface1_GetDesignGlyphAdvances,
1353 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1354 dwritefontface1_GetKerningPairAdjustments,
1355 dwritefontface1_HasKerningPairs,
1356 dwritefontface1_GetRecommendedRenderingMode,
1357 dwritefontface1_GetVerticalGlyphVariants,
1358 dwritefontface1_HasVerticalGlyphVariants,
1359 dwritefontface2_IsColorFont,
1360 dwritefontface2_GetColorPaletteCount,
1361 dwritefontface2_GetPaletteEntryCount,
1362 dwritefontface2_GetPaletteEntries,
1363 dwritefontface2_GetRecommendedRenderingMode,
1364 dwritefontface3_GetFontFaceReference,
1365 dwritefontface3_GetPanose,
1366 dwritefontface3_GetWeight,
1367 dwritefontface3_GetStretch,
1368 dwritefontface3_GetStyle,
1369 dwritefontface3_GetFamilyNames,
1370 dwritefontface3_GetFaceNames,
1371 dwritefontface3_GetInformationalStrings,
1372 dwritefontface3_HasCharacter,
1373 dwritefontface3_GetRecommendedRenderingMode,
1374 dwritefontface3_IsCharacterLocal,
1375 dwritefontface3_IsGlyphLocal,
1376 dwritefontface3_AreCharactersLocal,
1377 dwritefontface3_AreGlyphsLocal,
1378 dwritefontface4_GetGlyphImageFormats_,
1379 dwritefontface4_GetGlyphImageFormats,
1380 dwritefontface4_GetGlyphImageData,
1381 dwritefontface4_ReleaseGlyphImageData
1384 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace4 **fontface)
1386 struct dwrite_font_data *data = font->data;
1387 struct fontface_desc desc;
1388 struct list *cached_list;
1389 HRESULT hr;
1391 *fontface = NULL;
1393 hr = factory_get_cached_fontface(font->family->collection->factory, &data->file, data->face_index,
1394 font->data->simulations, &cached_list, &IID_IDWriteFontFace4, (void **)fontface);
1395 if (hr == S_OK)
1396 return hr;
1398 desc.factory = font->family->collection->factory;
1399 desc.face_type = data->face_type;
1400 desc.files = &data->file;
1401 desc.files_number = 1;
1402 desc.index = data->face_index;
1403 desc.simulations = data->simulations;
1404 desc.font_data = data;
1405 return create_fontface(&desc, cached_list, fontface);
1408 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1410 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1412 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1414 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1415 IsEqualIID(riid, &IID_IDWriteFont2) ||
1416 IsEqualIID(riid, &IID_IDWriteFont1) ||
1417 IsEqualIID(riid, &IID_IDWriteFont) ||
1418 IsEqualIID(riid, &IID_IUnknown))
1420 *obj = iface;
1421 IDWriteFont3_AddRef(iface);
1422 return S_OK;
1425 WARN("%s not implemented.\n", debugstr_guid(riid));
1427 *obj = NULL;
1428 return E_NOINTERFACE;
1431 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1433 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1434 ULONG ref = InterlockedIncrement(&This->ref);
1435 TRACE("(%p)->(%d)\n", This, ref);
1436 return ref;
1439 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1441 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1442 ULONG ref = InterlockedDecrement(&This->ref);
1444 TRACE("(%p)->(%d)\n", This, ref);
1446 if (!ref) {
1447 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1448 release_font_data(This->data);
1449 heap_free(This);
1452 return ref;
1455 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1457 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1458 TRACE("(%p)->(%p)\n", This, family);
1460 *family = (IDWriteFontFamily*)This->family;
1461 IDWriteFontFamily_AddRef(*family);
1462 return S_OK;
1465 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1467 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1468 TRACE("(%p)\n", This);
1469 return This->data->weight;
1472 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1474 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1475 TRACE("(%p)\n", This);
1476 return This->data->stretch;
1479 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1481 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1482 TRACE("(%p)\n", This);
1483 return This->style;
1486 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1488 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1489 IDWriteFontFace4 *fontface;
1490 HRESULT hr;
1491 BOOL ret;
1493 TRACE("(%p)\n", This);
1495 hr = get_fontface_from_font(This, &fontface);
1496 if (FAILED(hr))
1497 return FALSE;
1499 ret = IDWriteFontFace4_IsSymbolFont(fontface);
1500 IDWriteFontFace4_Release(fontface);
1501 return ret;
1504 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1506 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1507 TRACE("(%p)->(%p)\n", This, names);
1508 return clone_localizedstring(This->data->names, names);
1511 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1512 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1514 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1515 struct dwrite_font_data *data = This->data;
1516 HRESULT hr;
1518 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1520 *exists = FALSE;
1521 *strings = NULL;
1523 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1524 return S_OK;
1526 if (!data->info_strings[stringid]) {
1527 IDWriteFontFace4 *fontface;
1528 const void *table_data;
1529 BOOL table_exists;
1530 void *context;
1531 UINT32 size;
1533 hr = get_fontface_from_font(This, &fontface);
1534 if (FAILED(hr))
1535 return hr;
1537 table_exists = FALSE;
1538 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1539 if (FAILED(hr) || !table_exists)
1540 WARN("no NAME table found.\n");
1542 if (table_exists) {
1543 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1544 IDWriteFontFace4_ReleaseFontTable(fontface, context);
1545 if (FAILED(hr) || !data->info_strings[stringid])
1546 return hr;
1548 IDWriteFontFace4_Release(fontface);
1551 hr = clone_localizedstring(data->info_strings[stringid], strings);
1552 if (FAILED(hr))
1553 return hr;
1555 *exists = TRUE;
1556 return S_OK;
1559 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1561 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1562 TRACE("(%p)\n", This);
1563 return This->data->simulations;
1566 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1568 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1570 TRACE("(%p)->(%p)\n", This, metrics);
1571 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1574 static HRESULT font_has_character(struct dwrite_font *font, UINT32 ch, BOOL *exists)
1576 IDWriteFontFace4 *fontface;
1577 UINT16 index;
1578 HRESULT hr;
1580 *exists = FALSE;
1582 hr = get_fontface_from_font(font, &fontface);
1583 if (FAILED(hr))
1584 return hr;
1586 index = 0;
1587 hr = IDWriteFontFace4_GetGlyphIndices(fontface, &ch, 1, &index);
1588 IDWriteFontFace4_Release(fontface);
1589 if (FAILED(hr))
1590 return hr;
1592 *exists = index != 0;
1593 return S_OK;
1596 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 ch, BOOL *exists)
1598 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1600 TRACE("(%p)->(%#x %p)\n", This, ch, exists);
1602 return font_has_character(This, ch, exists);
1605 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1607 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1608 TRACE("(%p)->(%p)\n", This, fontface);
1609 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1612 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1614 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1615 TRACE("(%p)->(%p)\n", This, metrics);
1616 *metrics = This->data->metrics;
1619 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1621 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1622 TRACE("(%p)->(%p)\n", This, panose);
1623 *panose = This->data->panose;
1626 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1628 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1629 IDWriteFontFace4 *fontface;
1630 HRESULT hr;
1632 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1634 hr = get_fontface_from_font(This, &fontface);
1635 if (FAILED(hr))
1636 return hr;
1638 hr = IDWriteFontFace4_GetUnicodeRanges(fontface, max_count, ranges, count);
1639 IDWriteFontFace4_Release(fontface);
1640 return hr;
1643 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1645 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1646 IDWriteFontFace4 *fontface;
1647 HRESULT hr;
1648 BOOL ret;
1650 TRACE("(%p)\n", This);
1652 hr = get_fontface_from_font(This, &fontface);
1653 if (FAILED(hr))
1654 return FALSE;
1656 ret = IDWriteFontFace4_IsMonospacedFont(fontface);
1657 IDWriteFontFace4_Release(fontface);
1658 return ret;
1661 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1663 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1664 IDWriteFontFace4 *fontface;
1665 HRESULT hr;
1666 BOOL ret;
1668 TRACE("(%p)\n", This);
1670 hr = get_fontface_from_font(This, &fontface);
1671 if (FAILED(hr))
1672 return FALSE;
1674 ret = IDWriteFontFace4_IsColorFont(fontface);
1675 IDWriteFontFace4_Release(fontface);
1676 return ret;
1679 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1681 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1683 TRACE("(%p)->(%p)\n", This, fontface);
1685 return get_fontface_from_font(This, (IDWriteFontFace4 **)fontface);
1688 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1690 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1691 FIXME("(%p)->(%p): stub\n", This, font);
1692 return FALSE;
1695 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1697 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1699 TRACE("(%p)->(%p)\n", This, reference);
1701 return IDWriteFactory5_CreateFontFaceReference_(This->family->collection->factory, This->data->file,
1702 This->data->face_index, This->data->simulations, reference);
1705 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1707 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1708 BOOL ret;
1710 TRACE("(%p)->(%#x)\n", This, ch);
1712 return font_has_character(This, ch, &ret) == S_OK && ret;
1715 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1717 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1718 FIXME("(%p): stub\n", This);
1719 return DWRITE_LOCALITY_LOCAL;
1722 static const IDWriteFont3Vtbl dwritefontvtbl = {
1723 dwritefont_QueryInterface,
1724 dwritefont_AddRef,
1725 dwritefont_Release,
1726 dwritefont_GetFontFamily,
1727 dwritefont_GetWeight,
1728 dwritefont_GetStretch,
1729 dwritefont_GetStyle,
1730 dwritefont_IsSymbolFont,
1731 dwritefont_GetFaceNames,
1732 dwritefont_GetInformationalStrings,
1733 dwritefont_GetSimulations,
1734 dwritefont_GetMetrics,
1735 dwritefont_HasCharacter,
1736 dwritefont_CreateFontFace,
1737 dwritefont1_GetMetrics,
1738 dwritefont1_GetPanose,
1739 dwritefont1_GetUnicodeRanges,
1740 dwritefont1_IsMonospacedFont,
1741 dwritefont2_IsColorFont,
1742 dwritefont3_CreateFontFace,
1743 dwritefont3_Equals,
1744 dwritefont3_GetFontFaceReference,
1745 dwritefont3_HasCharacter,
1746 dwritefont3_GetLocality
1749 static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
1751 if (!iface)
1752 return NULL;
1753 assert(iface->lpVtbl == (IDWriteFontVtbl*)&dwritefontvtbl);
1754 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
1757 static struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
1759 if (!iface)
1760 return NULL;
1761 assert(iface->lpVtbl == (IDWriteFontFaceVtbl*)&dwritefontfacevtbl);
1762 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
1765 void get_logfont_from_font(IDWriteFont *iface, LOGFONTW *lf)
1767 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1768 *lf = font->data->lf;
1771 void get_logfont_from_fontface(IDWriteFontFace *iface, LOGFONTW *lf)
1773 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1774 *lf = fontface->lf;
1777 HRESULT get_fontsig_from_font(IDWriteFont *iface, FONTSIGNATURE *fontsig)
1779 struct dwrite_font *font = unsafe_impl_from_IDWriteFont(iface);
1780 *fontsig = font->data->fontsig;
1781 return S_OK;
1784 HRESULT get_fontsig_from_fontface(IDWriteFontFace *iface, FONTSIGNATURE *fontsig)
1786 struct dwrite_fontface *fontface = unsafe_impl_from_IDWriteFontFace(iface);
1787 *fontsig = fontface->fontsig;
1788 return S_OK;
1791 static HRESULT create_font(struct dwrite_fontfamily *family, UINT32 index, IDWriteFont3 **font)
1793 struct dwrite_font *This;
1795 *font = NULL;
1797 This = heap_alloc(sizeof(*This));
1798 if (!This)
1799 return E_OUTOFMEMORY;
1801 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1802 This->ref = 1;
1803 This->family = family;
1804 IDWriteFontFamily1_AddRef(&family->IDWriteFontFamily1_iface);
1805 This->data = family->data->fonts[index];
1806 This->style = This->data->style;
1807 addref_font_data(This->data);
1809 *font = &This->IDWriteFont3_iface;
1811 return S_OK;
1814 /* IDWriteFontList1 */
1815 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1817 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1819 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1821 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1822 IsEqualIID(riid, &IID_IDWriteFontList) ||
1823 IsEqualIID(riid, &IID_IUnknown))
1825 *obj = iface;
1826 IDWriteFontList1_AddRef(iface);
1827 return S_OK;
1830 WARN("%s not implemented.\n", debugstr_guid(riid));
1832 *obj = NULL;
1833 return E_NOINTERFACE;
1836 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1838 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1839 ULONG ref = InterlockedIncrement(&This->ref);
1840 TRACE("(%p)->(%d)\n", This, ref);
1841 return ref;
1844 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1846 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1847 ULONG ref = InterlockedDecrement(&This->ref);
1849 TRACE("(%p)->(%d)\n", This, ref);
1851 if (!ref) {
1852 UINT32 i;
1854 for (i = 0; i < This->font_count; i++)
1855 release_font_data(This->fonts[i]);
1856 IDWriteFontFamily1_Release(&This->family->IDWriteFontFamily1_iface);
1857 heap_free(This->fonts);
1858 heap_free(This);
1861 return ref;
1864 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1866 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1867 return IDWriteFontFamily1_GetFontCollection(&This->family->IDWriteFontFamily1_iface, collection);
1870 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1872 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1873 TRACE("(%p)\n", This);
1874 return This->font_count;
1877 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1879 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1881 TRACE("(%p)->(%u %p)\n", This, index, font);
1883 *font = NULL;
1885 if (This->font_count == 0)
1886 return S_FALSE;
1888 if (index >= This->font_count)
1889 return E_INVALIDARG;
1891 return create_font(This->family, index, (IDWriteFont3 **)font);
1894 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1896 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1898 FIXME("(%p)->(%u): stub\n", This, index);
1900 return DWRITE_LOCALITY_LOCAL;
1903 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1905 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1907 TRACE("(%p)->(%u %p)\n", This, index, font);
1909 *font = NULL;
1911 if (This->font_count == 0)
1912 return S_FALSE;
1914 if (index >= This->font_count)
1915 return E_FAIL;
1917 return create_font(This->family, index, font);
1920 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1921 IDWriteFontFaceReference **reference)
1923 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1924 IDWriteFont3 *font;
1925 HRESULT hr;
1927 TRACE("(%p)->(%u %p)\n", This, index, reference);
1929 *reference = NULL;
1931 hr = IDWriteFontList1_GetFont(iface, index, &font);
1932 if (FAILED(hr))
1933 return hr;
1935 hr = IDWriteFont3_GetFontFaceReference(font, reference);
1936 IDWriteFont3_Release(font);
1938 return hr;
1941 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1942 dwritefontlist_QueryInterface,
1943 dwritefontlist_AddRef,
1944 dwritefontlist_Release,
1945 dwritefontlist_GetFontCollection,
1946 dwritefontlist_GetFontCount,
1947 dwritefontlist_GetFont,
1948 dwritefontlist1_GetFontLocality,
1949 dwritefontlist1_GetFont,
1950 dwritefontlist1_GetFontFaceReference
1953 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1955 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1957 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1959 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1960 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1961 IsEqualIID(riid, &IID_IDWriteFontList) ||
1962 IsEqualIID(riid, &IID_IUnknown))
1964 *obj = iface;
1965 IDWriteFontFamily1_AddRef(iface);
1966 return S_OK;
1969 WARN("%s not implemented.\n", debugstr_guid(riid));
1971 *obj = NULL;
1972 return E_NOINTERFACE;
1975 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1977 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1978 ULONG ref = InterlockedIncrement(&This->ref);
1979 TRACE("(%p)->(%d)\n", This, ref);
1980 return ref;
1983 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1985 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1986 ULONG ref = InterlockedDecrement(&This->ref);
1988 TRACE("(%p)->(%d)\n", This, ref);
1990 if (!ref)
1992 IDWriteFontCollection1_Release(&This->collection->IDWriteFontCollection1_iface);
1993 release_fontfamily_data(This->data);
1994 heap_free(This);
1997 return ref;
2000 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
2002 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2004 TRACE("(%p)->(%p)\n", This, collection);
2006 *collection = (IDWriteFontCollection*)This->collection;
2007 IDWriteFontCollection_AddRef(*collection);
2008 return S_OK;
2011 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
2013 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2014 TRACE("(%p)\n", This);
2015 return This->data->font_count;
2018 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
2020 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2022 TRACE("(%p)->(%u %p)\n", This, index, font);
2024 *font = NULL;
2026 if (This->data->font_count == 0)
2027 return S_FALSE;
2029 if (index >= This->data->font_count)
2030 return E_INVALIDARG;
2032 return create_font(This, index, (IDWriteFont3 **)font);
2035 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
2037 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2038 return clone_localizedstring(This->data->familyname, names);
2041 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
2042 const struct dwrite_font_propvec *req)
2044 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
2045 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
2046 FLOAT cur_req_prod, next_req_prod;
2048 if (next_to_req < cur_to_req)
2049 return TRUE;
2051 if (next_to_req > cur_to_req)
2052 return FALSE;
2054 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
2055 next_req_prod = get_font_prop_vec_dotproduct(next, req);
2057 if (next_req_prod > cur_req_prod)
2058 return TRUE;
2060 if (next_req_prod < cur_req_prod)
2061 return FALSE;
2063 if (next->stretch > cur->stretch)
2064 return TRUE;
2065 if (next->stretch < cur->stretch)
2066 return FALSE;
2068 if (next->style > cur->style)
2069 return TRUE;
2070 if (next->style < cur->style)
2071 return FALSE;
2073 if (next->weight > cur->weight)
2074 return TRUE;
2075 if (next->weight < cur->weight)
2076 return FALSE;
2078 /* full match, no reason to prefer new variant */
2079 return FALSE;
2082 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2083 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
2085 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2086 struct dwrite_font_propvec req;
2087 UINT32 i, match;
2089 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
2091 if (This->data->font_count == 0) {
2092 *font = NULL;
2093 return DWRITE_E_NOFONT;
2096 init_font_prop_vec(weight, stretch, style, &req);
2097 match = 0;
2099 for (i = 1; i < This->data->font_count; i++) {
2100 if (is_better_font_match(&This->data->fonts[i]->propvec, &This->data->fonts[match]->propvec, &req))
2101 match = i;
2104 return create_font(This, match, (IDWriteFont3 **)font);
2107 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
2109 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
2111 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
2114 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
2116 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
2119 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
2121 UINT32 b = fonts->font_count - 1, j, t;
2123 while (1) {
2124 t = b;
2126 for (j = 0; j < b; j++) {
2127 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
2128 struct dwrite_font_data *s = fonts->fonts[j];
2129 fonts->fonts[j] = fonts->fonts[j+1];
2130 fonts->fonts[j+1] = s;
2131 t = j;
2135 if (t == b)
2136 break;
2137 b = t;
2141 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
2142 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
2144 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2145 matching_filter_func func = NULL;
2146 struct dwrite_font_propvec req;
2147 struct dwrite_fontlist *fonts;
2148 UINT32 i;
2150 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
2152 *ret = NULL;
2154 fonts = heap_alloc(sizeof(*fonts));
2155 if (!fonts)
2156 return E_OUTOFMEMORY;
2158 /* Allocate as many as family has, not all of them will be necessary used. */
2159 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
2160 if (!fonts->fonts) {
2161 heap_free(fonts);
2162 return E_OUTOFMEMORY;
2165 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2166 fonts->ref = 1;
2167 fonts->family = This;
2168 IDWriteFontFamily1_AddRef(&fonts->family->IDWriteFontFamily1_iface);
2169 fonts->font_count = 0;
2171 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2172 if (style == DWRITE_FONT_STYLE_NORMAL) {
2173 if (This->data->has_normal_face || This->data->has_italic_face)
2174 func = is_font_acceptable_for_normal;
2176 else /* requested oblique or italic */ {
2177 if (This->data->has_oblique_face || This->data->has_italic_face)
2178 func = is_font_acceptable_for_oblique_italic;
2181 for (i = 0; i < This->data->font_count; i++) {
2182 if (!func || func(This->data->fonts[i])) {
2183 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2184 addref_font_data(This->data->fonts[i]);
2185 fonts->font_count++;
2189 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2190 init_font_prop_vec(weight, stretch, style, &req);
2191 matchingfonts_sort(fonts, &req);
2193 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2194 return S_OK;
2197 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2199 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2201 FIXME("(%p)->(%u): stub\n", This, index);
2203 return DWRITE_LOCALITY_LOCAL;
2206 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2208 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2210 TRACE("(%p)->(%u %p)\n", This, index, font);
2212 *font = NULL;
2214 if (This->data->font_count == 0)
2215 return S_FALSE;
2217 if (index >= This->data->font_count)
2218 return E_FAIL;
2220 return create_font(This, index, font);
2223 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2224 IDWriteFontFaceReference **reference)
2226 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2227 IDWriteFont3 *font;
2228 HRESULT hr;
2230 TRACE("(%p)->(%u %p)\n", This, index, reference);
2232 *reference = NULL;
2234 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2235 if (FAILED(hr))
2236 return hr;
2238 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2239 IDWriteFont3_Release(font);
2241 return hr;
2244 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2245 dwritefontfamily_QueryInterface,
2246 dwritefontfamily_AddRef,
2247 dwritefontfamily_Release,
2248 dwritefontfamily_GetFontCollection,
2249 dwritefontfamily_GetFontCount,
2250 dwritefontfamily_GetFont,
2251 dwritefontfamily_GetFamilyNames,
2252 dwritefontfamily_GetFirstMatchingFont,
2253 dwritefontfamily_GetMatchingFonts,
2254 dwritefontfamily1_GetFontLocality,
2255 dwritefontfamily1_GetFont,
2256 dwritefontfamily1_GetFontFaceReference
2259 static HRESULT create_fontfamily(struct dwrite_fontcollection *collection, UINT32 index, IDWriteFontFamily1 **family)
2261 struct dwrite_fontfamily *This;
2263 *family = NULL;
2265 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2266 if (!This) return E_OUTOFMEMORY;
2268 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2269 This->ref = 1;
2270 This->collection = collection;
2271 IDWriteFontCollection1_AddRef(&collection->IDWriteFontCollection1_iface);
2272 This->data = collection->family_data[index];
2273 InterlockedIncrement(&This->data->ref);
2275 *family = &This->IDWriteFontFamily1_iface;
2277 return S_OK;
2280 BOOL is_system_collection(IDWriteFontCollection *collection)
2282 void *obj;
2283 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2286 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2288 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2289 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2291 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2292 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2293 IsEqualIID(riid, &IID_IUnknown))
2295 *obj = iface;
2296 IDWriteFontCollection1_AddRef(iface);
2297 return S_OK;
2300 *obj = NULL;
2302 if (IsEqualIID(riid, &IID_issystemcollection))
2303 return S_OK;
2305 WARN("%s not implemented.\n", debugstr_guid(riid));
2307 return E_NOINTERFACE;
2310 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2312 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2313 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2315 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2316 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2317 IsEqualIID(riid, &IID_IUnknown))
2319 *obj = iface;
2320 IDWriteFontCollection1_AddRef(iface);
2321 return S_OK;
2324 WARN("%s not implemented.\n", debugstr_guid(riid));
2326 *obj = NULL;
2328 return E_NOINTERFACE;
2331 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2333 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2334 ULONG ref = InterlockedIncrement(&This->ref);
2335 TRACE("(%p)->(%d)\n", This, ref);
2336 return ref;
2339 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2341 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2342 ULONG ref = InterlockedDecrement(&This->ref);
2344 TRACE("(%p)->(%d)\n", This, ref);
2346 if (!ref) {
2347 int i;
2349 factory_detach_fontcollection(This->factory, iface);
2350 for (i = 0; i < This->family_count; i++)
2351 release_fontfamily_data(This->family_data[i]);
2352 heap_free(This->family_data);
2353 heap_free(This);
2356 return ref;
2359 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2361 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2362 TRACE("(%p)\n", This);
2363 return This->family_count;
2366 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2368 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2370 TRACE("(%p)->(%u %p)\n", This, index, family);
2372 if (index >= This->family_count) {
2373 *family = NULL;
2374 return E_FAIL;
2377 return create_fontfamily(This, index, (IDWriteFontFamily1 **)family);
2380 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2382 UINT32 i;
2384 for (i = 0; i < collection->family_count; i++) {
2385 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2386 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2387 HRESULT hr;
2389 for (j = 0; j < count; j++) {
2390 WCHAR buffer[255];
2391 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2392 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2393 return i;
2397 return ~0u;
2400 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2402 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2403 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2404 *index = collection_find_family(This, name);
2405 *exists = *index != ~0u;
2406 return S_OK;
2409 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2411 UINT32 left_key_size, right_key_size;
2412 const void *left_key, *right_key;
2413 HRESULT hr;
2415 if (left == right)
2416 return TRUE;
2418 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2419 if (FAILED(hr))
2420 return FALSE;
2422 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2423 if (FAILED(hr))
2424 return FALSE;
2426 if (left_key_size != right_key_size)
2427 return FALSE;
2429 return !memcmp(left_key, right_key, left_key_size);
2432 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2434 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2435 IDWriteFontFamily1 *family;
2436 UINT32 i, j, face_index;
2437 BOOL found_font = FALSE;
2438 IDWriteFontFile *file;
2439 HRESULT hr;
2441 TRACE("(%p)->(%p %p)\n", This, face, font);
2443 *font = NULL;
2445 if (!face)
2446 return E_INVALIDARG;
2448 i = 1;
2449 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2450 if (FAILED(hr))
2451 return hr;
2452 face_index = IDWriteFontFace_GetIndex(face);
2454 found_font = FALSE;
2455 for (i = 0; i < This->family_count; i++) {
2456 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2458 for (j = 0; j < family_data->font_count; j++) {
2459 struct dwrite_font_data *font_data = family_data->fonts[j];
2461 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2462 found_font = TRUE;
2463 break;
2467 if (found_font)
2468 break;
2470 IDWriteFontFile_Release(file);
2472 if (!found_font)
2473 return DWRITE_E_NOFONT;
2475 hr = create_fontfamily(This, i, &family);
2476 if (FAILED(hr))
2477 return hr;
2479 hr = create_font(impl_from_IDWriteFontFamily1(family), j, (IDWriteFont3 **)font);
2480 IDWriteFontFamily1_Release(family);
2481 return hr;
2484 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2486 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2488 FIXME("(%p)->(%p): stub\n", This, fontset);
2490 return E_NOTIMPL;
2493 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2495 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2497 TRACE("(%p)->(%u %p)\n", This, index, family);
2499 if (index >= This->family_count) {
2500 *family = NULL;
2501 return E_FAIL;
2504 return create_fontfamily(This, index, family);
2507 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2508 dwritefontcollection_QueryInterface,
2509 dwritefontcollection_AddRef,
2510 dwritefontcollection_Release,
2511 dwritefontcollection_GetFontFamilyCount,
2512 dwritefontcollection_GetFontFamily,
2513 dwritefontcollection_FindFamilyName,
2514 dwritefontcollection_GetFontFromFontFace,
2515 dwritefontcollection1_GetFontSet,
2516 dwritefontcollection1_GetFontFamily
2519 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2520 dwritesystemfontcollection_QueryInterface,
2521 dwritefontcollection_AddRef,
2522 dwritefontcollection_Release,
2523 dwritefontcollection_GetFontFamilyCount,
2524 dwritefontcollection_GetFontFamily,
2525 dwritefontcollection_FindFamilyName,
2526 dwritefontcollection_GetFontFromFontFace,
2527 dwritefontcollection1_GetFontSet,
2528 dwritefontcollection1_GetFontFamily
2531 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2533 if (family_data->font_count + 1 >= family_data->font_alloc) {
2534 struct dwrite_font_data **new_list;
2535 UINT32 new_alloc;
2537 new_alloc = family_data->font_alloc * 2;
2538 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2539 if (!new_list)
2540 return E_OUTOFMEMORY;
2541 family_data->fonts = new_list;
2542 family_data->font_alloc = new_alloc;
2545 family_data->fonts[family_data->font_count] = font_data;
2546 family_data->font_count++;
2547 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2548 family_data->has_normal_face = 1;
2549 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2550 family_data->has_oblique_face = 1;
2551 else
2552 family_data->has_italic_face = 1;
2553 return S_OK;
2556 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2558 if (collection->family_alloc < collection->family_count + 1) {
2559 struct dwrite_fontfamily_data **new_list;
2560 UINT32 new_alloc;
2562 new_alloc = collection->family_alloc * 2;
2563 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2564 if (!new_list)
2565 return E_OUTOFMEMORY;
2567 collection->family_alloc = new_alloc;
2568 collection->family_data = new_list;
2571 collection->family_data[collection->family_count++] = family;
2572 return S_OK;
2575 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2577 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2578 collection->ref = 1;
2579 collection->family_count = 0;
2580 collection->family_alloc = is_system ? 30 : 5;
2581 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2582 if (!collection->family_data)
2583 return E_OUTOFMEMORY;
2585 return S_OK;
2588 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2590 IDWriteFontFileLoader *loader;
2591 const void *key;
2592 UINT32 key_size;
2593 HRESULT hr;
2595 *stream = NULL;
2597 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2598 if (FAILED(hr))
2599 return hr;
2601 hr = IDWriteFontFile_GetLoader(file, &loader);
2602 if (FAILED(hr))
2603 return hr;
2605 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2606 IDWriteFontFileLoader_Release(loader);
2607 if (FAILED(hr))
2608 return hr;
2610 return hr;
2613 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2615 BOOL exists = FALSE;
2616 UINT32 index;
2617 HRESULT hr;
2619 buffer[0] = 0;
2620 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2621 if (FAILED(hr) || !exists)
2622 return;
2624 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2627 static int trim_spaces(WCHAR *in, WCHAR *ret)
2629 int len;
2631 while (isspaceW(*in))
2632 in++;
2634 ret[0] = 0;
2635 if (!(len = strlenW(in)))
2636 return 0;
2638 while (isspaceW(in[len-1]))
2639 len--;
2641 memcpy(ret, in, len*sizeof(WCHAR));
2642 ret[len] = 0;
2644 return len;
2647 struct name_token {
2648 struct list entry;
2649 const WCHAR *ptr;
2650 INT len; /* token length */
2651 INT fulllen; /* full length including following separators */
2654 static inline BOOL is_name_separator_char(WCHAR ch)
2656 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2659 struct name_pattern {
2660 const WCHAR *part1; /* NULL indicates end of list */
2661 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2664 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2666 const struct name_pattern *pattern;
2667 struct name_token *token;
2668 int i = 0;
2670 while ((pattern = &patterns[i++])->part1) {
2671 int len_part1 = strlenW(pattern->part1);
2672 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2674 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2675 if (len_part2 == 0) {
2676 /* simple case with single part pattern */
2677 if (token->len != len_part1)
2678 continue;
2680 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2681 if (match) *match = *token;
2682 list_remove(&token->entry);
2683 heap_free(token);
2684 return TRUE;
2687 else {
2688 struct name_token *next_token;
2689 struct list *next_entry;
2691 /* pattern parts are stored in reading order, tokens list is reversed */
2692 if (token->len < len_part2)
2693 continue;
2695 /* it's possible to have combined string as a token, like ExtraCondensed */
2696 if (token->len == len_part1 + len_part2) {
2697 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2698 continue;
2700 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2701 continue;
2703 /* combined string match */
2704 if (match) *match = *token;
2705 list_remove(&token->entry);
2706 heap_free(token);
2707 return TRUE;
2710 /* now it's only possible to have two tokens matched to respective pattern parts */
2711 if (token->len != len_part2)
2712 continue;
2714 next_entry = list_next(tokens, &token->entry);
2715 if (next_entry) {
2716 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2717 if (next_token->len != len_part1)
2718 continue;
2720 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2721 continue;
2723 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2724 continue;
2726 /* both parts matched, remove tokens */
2727 if (match) {
2728 match->ptr = next_token->ptr;
2729 match->len = (token->ptr - next_token->ptr) + token->len;
2731 list_remove(&token->entry);
2732 list_remove(&next_token->entry);
2733 heap_free(next_token);
2734 heap_free(token);
2735 return TRUE;
2741 if (match) {
2742 match->ptr = NULL;
2743 match->len = 0;
2745 return FALSE;
2748 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2750 static const WCHAR itaW[] = {'i','t','a',0};
2751 static const WCHAR italW[] = {'i','t','a','l',0};
2752 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2753 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2755 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2756 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2757 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2758 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2760 static const struct name_pattern italic_patterns[] = {
2761 { itaW },
2762 { italW },
2763 { italicW },
2764 { cursiveW },
2765 { kursivW },
2766 { NULL }
2769 static const struct name_pattern oblique_patterns[] = {
2770 { inclinedW },
2771 { obliqueW },
2772 { backslantedW },
2773 { backslantW },
2774 { slantedW },
2775 { NULL }
2778 /* italic patterns first */
2779 if (match_pattern_list(tokens, italic_patterns, match))
2780 return DWRITE_FONT_STYLE_ITALIC;
2782 /* oblique patterns */
2783 if (match_pattern_list(tokens, oblique_patterns, match))
2784 return DWRITE_FONT_STYLE_OBLIQUE;
2786 return style;
2789 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2790 struct name_token *match)
2792 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2793 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2794 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2795 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2796 static const WCHAR wideW[] = {'w','i','d','e',0};
2797 static const WCHAR condW[] = {'c','o','n','d',0};
2799 static const struct name_pattern ultracondensed_patterns[] = {
2800 { extraW, compressedW },
2801 { extW, compressedW },
2802 { ultraW, compressedW },
2803 { ultraW, condensedW },
2804 { ultraW, condW },
2805 { NULL }
2808 static const struct name_pattern extracondensed_patterns[] = {
2809 { compressedW },
2810 { extraW, condensedW },
2811 { extW, condensedW },
2812 { extraW, condW },
2813 { extW, condW },
2814 { NULL }
2817 static const struct name_pattern semicondensed_patterns[] = {
2818 { narrowW },
2819 { compactW },
2820 { semiW, condensedW },
2821 { semiW, condW },
2822 { NULL }
2825 static const struct name_pattern semiexpanded_patterns[] = {
2826 { wideW },
2827 { semiW, expandedW },
2828 { semiW, extendedW },
2829 { NULL }
2832 static const struct name_pattern extraexpanded_patterns[] = {
2833 { extraW, expandedW },
2834 { extW, expandedW },
2835 { extraW, extendedW },
2836 { extW, extendedW },
2837 { NULL }
2840 static const struct name_pattern ultraexpanded_patterns[] = {
2841 { ultraW, expandedW },
2842 { ultraW, extendedW },
2843 { NULL }
2846 static const struct name_pattern condensed_patterns[] = {
2847 { condensedW },
2848 { condW },
2849 { NULL }
2852 static const struct name_pattern expanded_patterns[] = {
2853 { expandedW },
2854 { extendedW },
2855 { NULL }
2858 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2859 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2861 if (match_pattern_list(tokens, extracondensed_patterns, match))
2862 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2864 if (match_pattern_list(tokens, semicondensed_patterns, match))
2865 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2867 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2868 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2870 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2871 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2873 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2874 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2876 if (match_pattern_list(tokens, condensed_patterns, match))
2877 return DWRITE_FONT_STRETCH_CONDENSED;
2879 if (match_pattern_list(tokens, expanded_patterns, match))
2880 return DWRITE_FONT_STRETCH_EXPANDED;
2882 return stretch;
2885 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2886 struct name_token *match)
2888 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2889 static const WCHAR nordW[] = {'n','o','r','d',0};
2891 static const struct name_pattern thin_patterns[] = {
2892 { extraW, thinW },
2893 { extW, thinW },
2894 { ultraW, thinW },
2895 { NULL }
2898 static const struct name_pattern extralight_patterns[] = {
2899 { extraW, lightW },
2900 { extW, lightW },
2901 { ultraW, lightW },
2902 { NULL }
2905 static const struct name_pattern semilight_patterns[] = {
2906 { semiW, lightW },
2907 { NULL }
2910 static const struct name_pattern demibold_patterns[] = {
2911 { semiW, boldW },
2912 { demiW, boldW },
2913 { NULL }
2916 static const struct name_pattern extrabold_patterns[] = {
2917 { extraW, boldW },
2918 { extW, boldW },
2919 { ultraW, boldW },
2920 { NULL }
2923 static const struct name_pattern extrablack_patterns[] = {
2924 { extraW, blackW },
2925 { extW, blackW },
2926 { ultraW, blackW },
2927 { NULL }
2930 static const struct name_pattern bold_patterns[] = {
2931 { boldW },
2932 { NULL }
2935 static const struct name_pattern thin2_patterns[] = {
2936 { thinW },
2937 { NULL }
2940 static const struct name_pattern light_patterns[] = {
2941 { lightW },
2942 { NULL }
2945 static const struct name_pattern medium_patterns[] = {
2946 { mediumW },
2947 { NULL }
2950 static const struct name_pattern black_patterns[] = {
2951 { blackW },
2952 { heavyW },
2953 { nordW },
2954 { NULL }
2957 static const struct name_pattern demibold2_patterns[] = {
2958 { demiW },
2959 { NULL }
2962 static const struct name_pattern extrabold2_patterns[] = {
2963 { ultraW },
2964 { NULL }
2967 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2968 matching pattern. */
2970 if (match_pattern_list(tokens, thin_patterns, match))
2971 return DWRITE_FONT_WEIGHT_THIN;
2973 if (match_pattern_list(tokens, extralight_patterns, match))
2974 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2976 if (match_pattern_list(tokens, semilight_patterns, match))
2977 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2979 if (match_pattern_list(tokens, demibold_patterns, match))
2980 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2982 if (match_pattern_list(tokens, extrabold_patterns, match))
2983 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2985 if (match_pattern_list(tokens, extrablack_patterns, match))
2986 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2988 if (match_pattern_list(tokens, bold_patterns, match))
2989 return DWRITE_FONT_WEIGHT_BOLD;
2991 if (match_pattern_list(tokens, thin2_patterns, match))
2992 return DWRITE_FONT_WEIGHT_THIN;
2994 if (match_pattern_list(tokens, light_patterns, match))
2995 return DWRITE_FONT_WEIGHT_LIGHT;
2997 if (match_pattern_list(tokens, medium_patterns, match))
2998 return DWRITE_FONT_WEIGHT_MEDIUM;
3000 if (match_pattern_list(tokens, black_patterns, match))
3001 return DWRITE_FONT_WEIGHT_BLACK;
3003 if (match_pattern_list(tokens, black_patterns, match))
3004 return DWRITE_FONT_WEIGHT_BLACK;
3006 if (match_pattern_list(tokens, demibold2_patterns, match))
3007 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
3009 if (match_pattern_list(tokens, extrabold2_patterns, match))
3010 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
3012 /* FIXME: use abbreviated names to extract weight */
3014 return weight;
3017 struct knownweight_entry {
3018 const WCHAR *nameW;
3019 DWRITE_FONT_WEIGHT weight;
3022 static int compare_knownweights(const void *a, const void* b)
3024 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
3025 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
3026 int ret = 0;
3028 if (target > entry->weight)
3029 ret = 1;
3030 else if (target < entry->weight)
3031 ret = -1;
3033 return ret;
3036 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
3038 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
3039 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
3040 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
3041 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
3042 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
3043 const struct knownweight_entry *ptr;
3045 static const struct knownweight_entry knownweights[] = {
3046 { thinW, DWRITE_FONT_WEIGHT_THIN },
3047 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
3048 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
3049 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
3050 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
3051 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
3052 { boldW, DWRITE_FONT_WEIGHT_BOLD },
3053 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
3054 { blackW, DWRITE_FONT_WEIGHT_BLACK },
3055 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
3058 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
3059 compare_knownweights);
3060 if (!ptr) {
3061 nameW[0] = 0;
3062 return FALSE;
3065 strcpyW(nameW, ptr->nameW);
3066 return TRUE;
3069 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
3071 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
3072 strW[name->len] = 0;
3075 /* Modifies facenameW string, and returns pointer to regular term that was removed */
3076 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
3078 static const WCHAR bookW[] = {'B','o','o','k',0};
3079 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
3080 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
3081 static const WCHAR romanW[] = {'R','o','m','a','n',0};
3082 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
3084 static const WCHAR *regular_patterns[] = {
3085 bookW,
3086 normalW,
3087 regularW,
3088 romanW,
3089 uprightW,
3090 NULL
3093 const WCHAR *regular_ptr = NULL, *ptr;
3094 int i = 0;
3096 if (len == -1)
3097 len = strlenW(facenameW);
3099 /* remove rightmost regular variant from face name */
3100 while (!regular_ptr && (ptr = regular_patterns[i++])) {
3101 int pattern_len = strlenW(ptr);
3102 WCHAR *src;
3104 if (pattern_len > len)
3105 continue;
3107 src = facenameW + len - pattern_len;
3108 while (src >= facenameW) {
3109 if (!strncmpiW(src, ptr, pattern_len)) {
3110 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
3111 len = strlenW(facenameW);
3112 regular_ptr = ptr;
3113 break;
3115 else
3116 src--;
3120 return regular_ptr;
3123 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
3125 const WCHAR *ptr;
3127 list_init(tokens);
3128 ptr = nameW;
3130 while (*ptr) {
3131 struct name_token *token = heap_alloc(sizeof(*token));
3132 token->ptr = ptr;
3133 token->len = 0;
3134 token->fulllen = 0;
3136 while (*ptr && !is_name_separator_char(*ptr)) {
3137 token->len++;
3138 token->fulllen++;
3139 ptr++;
3142 /* skip separators */
3143 while (is_name_separator_char(*ptr)) {
3144 token->fulllen++;
3145 ptr++;
3148 list_add_head(tokens, &token->entry);
3152 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
3154 struct name_token *token, *token2;
3155 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
3156 int len;
3158 list_remove(&token->entry);
3160 /* don't include last separator */
3161 len = list_empty(tokens) ? token->len : token->fulllen;
3162 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3163 nameW += len;
3165 heap_free(token);
3167 *nameW = 0;
3170 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3172 struct name_token stretch_name, weight_name, style_name;
3173 WCHAR familynameW[255], facenameW[255], finalW[255];
3174 WCHAR weightW[32], stretchW[32], styleW[32];
3175 const WCHAR *regular_ptr = NULL;
3176 DWRITE_FONT_STRETCH stretch;
3177 DWRITE_FONT_WEIGHT weight;
3178 struct list tokens;
3179 int len;
3181 /* remove leading and trailing spaces from family and face name */
3182 trim_spaces(familyW, familynameW);
3183 len = trim_spaces(faceW, facenameW);
3185 /* remove rightmost regular variant from face name */
3186 regular_ptr = facename_remove_regular_term(facenameW, len);
3188 /* append face name to family name, FIXME check if face name is a substring of family name */
3189 if (*facenameW) {
3190 strcatW(familynameW, spaceW);
3191 strcatW(familynameW, facenameW);
3194 /* tokenize with " .-_" */
3195 fontname_tokenize(&tokens, familynameW);
3197 /* extract and resolve style */
3198 font->style = font_extract_style(&tokens, font->style, &style_name);
3200 /* extract stretch */
3201 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3203 /* extract weight */
3204 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3206 /* resolve weight */
3207 if (weight != font->weight) {
3208 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3209 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3210 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3211 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3212 !(abs(weight - font->weight) <= 150 &&
3213 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3214 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3215 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3217 font->weight = weight;
3221 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3222 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3223 stretch itself is normal (extracted stretch is never normal). */
3224 if (stretch != font->stretch) {
3225 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3226 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3227 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3229 font->stretch = stretch;
3233 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3235 /* get final combined string from what's left in token list, list is released */
3236 fontname_tokens_to_str(&tokens, finalW);
3238 if (!strcmpW(familyW, finalW))
3239 return FALSE;
3241 /* construct face name */
3242 strcpyW(familyW, finalW);
3244 /* resolved weight name */
3245 if (weight_name.ptr)
3246 font_name_token_to_str(&weight_name, weightW);
3247 /* ignore normal weight */
3248 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3249 weightW[0] = 0;
3250 /* for known weight values use appropriate names */
3251 else if (is_known_weight_value(font->weight, weightW)) {
3253 /* use Wnnn format as a fallback in case weight is not one of known values */
3254 else {
3255 static const WCHAR fmtW[] = {'W','%','d',0};
3256 sprintfW(weightW, fmtW, font->weight);
3259 /* resolved stretch name */
3260 if (stretch_name.ptr)
3261 font_name_token_to_str(&stretch_name, stretchW);
3262 /* ignore normal stretch */
3263 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3264 stretchW[0] = 0;
3265 /* use predefined stretch names */
3266 else {
3267 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3268 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3269 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3270 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3271 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3272 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3274 static const WCHAR *stretchnamesW[] = {
3275 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3276 ultracondensedW,
3277 extracondensedW,
3278 condensedW,
3279 semicondensedW,
3280 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3281 semiexpandedW,
3282 expandedW,
3283 extraexpandedW,
3284 ultraexpandedW
3286 strcpyW(stretchW, stretchnamesW[font->stretch]);
3289 /* resolved style name */
3290 if (style_name.ptr)
3291 font_name_token_to_str(&style_name, styleW);
3292 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3293 styleW[0] = 0;
3294 /* use predefined names */
3295 else {
3296 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3297 strcpyW(styleW, italicW);
3298 else
3299 strcpyW(styleW, obliqueW);
3302 /* use Regular match if it was found initially */
3303 if (!*weightW && !*stretchW && !*styleW)
3304 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3305 else {
3306 faceW[0] = 0;
3307 if (*stretchW)
3308 strcpyW(faceW, stretchW);
3309 if (*weightW) {
3310 if (*faceW)
3311 strcatW(faceW, spaceW);
3312 strcatW(faceW, weightW);
3314 if (*styleW) {
3315 if (*faceW)
3316 strcatW(faceW, spaceW);
3317 strcatW(faceW, styleW);
3321 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3322 return TRUE;
3325 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
3327 struct file_stream_desc stream_desc;
3328 struct dwrite_font_props props;
3329 struct dwrite_font_data *data;
3330 IDWriteFontFileStream *stream;
3331 WCHAR familyW[255], faceW[255];
3332 HRESULT hr;
3334 *ret = NULL;
3335 data = heap_alloc_zero(sizeof(*data));
3336 if (!data)
3337 return E_OUTOFMEMORY;
3339 hr = get_filestream_from_file(desc->files[0], &stream);
3340 if (FAILED(hr)) {
3341 heap_free(data);
3342 return hr;
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 = 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 IDWriteFontFileStream_Release(stream);
3364 if (FAILED(hr)) {
3365 WARN("unable to get family name from font\n");
3366 release_font_data(data);
3367 return hr;
3370 data->style = props.style;
3371 data->stretch = props.stretch;
3372 data->weight = props.weight;
3373 data->panose = props.panose;
3374 data->fontsig = props.fontsig;
3375 data->lf = props.lf;
3377 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3378 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3379 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3380 set_en_localizedstring(*family_name, familyW);
3381 set_en_localizedstring(data->names, faceW);
3384 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3386 *ret = data;
3387 return S_OK;
3390 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim,
3391 const WCHAR *facenameW, struct dwrite_font_data **ret)
3393 struct dwrite_font_data *data;
3395 *ret = NULL;
3397 data = heap_alloc_zero(sizeof(*data));
3398 if (!data)
3399 return E_OUTOFMEMORY;
3401 *data = *src;
3402 data->ref = 1;
3403 data->simulations |= sim;
3404 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3405 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3406 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3407 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3408 memset(data->info_strings, 0, sizeof(data->info_strings));
3409 data->names = NULL;
3410 IDWriteFontFile_AddRef(data->file);
3412 create_localizedstrings(&data->names);
3413 add_localizedstring(data->names, enusW, facenameW);
3415 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3417 *ret = data;
3418 return S_OK;
3421 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3423 struct dwrite_fontfamily_data *data;
3425 data = heap_alloc(sizeof(*data));
3426 if (!data)
3427 return E_OUTOFMEMORY;
3429 data->ref = 1;
3430 data->font_count = 0;
3431 data->font_alloc = 2;
3432 data->has_normal_face = 0;
3433 data->has_oblique_face = 0;
3434 data->has_italic_face = 0;
3436 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3437 if (!data->fonts) {
3438 heap_free(data);
3439 return E_OUTOFMEMORY;
3442 data->familyname = familyname;
3443 IDWriteLocalizedStrings_AddRef(familyname);
3445 *ret = data;
3446 return S_OK;
3449 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3451 UINT32 i, j, heaviest;
3453 for (i = 0; i < family->font_count; i++) {
3454 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3455 heaviest = i;
3457 if (family->fonts[i]->bold_sim_tested)
3458 continue;
3460 family->fonts[i]->bold_sim_tested = 1;
3461 for (j = i; j < family->font_count; j++) {
3462 if (family->fonts[j]->bold_sim_tested)
3463 continue;
3465 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3466 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3467 if (family->fonts[j]->weight > weight) {
3468 weight = family->fonts[j]->weight;
3469 heaviest = j;
3471 family->fonts[j]->bold_sim_tested = 1;
3475 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3476 static const struct name_pattern weightsim_patterns[] = {
3477 { extraW, lightW },
3478 { extW, lightW },
3479 { ultraW, lightW },
3480 { semiW, lightW },
3481 { semiW, boldW },
3482 { demiW, boldW },
3483 { boldW },
3484 { thinW },
3485 { lightW },
3486 { mediumW },
3487 { demiW },
3488 { NULL }
3491 WCHAR facenameW[255], initialW[255];
3492 struct dwrite_font_data *boldface;
3493 struct list tokens;
3495 /* add Bold simulation based on heaviest face data */
3497 /* Simulated face name should only contain Bold as weight term,
3498 so remove existing regular and weight terms. */
3499 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3500 facename_remove_regular_term(initialW, -1);
3502 /* remove current weight pattern */
3503 fontname_tokenize(&tokens, initialW);
3504 match_pattern_list(&tokens, weightsim_patterns, NULL);
3505 fontname_tokens_to_str(&tokens, facenameW);
3507 /* Bold suffix for new name */
3508 if (*facenameW)
3509 strcatW(facenameW, spaceW);
3510 strcatW(facenameW, boldW);
3512 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3513 boldface->bold_sim_tested = 1;
3514 boldface->lf.lfWeight += (FW_BOLD - FW_REGULAR) / 2 + 1;
3515 fontfamily_add_font(family, boldface);
3521 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3523 UINT32 i, j;
3525 for (i = 0; i < family->font_count; i++) {
3526 UINT32 regular = ~0u, oblique = ~0u;
3527 struct dwrite_font_data *obliqueface;
3528 WCHAR facenameW[255];
3530 if (family->fonts[i]->oblique_sim_tested)
3531 continue;
3533 family->fonts[i]->oblique_sim_tested = 1;
3534 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3535 regular = i;
3536 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3537 oblique = i;
3539 /* find regular style with same weight/stretch values */
3540 for (j = i; j < family->font_count; j++) {
3541 if (family->fonts[j]->oblique_sim_tested)
3542 continue;
3544 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3545 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3547 family->fonts[j]->oblique_sim_tested = 1;
3548 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3549 regular = j;
3551 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3552 oblique = j;
3555 if (regular != ~0u && oblique != ~0u)
3556 break;
3559 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3560 if (regular == ~0u)
3561 continue;
3563 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3564 if (oblique != ~0u)
3565 continue;
3567 /* add oblique simulation based on this regular face */
3569 /* remove regular term if any, append 'Oblique' */
3570 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3571 facename_remove_regular_term(facenameW, -1);
3573 if (*facenameW)
3574 strcatW(facenameW, spaceW);
3575 strcatW(facenameW, obliqueW);
3577 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3578 obliqueface->oblique_sim_tested = 1;
3579 obliqueface->lf.lfItalic = 1;
3580 fontfamily_add_font(family, obliqueface);
3585 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3586 const WCHAR *replacement_name)
3588 UINT32 i = collection_find_family(collection, replacement_name);
3589 struct dwrite_fontfamily_data *target;
3590 IDWriteLocalizedStrings *strings;
3591 HRESULT hr;
3593 /* replacement does not exist */
3594 if (i == ~0u)
3595 return FALSE;
3597 hr = create_localizedstrings(&strings);
3598 if (FAILED(hr))
3599 return FALSE;
3601 /* add a new family with target name, reuse font data from replacement */
3602 add_localizedstring(strings, enusW, target_name);
3603 hr = init_fontfamily_data(strings, &target);
3604 if (hr == S_OK) {
3605 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3606 WCHAR nameW[255];
3608 for (i = 0; i < replacement->font_count; i++) {
3609 fontfamily_add_font(target, replacement->fonts[i]);
3610 addref_font_data(replacement->fonts[i]);
3613 fontcollection_add_family(collection, target);
3614 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3615 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3617 IDWriteLocalizedStrings_Release(strings);
3618 return TRUE;
3621 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3622 system font collections. */
3623 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3625 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3626 WCHAR *name;
3627 void *data;
3628 HKEY hkey;
3630 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3631 return;
3633 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3634 RegCloseKey(hkey);
3635 return;
3638 max_namelen++; /* returned value doesn't include room for '\0' */
3639 name = heap_alloc(max_namelen * sizeof(WCHAR));
3640 data = heap_alloc(max_datalen);
3642 datalen = max_datalen;
3643 namelen = max_namelen;
3644 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3645 if (collection_find_family(collection, name) == ~0u) {
3646 if (type == REG_MULTI_SZ) {
3647 WCHAR *replacement = data;
3648 while (*replacement) {
3649 if (fontcollection_add_replacement(collection, name, replacement))
3650 break;
3651 replacement += strlenW(replacement) + 1;
3654 else if (type == REG_SZ)
3655 fontcollection_add_replacement(collection, name, data);
3657 else
3658 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3660 datalen = max_datalen;
3661 namelen = max_namelen;
3664 heap_free(data);
3665 heap_free(name);
3666 RegCloseKey(hkey);
3669 HRESULT create_font_collection(IDWriteFactory5 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3670 IDWriteFontCollection1 **ret)
3672 struct fontfile_enum {
3673 struct list entry;
3674 IDWriteFontFile *file;
3676 struct fontfile_enum *fileenum, *fileenum2;
3677 struct dwrite_fontcollection *collection;
3678 struct list scannedfiles;
3679 BOOL current = FALSE;
3680 HRESULT hr = S_OK;
3681 UINT32 i;
3683 *ret = NULL;
3685 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3686 if (!collection) return E_OUTOFMEMORY;
3688 hr = init_font_collection(collection, is_system);
3689 if (FAILED(hr)) {
3690 heap_free(collection);
3691 return hr;
3694 *ret = &collection->IDWriteFontCollection1_iface;
3696 TRACE("building font collection:\n");
3698 list_init(&scannedfiles);
3699 while (hr == S_OK) {
3700 DWRITE_FONT_FACE_TYPE face_type;
3701 DWRITE_FONT_FILE_TYPE file_type;
3702 BOOL supported, same = FALSE;
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 /* failed font files are skipped */
3727 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3728 if (FAILED(hr) || !supported || face_count == 0) {
3729 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3730 IDWriteFontFile_Release(file);
3731 hr = S_OK;
3732 continue;
3735 /* add to scanned list */
3736 fileenum = heap_alloc(sizeof(*fileenum));
3737 fileenum->file = file;
3738 list_add_tail(&scannedfiles, &fileenum->entry);
3740 for (i = 0; i < face_count; i++) {
3741 IDWriteLocalizedStrings *family_name = NULL;
3742 struct dwrite_font_data *font_data;
3743 struct fontface_desc desc;
3744 WCHAR familyW[255];
3745 UINT32 index;
3747 desc.factory = factory;
3748 desc.face_type = face_type;
3749 desc.files = &file;
3750 desc.files_number = 1;
3751 desc.index = i;
3752 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3753 desc.font_data = NULL;
3755 /* alloc and init new font data structure */
3756 hr = init_font_data(&desc, &family_name, &font_data);
3757 if (FAILED(hr)) {
3758 /* move to next one */
3759 hr = S_OK;
3760 continue;
3763 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3765 /* ignore dot named faces */
3766 if (familyW[0] == '.') {
3767 WARN("Ignoring face %s\n", debugstr_w(familyW));
3768 IDWriteLocalizedStrings_Release(family_name);
3769 release_font_data(font_data);
3770 continue;
3773 index = collection_find_family(collection, familyW);
3774 if (index != ~0u)
3775 hr = fontfamily_add_font(collection->family_data[index], font_data);
3776 else {
3777 struct dwrite_fontfamily_data *family_data;
3779 /* create and init new family */
3780 hr = init_fontfamily_data(family_name, &family_data);
3781 if (hr == S_OK) {
3782 /* add font to family, family - to collection */
3783 hr = fontfamily_add_font(family_data, font_data);
3784 if (hr == S_OK)
3785 hr = fontcollection_add_family(collection, family_data);
3787 if (FAILED(hr))
3788 release_fontfamily_data(family_data);
3792 IDWriteLocalizedStrings_Release(family_name);
3794 if (FAILED(hr))
3795 break;
3799 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3800 IDWriteFontFile_Release(fileenum->file);
3801 list_remove(&fileenum->entry);
3802 heap_free(fileenum);
3805 for (i = 0; i < collection->family_count; i++) {
3806 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3807 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3810 if (is_system)
3811 fontcollection_add_replacements(collection);
3813 collection->factory = factory;
3814 IDWriteFactory5_AddRef(factory);
3816 return hr;
3819 struct system_fontfile_enumerator
3821 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3822 LONG ref;
3824 IDWriteFactory5 *factory;
3825 HKEY hkey;
3826 int index;
3828 WCHAR *value;
3829 DWORD max_val_count;
3832 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3834 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3837 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3839 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3840 IDWriteFontFileEnumerator_AddRef(iface);
3841 *obj = iface;
3842 return S_OK;
3845 WARN("%s not implemented.\n", debugstr_guid(riid));
3847 *obj = NULL;
3849 return E_NOINTERFACE;
3852 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3854 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3855 return InterlockedIncrement(&enumerator->ref);
3858 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3860 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3861 ULONG ref = InterlockedDecrement(&enumerator->ref);
3863 if (!ref) {
3864 IDWriteFactory5_Release(enumerator->factory);
3865 RegCloseKey(enumerator->hkey);
3866 heap_free(enumerator->value);
3867 heap_free(enumerator);
3870 return ref;
3873 static HRESULT create_local_file_reference(IDWriteFactory5 *factory, const WCHAR *filename, IDWriteFontFile **file)
3875 HRESULT hr;
3877 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3878 if (!strchrW(filename, '\\')) {
3879 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3880 WCHAR fullpathW[MAX_PATH];
3882 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3883 strcatW(fullpathW, fontsW);
3884 strcatW(fullpathW, filename);
3886 hr = IDWriteFactory5_CreateFontFileReference(factory, fullpathW, NULL, file);
3888 else
3889 hr = IDWriteFactory5_CreateFontFileReference(factory, filename, NULL, file);
3891 return hr;
3894 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3896 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3897 DWORD ret, type, val_count, count;
3898 WCHAR *value, *filename;
3899 HRESULT hr;
3901 *file = NULL;
3903 if (enumerator->index < 0)
3904 return E_FAIL;
3906 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3907 if (ret != ERROR_SUCCESS)
3908 return E_FAIL;
3910 val_count++;
3911 value = heap_alloc( val_count * sizeof(value[0]) );
3912 filename = heap_alloc(count);
3913 if (!value || !filename) {
3914 heap_free(value);
3915 heap_free(filename);
3916 return E_OUTOFMEMORY;
3919 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3920 if (ret) {
3921 heap_free(value);
3922 heap_free(filename);
3923 return E_FAIL;
3926 hr = create_local_file_reference(enumerator->factory, filename, file);
3928 heap_free(value);
3929 heap_free(filename);
3930 return hr;
3933 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3935 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3937 *current = FALSE;
3938 enumerator->index++;
3940 if (!enumerator->value) {
3941 if (RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3942 &enumerator->max_val_count, NULL, NULL, NULL))
3943 return E_FAIL;
3945 enumerator->max_val_count++;
3946 if (!(enumerator->value = heap_alloc(enumerator->max_val_count * sizeof(*enumerator->value))))
3947 return E_OUTOFMEMORY;
3950 /* iterate until we find next string value */
3951 for (;;) {
3952 DWORD type = 0, count, val_count;
3954 val_count = enumerator->max_val_count;
3955 *enumerator->value = 0;
3956 if (RegEnumValueW(enumerator->hkey, enumerator->index, enumerator->value, &val_count,
3957 NULL, &type, NULL, &count))
3958 break;
3959 if (type == REG_SZ && *enumerator->value && *enumerator->value != '@') {
3960 *current = TRUE;
3961 break;
3963 enumerator->index++;
3966 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3967 return S_OK;
3970 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3972 systemfontfileenumerator_QueryInterface,
3973 systemfontfileenumerator_AddRef,
3974 systemfontfileenumerator_Release,
3975 systemfontfileenumerator_MoveNext,
3976 systemfontfileenumerator_GetCurrentFontFile
3979 static HRESULT create_system_fontfile_enumerator(IDWriteFactory5 *factory, IDWriteFontFileEnumerator **ret)
3981 struct system_fontfile_enumerator *enumerator;
3982 static const WCHAR fontslistW[] = {
3983 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3984 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3985 'F','o','n','t','s',0
3988 *ret = NULL;
3990 enumerator = heap_alloc(sizeof(*enumerator));
3991 if (!enumerator)
3992 return E_OUTOFMEMORY;
3994 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3995 enumerator->ref = 1;
3996 enumerator->factory = factory;
3997 enumerator->index = -1;
3998 enumerator->value = NULL;
3999 enumerator->max_val_count = 0;
4000 IDWriteFactory5_AddRef(factory);
4002 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
4003 ERR("failed to open fonts list key\n");
4004 IDWriteFactory5_Release(factory);
4005 heap_free(enumerator);
4006 return E_FAIL;
4009 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
4011 return S_OK;
4014 HRESULT get_system_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **collection)
4016 IDWriteFontFileEnumerator *enumerator;
4017 HRESULT hr;
4019 *collection = NULL;
4021 hr = create_system_fontfile_enumerator(factory, &enumerator);
4022 if (FAILED(hr))
4023 return hr;
4025 TRACE("building system font collection for factory %p\n", factory);
4026 hr = create_font_collection(factory, enumerator, TRUE, collection);
4027 IDWriteFontFileEnumerator_Release(enumerator);
4028 return hr;
4031 static HRESULT eudc_collection_add_family(IDWriteFactory5 *factory, struct dwrite_fontcollection *collection,
4032 const WCHAR *keynameW, const WCHAR *pathW)
4034 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};
4035 static const WCHAR emptyW[] = {0};
4036 IDWriteLocalizedStrings *names;
4037 DWRITE_FONT_FACE_TYPE face_type;
4038 DWRITE_FONT_FILE_TYPE file_type;
4039 BOOL supported;
4040 UINT32 face_count, i;
4041 IDWriteFontFile *file;
4042 HRESULT hr;
4043 struct dwrite_fontfamily_data *family_data;
4045 /* create font file from this path */
4046 hr = create_local_file_reference(factory, pathW, &file);
4047 if (FAILED(hr))
4048 return S_FALSE;
4050 /* failed font files are skipped */
4051 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
4052 if (FAILED(hr) || !supported || face_count == 0) {
4053 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
4054 IDWriteFontFile_Release(file);
4055 return S_FALSE;
4058 /* create and init new family */
4060 /* Family names are added for non-specific locale, represented with empty string.
4061 Default family appears with empty family name. */
4062 create_localizedstrings(&names);
4063 if (!strcmpiW(keynameW, defaultfontW))
4064 add_localizedstring(names, emptyW, emptyW);
4065 else
4066 add_localizedstring(names, emptyW, keynameW);
4068 hr = init_fontfamily_data(names, &family_data);
4069 IDWriteLocalizedStrings_Release(names);
4070 if (hr != S_OK) {
4071 IDWriteFontFile_Release(file);
4072 return hr;
4075 /* fill with faces */
4076 for (i = 0; i < face_count; i++) {
4077 struct dwrite_font_data *font_data;
4078 struct fontface_desc desc;
4080 /* alloc and init new font data structure */
4081 desc.factory = factory;
4082 desc.face_type = face_type;
4083 desc.index = i;
4084 desc.files = &file;
4085 desc.files_number = 1;
4086 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
4087 desc.font_data = NULL;
4089 hr = init_font_data(&desc, &names, &font_data);
4090 if (FAILED(hr))
4091 continue;
4093 IDWriteLocalizedStrings_Release(names);
4095 /* add font to family */
4096 hr = fontfamily_add_font(family_data, font_data);
4097 if (hr != S_OK)
4098 release_font_data(font_data);
4101 /* add family to collection */
4102 hr = fontcollection_add_family(collection, family_data);
4103 if (FAILED(hr))
4104 release_fontfamily_data(family_data);
4105 IDWriteFontFile_Release(file);
4107 return hr;
4110 HRESULT get_eudc_fontcollection(IDWriteFactory5 *factory, IDWriteFontCollection1 **ret)
4112 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
4113 struct dwrite_fontcollection *collection;
4114 static const WCHAR emptyW[] = {0};
4115 WCHAR eudckeypathW[16];
4116 HKEY eudckey;
4117 DWORD index;
4118 BOOL exists;
4119 LONG retval;
4120 HRESULT hr;
4121 UINT32 i;
4123 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
4125 *ret = NULL;
4127 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
4128 if (!collection) return E_OUTOFMEMORY;
4130 hr = init_font_collection(collection, FALSE);
4131 if (FAILED(hr)) {
4132 heap_free(collection);
4133 return hr;
4136 *ret = &collection->IDWriteFontCollection1_iface;
4137 collection->factory = factory;
4138 IDWriteFactory5_AddRef(factory);
4140 /* return empty collection if EUDC fonts are not configured */
4141 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
4142 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
4143 return S_OK;
4145 retval = ERROR_SUCCESS;
4146 index = 0;
4147 while (retval != ERROR_NO_MORE_ITEMS) {
4148 WCHAR keynameW[64], pathW[MAX_PATH];
4149 DWORD type, path_len, name_len;
4151 path_len = sizeof(pathW)/sizeof(*pathW);
4152 name_len = sizeof(keynameW)/sizeof(*keynameW);
4153 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
4154 if (retval || type != REG_SZ)
4155 continue;
4157 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
4158 if (hr != S_OK)
4159 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
4161 RegCloseKey(eudckey);
4163 /* try to add global default if not defined for specific codepage */
4164 exists = FALSE;
4165 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
4166 &index, &exists);
4167 if (FAILED(hr) || !exists) {
4168 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
4169 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
4170 if (hr != S_OK)
4171 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
4174 /* EUDC collection offers simulated faces too */
4175 for (i = 0; i < collection->family_count; i++) {
4176 fontfamily_add_bold_simulated_face(collection->family_data[i]);
4177 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
4180 return S_OK;
4183 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4185 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4187 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4189 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4191 *obj = iface;
4192 IDWriteFontFile_AddRef(iface);
4193 return S_OK;
4196 WARN("%s not implemented.\n", debugstr_guid(riid));
4198 *obj = NULL;
4199 return E_NOINTERFACE;
4202 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4204 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4205 ULONG ref = InterlockedIncrement(&This->ref);
4206 TRACE("(%p)->(%d)\n", This, ref);
4207 return ref;
4210 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4212 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4213 ULONG ref = InterlockedDecrement(&This->ref);
4215 TRACE("(%p)->(%d)\n", This, ref);
4217 if (!ref)
4219 IDWriteFontFileLoader_Release(This->loader);
4220 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4221 heap_free(This->reference_key);
4222 heap_free(This);
4225 return ref;
4228 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4230 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4231 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4232 *fontFileReferenceKey = This->reference_key;
4233 *fontFileReferenceKeySize = This->key_size;
4235 return S_OK;
4238 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4240 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4241 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4242 *fontFileLoader = This->loader;
4243 IDWriteFontFileLoader_AddRef(This->loader);
4245 return S_OK;
4248 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
4249 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
4251 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4252 IDWriteFontFileStream *stream;
4253 HRESULT hr;
4255 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
4257 *isSupportedFontType = FALSE;
4258 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4259 if (fontFaceType)
4260 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4261 *numberOfFaces = 0;
4263 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4264 if (FAILED(hr))
4265 return hr;
4267 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
4269 /* TODO: Further Analysis */
4270 IDWriteFontFileStream_Release(stream);
4271 return S_OK;
4274 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4275 dwritefontfile_QueryInterface,
4276 dwritefontfile_AddRef,
4277 dwritefontfile_Release,
4278 dwritefontfile_GetReferenceKey,
4279 dwritefontfile_GetLoader,
4280 dwritefontfile_Analyze,
4283 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size,
4284 IDWriteFontFile **ret)
4286 struct dwrite_fontfile *file;
4287 void *key;
4289 *ret = NULL;
4291 file = heap_alloc(sizeof(*file));
4292 key = heap_alloc(key_size);
4293 if (!file || !key) {
4294 heap_free(file);
4295 heap_free(key);
4296 return E_OUTOFMEMORY;
4299 file->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4300 file->ref = 1;
4301 IDWriteFontFileLoader_AddRef(loader);
4302 file->loader = loader;
4303 file->stream = NULL;
4304 file->reference_key = key;
4305 memcpy(file->reference_key, reference_key, key_size);
4306 file->key_size = key_size;
4308 *ret = &file->IDWriteFontFile_iface;
4310 return S_OK;
4313 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
4315 IDWriteFontFileLoader *loader;
4316 UINT32 key_size;
4317 const void *key;
4318 HRESULT hr;
4320 *stream = NULL;
4321 hr = IDWriteFontFile_GetLoader(file, &loader);
4322 if (FAILED(hr))
4323 return hr;
4325 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
4326 if (FAILED(hr)) {
4327 IDWriteFontFileLoader_Release(loader);
4328 return hr;
4331 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
4332 IDWriteFontFileLoader_Release(loader);
4334 return hr;
4337 HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_list, IDWriteFontFace4 **ret)
4339 struct file_stream_desc stream_desc;
4340 struct dwrite_fontface *fontface;
4341 HRESULT hr = S_OK;
4342 BOOL is_symbol;
4343 int i;
4345 *ret = NULL;
4347 fontface = heap_alloc_zero(sizeof(struct dwrite_fontface));
4348 if (!fontface)
4349 return E_OUTOFMEMORY;
4351 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4352 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * desc->files_number);
4354 if (!fontface->files || !fontface->streams) {
4355 heap_free(fontface->files);
4356 heap_free(fontface->streams);
4357 heap_free(fontface);
4358 return E_OUTOFMEMORY;
4361 fontface->IDWriteFontFace4_iface.lpVtbl = &dwritefontfacevtbl;
4362 fontface->ref = 1;
4363 fontface->type = desc->face_type;
4364 fontface->file_count = desc->files_number;
4365 fontface->cmap.exists = TRUE;
4366 fontface->vdmx.exists = TRUE;
4367 fontface->gasp.exists = TRUE;
4368 fontface->cpal.exists = TRUE;
4369 fontface->colr.exists = TRUE;
4370 fontface->index = desc->index;
4371 fontface->simulations = desc->simulations;
4372 IDWriteFactory5_AddRef(fontface->factory = desc->factory);
4374 for (i = 0; i < fontface->file_count; i++) {
4375 hr = get_stream_from_file(desc->files[i], &fontface->streams[i]);
4376 if (FAILED(hr)) {
4377 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4378 return hr;
4381 fontface->files[i] = desc->files[i];
4382 IDWriteFontFile_AddRef(fontface->files[i]);
4385 stream_desc.stream = fontface->streams[0];
4386 stream_desc.face_type = desc->face_type;
4387 stream_desc.face_index = desc->index;
4388 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4389 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4390 /* TODO: test what happens if caret is already slanted */
4391 if (fontface->caret.slopeRise == 1) {
4392 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4393 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4397 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace4_iface, &is_symbol);
4398 if (is_symbol)
4399 fontface->flags |= FONTFACE_IS_SYMBOL;
4400 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace4_iface))
4401 fontface->flags |= FONTFACE_HAS_KERNING_PAIRS;
4402 if (freetype_is_monospaced(&fontface->IDWriteFontFace4_iface))
4403 fontface->flags |= FONTFACE_IS_MONOSPACED;
4404 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace4_iface))
4405 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4406 fontface->glyph_image_formats = opentype_get_glyph_image_formats(&fontface->IDWriteFontFace4_iface);
4408 /* Font properties are reused from font object when 'normal' face creation path is used:
4409 collection -> family -> matching font -> fontface.
4411 If face is created directly from factory we have to go through properties resolution.
4413 if (desc->font_data) {
4414 fontface->weight = desc->font_data->weight;
4415 fontface->style = desc->font_data->style;
4416 fontface->stretch = desc->font_data->stretch;
4417 fontface->panose = desc->font_data->panose;
4418 fontface->fontsig = desc->font_data->fontsig;
4419 fontface->lf = desc->font_data->lf;
4421 else {
4422 IDWriteLocalizedStrings *names;
4423 struct dwrite_font_data *data;
4425 hr = init_font_data(desc, &names, &data);
4426 if (FAILED(hr)) {
4427 IDWriteFontFace4_Release(&fontface->IDWriteFontFace4_iface);
4428 return hr;
4431 fontface->weight = data->weight;
4432 fontface->style = data->style;
4433 fontface->stretch = data->stretch;
4434 fontface->panose = data->panose;
4435 fontface->fontsig = data->fontsig;
4436 fontface->lf = data->lf;
4438 IDWriteLocalizedStrings_Release(names);
4439 release_font_data(data);
4442 fontface->cached = factory_cache_fontface(fontface->factory, cached_list, &fontface->IDWriteFontFace4_iface);
4444 *ret = &fontface->IDWriteFontFace4_iface;
4445 return S_OK;
4448 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4449 struct local_refkey
4451 FILETIME writetime;
4452 WCHAR name[1];
4455 struct local_cached_stream
4457 struct list entry;
4458 IDWriteFontFileStream *stream;
4459 struct local_refkey *key;
4460 UINT32 key_size;
4463 struct dwrite_localfontfilestream
4465 IDWriteFontFileStream IDWriteFontFileStream_iface;
4466 LONG ref;
4468 struct local_cached_stream *entry;
4469 const void *file_ptr;
4470 UINT64 size;
4473 struct dwrite_localfontfileloader {
4474 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4475 LONG ref;
4477 struct list streams;
4478 CRITICAL_SECTION cs;
4481 static struct dwrite_localfontfileloader local_fontfile_loader;
4483 struct dwrite_inmemory_stream_data
4485 LONG ref;
4486 IUnknown *owner;
4487 void *data;
4488 UINT32 size;
4491 struct dwrite_inmemory_filestream
4493 IDWriteFontFileStream IDWriteFontFileStream_iface;
4494 LONG ref;
4496 struct dwrite_inmemory_stream_data *data;
4499 struct dwrite_inmemory_fileloader
4501 IDWriteInMemoryFontFileLoader IDWriteInMemoryFontFileLoader_iface;
4502 LONG ref;
4504 struct dwrite_inmemory_stream_data **streams;
4505 UINT32 filecount;
4506 UINT32 capacity;
4509 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4511 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4514 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4516 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4519 static inline struct dwrite_inmemory_fileloader *impl_from_IDWriteInMemoryFontFileLoader(IDWriteInMemoryFontFileLoader *iface)
4521 return CONTAINING_RECORD(iface, struct dwrite_inmemory_fileloader, IDWriteInMemoryFontFileLoader_iface);
4524 static inline struct dwrite_inmemory_filestream *inmemory_impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4526 return CONTAINING_RECORD(iface, struct dwrite_inmemory_filestream, IDWriteFontFileStream_iface);
4529 static void release_inmemory_stream(struct dwrite_inmemory_stream_data *stream)
4531 if (InterlockedDecrement(&stream->ref) == 0) {
4532 if (stream->owner)
4533 IUnknown_Release(stream->owner);
4534 else
4535 heap_free(stream->data);
4536 heap_free(stream);
4540 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4542 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4544 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4546 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) ||
4547 IsEqualIID(riid, &IID_IUnknown))
4549 *obj = iface;
4550 if (InterlockedIncrement(&This->ref) == 1) {
4551 InterlockedDecrement(&This->ref);
4552 *obj = NULL;
4553 return E_FAIL;
4555 return S_OK;
4558 WARN("%s not implemented.\n", debugstr_guid(riid));
4560 *obj = NULL;
4561 return E_NOINTERFACE;
4564 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4566 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4567 ULONG ref = InterlockedIncrement(&This->ref);
4568 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4569 return ref;
4572 static inline void release_cached_stream(struct local_cached_stream *stream)
4574 list_remove(&stream->entry);
4575 heap_free(stream->key);
4576 heap_free(stream);
4579 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4581 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4582 ULONG ref = InterlockedDecrement(&This->ref);
4584 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4586 if (!ref) {
4587 UnmapViewOfFile(This->file_ptr);
4589 EnterCriticalSection(&local_fontfile_loader.cs);
4590 release_cached_stream(This->entry);
4591 LeaveCriticalSection(&local_fontfile_loader.cs);
4593 heap_free(This);
4596 return ref;
4599 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
4600 UINT64 offset, UINT64 fragment_size, void **fragment_context)
4602 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4604 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", This, fragment_start,
4605 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4607 *fragment_context = NULL;
4609 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4610 *fragment_start = NULL;
4611 return E_FAIL;
4614 *fragment_start = (char*)This->file_ptr + offset;
4615 return S_OK;
4618 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4620 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4621 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4624 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4626 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4627 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4628 *size = This->size;
4629 return S_OK;
4632 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4634 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4635 ULARGE_INTEGER li;
4637 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4639 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4640 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4641 *last_writetime = li.QuadPart;
4643 return S_OK;
4646 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4648 localfontfilestream_QueryInterface,
4649 localfontfilestream_AddRef,
4650 localfontfilestream_Release,
4651 localfontfilestream_ReadFileFragment,
4652 localfontfilestream_ReleaseFileFragment,
4653 localfontfilestream_GetFileSize,
4654 localfontfilestream_GetLastWriteTime
4657 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4659 struct dwrite_localfontfilestream *This;
4661 *ret = NULL;
4663 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4664 if (!This)
4665 return E_OUTOFMEMORY;
4667 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4668 This->ref = 1;
4670 This->file_ptr = file_ptr;
4671 This->size = size;
4672 This->entry = entry;
4674 *ret = &This->IDWriteFontFileStream_iface;
4675 return S_OK;
4678 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4680 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4682 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4684 if (IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader) ||
4685 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
4686 IsEqualIID(riid, &IID_IUnknown))
4688 *obj = iface;
4689 IDWriteLocalFontFileLoader_AddRef(iface);
4690 return S_OK;
4693 WARN("%s not implemented.\n", debugstr_guid(riid));
4695 *obj = NULL;
4696 return E_NOINTERFACE;
4699 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4701 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4702 ULONG ref = InterlockedIncrement(&This->ref);
4703 TRACE("(%p)->(%d)\n", This, ref);
4704 return ref;
4707 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4709 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4710 ULONG ref = InterlockedDecrement(&This->ref);
4712 TRACE("(%p)->(%d)\n", This, ref);
4714 return ref;
4717 static HRESULT create_local_cached_stream(const void *key, UINT32 key_size, struct local_cached_stream **ret)
4719 const struct local_refkey *refkey = key;
4720 struct local_cached_stream *stream;
4721 IDWriteFontFileStream *filestream;
4722 HANDLE file, mapping;
4723 LARGE_INTEGER size;
4724 void *file_ptr;
4725 HRESULT hr = S_OK;
4727 *ret = NULL;
4729 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4730 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4731 if (file == INVALID_HANDLE_VALUE) {
4732 WARN_(dwrite_file)("Failed to open the file %s, error %d.\n", debugstr_w(refkey->name), GetLastError());
4733 return E_FAIL;
4736 GetFileSizeEx(file, &size);
4737 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4738 CloseHandle(file);
4739 if (!mapping)
4740 return E_FAIL;
4742 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4743 CloseHandle(mapping);
4744 if (!file_ptr) {
4745 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4746 return E_FAIL;
4749 stream = heap_alloc(sizeof(*stream));
4750 if (!stream) {
4751 UnmapViewOfFile(file_ptr);
4752 return E_OUTOFMEMORY;
4755 stream->key = heap_alloc(key_size);
4756 if (!stream->key) {
4757 UnmapViewOfFile(file_ptr);
4758 heap_free(stream);
4759 return E_OUTOFMEMORY;
4762 stream->key_size = key_size;
4763 memcpy(stream->key, key, key_size);
4765 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4766 if (FAILED(hr)) {
4767 UnmapViewOfFile(file_ptr);
4768 heap_free(stream->key);
4769 heap_free(stream);
4770 return hr;
4773 stream->stream = filestream;
4775 *ret = stream;
4777 return S_OK;
4780 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key,
4781 UINT32 key_size, IDWriteFontFileStream **ret)
4783 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4784 const struct local_refkey *refkey = key;
4785 struct local_cached_stream *stream;
4786 HRESULT hr = S_OK;
4788 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, ret);
4789 TRACE("name: %s\n", debugstr_w(refkey->name));
4791 EnterCriticalSection(&This->cs);
4793 *ret = NULL;
4795 /* search cache first */
4796 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4797 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4798 IDWriteFontFileStream_QueryInterface(stream->stream, &IID_IDWriteFontFileStream, (void **)ret);
4799 break;
4803 if (*ret == NULL && (hr = create_local_cached_stream(key, key_size, &stream)) == S_OK) {
4804 list_add_head(&This->streams, &stream->entry);
4805 *ret = stream->stream;
4808 LeaveCriticalSection(&This->cs);
4810 return hr;
4813 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4815 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4816 const struct local_refkey *refkey = key;
4818 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4820 *length = strlenW(refkey->name);
4821 return S_OK;
4824 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4826 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4827 const struct local_refkey *refkey = key;
4829 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4831 if (length < strlenW(refkey->name))
4832 return E_INVALIDARG;
4834 strcpyW(path, refkey->name);
4835 return S_OK;
4838 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key,
4839 UINT32 key_size, FILETIME *writetime)
4841 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4842 const struct local_refkey *refkey = key;
4844 TRACE("(%p)->(%p, %u, %p)\n", This, key, key_size, writetime);
4846 *writetime = refkey->writetime;
4847 return S_OK;
4850 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4851 localfontfileloader_QueryInterface,
4852 localfontfileloader_AddRef,
4853 localfontfileloader_Release,
4854 localfontfileloader_CreateStreamFromKey,
4855 localfontfileloader_GetFilePathLengthFromKey,
4856 localfontfileloader_GetFilePathFromKey,
4857 localfontfileloader_GetLastWriteTimeFromKey
4860 void init_local_fontfile_loader(void)
4862 local_fontfile_loader.IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4863 local_fontfile_loader.ref = 1;
4864 list_init(&local_fontfile_loader.streams);
4865 InitializeCriticalSection(&local_fontfile_loader.cs);
4866 local_fontfile_loader.cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": localfileloader.lock");
4869 IDWriteFontFileLoader *get_local_fontfile_loader(void)
4871 return (IDWriteFontFileLoader *)&local_fontfile_loader.IDWriteLocalFontFileLoader_iface;
4874 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4876 struct local_refkey *refkey;
4878 if (!path)
4879 return E_INVALIDARG;
4881 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4882 *key = NULL;
4884 refkey = heap_alloc(*size);
4885 if (!refkey)
4886 return E_OUTOFMEMORY;
4888 if (writetime)
4889 refkey->writetime = *writetime;
4890 else {
4891 WIN32_FILE_ATTRIBUTE_DATA info;
4893 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4894 refkey->writetime = info.ftLastWriteTime;
4895 else
4896 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4898 strcpyW(refkey->name, path);
4900 *key = refkey;
4902 return S_OK;
4905 /* IDWriteGlyphRunAnalysis */
4906 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4908 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4910 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4912 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4913 IsEqualIID(riid, &IID_IUnknown))
4915 *ppv = iface;
4916 IDWriteGlyphRunAnalysis_AddRef(iface);
4917 return S_OK;
4920 WARN("%s not implemented.\n", debugstr_guid(riid));
4922 *ppv = NULL;
4923 return E_NOINTERFACE;
4926 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4928 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4929 ULONG ref = InterlockedIncrement(&This->ref);
4930 TRACE("(%p)->(%u)\n", This, ref);
4931 return ref;
4934 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4936 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4937 ULONG ref = InterlockedDecrement(&This->ref);
4939 TRACE("(%p)->(%u)\n", This, ref);
4941 if (!ref) {
4942 if (This->run.fontFace)
4943 IDWriteFontFace_Release(This->run.fontFace);
4944 heap_free(This->glyphs);
4945 heap_free(This->origins);
4946 heap_free(This->bitmap);
4947 heap_free(This);
4950 return ref;
4953 static BOOL is_natural_rendering_mode(DWRITE_RENDERING_MODE1 mode)
4955 switch (mode)
4957 case DWRITE_RENDERING_MODE1_NATURAL:
4958 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
4959 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
4960 return TRUE;
4961 default:
4962 return FALSE;
4966 static UINT32 get_glyph_bitmap_pitch(DWRITE_RENDERING_MODE1 rendering_mode, INT width)
4968 return rendering_mode == DWRITE_RENDERING_MODE1_ALIASED ? ((width + 31) >> 5) << 2 : (width + 3) / 4 * 4;
4971 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4973 struct dwrite_glyphbitmap glyph_bitmap;
4974 IDWriteFontFace4 *fontface;
4975 HRESULT hr;
4976 UINT32 i;
4978 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4979 *bounds = analysis->bounds;
4980 return;
4983 if (analysis->run.isSideways)
4984 FIXME("sideways runs are not supported.\n");
4986 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
4987 if (FAILED(hr))
4988 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
4990 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4991 glyph_bitmap.fontface = fontface;
4992 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
4993 glyph_bitmap.emsize = analysis->run.fontEmSize;
4994 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
4995 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4996 glyph_bitmap.m = &analysis->m;
4998 for (i = 0; i < analysis->run.glyphCount; i++) {
4999 RECT *bbox = &glyph_bitmap.bbox;
5000 UINT32 bitmap_size;
5002 glyph_bitmap.index = analysis->run.glyphIndices[i];
5003 freetype_get_glyph_bbox(&glyph_bitmap);
5005 bitmap_size = get_glyph_bitmap_pitch(analysis->rendering_mode, bbox->right - bbox->left) *
5006 (bbox->bottom - bbox->top);
5007 if (bitmap_size > analysis->max_glyph_bitmap_size)
5008 analysis->max_glyph_bitmap_size = bitmap_size;
5010 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5011 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
5014 IDWriteFontFace4_Release(fontface);
5016 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
5017 *bounds = analysis->bounds;
5020 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
5022 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5024 TRACE("(%p)->(%d %p)\n", This, type, bounds);
5026 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
5027 SetRectEmpty(bounds);
5028 return E_INVALIDARG;
5031 if (type != This->texture_type) {
5032 SetRectEmpty(bounds);
5033 return S_OK;
5036 glyphrunanalysis_get_texturebounds(This, bounds);
5037 return S_OK;
5040 static inline int get_dib_stride( int width, int bpp )
5042 return ((width * bpp + 31) >> 3) & ~3;
5045 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
5047 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5048 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
5049 (runbounds->left - bounds->left) * 3;
5050 else
5051 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
5052 runbounds->left - bounds->left;
5055 static HRESULT glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis)
5057 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
5058 struct dwrite_glyphbitmap glyph_bitmap;
5059 IDWriteFontFace4 *fontface;
5060 D2D_POINT_2F origin;
5061 UINT32 i, size;
5062 HRESULT hr;
5063 RECT *bbox;
5065 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace4, (void **)&fontface);
5066 if (FAILED(hr)) {
5067 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5068 return hr;
5071 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
5072 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5073 size *= 3;
5074 if (!(analysis->bitmap = heap_alloc_zero(size))) {
5075 WARN("Failed to allocate run bitmap, %s, type %s.\n", wine_dbgstr_rect(&analysis->bounds),
5076 analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? "3x1" : "1x1");
5077 IDWriteFontFace4_Release(fontface);
5078 return E_OUTOFMEMORY;
5081 origin.x = origin.y = 0.0f;
5083 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
5084 glyph_bitmap.fontface = fontface;
5085 glyph_bitmap.simulations = IDWriteFontFace4_GetSimulations(fontface);
5086 glyph_bitmap.emsize = analysis->run.fontEmSize;
5087 glyph_bitmap.nohint = is_natural_rendering_mode(analysis->rendering_mode);
5088 glyph_bitmap.aliased = analysis->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED;
5089 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5090 glyph_bitmap.m = &analysis->m;
5091 if (!(glyph_bitmap.buf = heap_alloc(analysis->max_glyph_bitmap_size))) {
5092 IDWriteFontFace4_Release(fontface);
5093 return E_OUTOFMEMORY;
5096 bbox = &glyph_bitmap.bbox;
5098 for (i = 0; i < analysis->run.glyphCount; i++) {
5099 BYTE *src = glyph_bitmap.buf, *dst;
5100 int x, y, width, height;
5101 BOOL is_1bpp;
5103 glyph_bitmap.index = analysis->run.glyphIndices[i];
5104 freetype_get_glyph_bbox(&glyph_bitmap);
5106 if (IsRectEmpty(bbox))
5107 continue;
5109 width = bbox->right - bbox->left;
5110 height = bbox->bottom - bbox->top;
5112 glyph_bitmap.pitch = get_glyph_bitmap_pitch(analysis->rendering_mode, width);
5113 memset(src, 0, height * glyph_bitmap.pitch);
5114 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
5116 OffsetRect(bbox, analysis->origins[i].x, analysis->origins[i].y);
5118 /* blit to analysis bitmap */
5119 dst = get_pixel_ptr(analysis->bitmap, analysis->texture_type, bbox, &analysis->bounds);
5121 if (is_1bpp) {
5122 /* convert 1bpp to 8bpp/24bpp */
5123 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5124 for (y = 0; y < height; y++) {
5125 for (x = 0; x < width; x++)
5126 if (src[x / 8] & masks[x % 8])
5127 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
5128 src += glyph_bitmap.pitch;
5129 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5132 else {
5133 for (y = 0; y < height; y++) {
5134 for (x = 0; x < width; x++)
5135 if (src[x / 8] & masks[x % 8])
5136 dst[x] = DWRITE_ALPHA_MAX;
5137 src += glyph_bitmap.pitch;
5138 dst += analysis->bounds.right - analysis->bounds.left;
5142 else {
5143 if (analysis->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
5144 for (y = 0; y < height; y++) {
5145 for (x = 0; x < width; x++)
5146 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
5147 src += glyph_bitmap.pitch;
5148 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
5151 else {
5152 for (y = 0; y < height; y++) {
5153 for (x = 0; x < width; x++)
5154 dst[x] |= src[x];
5155 src += glyph_bitmap.pitch;
5156 dst += analysis->bounds.right - analysis->bounds.left;
5161 heap_free(glyph_bitmap.buf);
5163 IDWriteFontFace4_Release(fontface);
5165 analysis->flags |= RUNANALYSIS_BITMAP_READY;
5167 /* we don't need this anymore */
5168 heap_free(analysis->glyphs);
5169 heap_free(analysis->origins);
5170 IDWriteFontFace_Release(analysis->run.fontFace);
5172 analysis->glyphs = NULL;
5173 analysis->origins = NULL;
5174 analysis->run.glyphIndices = NULL;
5175 analysis->run.fontFace = NULL;
5177 return S_OK;
5180 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
5181 RECT const *bounds, BYTE *bitmap, UINT32 size)
5183 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5184 UINT32 required;
5185 RECT runbounds;
5187 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
5189 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
5190 return E_INVALIDARG;
5192 /* make sure buffer is large enough for requested texture type */
5193 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
5194 if (This->texture_type == DWRITE_TEXTURE_CLEARTYPE_3x1)
5195 required *= 3;
5197 if (size < required)
5198 return E_NOT_SUFFICIENT_BUFFER;
5200 /* validate requested texture type */
5201 if (This->texture_type != type)
5202 return DWRITE_E_UNSUPPORTEDOPERATION;
5204 memset(bitmap, 0, size);
5205 glyphrunanalysis_get_texturebounds(This, &runbounds);
5206 if (IntersectRect(&runbounds, &runbounds, bounds)) {
5207 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
5208 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
5209 int dst_width = (bounds->right - bounds->left) * pixel_size;
5210 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
5211 BYTE *src, *dst;
5212 int y;
5214 if (!(This->flags & RUNANALYSIS_BITMAP_READY)) {
5215 HRESULT hr;
5217 if (FAILED(hr = glyphrunanalysis_render(This)))
5218 return hr;
5221 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
5222 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
5224 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
5225 memcpy(dst, src, draw_width);
5226 src += src_width;
5227 dst += dst_width;
5231 return S_OK;
5234 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
5235 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
5237 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
5239 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
5241 if (!params)
5242 return E_INVALIDARG;
5244 switch (This->rendering_mode)
5246 case DWRITE_RENDERING_MODE1_GDI_CLASSIC:
5247 case DWRITE_RENDERING_MODE1_GDI_NATURAL:
5249 UINT value = 0;
5250 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5251 *gamma = (FLOAT)value / 1000.0f;
5252 *contrast = 0.0f;
5253 *cleartypelevel = 1.0f;
5254 break;
5256 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED:
5257 WARN("NATURAL_SYMMETRIC_DOWNSAMPLED mode is ignored.\n");
5258 /* fallthrough */
5259 case DWRITE_RENDERING_MODE1_ALIASED:
5260 case DWRITE_RENDERING_MODE1_NATURAL:
5261 case DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC:
5262 *gamma = IDWriteRenderingParams_GetGamma(params);
5263 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5264 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5265 break;
5266 default:
5270 return S_OK;
5273 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5274 glyphrunanalysis_QueryInterface,
5275 glyphrunanalysis_AddRef,
5276 glyphrunanalysis_Release,
5277 glyphrunanalysis_GetAlphaTextureBounds,
5278 glyphrunanalysis_CreateAlphaTexture,
5279 glyphrunanalysis_GetAlphaBlendParams
5282 static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
5284 D2D_POINT_2F ret;
5285 ret.x = point->x * m->m11 + point->y * m->m21 + m->dx;
5286 ret.y = point->x * m->m12 + point->y * m->m22 + m->dy;
5287 *point = ret;
5290 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5292 struct dwrite_glyphrunanalysis *analysis;
5293 DWRITE_FONT_METRICS metrics;
5294 IDWriteFontFace1 *fontface1;
5295 D2D_POINT_2F origin;
5296 FLOAT rtl_factor;
5297 HRESULT hr;
5298 UINT32 i;
5300 *ret = NULL;
5302 /* Check rendering, antialising, measuring, and grid fitting modes. */
5303 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED ||
5304 desc->rendering_mode == DWRITE_RENDERING_MODE1_OUTLINE ||
5305 desc->rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT)
5306 return E_INVALIDARG;
5308 if ((UINT32)desc->aa_mode > DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5309 return E_INVALIDARG;
5311 if ((UINT32)desc->gridfit_mode > DWRITE_GRID_FIT_MODE_ENABLED)
5312 return E_INVALIDARG;
5314 if ((UINT32)desc->measuring_mode > DWRITE_MEASURING_MODE_GDI_NATURAL)
5315 return E_INVALIDARG;
5317 analysis = heap_alloc(sizeof(*analysis));
5318 if (!analysis)
5319 return E_OUTOFMEMORY;
5321 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5322 analysis->ref = 1;
5323 analysis->rendering_mode = desc->rendering_mode;
5325 if (desc->rendering_mode == DWRITE_RENDERING_MODE1_ALIASED
5326 || desc->aa_mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE)
5327 analysis->texture_type = DWRITE_TEXTURE_ALIASED_1x1;
5328 else
5329 analysis->texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
5331 analysis->flags = 0;
5332 analysis->bitmap = NULL;
5333 analysis->max_glyph_bitmap_size = 0;
5334 SetRectEmpty(&analysis->bounds);
5335 analysis->run = *desc->run;
5336 analysis->run.fontEmSize *= desc->ppdip;
5337 IDWriteFontFace_AddRef(analysis->run.fontFace);
5338 analysis->glyphs = heap_alloc(desc->run->glyphCount * sizeof(*analysis->glyphs));
5339 analysis->origins = heap_alloc(desc->run->glyphCount * sizeof(*analysis->origins));
5341 if (!analysis->glyphs || !analysis->origins) {
5342 heap_free(analysis->glyphs);
5343 heap_free(analysis->origins);
5345 analysis->glyphs = NULL;
5346 analysis->origins = NULL;
5348 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5349 return E_OUTOFMEMORY;
5352 /* check if transform is usable */
5353 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5354 analysis->m = *desc->transform;
5355 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5357 else
5358 memset(&analysis->m, 0, sizeof(analysis->m));
5360 analysis->run.glyphIndices = analysis->glyphs;
5361 analysis->run.glyphAdvances = NULL;
5362 analysis->run.glyphOffsets = NULL;
5364 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5366 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5368 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
5369 if (FAILED(hr = IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1)))
5370 WARN("Failed to get IDWriteFontFace1, %#x.\n", hr);
5372 origin.x = desc->origin_x * desc->ppdip;
5373 origin.y = desc->origin_y * desc->ppdip;
5374 for (i = 0; i < desc->run->glyphCount; i++) {
5375 FLOAT advance;
5377 /* Use nominal advances if not provided by caller. */
5378 if (desc->run->glyphAdvances)
5379 advance = rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip;
5380 else {
5381 INT32 a;
5383 advance = 0.0f;
5384 switch (desc->measuring_mode)
5386 case DWRITE_MEASURING_MODE_NATURAL:
5387 if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a,
5388 desc->run->isSideways)))
5389 advance = rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip;
5390 break;
5391 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5392 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5393 if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize,
5394 desc->ppdip, desc->transform, desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL,
5395 desc->run->isSideways, 1, desc->run->glyphIndices + i, &a)))
5396 advance = rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f);
5397 break;
5398 default:
5403 analysis->origins[i] = origin;
5405 /* Offsets are optional, appled to pre-transformed origin. */
5406 if (desc->run->glyphOffsets) {
5407 FLOAT advanceoffset = rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip;
5408 FLOAT ascenderoffset = -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip;
5410 if (desc->run->isSideways) {
5411 analysis->origins[i].x += ascenderoffset;
5412 analysis->origins[i].y += advanceoffset;
5414 else {
5415 analysis->origins[i].x += advanceoffset;
5416 analysis->origins[i].y += ascenderoffset;
5420 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5421 transform_point(analysis->origins + i, &analysis->m);
5423 if (desc->run->isSideways)
5424 origin.y += advance;
5425 else
5426 origin.x += advance;
5429 IDWriteFontFace1_Release(fontface1);
5431 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5432 return S_OK;
5435 /* IDWriteColorGlyphRunEnumerator */
5436 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5438 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5440 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5442 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5443 IsEqualIID(riid, &IID_IUnknown))
5445 *ppv = iface;
5446 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5447 return S_OK;
5450 WARN("%s not implemented.\n", debugstr_guid(riid));
5452 *ppv = NULL;
5453 return E_NOINTERFACE;
5456 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5458 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5459 ULONG ref = InterlockedIncrement(&This->ref);
5460 TRACE("(%p)->(%u)\n", This, ref);
5461 return ref;
5464 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5466 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5467 ULONG ref = InterlockedDecrement(&This->ref);
5469 TRACE("(%p)->(%u)\n", This, ref);
5471 if (!ref) {
5472 heap_free(This->advances);
5473 heap_free(This->color_advances);
5474 heap_free(This->offsets);
5475 heap_free(This->color_offsets);
5476 heap_free(This->glyphindices);
5477 heap_free(This->glyphs);
5478 if (This->colr.context)
5479 IDWriteFontFace4_ReleaseFontTable(This->fontface, This->colr.context);
5480 IDWriteFontFace4_Release(This->fontface);
5481 heap_free(This);
5484 return ref;
5487 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5489 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5490 FLOAT origin = 0.0f;
5492 if (g == 0)
5493 return 0.0f;
5495 while (g--)
5496 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5497 return origin;
5500 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5502 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5503 FLOAT advance_adj = 0.0f;
5504 BOOL got_palette_index;
5505 UINT32 g;
5507 /* start with regular glyphs */
5508 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5509 UINT32 first_glyph = 0;
5511 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5512 if (glyphenum->glyphs[g].num_layers == 0) {
5513 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5514 first_glyph = min(first_glyph, g);
5516 else
5517 glyphenum->glyphindices[g] = 1;
5518 glyphenum->color_advances[g] = glyphenum->advances[g];
5519 if (glyphenum->color_offsets)
5520 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5523 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5524 colorrun->baselineOriginY = glyphenum->origin_y;
5525 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5526 colorrun->paletteIndex = 0xffff;
5527 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5528 glyphenum->has_regular_glyphs = FALSE;
5529 return TRUE;
5531 else {
5532 colorrun->glyphRun.glyphCount = 0;
5533 got_palette_index = FALSE;
5536 advance_adj = 0.0f;
5537 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5539 glyphenum->glyphindices[g] = 1;
5541 /* all glyph layers were returned */
5542 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5543 advance_adj += glyphenum->advances[g];
5544 continue;
5547 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5548 UINT32 index = colorrun->glyphRun.glyphCount;
5549 if (!got_palette_index) {
5550 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5551 /* use foreground color or request one from the font */
5552 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5553 if (colorrun->paletteIndex != 0xffff) {
5554 HRESULT hr = IDWriteFontFace4_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5555 1, &colorrun->runColor);
5556 if (FAILED(hr))
5557 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5558 glyphenum->palette, colorrun->paletteIndex, hr);
5560 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5561 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5562 colorrun->baselineOriginY = glyphenum->origin_y;
5563 glyphenum->color_advances[index] = glyphenum->advances[g];
5564 got_palette_index = TRUE;
5567 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5568 /* offsets are relative to glyph origin, nothing to fix up */
5569 if (glyphenum->color_offsets)
5570 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5571 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5572 if (index)
5573 glyphenum->color_advances[index-1] += advance_adj;
5574 colorrun->glyphRun.glyphCount++;
5575 advance_adj = 0.0f;
5577 else
5578 advance_adj += glyphenum->advances[g];
5581 /* reset last advance */
5582 if (colorrun->glyphRun.glyphCount)
5583 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5585 return colorrun->glyphRun.glyphCount > 0;
5588 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5590 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5592 TRACE("(%p)->(%p)\n", This, has_run);
5594 *has_run = FALSE;
5596 This->colorrun.glyphRun.glyphCount = 0;
5597 while (This->current_layer < This->max_layer_num) {
5598 if (colorglyphenum_build_color_run(This))
5599 break;
5600 else
5601 This->current_layer++;
5604 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5606 return S_OK;
5609 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5611 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5613 TRACE("(%p)->(%p)\n", This, run);
5615 if (This->colorrun.glyphRun.glyphCount == 0) {
5616 *run = NULL;
5617 return E_NOT_VALID_STATE;
5620 *run = &This->colorrun;
5621 return S_OK;
5624 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5625 colorglyphenum_QueryInterface,
5626 colorglyphenum_AddRef,
5627 colorglyphenum_Release,
5628 colorglyphenum_MoveNext,
5629 colorglyphenum_GetCurrentRun
5632 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5633 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5635 struct dwrite_colorglyphenum *colorglyphenum;
5636 BOOL colorfont, has_colored_glyph;
5637 IDWriteFontFace4 *fontface;
5638 HRESULT hr;
5639 UINT32 i;
5641 *ret = NULL;
5643 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace4, (void**)&fontface);
5644 if (FAILED(hr)) {
5645 WARN("failed to get IDWriteFontFace4, 0x%08x\n", hr);
5646 return hr;
5649 colorfont = IDWriteFontFace4_IsColorFont(fontface) && IDWriteFontFace4_GetColorPaletteCount(fontface) > palette;
5650 if (!colorfont) {
5651 hr = DWRITE_E_NOCOLOR;
5652 goto failed;
5655 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5656 if (!colorglyphenum) {
5657 hr = E_OUTOFMEMORY;
5658 goto failed;
5661 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5662 colorglyphenum->ref = 1;
5663 colorglyphenum->origin_x = originX;
5664 colorglyphenum->origin_y = originY;
5665 colorglyphenum->fontface = fontface;
5666 colorglyphenum->glyphs = NULL;
5667 colorglyphenum->run = *run;
5668 colorglyphenum->run.glyphIndices = NULL;
5669 colorglyphenum->run.glyphAdvances = NULL;
5670 colorglyphenum->run.glyphOffsets = NULL;
5671 colorglyphenum->palette = palette;
5672 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5673 colorglyphenum->colr.exists = TRUE;
5674 get_fontface_table(fontface, MS_COLR_TAG, &colorglyphenum->colr);
5675 colorglyphenum->current_layer = 0;
5676 colorglyphenum->max_layer_num = 0;
5678 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5680 has_colored_glyph = FALSE;
5681 colorglyphenum->has_regular_glyphs = FALSE;
5682 for (i = 0; i < run->glyphCount; i++) {
5683 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5684 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5685 has_colored_glyph = TRUE;
5687 if (colorglyphenum->glyphs[i].num_layers == 0)
5688 colorglyphenum->has_regular_glyphs = TRUE;
5691 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5692 is supposed to proceed normally, like if font had no color info at all. */
5693 if (!has_colored_glyph) {
5694 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5695 return DWRITE_E_NOCOLOR;
5698 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5699 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5700 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5701 if (run->glyphOffsets) {
5702 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5703 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5704 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5707 colorglyphenum->colorrun.glyphRun.fontFace = (IDWriteFontFace*)fontface;
5708 colorglyphenum->colorrun.glyphRun.fontEmSize = run->fontEmSize;
5709 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5710 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5711 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5712 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5714 if (run->glyphAdvances)
5715 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5716 else {
5717 DWRITE_FONT_METRICS metrics;
5719 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5720 for (i = 0; i < run->glyphCount; i++) {
5721 HRESULT hr;
5722 INT32 a;
5724 switch (measuring_mode)
5726 case DWRITE_MEASURING_MODE_NATURAL:
5727 hr = IDWriteFontFace4_GetDesignGlyphAdvances(fontface, 1, run->glyphIndices + i, &a, run->isSideways);
5728 if (FAILED(hr))
5729 a = 0;
5730 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5731 break;
5732 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5733 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5734 hr = IDWriteFontFace4_GetGdiCompatibleGlyphAdvances(fontface, run->fontEmSize, 1.0f, transform,
5735 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5736 if (FAILED(hr))
5737 colorglyphenum->advances[i] = 0.0f;
5738 else
5739 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5740 break;
5741 default:
5747 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5748 return S_OK;
5750 failed:
5751 IDWriteFontFace4_Release(fontface);
5752 return hr;
5755 /* IDWriteFontFaceReference */
5756 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5758 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5760 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5762 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5763 *obj = iface;
5764 IDWriteFontFaceReference_AddRef(iface);
5765 return S_OK;
5768 WARN("%s not implemented.\n", debugstr_guid(riid));
5770 *obj = NULL;
5772 return E_NOINTERFACE;
5775 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5777 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5778 ULONG ref = InterlockedIncrement(&This->ref);
5779 TRACE("(%p)->(%u)\n", This, ref);
5780 return ref;
5783 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5785 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5786 ULONG ref = InterlockedDecrement(&This->ref);
5788 TRACE("(%p)->(%u)\n", This, ref);
5790 if (!ref) {
5791 IDWriteFontFile_Release(This->file);
5792 IDWriteFactory5_Release(This->factory);
5793 heap_free(This);
5796 return ref;
5799 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5801 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5803 TRACE("(%p)->(%p)\n", This, fontface);
5805 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5808 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5809 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5811 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5812 DWRITE_FONT_FILE_TYPE file_type;
5813 DWRITE_FONT_FACE_TYPE face_type;
5814 IDWriteFontFace *fontface;
5815 BOOL is_supported;
5816 UINT32 face_num;
5817 HRESULT hr;
5819 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5821 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5822 if (FAILED(hr))
5823 return hr;
5825 hr = IDWriteFactory5_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5826 if (SUCCEEDED(hr)) {
5827 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)ret);
5828 IDWriteFontFace_Release(fontface);
5831 return hr;
5834 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5836 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5837 IDWriteFontFile *file;
5838 BOOL ret;
5840 TRACE("(%p)->(%p)\n", This, ref);
5842 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5843 return FALSE;
5845 ret = is_same_fontfile(This->file, file) &&
5846 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5847 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5848 IDWriteFontFile_Release(file);
5850 return ret;
5853 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5855 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5857 TRACE("(%p)\n", This);
5859 return This->index;
5862 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5864 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5866 TRACE("(%p)\n", This);
5868 return This->simulations;
5871 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5873 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5874 IDWriteFontFileLoader *loader;
5875 const void *key;
5876 UINT32 key_size;
5877 HRESULT hr;
5879 TRACE("(%p)->(%p)\n", This, file);
5881 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5882 if (FAILED(hr))
5883 return hr;
5885 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5886 if (FAILED(hr))
5887 return hr;
5889 hr = IDWriteFactory5_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5890 IDWriteFontFileLoader_Release(loader);
5892 return hr;
5895 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5897 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5899 FIXME("(%p): stub\n", This);
5901 return 0;
5904 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5906 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5908 FIXME("(%p): stub\n", This);
5910 return 0;
5913 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5915 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5917 FIXME("(%p)->(%p): stub\n", This, writetime);
5919 return E_NOTIMPL;
5922 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5924 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5926 FIXME("(%p): stub\n", This);
5928 return DWRITE_LOCALITY_LOCAL;
5931 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5933 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5935 FIXME("(%p): stub\n", This);
5937 return E_NOTIMPL;
5940 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5941 UINT32 count)
5943 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5945 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5947 return E_NOTIMPL;
5950 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5951 UINT32 count)
5953 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5955 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5957 return E_NOTIMPL;
5960 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5961 UINT64 offset, UINT64 size)
5963 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5965 FIXME("(%p)->(0x%s 0x%s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5967 return E_NOTIMPL;
5970 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5971 fontfacereference_QueryInterface,
5972 fontfacereference_AddRef,
5973 fontfacereference_Release,
5974 fontfacereference_CreateFontFace,
5975 fontfacereference_CreateFontFaceWithSimulations,
5976 fontfacereference_Equals,
5977 fontfacereference_GetFontFaceIndex,
5978 fontfacereference_GetSimulations,
5979 fontfacereference_GetFontFile,
5980 fontfacereference_GetLocalFileSize,
5981 fontfacereference_GetFileSize,
5982 fontfacereference_GetFileTime,
5983 fontfacereference_GetLocality,
5984 fontfacereference_EnqueueFontDownloadRequest,
5985 fontfacereference_EnqueueCharacterDownloadRequest,
5986 fontfacereference_EnqueueGlyphDownloadRequest,
5987 fontfacereference_EnqueueFileFragmentDownloadRequest
5990 HRESULT create_fontfacereference(IDWriteFactory5 *factory, IDWriteFontFile *file, UINT32 index,
5991 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5993 struct dwrite_fontfacereference *ref;
5995 *ret = NULL;
5997 if (!is_simulation_valid(simulations))
5998 return E_INVALIDARG;
6000 ref = heap_alloc(sizeof(*ref));
6001 if (!ref)
6002 return E_OUTOFMEMORY;
6004 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
6005 ref->ref = 1;
6007 ref->factory = factory;
6008 IDWriteFactory5_AddRef(ref->factory);
6009 ref->file = file;
6010 IDWriteFontFile_AddRef(ref->file);
6011 ref->index = index;
6012 ref->simulations = simulations;
6013 *ret = &ref->IDWriteFontFaceReference_iface;
6015 return S_OK;
6018 static HRESULT WINAPI inmemoryfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
6020 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6022 TRACE_(dwrite_file)("(%p)->(%s, %p)\n", stream, debugstr_guid(riid), obj);
6024 if (IsEqualIID(riid, &IID_IDWriteFontFileStream) || IsEqualIID(riid, &IID_IUnknown)) {
6025 *obj = iface;
6026 IDWriteFontFileStream_AddRef(iface);
6027 return S_OK;
6030 *obj = NULL;
6032 WARN("%s not implemented.\n", debugstr_guid(riid));
6033 return E_NOINTERFACE;
6036 static ULONG WINAPI inmemoryfilestream_AddRef(IDWriteFontFileStream *iface)
6038 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6039 ULONG ref = InterlockedIncrement(&stream->ref);
6040 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6041 return ref;
6044 static ULONG WINAPI inmemoryfilestream_Release(IDWriteFontFileStream *iface)
6046 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6047 ULONG ref = InterlockedDecrement(&stream->ref);
6049 TRACE_(dwrite_file)("(%p)->(%u)\n", stream, ref);
6051 if (!ref) {
6052 release_inmemory_stream(stream->data);
6053 heap_free(stream);
6056 return ref;
6059 static HRESULT WINAPI inmemoryfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start,
6060 UINT64 offset, UINT64 fragment_size, void **fragment_context)
6062 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6064 TRACE_(dwrite_file)("(%p)->(%p, 0x%s, 0x%s, %p)\n", stream, fragment_start,
6065 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
6067 *fragment_context = NULL;
6069 if ((offset >= stream->data->size - 1) || (fragment_size > stream->data->size - offset)) {
6070 *fragment_start = NULL;
6071 return E_FAIL;
6074 *fragment_start = (char *)stream->data->data + offset;
6075 return S_OK;
6078 static void WINAPI inmemoryfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
6080 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6082 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, fragment_context);
6085 static HRESULT WINAPI inmemoryfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
6087 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6089 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, size);
6091 *size = stream->data->size;
6093 return S_OK;
6096 static HRESULT WINAPI inmemoryfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
6098 struct dwrite_inmemory_filestream *stream = inmemory_impl_from_IDWriteFontFileStream(iface);
6100 TRACE_(dwrite_file)("(%p)->(%p)\n", stream, last_writetime);
6102 *last_writetime = 0;
6104 return E_NOTIMPL;
6107 static const IDWriteFontFileStreamVtbl inmemoryfilestreamvtbl = {
6108 inmemoryfilestream_QueryInterface,
6109 inmemoryfilestream_AddRef,
6110 inmemoryfilestream_Release,
6111 inmemoryfilestream_ReadFileFragment,
6112 inmemoryfilestream_ReleaseFileFragment,
6113 inmemoryfilestream_GetFileSize,
6114 inmemoryfilestream_GetLastWriteTime,
6117 static HRESULT WINAPI inmemoryfontfileloader_QueryInterface(IDWriteInMemoryFontFileLoader *iface,
6118 REFIID riid, void **obj)
6120 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6122 TRACE("(%p)->(%s, %p)\n", loader, debugstr_guid(riid), obj);
6124 if (IsEqualIID(riid, &IID_IDWriteInMemoryFontFileLoader) ||
6125 IsEqualIID(riid, &IID_IDWriteFontFileLoader) ||
6126 IsEqualIID(riid, &IID_IUnknown))
6128 *obj = iface;
6129 IDWriteInMemoryFontFileLoader_AddRef(iface);
6130 return S_OK;
6133 WARN("%s not implemented.\n", debugstr_guid(riid));
6135 *obj = NULL;
6137 return E_NOINTERFACE;
6140 static ULONG WINAPI inmemoryfontfileloader_AddRef(IDWriteInMemoryFontFileLoader *iface)
6142 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6143 ULONG ref = InterlockedIncrement(&loader->ref);
6144 TRACE("(%p)->(%u)\n", loader, ref);
6145 return ref;
6148 static ULONG WINAPI inmemoryfontfileloader_Release(IDWriteInMemoryFontFileLoader *iface)
6150 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6151 ULONG ref = InterlockedDecrement(&loader->ref);
6153 TRACE("(%p)->(%u)\n", loader, ref);
6155 if (!ref) {
6156 UINT32 i;
6158 for (i = 0; i < loader->filecount; i++)
6159 release_inmemory_stream(loader->streams[i]);
6160 heap_free(loader->streams);
6161 heap_free(loader);
6164 return ref;
6167 static HRESULT WINAPI inmemoryfontfileloader_CreateStreamFromKey(IDWriteInMemoryFontFileLoader *iface,
6168 void const *key, UINT32 key_size, IDWriteFontFileStream **ret)
6170 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6171 struct dwrite_inmemory_filestream *stream;
6172 DWORD index;
6174 TRACE("(%p)->(%p, %u, %p)\n", loader, key, key_size, ret);
6176 *ret = NULL;
6178 if (key_size != sizeof(DWORD))
6179 return E_INVALIDARG;
6181 index = *(DWORD *)key;
6183 if (index >= loader->filecount)
6184 return E_INVALIDARG;
6186 if (!(stream = heap_alloc(sizeof(*stream))))
6187 return E_OUTOFMEMORY;
6189 stream->IDWriteFontFileStream_iface.lpVtbl = &inmemoryfilestreamvtbl;
6190 stream->ref = 1;
6191 stream->data = loader->streams[index];
6192 InterlockedIncrement(&stream->data->ref);
6194 *ret = &stream->IDWriteFontFileStream_iface;
6196 return S_OK;
6199 static HRESULT WINAPI inmemoryfontfileloader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader *iface,
6200 IDWriteFactory *factory, void const *data, UINT32 data_size, IUnknown *owner, IDWriteFontFile **fontfile)
6202 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6203 struct dwrite_inmemory_stream_data *stream;
6204 DWORD key;
6206 TRACE("(%p)->(%p, %p, %u, %p, %p)\n", loader, factory, data, data_size, owner, fontfile);
6208 *fontfile = NULL;
6210 if (loader->filecount == loader->capacity) {
6211 if (loader->streams) {
6212 struct dwrite_inmemory_stream_data **ptr;
6214 if (!(ptr = heap_realloc(loader->streams, 2 * loader->capacity * sizeof(*loader->streams))))
6215 return E_OUTOFMEMORY;
6217 loader->streams = ptr;
6218 loader->capacity *= 2;
6220 else {
6221 loader->capacity = 16;
6222 loader->streams = heap_alloc(loader->capacity * sizeof(*loader->streams));
6226 if (!(stream = heap_alloc(sizeof(*stream))))
6227 return E_OUTOFMEMORY;
6229 stream->ref = 1;
6230 stream->size = data_size;
6231 stream->owner = owner;
6232 if (stream->owner) {
6233 IUnknown_AddRef(stream->owner);
6234 stream->data = (void *)data;
6236 else {
6237 if (!(stream->data = heap_alloc(data_size))) {
6238 heap_free(stream);
6239 return E_OUTOFMEMORY;
6241 memcpy(stream->data, data, data_size);
6244 key = loader->filecount;
6245 loader->streams[loader->filecount++] = stream;
6247 return IDWriteFactory_CreateCustomFontFileReference(factory, &key, sizeof(key),
6248 (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface, fontfile);
6251 static UINT32 WINAPI inmemoryfontfileloader_GetFileCount(IDWriteInMemoryFontFileLoader *iface)
6253 struct dwrite_inmemory_fileloader *loader = impl_from_IDWriteInMemoryFontFileLoader(iface);
6255 TRACE("(%p)\n", loader);
6257 return loader->filecount;
6260 static const IDWriteInMemoryFontFileLoaderVtbl inmemoryfontfileloadervtbl =
6262 inmemoryfontfileloader_QueryInterface,
6263 inmemoryfontfileloader_AddRef,
6264 inmemoryfontfileloader_Release,
6265 inmemoryfontfileloader_CreateStreamFromKey,
6266 inmemoryfontfileloader_CreateInMemoryFontFileReference,
6267 inmemoryfontfileloader_GetFileCount,
6270 HRESULT create_inmemory_fileloader(IDWriteFontFileLoader **ret)
6272 struct dwrite_inmemory_fileloader *loader;
6274 *ret = NULL;
6276 loader = heap_alloc_zero(sizeof(*loader));
6277 if (!loader)
6278 return E_OUTOFMEMORY;
6280 loader->IDWriteInMemoryFontFileLoader_iface.lpVtbl = &inmemoryfontfileloadervtbl;
6281 loader->ref = 1;
6283 *ret = (IDWriteFontFileLoader *)&loader->IDWriteInMemoryFontFileLoader_iface;
6285 return S_OK;