wined3d: Add AMD Radeon HD 6480G IGP.
[wine.git] / dlls / dwrite / font.c
blobe529d6f1f7fe2334dac2ada899011b0acb264f0d
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <math.h>
24 #define COBJMACROS
26 #include "dwrite_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
29 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file);
31 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
32 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
33 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
34 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
35 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
36 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
37 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
38 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
40 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
42 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
43 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
44 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
46 static const WCHAR extraW[] = {'e','x','t','r','a',0};
47 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
48 static const WCHAR semiW[] = {'s','e','m','i',0};
49 static const WCHAR extW[] = {'e','x','t',0};
50 static const WCHAR thinW[] = {'t','h','i','n',0};
51 static const WCHAR lightW[] = {'l','i','g','h','t',0};
52 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
53 static const WCHAR blackW[] = {'b','l','a','c','k',0};
54 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
55 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
56 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
57 static const WCHAR boldW[] = {'B','o','l','d',0};
58 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
59 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
60 static const WCHAR demiW[] = {'d','e','m','i',0};
61 static const WCHAR spaceW[] = {' ',0};
62 static const WCHAR enusW[] = {'e','n','-','u','s',0};
64 struct dwrite_font_propvec {
65 FLOAT stretch;
66 FLOAT style;
67 FLOAT weight;
70 struct dwrite_font_data {
71 LONG ref;
73 DWRITE_FONT_STYLE style;
74 DWRITE_FONT_STRETCH stretch;
75 DWRITE_FONT_WEIGHT weight;
76 DWRITE_PANOSE panose;
77 struct dwrite_font_propvec propvec;
79 DWRITE_FONT_METRICS1 metrics;
80 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
81 IDWriteLocalizedStrings *names;
83 /* data needed to create fontface instance */
84 IDWriteFactory3 *factory;
85 DWRITE_FONT_FACE_TYPE face_type;
86 IDWriteFontFile *file;
87 UINT32 face_index;
89 WCHAR *facename;
91 USHORT simulations;
93 /* used to mark font as tested when scanning for simulation candidate */
94 BOOL bold_sim_tested : 1;
95 BOOL oblique_sim_tested : 1;
98 struct dwrite_fontlist {
99 IDWriteFontList1 IDWriteFontList1_iface;
100 LONG ref;
102 IDWriteFontFamily1 *family;
103 struct dwrite_font_data **fonts;
104 UINT32 font_count;
107 struct dwrite_fontfamily_data {
108 LONG ref;
110 IDWriteLocalizedStrings *familyname;
112 struct dwrite_font_data **fonts;
113 UINT32 font_count;
114 UINT32 font_alloc;
115 BOOL has_normal_face : 1;
116 BOOL has_oblique_face : 1;
117 BOOL has_italic_face : 1;
120 struct dwrite_fontcollection {
121 IDWriteFontCollection1 IDWriteFontCollection1_iface;
122 LONG ref;
124 struct dwrite_fontfamily_data **family_data;
125 UINT32 family_count;
126 UINT32 family_alloc;
129 struct dwrite_fontfamily {
130 IDWriteFontFamily1 IDWriteFontFamily1_iface;
131 LONG ref;
133 struct dwrite_fontfamily_data *data;
135 IDWriteFontCollection1 *collection;
138 struct dwrite_font {
139 IDWriteFont3 IDWriteFont3_iface;
140 LONG ref;
142 IDWriteFontFamily1 *family;
144 DWRITE_FONT_STYLE style;
145 struct dwrite_font_data *data;
148 struct dwrite_fonttable {
149 void *data;
150 void *context;
151 UINT32 size;
152 BOOL exists;
155 enum runanalysis_flags {
156 RUNANALYSIS_BOUNDS_READY = 1 << 0,
157 RUNANALYSIS_BITMAP_READY = 1 << 1,
158 RUNANALYSIS_USE_TRANSFORM = 1 << 2
161 struct dwrite_glyphrunanalysis {
162 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
163 LONG ref;
165 DWRITE_RENDERING_MODE rendering_mode;
166 DWRITE_GLYPH_RUN run; /* glyphAdvances and glyphOffsets are not used */
167 DWRITE_MATRIX m;
168 FLOAT ppdip;
169 UINT16 *glyphs;
170 D2D_POINT_2F origin;
171 D2D_POINT_2F *advances;
172 D2D_POINT_2F *advanceoffsets;
173 D2D_POINT_2F *ascenderoffsets;
175 UINT8 flags;
176 RECT bounds;
177 BYTE *bitmap;
180 struct dwrite_colorglyphenum {
181 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
182 LONG ref;
184 FLOAT origin_x; /* original run origin */
185 FLOAT origin_y;
187 IDWriteFontFace3 *fontface; /* for convenience */
188 DWRITE_COLOR_GLYPH_RUN colorrun; /* returned with GetCurrentRun() */
189 DWRITE_GLYPH_RUN run; /* base run */
190 UINT32 palette; /* palette index to get layer color from */
191 FLOAT *advances; /* original or measured advances for base glyphs */
192 FLOAT *color_advances; /* returned color run points to this */
193 DWRITE_GLYPH_OFFSET *offsets; /* original offsets, or NULL */
194 DWRITE_GLYPH_OFFSET *color_offsets; /* returned color run offsets, or NULL */
195 UINT16 *glyphindices; /* returned color run points to this */
196 struct dwrite_colorglyph *glyphs; /* current glyph color info */
197 BOOL has_regular_glyphs; /* TRUE if there's any glyph without a color */
198 UINT16 current_layer; /* enumerator position, updated with MoveNext */
199 UINT16 max_layer_num; /* max number of layers for this run */
200 struct dwrite_fonttable colr; /* used to access layers */
203 #define GLYPH_BLOCK_SHIFT 8
204 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
205 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
206 #define GLYPH_MAX 65536
208 enum fontface_flags {
209 FONTFACE_IS_SYMBOL = 1 << 0,
210 FONTFACE_IS_MONOSPACED = 1 << 1,
211 FONTFACE_HAS_KERN_PAIRS = 1 << 2,
212 FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3
215 struct dwrite_fontface {
216 IDWriteFontFace3 IDWriteFontFace3_iface;
217 LONG ref;
219 IDWriteFontFileStream **streams;
220 IDWriteFontFile **files;
221 UINT32 file_count;
222 UINT32 index;
224 USHORT simulations;
225 DWRITE_FONT_FACE_TYPE type;
226 DWRITE_FONT_METRICS1 metrics;
227 DWRITE_CARET_METRICS caret;
228 INT charmap;
229 UINT16 flags;
231 struct dwrite_fonttable cmap;
232 struct dwrite_fonttable vdmx;
233 struct dwrite_fonttable gasp;
234 struct dwrite_fonttable cpal;
235 struct dwrite_fonttable colr;
236 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
238 DWRITE_FONT_STYLE style;
239 DWRITE_FONT_STRETCH stretch;
240 DWRITE_FONT_WEIGHT weight;
241 DWRITE_PANOSE panose;
244 struct dwrite_fontfile {
245 IDWriteFontFile IDWriteFontFile_iface;
246 LONG ref;
248 IDWriteFontFileLoader *loader;
249 void *reference_key;
250 UINT32 key_size;
251 IDWriteFontFileStream *stream;
254 struct dwrite_fontfacereference {
255 IDWriteFontFaceReference IDWriteFontFaceReference_iface;
256 LONG ref;
258 IDWriteFontFile *file;
259 UINT32 index;
260 USHORT simulations;
261 IDWriteFactory3 *factory;
264 static inline struct dwrite_fontface *impl_from_IDWriteFontFace3(IDWriteFontFace3 *iface)
266 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace3_iface);
269 static inline struct dwrite_font *impl_from_IDWriteFont3(IDWriteFont3 *iface)
271 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
274 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
276 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
279 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily1(IDWriteFontFamily1 *iface)
281 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily1_iface);
284 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection1(IDWriteFontCollection1 *iface)
286 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection1_iface);
289 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
291 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
294 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
296 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
299 static inline struct dwrite_fontlist *impl_from_IDWriteFontList1(IDWriteFontList1 *iface)
301 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList1_iface);
304 static inline struct dwrite_fontfacereference *impl_from_IDWriteFontFaceReference(IDWriteFontFaceReference *iface)
306 return CONTAINING_RECORD(iface, struct dwrite_fontfacereference, IDWriteFontFaceReference_iface);
309 static inline const char *debugstr_tag(UINT32 tag)
311 return debugstr_an((char*)&tag, 4);
314 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
316 static const DWRITE_GLYPH_METRICS nil;
317 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
319 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
320 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
321 return S_OK;
324 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
326 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
328 if (!*block) {
329 /* start new block */
330 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
331 if (!*block)
332 return E_OUTOFMEMORY;
335 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
336 return S_OK;
339 static void* get_fontface_table(IDWriteFontFace3 *fontface, UINT32 tag, struct dwrite_fonttable *table)
341 HRESULT hr;
343 if (table->data || !table->exists)
344 return table->data;
346 table->exists = FALSE;
347 hr = IDWriteFontFace3_TryGetFontTable(fontface, tag, (const void**)&table->data, &table->size, &table->context,
348 &table->exists);
349 if (FAILED(hr) || !table->exists) {
350 WARN("Font does not have a %s table\n", debugstr_tag(tag));
351 return NULL;
354 return table->data;
357 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
358 struct dwrite_font_propvec *vec)
360 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
361 vec->style = style * 7.0f;
362 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
365 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
367 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
370 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
372 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
375 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
377 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CMAP_TAG, &fontface->cmap);
380 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
382 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_VDMX_TAG, &fontface->vdmx);
385 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
387 void *ptr = get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_GASP_TAG, &fontface->gasp);
388 *size = fontface->gasp.size;
389 return ptr;
392 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
394 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_CPAL_TAG, &fontface->cpal);
397 static inline void* get_fontface_colr(struct dwrite_fontface *fontface)
399 return get_fontface_table(&fontface->IDWriteFontFace3_iface, MS_COLR_TAG, &fontface->colr);
402 static void release_font_data(struct dwrite_font_data *data)
404 int i;
406 if (InterlockedDecrement(&data->ref) > 0)
407 return;
409 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
410 if (data->info_strings[i])
411 IDWriteLocalizedStrings_Release(data->info_strings[i]);
413 if (data->names)
414 IDWriteLocalizedStrings_Release(data->names);
416 IDWriteFontFile_Release(data->file);
417 IDWriteFactory3_Release(data->factory);
418 heap_free(data->facename);
419 heap_free(data);
422 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
424 int i;
426 if (InterlockedDecrement(&data->ref) > 0)
427 return;
429 for (i = 0; i < data->font_count; i++)
430 release_font_data(data->fonts[i]);
431 heap_free(data->fonts);
432 IDWriteLocalizedStrings_Release(data->familyname);
433 heap_free(data);
436 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace3 *iface, REFIID riid, void **obj)
438 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
440 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
442 if (IsEqualIID(riid, &IID_IDWriteFontFace3) ||
443 IsEqualIID(riid, &IID_IDWriteFontFace2) ||
444 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
445 IsEqualIID(riid, &IID_IDWriteFontFace) ||
446 IsEqualIID(riid, &IID_IUnknown))
448 *obj = iface;
449 IDWriteFontFace3_AddRef(iface);
450 return S_OK;
453 *obj = NULL;
454 return E_NOINTERFACE;
457 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace3 *iface)
459 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
460 ULONG ref = InterlockedIncrement(&This->ref);
461 TRACE("(%p)->(%d)\n", This, ref);
462 return ref;
465 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace3 *iface)
467 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
468 ULONG ref = InterlockedDecrement(&This->ref);
470 TRACE("(%p)->(%d)\n", This, ref);
472 if (!ref) {
473 UINT32 i;
475 if (This->cmap.context)
476 IDWriteFontFace3_ReleaseFontTable(iface, This->cmap.context);
477 if (This->vdmx.context)
478 IDWriteFontFace3_ReleaseFontTable(iface, This->vdmx.context);
479 if (This->gasp.context)
480 IDWriteFontFace3_ReleaseFontTable(iface, This->gasp.context);
481 if (This->cpal.context)
482 IDWriteFontFace3_ReleaseFontTable(iface, This->cpal.context);
483 if (This->colr.context)
484 IDWriteFontFace3_ReleaseFontTable(iface, This->colr.context);
485 for (i = 0; i < This->file_count; i++) {
486 if (This->streams[i])
487 IDWriteFontFileStream_Release(This->streams[i]);
488 if (This->files[i])
489 IDWriteFontFile_Release(This->files[i]);
491 heap_free(This->streams);
492 heap_free(This->files);
494 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
495 heap_free(This->glyphs[i]);
497 freetype_notify_cacheremove(iface);
498 heap_free(This);
501 return ref;
504 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace3 *iface)
506 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
507 TRACE("(%p)\n", This);
508 return This->type;
511 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace3 *iface, UINT32 *number_of_files,
512 IDWriteFontFile **fontfiles)
514 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
515 int i;
517 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
518 if (fontfiles == NULL)
520 *number_of_files = This->file_count;
521 return S_OK;
523 if (*number_of_files < This->file_count)
524 return E_INVALIDARG;
526 for (i = 0; i < This->file_count; i++)
528 IDWriteFontFile_AddRef(This->files[i]);
529 fontfiles[i] = This->files[i];
532 return S_OK;
535 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace3 *iface)
537 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
538 TRACE("(%p)\n", This);
539 return This->index;
542 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace3 *iface)
544 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
545 TRACE("(%p)\n", This);
546 return This->simulations;
549 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace3 *iface)
551 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
552 TRACE("(%p)\n", This);
553 return !!(This->flags & FONTFACE_IS_SYMBOL);
556 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS *metrics)
558 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
559 TRACE("(%p)->(%p)\n", This, metrics);
560 memcpy(metrics, &This->metrics, sizeof(*metrics));
563 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace3 *iface)
565 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
566 TRACE("(%p)\n", This);
567 return freetype_get_glyphcount(iface);
570 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace3 *iface,
571 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
573 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
574 HRESULT hr;
575 UINT32 i;
577 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
579 if (!glyphs)
580 return E_INVALIDARG;
582 if (is_sideways)
583 FIXME("sideways metrics are not supported.\n");
585 for (i = 0; i < glyph_count; i++) {
586 DWRITE_GLYPH_METRICS metrics;
588 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
589 if (hr != S_OK) {
590 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
591 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
592 if (FAILED(hr))
593 return hr;
595 ret[i] = metrics;
598 return S_OK;
601 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace3 *iface, UINT32 const *codepoints,
602 UINT32 count, UINT16 *glyph_indices)
604 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
606 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
608 if (!glyph_indices)
609 return E_INVALIDARG;
611 if (!codepoints) {
612 memset(glyph_indices, 0, count*sizeof(UINT16));
613 return E_INVALIDARG;
616 freetype_get_glyphs(iface, This->charmap, codepoints, count, glyph_indices);
617 return S_OK;
620 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace3 *iface, UINT32 table_tag,
621 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
623 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
624 struct file_stream_desc stream_desc;
626 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
628 stream_desc.stream = This->streams[0];
629 stream_desc.face_type = This->type;
630 stream_desc.face_index = This->index;
631 return opentype_get_font_table(&stream_desc, table_tag, table_data, context, table_size, exists);
634 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace3 *iface, void *table_context)
636 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
638 TRACE("(%p)->(%p)\n", This, table_context);
640 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
643 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace3 *iface, FLOAT emSize,
644 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
645 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
647 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
649 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
650 count, is_sideways, is_rtl, sink);
652 if (!glyphs || !sink)
653 return E_INVALIDARG;
655 if (is_sideways)
656 FIXME("sideways mode is not supported.\n");
658 return freetype_get_glyphrun_outline(iface, emSize, glyphs, advances, offsets, count, is_rtl, sink);
661 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
662 FLOAT ppem, WORD gasp)
664 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
666 switch (measuring)
668 case DWRITE_MEASURING_MODE_NATURAL:
670 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
671 mode = DWRITE_RENDERING_MODE_NATURAL;
672 else
673 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
674 break;
676 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
677 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
678 break;
679 case DWRITE_MEASURING_MODE_GDI_NATURAL:
680 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
681 break;
682 default:
686 return mode;
689 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
690 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
692 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
693 WORD gasp, *ptr;
694 UINT32 size;
695 FLOAT ppem;
697 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
699 if (!params) {
700 *mode = DWRITE_RENDERING_MODE_DEFAULT;
701 return E_INVALIDARG;
704 *mode = IDWriteRenderingParams_GetRenderingMode(params);
705 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
706 return S_OK;
708 ppem = emSize * ppdip;
710 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
711 *mode = DWRITE_RENDERING_MODE_OUTLINE;
712 return S_OK;
715 ptr = get_fontface_gasp(This, &size);
716 gasp = opentype_get_gasp_flags(ptr, size, ppem);
717 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
718 return S_OK;
721 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT pixels_per_dip,
722 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
724 DWRITE_FONT_METRICS1 metrics1;
725 HRESULT hr = IDWriteFontFace3_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
726 memcpy(metrics, &metrics1, sizeof(*metrics));
727 return hr;
730 static inline int round_metric(FLOAT metric)
732 return (int)floorf(metric + 0.5f);
735 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT ppdip,
736 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
737 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
739 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
740 DWRITE_MEASURING_MODE mode;
741 FLOAT scale, size;
742 HRESULT hr;
743 UINT32 i;
745 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
746 glyph_count, metrics, is_sideways);
748 if (m && memcmp(m, &identity, sizeof(*m)))
749 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
751 size = emSize * ppdip;
752 scale = size / This->metrics.designUnitsPerEm;
753 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
755 for (i = 0; i < glyph_count; i++) {
756 DWRITE_GLYPH_METRICS *ret = metrics + i;
757 DWRITE_GLYPH_METRICS design;
759 hr = IDWriteFontFace3_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
760 if (FAILED(hr))
761 return hr;
763 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
764 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
766 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
767 SCALE_METRIC(leftSideBearing);
768 SCALE_METRIC(rightSideBearing);
769 SCALE_METRIC(topSideBearing);
770 SCALE_METRIC(advanceHeight);
771 SCALE_METRIC(bottomSideBearing);
772 SCALE_METRIC(verticalOriginY);
773 #undef SCALE_METRIC
776 return S_OK;
779 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace3 *iface, DWRITE_FONT_METRICS1 *metrics)
781 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
782 TRACE("(%p)->(%p)\n", This, metrics);
783 *metrics = This->metrics;
786 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3 *iface, FLOAT em_size, FLOAT pixels_per_dip,
787 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
789 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
790 const DWRITE_FONT_METRICS1 *design = &This->metrics;
791 UINT16 ascent, descent;
792 FLOAT scale;
794 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
796 if (em_size <= 0.0f || pixels_per_dip <= 0.0f) {
797 memset(metrics, 0, sizeof(*metrics));
798 return E_INVALIDARG;
801 em_size *= pixels_per_dip;
802 if (m && m->m22 != 0.0f)
803 em_size *= fabs(m->m22);
805 scale = em_size / design->designUnitsPerEm;
806 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
807 ascent = round_metric(design->ascent * scale);
808 descent = round_metric(design->descent * scale);
811 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
812 metrics->designUnitsPerEm = design->designUnitsPerEm;
813 metrics->ascent = round_metric(ascent / scale);
814 metrics->descent = round_metric(descent / scale);
816 SCALE_METRIC(lineGap);
817 SCALE_METRIC(capHeight);
818 SCALE_METRIC(xHeight);
819 SCALE_METRIC(underlinePosition);
820 SCALE_METRIC(underlineThickness);
821 SCALE_METRIC(strikethroughPosition);
822 SCALE_METRIC(strikethroughThickness);
823 SCALE_METRIC(glyphBoxLeft);
824 SCALE_METRIC(glyphBoxTop);
825 SCALE_METRIC(glyphBoxRight);
826 SCALE_METRIC(glyphBoxBottom);
827 SCALE_METRIC(subscriptPositionX);
828 SCALE_METRIC(subscriptPositionY);
829 SCALE_METRIC(subscriptSizeX);
830 SCALE_METRIC(subscriptSizeY);
831 SCALE_METRIC(superscriptPositionX);
832 SCALE_METRIC(superscriptPositionY);
833 SCALE_METRIC(superscriptSizeX);
834 SCALE_METRIC(superscriptSizeY);
836 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
837 #undef SCALE_METRIC
839 return S_OK;
842 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace3 *iface, DWRITE_CARET_METRICS *metrics)
844 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
845 TRACE("(%p)->(%p)\n", This, metrics);
846 *metrics = This->caret;
849 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace3 *iface, UINT32 max_count,
850 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
852 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
854 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
856 *count = 0;
857 if (max_count && !ranges)
858 return E_INVALIDARG;
860 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
863 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace3 *iface)
865 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
866 TRACE("(%p)\n", This);
867 return !!(This->flags & FONTFACE_IS_MONOSPACED);
870 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3 *iface,
871 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
873 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
874 UINT32 i;
876 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
878 if (is_sideways)
879 FIXME("sideways mode not supported\n");
881 for (i = 0; i < glyph_count; i++)
882 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
884 return S_OK;
887 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3 *iface,
888 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
889 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
891 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
892 DWRITE_MEASURING_MODE mode;
893 UINT32 i;
895 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
896 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
898 if (em_size < 0.0f || ppdip <= 0.0f) {
899 memset(advances, 0, sizeof(*advances) * glyph_count);
900 return E_INVALIDARG;
903 em_size *= ppdip;
904 if (em_size == 0.0f) {
905 memset(advances, 0, sizeof(*advances) * glyph_count);
906 return S_OK;
909 if (m && memcmp(m, &identity, sizeof(*m)))
910 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
912 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
913 for (i = 0; i < glyph_count; i++) {
914 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
915 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
918 return S_OK;
921 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3 *iface, UINT32 count,
922 const UINT16 *indices, INT32 *adjustments)
924 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
925 UINT32 i;
927 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
929 if (!(indices || adjustments) || !count)
930 return E_INVALIDARG;
932 if (!indices || count == 1) {
933 memset(adjustments, 0, count*sizeof(INT32));
934 return E_INVALIDARG;
937 if (This->flags & FONTFACE_HAS_KERN_PAIRS) {
938 memset(adjustments, 0, count*sizeof(INT32));
939 return S_OK;
942 for (i = 0; i < count-1; i++)
943 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
944 adjustments[count-1] = 0;
946 return S_OK;
949 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace3 *iface)
951 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
952 TRACE("(%p)\n", This);
953 return !!(This->flags & FONTFACE_HAS_KERN_PAIRS);
956 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3 *iface,
957 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
958 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
960 DWRITE_GRID_FIT_MODE gridfitmode;
961 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2*)iface, font_emsize, dpiX, dpiY, transform, is_sideways,
962 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
965 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3 *iface, UINT32 glyph_count,
966 const UINT16 *nominal_indices, UINT16 *vertical_indices)
968 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
969 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
970 return E_NOTIMPL;
973 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3 *iface)
975 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
976 TRACE("(%p)\n", This);
977 return !!(This->flags & FONTFACE_HAS_VERTICAL_VARIANTS);
980 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace3 *iface)
982 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
983 TRACE("(%p)\n", This);
984 return get_fontface_cpal(This) && get_fontface_colr(This);
987 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace3 *iface)
989 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
990 TRACE("(%p)\n", This);
991 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
994 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3 *iface)
996 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
997 TRACE("(%p)\n", This);
998 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1001 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace3 *iface, UINT32 palette_index,
1002 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1004 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1005 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1006 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1009 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize,
1010 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1011 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1012 DWRITE_GRID_FIT_MODE *gridfitmode)
1014 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1015 FLOAT emthreshold;
1016 WORD gasp, *ptr;
1017 UINT32 size;
1019 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1020 measuringmode, params, renderingmode, gridfitmode);
1022 if (m)
1023 FIXME("transform not supported %s\n", debugstr_matrix(m));
1025 if (is_sideways)
1026 FIXME("sideways mode not supported\n");
1028 emSize *= max(dpiX, dpiY) / 96.0f;
1030 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1031 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1032 if (params) {
1033 IDWriteRenderingParams2 *params2;
1034 HRESULT hr;
1036 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1037 if (hr == S_OK) {
1038 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1039 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1040 IDWriteRenderingParams2_Release(params2);
1042 else
1043 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1046 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1048 ptr = get_fontface_gasp(This, &size);
1049 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1051 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1052 if (emSize >= emthreshold)
1053 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1054 else
1055 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1058 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1059 if (emSize >= emthreshold)
1060 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1061 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1062 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1063 else
1064 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1067 return S_OK;
1070 static HRESULT WINAPI dwritefontface3_GetFontFaceReference(IDWriteFontFace3 *iface, IDWriteFontFaceReference **ref)
1072 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1073 FIXME("(%p)->(%p): stub\n", This, ref);
1074 return E_NOTIMPL;
1077 static void WINAPI dwritefontface3_GetPanose(IDWriteFontFace3 *iface, DWRITE_PANOSE *panose)
1079 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1080 TRACE("(%p)->(%p)\n", This, panose);
1081 *panose = This->panose;
1084 static DWRITE_FONT_WEIGHT WINAPI dwritefontface3_GetWeight(IDWriteFontFace3 *iface)
1086 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1087 TRACE("(%p)\n", This);
1088 return This->weight;
1091 static DWRITE_FONT_STRETCH WINAPI dwritefontface3_GetStretch(IDWriteFontFace3 *iface)
1093 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1094 TRACE("(%p)\n", This);
1095 return This->stretch;
1098 static DWRITE_FONT_STYLE WINAPI dwritefontface3_GetStyle(IDWriteFontFace3 *iface)
1100 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1101 TRACE("(%p)\n", This);
1102 return This->style;
1105 static HRESULT WINAPI dwritefontface3_GetFamilyNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1107 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1108 FIXME("(%p)->(%p): stub\n", This, names);
1109 return E_NOTIMPL;
1112 static HRESULT WINAPI dwritefontface3_GetFaceNames(IDWriteFontFace3 *iface, IDWriteLocalizedStrings **names)
1114 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1115 FIXME("(%p)->(%p): stub\n", This, names);
1116 return E_NOTIMPL;
1119 static HRESULT WINAPI dwritefontface3_GetInformationalStrings(IDWriteFontFace3 *iface, DWRITE_INFORMATIONAL_STRING_ID stringid,
1120 IDWriteLocalizedStrings **strings, BOOL *exists)
1122 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1123 FIXME("(%p)->(%u %p %p): stub\n", This, stringid, strings, exists);
1124 return E_NOTIMPL;
1127 static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace3 *iface, UINT32 ch)
1129 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1130 UINT16 index;
1131 HRESULT hr;
1133 TRACE("(%p)->(0x%08x)\n", This, ch);
1135 index = 0;
1136 hr = IDWriteFontFace3_GetGlyphIndices(iface, &ch, 1, &index);
1137 if (FAILED(hr))
1138 return FALSE;
1140 return index != 0;
1143 static HRESULT WINAPI dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3 *iface, FLOAT emSize, FLOAT dpiX, FLOAT dpiY,
1144 DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode,
1145 IDWriteRenderingParams *params, DWRITE_RENDERING_MODE1 *rendering_mode, DWRITE_GRID_FIT_MODE *gridfit_mode)
1147 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1148 FLOAT emthreshold;
1149 WORD gasp, *ptr;
1150 UINT32 size;
1152 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1153 measuring_mode, params, rendering_mode, gridfit_mode);
1155 if (m)
1156 FIXME("transform not supported %s\n", debugstr_matrix(m));
1158 if (is_sideways)
1159 FIXME("sideways mode not supported\n");
1161 emSize *= max(dpiX, dpiY) / 96.0f;
1163 *rendering_mode = DWRITE_RENDERING_MODE_DEFAULT;
1164 *gridfit_mode = DWRITE_GRID_FIT_MODE_DEFAULT;
1165 if (params) {
1166 IDWriteRenderingParams3 *params3;
1167 HRESULT hr;
1169 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams3, (void**)&params3);
1170 if (hr == S_OK) {
1171 *rendering_mode = IDWriteRenderingParams3_GetRenderingMode1(params3);
1172 *gridfit_mode = IDWriteRenderingParams3_GetGridFitMode(params3);
1173 IDWriteRenderingParams3_Release(params3);
1175 else
1176 *rendering_mode = IDWriteRenderingParams_GetRenderingMode(params);
1179 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1181 ptr = get_fontface_gasp(This, &size);
1182 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1184 if (*rendering_mode == DWRITE_RENDERING_MODE1_DEFAULT) {
1185 if (emSize >= emthreshold)
1186 *rendering_mode = DWRITE_RENDERING_MODE1_OUTLINE;
1187 else
1188 *rendering_mode = fontface_renderingmode_from_measuringmode(measuring_mode, emSize, gasp);
1191 if (*gridfit_mode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1192 if (emSize >= emthreshold)
1193 *gridfit_mode = DWRITE_GRID_FIT_MODE_DISABLED;
1194 else if (measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1195 *gridfit_mode = DWRITE_GRID_FIT_MODE_ENABLED;
1196 else
1197 *gridfit_mode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1200 return S_OK;
1203 static BOOL WINAPI dwritefontface3_IsCharacterLocal(IDWriteFontFace3 *iface, UINT32 ch)
1205 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1206 FIXME("(%p)->(0x%x): stub\n", This, ch);
1207 return FALSE;
1210 static BOOL WINAPI dwritefontface3_IsGlyphLocal(IDWriteFontFace3 *iface, UINT16 glyph)
1212 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1213 FIXME("(%p)->(%u): stub\n", This, glyph);
1214 return FALSE;
1217 static HRESULT WINAPI dwritefontface3_AreCharactersLocal(IDWriteFontFace3 *iface, WCHAR const *text,
1218 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1220 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1221 FIXME("(%p)->(%s:%u %d %p): stub\n", This, debugstr_wn(text, count), count, enqueue_if_not, are_local);
1222 return E_NOTIMPL;
1225 static HRESULT WINAPI dwritefontface3_AreGlyphsLocal(IDWriteFontFace3 *iface, UINT16 const *glyphs,
1226 UINT32 count, BOOL enqueue_if_not, BOOL *are_local)
1228 struct dwrite_fontface *This = impl_from_IDWriteFontFace3(iface);
1229 FIXME("(%p)->(%p %u %d %p): stub\n", This, glyphs, count, enqueue_if_not, are_local);
1230 return E_NOTIMPL;
1233 static const IDWriteFontFace3Vtbl dwritefontfacevtbl = {
1234 dwritefontface_QueryInterface,
1235 dwritefontface_AddRef,
1236 dwritefontface_Release,
1237 dwritefontface_GetType,
1238 dwritefontface_GetFiles,
1239 dwritefontface_GetIndex,
1240 dwritefontface_GetSimulations,
1241 dwritefontface_IsSymbolFont,
1242 dwritefontface_GetMetrics,
1243 dwritefontface_GetGlyphCount,
1244 dwritefontface_GetDesignGlyphMetrics,
1245 dwritefontface_GetGlyphIndices,
1246 dwritefontface_TryGetFontTable,
1247 dwritefontface_ReleaseFontTable,
1248 dwritefontface_GetGlyphRunOutline,
1249 dwritefontface_GetRecommendedRenderingMode,
1250 dwritefontface_GetGdiCompatibleMetrics,
1251 dwritefontface_GetGdiCompatibleGlyphMetrics,
1252 dwritefontface1_GetMetrics,
1253 dwritefontface1_GetGdiCompatibleMetrics,
1254 dwritefontface1_GetCaretMetrics,
1255 dwritefontface1_GetUnicodeRanges,
1256 dwritefontface1_IsMonospacedFont,
1257 dwritefontface1_GetDesignGlyphAdvances,
1258 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1259 dwritefontface1_GetKerningPairAdjustments,
1260 dwritefontface1_HasKerningPairs,
1261 dwritefontface1_GetRecommendedRenderingMode,
1262 dwritefontface1_GetVerticalGlyphVariants,
1263 dwritefontface1_HasVerticalGlyphVariants,
1264 dwritefontface2_IsColorFont,
1265 dwritefontface2_GetColorPaletteCount,
1266 dwritefontface2_GetPaletteEntryCount,
1267 dwritefontface2_GetPaletteEntries,
1268 dwritefontface2_GetRecommendedRenderingMode,
1269 dwritefontface3_GetFontFaceReference,
1270 dwritefontface3_GetPanose,
1271 dwritefontface3_GetWeight,
1272 dwritefontface3_GetStretch,
1273 dwritefontface3_GetStyle,
1274 dwritefontface3_GetFamilyNames,
1275 dwritefontface3_GetFaceNames,
1276 dwritefontface3_GetInformationalStrings,
1277 dwritefontface3_HasCharacter,
1278 dwritefontface3_GetRecommendedRenderingMode,
1279 dwritefontface3_IsCharacterLocal,
1280 dwritefontface3_IsGlyphLocal,
1281 dwritefontface3_AreCharactersLocal,
1282 dwritefontface3_AreGlyphsLocal
1285 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace3 **fontface)
1287 struct dwrite_font_data *data = font->data;
1288 struct fontface_desc desc;
1289 struct list *cached_list;
1290 HRESULT hr;
1292 *fontface = NULL;
1294 hr = factory_get_cached_fontface(data->factory, &data->file, data->face_index,
1295 font->data->simulations, (IDWriteFontFace**)fontface, &cached_list);
1296 if (hr != S_FALSE)
1297 return hr;
1299 desc.factory = data->factory;
1300 desc.face_type = data->face_type;
1301 desc.files = &data->file;
1302 desc.files_number = 1;
1303 desc.index = data->face_index;
1304 desc.simulations = data->simulations;
1305 desc.font_data = data;
1306 hr = create_fontface(&desc, fontface);
1307 if (FAILED(hr))
1308 return hr;
1310 factory_cache_fontface(cached_list, *fontface);
1312 return S_OK;
1315 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont3 *iface, REFIID riid, void **obj)
1317 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1319 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1321 if (IsEqualIID(riid, &IID_IDWriteFont3) ||
1322 IsEqualIID(riid, &IID_IDWriteFont2) ||
1323 IsEqualIID(riid, &IID_IDWriteFont1) ||
1324 IsEqualIID(riid, &IID_IDWriteFont) ||
1325 IsEqualIID(riid, &IID_IUnknown))
1327 *obj = iface;
1328 IDWriteFont3_AddRef(iface);
1329 return S_OK;
1332 *obj = NULL;
1333 return E_NOINTERFACE;
1336 static ULONG WINAPI dwritefont_AddRef(IDWriteFont3 *iface)
1338 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1339 ULONG ref = InterlockedIncrement(&This->ref);
1340 TRACE("(%p)->(%d)\n", This, ref);
1341 return ref;
1344 static ULONG WINAPI dwritefont_Release(IDWriteFont3 *iface)
1346 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1347 ULONG ref = InterlockedDecrement(&This->ref);
1349 TRACE("(%p)->(%d)\n", This, ref);
1351 if (!ref) {
1352 IDWriteFontFamily1_Release(This->family);
1353 release_font_data(This->data);
1354 heap_free(This);
1357 return ref;
1360 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont3 *iface, IDWriteFontFamily **family)
1362 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1363 TRACE("(%p)->(%p)\n", This, family);
1365 *family = (IDWriteFontFamily*)This->family;
1366 IDWriteFontFamily_AddRef(*family);
1367 return S_OK;
1370 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont3 *iface)
1372 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1373 TRACE("(%p)\n", This);
1374 return This->data->weight;
1377 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont3 *iface)
1379 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1380 TRACE("(%p)\n", This);
1381 return This->data->stretch;
1384 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont3 *iface)
1386 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1387 TRACE("(%p)\n", This);
1388 return This->style;
1391 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont3 *iface)
1393 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1394 IDWriteFontFace3 *fontface;
1395 HRESULT hr;
1397 TRACE("(%p)\n", This);
1399 hr = get_fontface_from_font(This, &fontface);
1400 if (FAILED(hr))
1401 return FALSE;
1403 return IDWriteFontFace3_IsSymbolFont(fontface);
1406 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont3 *iface, IDWriteLocalizedStrings **names)
1408 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1409 TRACE("(%p)->(%p)\n", This, names);
1410 return clone_localizedstring(This->data->names, names);
1413 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont3 *iface,
1414 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1416 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1417 struct dwrite_font_data *data = This->data;
1418 HRESULT hr;
1420 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1422 *exists = FALSE;
1423 *strings = NULL;
1425 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1426 return S_OK;
1428 if (!data->info_strings[stringid]) {
1429 IDWriteFontFace3 *fontface;
1430 const void *table_data;
1431 BOOL table_exists;
1432 void *context;
1433 UINT32 size;
1435 hr = get_fontface_from_font(This, &fontface);
1436 if (FAILED(hr))
1437 return hr;
1439 table_exists = FALSE;
1440 hr = IDWriteFontFace3_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1441 if (FAILED(hr) || !table_exists)
1442 WARN("no NAME table found.\n");
1444 if (table_exists) {
1445 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1446 if (FAILED(hr) || !data->info_strings[stringid])
1447 return hr;
1448 IDWriteFontFace3_ReleaseFontTable(fontface, context);
1452 hr = clone_localizedstring(data->info_strings[stringid], strings);
1453 if (FAILED(hr))
1454 return hr;
1456 *exists = TRUE;
1457 return S_OK;
1460 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont3 *iface)
1462 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1463 TRACE("(%p)\n", This);
1464 return This->data->simulations;
1467 static void WINAPI dwritefont_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS *metrics)
1469 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1471 TRACE("(%p)->(%p)\n", This, metrics);
1472 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1475 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont3 *iface, UINT32 value, BOOL *exists)
1477 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1478 IDWriteFontFace3 *fontface;
1479 UINT16 index;
1480 HRESULT hr;
1482 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1484 *exists = FALSE;
1486 hr = get_fontface_from_font(This, &fontface);
1487 if (FAILED(hr))
1488 return hr;
1490 index = 0;
1491 hr = IDWriteFontFace3_GetGlyphIndices(fontface, &value, 1, &index);
1492 if (FAILED(hr))
1493 return hr;
1495 *exists = index != 0;
1496 return S_OK;
1499 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace **fontface)
1501 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1502 TRACE("(%p)->(%p)\n", This, fontface);
1503 return IDWriteFont3_CreateFontFace(iface, (IDWriteFontFace3**)fontface);
1506 static void WINAPI dwritefont1_GetMetrics(IDWriteFont3 *iface, DWRITE_FONT_METRICS1 *metrics)
1508 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1509 TRACE("(%p)->(%p)\n", This, metrics);
1510 *metrics = This->data->metrics;
1513 static void WINAPI dwritefont1_GetPanose(IDWriteFont3 *iface, DWRITE_PANOSE *panose)
1515 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1516 TRACE("(%p)->(%p)\n", This, panose);
1517 *panose = This->data->panose;
1520 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1522 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1523 IDWriteFontFace3 *fontface;
1524 HRESULT hr;
1526 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1528 hr = get_fontface_from_font(This, &fontface);
1529 if (FAILED(hr))
1530 return hr;
1532 return IDWriteFontFace3_GetUnicodeRanges(fontface, max_count, ranges, count);
1535 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface)
1537 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1538 IDWriteFontFace3 *fontface;
1539 HRESULT hr;
1541 TRACE("(%p)\n", This);
1543 hr = get_fontface_from_font(This, &fontface);
1544 if (FAILED(hr))
1545 return FALSE;
1547 return IDWriteFontFace3_IsMonospacedFont(fontface);
1550 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont3 *iface)
1552 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1553 IDWriteFontFace3 *fontface;
1554 HRESULT hr;
1556 TRACE("(%p)\n", This);
1558 hr = get_fontface_from_font(This, &fontface);
1559 if (FAILED(hr))
1560 return FALSE;
1562 return IDWriteFontFace3_IsColorFont(fontface);
1565 static HRESULT WINAPI dwritefont3_CreateFontFace(IDWriteFont3 *iface, IDWriteFontFace3 **fontface)
1567 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1568 HRESULT hr;
1570 TRACE("(%p)->(%p)\n", This, fontface);
1572 hr = get_fontface_from_font(This, fontface);
1573 if (hr == S_OK)
1574 IDWriteFontFace3_AddRef(*fontface);
1576 return hr;
1579 static BOOL WINAPI dwritefont3_Equals(IDWriteFont3 *iface, IDWriteFont *font)
1581 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1582 FIXME("(%p)->(%p): stub\n", This, font);
1583 return FALSE;
1586 static HRESULT WINAPI dwritefont3_GetFontFaceReference(IDWriteFont3 *iface, IDWriteFontFaceReference **reference)
1588 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1590 TRACE("(%p)->(%p)\n", This, reference);
1592 return IDWriteFactory3_CreateFontFaceReference_(This->data->factory, This->data->file, This->data->face_index,
1593 This->data->simulations, reference);
1596 static BOOL WINAPI dwritefont3_HasCharacter(IDWriteFont3 *iface, UINT32 ch)
1598 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1599 HRESULT hr;
1600 BOOL ret;
1602 TRACE("(%p)->(0x%x)\n", This, ch);
1604 hr = IDWriteFont_HasCharacter((IDWriteFont*)iface, ch, &ret);
1605 return hr == S_OK && ret;
1608 static DWRITE_LOCALITY WINAPI dwritefont3_GetLocality(IDWriteFont3 *iface)
1610 struct dwrite_font *This = impl_from_IDWriteFont3(iface);
1611 FIXME("(%p): stub\n", This);
1612 return DWRITE_LOCALITY_LOCAL;
1615 static const IDWriteFont3Vtbl dwritefontvtbl = {
1616 dwritefont_QueryInterface,
1617 dwritefont_AddRef,
1618 dwritefont_Release,
1619 dwritefont_GetFontFamily,
1620 dwritefont_GetWeight,
1621 dwritefont_GetStretch,
1622 dwritefont_GetStyle,
1623 dwritefont_IsSymbolFont,
1624 dwritefont_GetFaceNames,
1625 dwritefont_GetInformationalStrings,
1626 dwritefont_GetSimulations,
1627 dwritefont_GetMetrics,
1628 dwritefont_HasCharacter,
1629 dwritefont_CreateFontFace,
1630 dwritefont1_GetMetrics,
1631 dwritefont1_GetPanose,
1632 dwritefont1_GetUnicodeRanges,
1633 dwritefont1_IsMonospacedFont,
1634 dwritefont2_IsColorFont,
1635 dwritefont3_CreateFontFace,
1636 dwritefont3_Equals,
1637 dwritefont3_GetFontFaceReference,
1638 dwritefont3_HasCharacter,
1639 dwritefont3_GetLocality
1642 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily1 *family, IDWriteFont3 **font)
1644 struct dwrite_font *This;
1645 *font = NULL;
1647 This = heap_alloc(sizeof(struct dwrite_font));
1648 if (!This) return E_OUTOFMEMORY;
1650 This->IDWriteFont3_iface.lpVtbl = &dwritefontvtbl;
1651 This->ref = 1;
1652 This->family = family;
1653 IDWriteFontFamily1_AddRef(family);
1654 This->style = data->style;
1655 This->data = data;
1656 InterlockedIncrement(&This->data->ref);
1658 *font = &This->IDWriteFont3_iface;
1660 return S_OK;
1663 /* IDWriteFontList1 */
1664 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList1 *iface, REFIID riid, void **obj)
1666 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1668 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1670 if (IsEqualIID(riid, &IID_IDWriteFontList1) ||
1671 IsEqualIID(riid, &IID_IDWriteFontList) ||
1672 IsEqualIID(riid, &IID_IUnknown))
1674 *obj = iface;
1675 IDWriteFontList1_AddRef(iface);
1676 return S_OK;
1679 *obj = NULL;
1680 return E_NOINTERFACE;
1683 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList1 *iface)
1685 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1686 ULONG ref = InterlockedIncrement(&This->ref);
1687 TRACE("(%p)->(%d)\n", This, ref);
1688 return ref;
1691 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList1 *iface)
1693 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1694 ULONG ref = InterlockedDecrement(&This->ref);
1696 TRACE("(%p)->(%d)\n", This, ref);
1698 if (!ref) {
1699 UINT32 i;
1701 for (i = 0; i < This->font_count; i++)
1702 release_font_data(This->fonts[i]);
1703 IDWriteFontFamily1_Release(This->family);
1704 heap_free(This->fonts);
1705 heap_free(This);
1708 return ref;
1711 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList1 *iface, IDWriteFontCollection **collection)
1713 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1714 return IDWriteFontFamily1_GetFontCollection(This->family, collection);
1717 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList1 *iface)
1719 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1720 TRACE("(%p)\n", This);
1721 return This->font_count;
1724 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont **font)
1726 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1728 TRACE("(%p)->(%u %p)\n", This, index, font);
1730 *font = NULL;
1732 if (This->font_count == 0)
1733 return S_FALSE;
1735 if (index >= This->font_count)
1736 return E_INVALIDARG;
1738 return create_font(This->fonts[index], This->family, (IDWriteFont3**)font);
1741 static DWRITE_LOCALITY WINAPI dwritefontlist1_GetFontLocality(IDWriteFontList1 *iface, UINT32 index)
1743 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1745 FIXME("(%p)->(%u): stub\n", This, index);
1747 return DWRITE_LOCALITY_LOCAL;
1750 static HRESULT WINAPI dwritefontlist1_GetFont(IDWriteFontList1 *iface, UINT32 index, IDWriteFont3 **font)
1752 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1754 TRACE("(%p)->(%u %p)\n", This, index, font);
1756 *font = NULL;
1758 if (This->font_count == 0)
1759 return S_FALSE;
1761 if (index >= This->font_count)
1762 return E_FAIL;
1764 return create_font(This->fonts[index], This->family, font);
1767 static HRESULT WINAPI dwritefontlist1_GetFontFaceReference(IDWriteFontList1 *iface, UINT32 index,
1768 IDWriteFontFaceReference **reference)
1770 struct dwrite_fontlist *This = impl_from_IDWriteFontList1(iface);
1771 IDWriteFont3 *font;
1772 HRESULT hr;
1774 TRACE("(%p)->(%u %p)\n", This, index, reference);
1776 *reference = NULL;
1778 hr = IDWriteFontList1_GetFont(iface, index, &font);
1779 if (FAILED(hr))
1780 return hr;
1782 hr = IDWriteFont3_GetFontFaceReference(font, reference);
1783 IDWriteFont3_Release(font);
1785 return hr;
1788 static const IDWriteFontList1Vtbl dwritefontlistvtbl = {
1789 dwritefontlist_QueryInterface,
1790 dwritefontlist_AddRef,
1791 dwritefontlist_Release,
1792 dwritefontlist_GetFontCollection,
1793 dwritefontlist_GetFontCount,
1794 dwritefontlist_GetFont,
1795 dwritefontlist1_GetFontLocality,
1796 dwritefontlist1_GetFont,
1797 dwritefontlist1_GetFontFaceReference
1800 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily1 *iface, REFIID riid, void **obj)
1802 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1804 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1806 if (IsEqualIID(riid, &IID_IDWriteFontFamily1) ||
1807 IsEqualIID(riid, &IID_IDWriteFontFamily) ||
1808 IsEqualIID(riid, &IID_IDWriteFontList) ||
1809 IsEqualIID(riid, &IID_IUnknown))
1811 *obj = iface;
1812 IDWriteFontFamily1_AddRef(iface);
1813 return S_OK;
1816 *obj = NULL;
1817 return E_NOINTERFACE;
1820 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily1 *iface)
1822 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1823 ULONG ref = InterlockedIncrement(&This->ref);
1824 TRACE("(%p)->(%d)\n", This, ref);
1825 return ref;
1828 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily1 *iface)
1830 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1831 ULONG ref = InterlockedDecrement(&This->ref);
1833 TRACE("(%p)->(%d)\n", This, ref);
1835 if (!ref)
1837 IDWriteFontCollection1_Release(This->collection);
1838 release_fontfamily_data(This->data);
1839 heap_free(This);
1842 return ref;
1845 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily1 *iface, IDWriteFontCollection **collection)
1847 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1849 TRACE("(%p)->(%p)\n", This, collection);
1851 *collection = (IDWriteFontCollection*)This->collection;
1852 IDWriteFontCollection_AddRef(*collection);
1853 return S_OK;
1856 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily1 *iface)
1858 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1859 TRACE("(%p)\n", This);
1860 return This->data->font_count;
1863 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont **font)
1865 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1867 TRACE("(%p)->(%u %p)\n", This, index, font);
1869 *font = NULL;
1871 if (This->data->font_count == 0)
1872 return S_FALSE;
1874 if (index >= This->data->font_count)
1875 return E_INVALIDARG;
1877 return create_font(This->data->fonts[index], iface, (IDWriteFont3**)font);
1880 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily1 *iface, IDWriteLocalizedStrings **names)
1882 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1883 return clone_localizedstring(This->data->familyname, names);
1886 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1887 const struct dwrite_font_propvec *req)
1889 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1890 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1891 FLOAT cur_req_prod, next_req_prod;
1893 if (next_to_req < cur_to_req)
1894 return TRUE;
1896 if (next_to_req > cur_to_req)
1897 return FALSE;
1899 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1900 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1902 if (next_req_prod > cur_req_prod)
1903 return TRUE;
1905 if (next_req_prod < cur_req_prod)
1906 return FALSE;
1908 if (next->stretch > cur->stretch)
1909 return TRUE;
1910 if (next->stretch < cur->stretch)
1911 return FALSE;
1913 if (next->style > cur->style)
1914 return TRUE;
1915 if (next->style < cur->style)
1916 return FALSE;
1918 if (next->weight > cur->weight)
1919 return TRUE;
1920 if (next->weight < cur->weight)
1921 return FALSE;
1923 /* full match, no reason to prefer new variant */
1924 return FALSE;
1927 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1928 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1930 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1931 struct dwrite_font_propvec req;
1932 struct dwrite_font_data *match;
1933 UINT32 i;
1935 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1937 if (This->data->font_count == 0) {
1938 *font = NULL;
1939 return DWRITE_E_NOFONT;
1942 init_font_prop_vec(weight, stretch, style, &req);
1943 match = This->data->fonts[0];
1945 for (i = 1; i < This->data->font_count; i++) {
1946 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1947 match = This->data->fonts[i];
1950 return create_font(match, iface, (IDWriteFont3**)font);
1953 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1955 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1957 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1960 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1962 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1965 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1967 UINT32 b = fonts->font_count - 1, j, t;
1969 while (1) {
1970 t = b;
1972 for (j = 0; j < b; j++) {
1973 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1974 struct dwrite_font_data *s = fonts->fonts[j];
1975 fonts->fonts[j] = fonts->fonts[j+1];
1976 fonts->fonts[j+1] = s;
1977 t = j;
1981 if (t == b)
1982 break;
1983 b = t;
1987 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily1 *iface, DWRITE_FONT_WEIGHT weight,
1988 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1990 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
1991 matching_filter_func func = NULL;
1992 struct dwrite_font_propvec req;
1993 struct dwrite_fontlist *fonts;
1994 UINT32 i;
1996 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1998 *ret = NULL;
2000 fonts = heap_alloc(sizeof(*fonts));
2001 if (!fonts)
2002 return E_OUTOFMEMORY;
2004 /* Allocate as many as family has, not all of them will be necessary used. */
2005 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
2006 if (!fonts->fonts) {
2007 heap_free(fonts);
2008 return E_OUTOFMEMORY;
2011 fonts->IDWriteFontList1_iface.lpVtbl = &dwritefontlistvtbl;
2012 fonts->ref = 1;
2013 fonts->family = iface;
2014 IDWriteFontFamily1_AddRef(fonts->family);
2015 fonts->font_count = 0;
2017 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
2018 if (style == DWRITE_FONT_STYLE_NORMAL) {
2019 if (This->data->has_normal_face || This->data->has_italic_face)
2020 func = is_font_acceptable_for_normal;
2022 else /* requested oblique or italic */ {
2023 if (This->data->has_oblique_face || This->data->has_italic_face)
2024 func = is_font_acceptable_for_oblique_italic;
2027 for (i = 0; i < This->data->font_count; i++) {
2028 if (!func || func(This->data->fonts[i])) {
2029 fonts->fonts[fonts->font_count] = This->data->fonts[i];
2030 InterlockedIncrement(&This->data->fonts[i]->ref);
2031 fonts->font_count++;
2035 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
2036 init_font_prop_vec(weight, stretch, style, &req);
2037 matchingfonts_sort(fonts, &req);
2039 *ret = (IDWriteFontList*)&fonts->IDWriteFontList1_iface;
2040 return S_OK;
2043 static DWRITE_LOCALITY WINAPI dwritefontfamily1_GetFontLocality(IDWriteFontFamily1 *iface, UINT32 index)
2045 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2047 FIXME("(%p)->(%u): stub\n", This, index);
2049 return DWRITE_LOCALITY_LOCAL;
2052 static HRESULT WINAPI dwritefontfamily1_GetFont(IDWriteFontFamily1 *iface, UINT32 index, IDWriteFont3 **font)
2054 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2056 TRACE("(%p)->(%u %p)\n", This, index, font);
2058 *font = NULL;
2060 if (This->data->font_count == 0)
2061 return S_FALSE;
2063 if (index >= This->data->font_count)
2064 return E_FAIL;
2066 return create_font(This->data->fonts[index], iface, font);
2069 static HRESULT WINAPI dwritefontfamily1_GetFontFaceReference(IDWriteFontFamily1 *iface, UINT32 index,
2070 IDWriteFontFaceReference **reference)
2072 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily1(iface);
2073 IDWriteFont3 *font;
2074 HRESULT hr;
2076 TRACE("(%p)->(%u %p)\n", This, index, reference);
2078 *reference = NULL;
2080 hr = IDWriteFontFamily1_GetFont(iface, index, &font);
2081 if (FAILED(hr))
2082 return hr;
2084 hr = IDWriteFont3_GetFontFaceReference(font, reference);
2085 IDWriteFont3_Release(font);
2087 return hr;
2090 static const IDWriteFontFamily1Vtbl fontfamilyvtbl = {
2091 dwritefontfamily_QueryInterface,
2092 dwritefontfamily_AddRef,
2093 dwritefontfamily_Release,
2094 dwritefontfamily_GetFontCollection,
2095 dwritefontfamily_GetFontCount,
2096 dwritefontfamily_GetFont,
2097 dwritefontfamily_GetFamilyNames,
2098 dwritefontfamily_GetFirstMatchingFont,
2099 dwritefontfamily_GetMatchingFonts,
2100 dwritefontfamily1_GetFontLocality,
2101 dwritefontfamily1_GetFont,
2102 dwritefontfamily1_GetFontFaceReference
2105 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection1 *collection, IDWriteFontFamily1 **family)
2107 struct dwrite_fontfamily *This;
2109 *family = NULL;
2111 This = heap_alloc(sizeof(struct dwrite_fontfamily));
2112 if (!This) return E_OUTOFMEMORY;
2114 This->IDWriteFontFamily1_iface.lpVtbl = &fontfamilyvtbl;
2115 This->ref = 1;
2116 This->collection = collection;
2117 IDWriteFontCollection1_AddRef(collection);
2118 This->data = data;
2119 InterlockedIncrement(&This->data->ref);
2121 *family = &This->IDWriteFontFamily1_iface;
2123 return S_OK;
2126 BOOL is_system_collection(IDWriteFontCollection *collection)
2128 void *obj;
2129 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
2132 static HRESULT WINAPI dwritesystemfontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2134 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2135 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2137 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2138 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2139 IsEqualIID(riid, &IID_IUnknown))
2141 *obj = iface;
2142 IDWriteFontCollection1_AddRef(iface);
2143 return S_OK;
2146 *obj = NULL;
2148 if (IsEqualIID(riid, &IID_issystemcollection))
2149 return S_OK;
2151 return E_NOINTERFACE;
2154 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection1 *iface, REFIID riid, void **obj)
2156 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2157 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2159 if (IsEqualIID(riid, &IID_IDWriteFontCollection1) ||
2160 IsEqualIID(riid, &IID_IDWriteFontCollection) ||
2161 IsEqualIID(riid, &IID_IUnknown))
2163 *obj = iface;
2164 IDWriteFontCollection1_AddRef(iface);
2165 return S_OK;
2168 *obj = NULL;
2170 return E_NOINTERFACE;
2173 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection1 *iface)
2175 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2176 ULONG ref = InterlockedIncrement(&This->ref);
2177 TRACE("(%p)->(%d)\n", This, ref);
2178 return ref;
2181 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection1 *iface)
2183 unsigned int i;
2184 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2185 ULONG ref = InterlockedDecrement(&This->ref);
2186 TRACE("(%p)->(%d)\n", This, ref);
2188 if (!ref) {
2189 for (i = 0; i < This->family_count; i++)
2190 release_fontfamily_data(This->family_data[i]);
2191 heap_free(This->family_data);
2192 heap_free(This);
2195 return ref;
2198 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection1 *iface)
2200 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2201 TRACE("(%p)\n", This);
2202 return This->family_count;
2205 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily **family)
2207 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2209 TRACE("(%p)->(%u %p)\n", This, index, family);
2211 if (index >= This->family_count) {
2212 *family = NULL;
2213 return E_FAIL;
2216 return create_fontfamily(This->family_data[index], iface, (IDWriteFontFamily1**)family);
2219 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
2221 UINT32 i;
2223 for (i = 0; i < collection->family_count; i++) {
2224 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
2225 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
2226 HRESULT hr;
2228 for (j = 0; j < count; j++) {
2229 WCHAR buffer[255];
2230 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
2231 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
2232 return i;
2236 return ~0u;
2239 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection1 *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
2241 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2242 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
2243 *index = collection_find_family(This, name);
2244 *exists = *index != ~0u;
2245 return S_OK;
2248 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
2250 UINT32 left_key_size, right_key_size;
2251 const void *left_key, *right_key;
2252 HRESULT hr;
2254 if (left == right)
2255 return TRUE;
2257 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
2258 if (FAILED(hr))
2259 return FALSE;
2261 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
2262 if (FAILED(hr))
2263 return FALSE;
2265 if (left_key_size != right_key_size)
2266 return FALSE;
2268 return !memcmp(left_key, right_key, left_key_size);
2271 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection1 *iface, IDWriteFontFace *face, IDWriteFont **font)
2273 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2274 struct dwrite_fontfamily_data *found_family = NULL;
2275 struct dwrite_font_data *found_font = NULL;
2276 IDWriteFontFamily1 *family;
2277 UINT32 i, j, face_index;
2278 IDWriteFontFile *file;
2279 HRESULT hr;
2281 TRACE("(%p)->(%p %p)\n", This, face, font);
2283 *font = NULL;
2285 if (!face)
2286 return E_INVALIDARG;
2288 i = 1;
2289 hr = IDWriteFontFace_GetFiles(face, &i, &file);
2290 if (FAILED(hr))
2291 return hr;
2292 face_index = IDWriteFontFace_GetIndex(face);
2294 for (i = 0; i < This->family_count; i++) {
2295 struct dwrite_fontfamily_data *family_data = This->family_data[i];
2296 for (j = 0; j < family_data->font_count; j++) {
2297 struct dwrite_font_data *font_data = family_data->fonts[j];
2299 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
2300 found_font = font_data;
2301 found_family = family_data;
2302 break;
2307 if (!found_font)
2308 return DWRITE_E_NOFONT;
2310 hr = create_fontfamily(found_family, iface, &family);
2311 if (FAILED(hr))
2312 return hr;
2314 hr = create_font(found_font, family, (IDWriteFont3**)font);
2315 IDWriteFontFamily1_Release(family);
2316 return hr;
2319 static HRESULT WINAPI dwritefontcollection1_GetFontSet(IDWriteFontCollection1 *iface, IDWriteFontSet **fontset)
2321 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2323 FIXME("(%p)->(%p): stub\n", This, fontset);
2325 return E_NOTIMPL;
2328 static HRESULT WINAPI dwritefontcollection1_GetFontFamily(IDWriteFontCollection1 *iface, UINT32 index, IDWriteFontFamily1 **family)
2330 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection1(iface);
2332 TRACE("(%p)->(%u %p)\n", This, index, family);
2334 if (index >= This->family_count) {
2335 *family = NULL;
2336 return E_FAIL;
2339 return create_fontfamily(This->family_data[index], iface, family);
2342 static const IDWriteFontCollection1Vtbl fontcollectionvtbl = {
2343 dwritefontcollection_QueryInterface,
2344 dwritefontcollection_AddRef,
2345 dwritefontcollection_Release,
2346 dwritefontcollection_GetFontFamilyCount,
2347 dwritefontcollection_GetFontFamily,
2348 dwritefontcollection_FindFamilyName,
2349 dwritefontcollection_GetFontFromFontFace,
2350 dwritefontcollection1_GetFontSet,
2351 dwritefontcollection1_GetFontFamily
2354 static const IDWriteFontCollection1Vtbl systemfontcollectionvtbl = {
2355 dwritesystemfontcollection_QueryInterface,
2356 dwritefontcollection_AddRef,
2357 dwritefontcollection_Release,
2358 dwritefontcollection_GetFontFamilyCount,
2359 dwritefontcollection_GetFontFamily,
2360 dwritefontcollection_FindFamilyName,
2361 dwritefontcollection_GetFontFromFontFace,
2362 dwritefontcollection1_GetFontSet,
2363 dwritefontcollection1_GetFontFamily
2366 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2368 if (family_data->font_count + 1 >= family_data->font_alloc) {
2369 struct dwrite_font_data **new_list;
2370 UINT32 new_alloc;
2372 new_alloc = family_data->font_alloc * 2;
2373 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2374 if (!new_list)
2375 return E_OUTOFMEMORY;
2376 family_data->fonts = new_list;
2377 family_data->font_alloc = new_alloc;
2380 family_data->fonts[family_data->font_count] = font_data;
2381 family_data->font_count++;
2382 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2383 family_data->has_normal_face = 1;
2384 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2385 family_data->has_oblique_face = 1;
2386 else
2387 family_data->has_italic_face = 1;
2388 return S_OK;
2391 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2393 if (collection->family_alloc < collection->family_count + 1) {
2394 struct dwrite_fontfamily_data **new_list;
2395 UINT32 new_alloc;
2397 new_alloc = collection->family_alloc * 2;
2398 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2399 if (!new_list)
2400 return E_OUTOFMEMORY;
2402 collection->family_alloc = new_alloc;
2403 collection->family_data = new_list;
2406 collection->family_data[collection->family_count] = family;
2407 collection->family_count++;
2409 return S_OK;
2412 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2414 collection->IDWriteFontCollection1_iface.lpVtbl = is_system ? &systemfontcollectionvtbl : &fontcollectionvtbl;
2415 collection->ref = 1;
2416 collection->family_count = 0;
2417 collection->family_alloc = is_system ? 30 : 5;
2418 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2419 if (!collection->family_data)
2420 return E_OUTOFMEMORY;
2422 return S_OK;
2425 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2427 IDWriteFontFileLoader *loader;
2428 const void *key;
2429 UINT32 key_size;
2430 HRESULT hr;
2432 *stream = NULL;
2434 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2435 if (FAILED(hr))
2436 return hr;
2438 hr = IDWriteFontFile_GetLoader(file, &loader);
2439 if (FAILED(hr))
2440 return hr;
2442 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2443 IDWriteFontFileLoader_Release(loader);
2444 if (FAILED(hr))
2445 return hr;
2447 return hr;
2450 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2452 BOOL exists = FALSE;
2453 UINT32 index;
2454 HRESULT hr;
2456 buffer[0] = 0;
2457 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2458 if (FAILED(hr) || !exists)
2459 return;
2461 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2464 static int trim_spaces(WCHAR *in, WCHAR *ret)
2466 int len;
2468 while (isspaceW(*in))
2469 in++;
2471 ret[0] = 0;
2472 if (!(len = strlenW(in)))
2473 return 0;
2475 while (isspaceW(in[len-1]))
2476 len--;
2478 memcpy(ret, in, len*sizeof(WCHAR));
2479 ret[len] = 0;
2481 return len;
2484 struct name_token {
2485 struct list entry;
2486 const WCHAR *ptr;
2487 INT len; /* token length */
2488 INT fulllen; /* full length including following separators */
2491 static inline BOOL is_name_separator_char(WCHAR ch)
2493 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2496 struct name_pattern {
2497 const WCHAR *part1; /* NULL indicates end of list */
2498 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2501 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2503 const struct name_pattern *pattern;
2504 struct name_token *token;
2505 int i = 0;
2507 while ((pattern = &patterns[i++])->part1) {
2508 int len_part1 = strlenW(pattern->part1);
2509 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2511 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2512 if (len_part2 == 0) {
2513 /* simple case with single part pattern */
2514 if (token->len != len_part1)
2515 continue;
2517 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2518 if (match) *match = *token;
2519 list_remove(&token->entry);
2520 heap_free(token);
2521 return TRUE;
2524 else {
2525 struct name_token *next_token;
2526 struct list *next_entry;
2528 /* pattern parts are stored in reading order, tokens list is reversed */
2529 if (token->len < len_part2)
2530 continue;
2532 /* it's possible to have combined string as a token, like ExtraCondensed */
2533 if (token->len == len_part1 + len_part2) {
2534 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2535 continue;
2537 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2538 continue;
2540 /* combined string match */
2541 if (match) *match = *token;
2542 list_remove(&token->entry);
2543 heap_free(token);
2544 return TRUE;
2547 /* now it's only possible to have two tokens matched to respective pattern parts */
2548 if (token->len != len_part2)
2549 continue;
2551 next_entry = list_next(tokens, &token->entry);
2552 if (next_entry) {
2553 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2554 if (next_token->len != len_part1)
2555 continue;
2557 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2558 continue;
2560 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2561 continue;
2563 /* both parts matched, remove tokens */
2564 if (match) {
2565 match->ptr = next_token->ptr;
2566 match->len = (token->ptr - next_token->ptr) + token->len;
2568 list_remove(&token->entry);
2569 list_remove(&next_token->entry);
2570 heap_free(next_token);
2571 heap_free(token);
2572 return TRUE;
2578 if (match) {
2579 match->ptr = NULL;
2580 match->len = 0;
2582 return FALSE;
2585 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2587 static const WCHAR itaW[] = {'i','t','a',0};
2588 static const WCHAR italW[] = {'i','t','a','l',0};
2589 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2590 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2592 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2593 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2594 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2595 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2597 static const struct name_pattern italic_patterns[] = {
2598 { itaW },
2599 { italW },
2600 { italicW },
2601 { cursiveW },
2602 { kursivW },
2603 { NULL }
2606 static const struct name_pattern oblique_patterns[] = {
2607 { inclinedW },
2608 { obliqueW },
2609 { backslantedW },
2610 { backslantW },
2611 { slantedW },
2612 { NULL }
2615 /* italic patterns first */
2616 if (match_pattern_list(tokens, italic_patterns, match))
2617 return DWRITE_FONT_STYLE_ITALIC;
2619 /* oblique patterns */
2620 if (match_pattern_list(tokens, oblique_patterns, match))
2621 return DWRITE_FONT_STYLE_OBLIQUE;
2623 return style;
2626 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2627 struct name_token *match)
2629 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2630 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2631 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2632 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2633 static const WCHAR wideW[] = {'w','i','d','e',0};
2634 static const WCHAR condW[] = {'c','o','n','d',0};
2636 static const struct name_pattern ultracondensed_patterns[] = {
2637 { extraW, compressedW },
2638 { extW, compressedW },
2639 { ultraW, compressedW },
2640 { ultraW, condensedW },
2641 { ultraW, condW },
2642 { NULL }
2645 static const struct name_pattern extracondensed_patterns[] = {
2646 { compressedW },
2647 { extraW, condensedW },
2648 { extW, condensedW },
2649 { extraW, condW },
2650 { extW, condW },
2651 { NULL }
2654 static const struct name_pattern semicondensed_patterns[] = {
2655 { narrowW },
2656 { compactW },
2657 { semiW, condensedW },
2658 { semiW, condW },
2659 { NULL }
2662 static const struct name_pattern semiexpanded_patterns[] = {
2663 { wideW },
2664 { semiW, expandedW },
2665 { semiW, extendedW },
2666 { NULL }
2669 static const struct name_pattern extraexpanded_patterns[] = {
2670 { extraW, expandedW },
2671 { extW, expandedW },
2672 { extraW, extendedW },
2673 { extW, extendedW },
2674 { NULL }
2677 static const struct name_pattern ultraexpanded_patterns[] = {
2678 { ultraW, expandedW },
2679 { ultraW, extendedW },
2680 { NULL }
2683 static const struct name_pattern condensed_patterns[] = {
2684 { condensedW },
2685 { condW },
2686 { NULL }
2689 static const struct name_pattern expanded_patterns[] = {
2690 { expandedW },
2691 { extendedW },
2692 { NULL }
2695 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2696 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2698 if (match_pattern_list(tokens, extracondensed_patterns, match))
2699 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2701 if (match_pattern_list(tokens, semicondensed_patterns, match))
2702 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2704 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2705 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2707 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2708 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2710 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2711 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2713 if (match_pattern_list(tokens, condensed_patterns, match))
2714 return DWRITE_FONT_STRETCH_CONDENSED;
2716 if (match_pattern_list(tokens, expanded_patterns, match))
2717 return DWRITE_FONT_STRETCH_EXPANDED;
2719 return stretch;
2722 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2723 struct name_token *match)
2725 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2726 static const WCHAR nordW[] = {'n','o','r','d',0};
2728 static const struct name_pattern thin_patterns[] = {
2729 { extraW, thinW },
2730 { extW, thinW },
2731 { ultraW, thinW },
2732 { NULL }
2735 static const struct name_pattern extralight_patterns[] = {
2736 { extraW, lightW },
2737 { extW, lightW },
2738 { ultraW, lightW },
2739 { NULL }
2742 static const struct name_pattern semilight_patterns[] = {
2743 { semiW, lightW },
2744 { NULL }
2747 static const struct name_pattern demibold_patterns[] = {
2748 { semiW, boldW },
2749 { demiW, boldW },
2750 { NULL }
2753 static const struct name_pattern extrabold_patterns[] = {
2754 { extraW, boldW },
2755 { extW, boldW },
2756 { ultraW, boldW },
2757 { NULL }
2760 static const struct name_pattern extrablack_patterns[] = {
2761 { extraW, blackW },
2762 { extW, blackW },
2763 { ultraW, blackW },
2764 { NULL }
2767 static const struct name_pattern bold_patterns[] = {
2768 { boldW },
2769 { NULL }
2772 static const struct name_pattern thin2_patterns[] = {
2773 { thinW },
2774 { NULL }
2777 static const struct name_pattern light_patterns[] = {
2778 { lightW },
2779 { NULL }
2782 static const struct name_pattern medium_patterns[] = {
2783 { mediumW },
2784 { NULL }
2787 static const struct name_pattern black_patterns[] = {
2788 { blackW },
2789 { heavyW },
2790 { nordW },
2791 { NULL }
2794 static const struct name_pattern demibold2_patterns[] = {
2795 { demiW },
2796 { NULL }
2799 static const struct name_pattern extrabold2_patterns[] = {
2800 { ultraW },
2801 { NULL }
2804 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2805 matching pattern. */
2807 if (match_pattern_list(tokens, thin_patterns, match))
2808 return DWRITE_FONT_WEIGHT_THIN;
2810 if (match_pattern_list(tokens, extralight_patterns, match))
2811 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2813 if (match_pattern_list(tokens, semilight_patterns, match))
2814 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2816 if (match_pattern_list(tokens, demibold_patterns, match))
2817 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2819 if (match_pattern_list(tokens, extrabold_patterns, match))
2820 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2822 if (match_pattern_list(tokens, extrablack_patterns, match))
2823 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2825 if (match_pattern_list(tokens, bold_patterns, match))
2826 return DWRITE_FONT_WEIGHT_BOLD;
2828 if (match_pattern_list(tokens, thin2_patterns, match))
2829 return DWRITE_FONT_WEIGHT_THIN;
2831 if (match_pattern_list(tokens, light_patterns, match))
2832 return DWRITE_FONT_WEIGHT_LIGHT;
2834 if (match_pattern_list(tokens, medium_patterns, match))
2835 return DWRITE_FONT_WEIGHT_MEDIUM;
2837 if (match_pattern_list(tokens, black_patterns, match))
2838 return DWRITE_FONT_WEIGHT_BLACK;
2840 if (match_pattern_list(tokens, black_patterns, match))
2841 return DWRITE_FONT_WEIGHT_BLACK;
2843 if (match_pattern_list(tokens, demibold2_patterns, match))
2844 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2846 if (match_pattern_list(tokens, extrabold2_patterns, match))
2847 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2849 /* FIXME: use abbreviated names to extract weight */
2851 return weight;
2854 struct knownweight_entry {
2855 const WCHAR *nameW;
2856 DWRITE_FONT_WEIGHT weight;
2859 static int compare_knownweights(const void *a, const void* b)
2861 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2862 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2863 int ret = 0;
2865 if (target > entry->weight)
2866 ret = 1;
2867 else if (target < entry->weight)
2868 ret = -1;
2870 return ret;
2873 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2875 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2876 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2877 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2878 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2879 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2880 const struct knownweight_entry *ptr;
2882 static const struct knownweight_entry knownweights[] = {
2883 { thinW, DWRITE_FONT_WEIGHT_THIN },
2884 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2885 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2886 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2887 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2888 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2889 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2890 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2891 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2892 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2895 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2896 compare_knownweights);
2897 if (!ptr) {
2898 nameW[0] = 0;
2899 return FALSE;
2902 strcpyW(nameW, ptr->nameW);
2903 return TRUE;
2906 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2908 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2909 strW[name->len] = 0;
2912 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2913 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2915 static const WCHAR bookW[] = {'B','o','o','k',0};
2916 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2917 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2918 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2919 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2921 static const WCHAR *regular_patterns[] = {
2922 bookW,
2923 normalW,
2924 regularW,
2925 romanW,
2926 uprightW,
2927 NULL
2930 const WCHAR *regular_ptr = NULL, *ptr;
2931 int i = 0;
2933 if (len == -1)
2934 len = strlenW(facenameW);
2936 /* remove rightmost regular variant from face name */
2937 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2938 int pattern_len = strlenW(ptr);
2939 WCHAR *src;
2941 if (pattern_len > len)
2942 continue;
2944 src = facenameW + len - pattern_len;
2945 while (src >= facenameW) {
2946 if (!strncmpiW(src, ptr, pattern_len)) {
2947 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2948 len = strlenW(facenameW);
2949 regular_ptr = ptr;
2950 break;
2952 else
2953 src--;
2957 return regular_ptr;
2960 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2962 const WCHAR *ptr;
2964 list_init(tokens);
2965 ptr = nameW;
2967 while (*ptr) {
2968 struct name_token *token = heap_alloc(sizeof(*token));
2969 token->ptr = ptr;
2970 token->len = 0;
2971 token->fulllen = 0;
2973 while (*ptr && !is_name_separator_char(*ptr)) {
2974 token->len++;
2975 token->fulllen++;
2976 ptr++;
2979 /* skip separators */
2980 while (is_name_separator_char(*ptr)) {
2981 token->fulllen++;
2982 ptr++;
2985 list_add_head(tokens, &token->entry);
2989 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2991 struct name_token *token, *token2;
2992 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2993 int len;
2995 list_remove(&token->entry);
2997 /* don't include last separator */
2998 len = list_empty(tokens) ? token->len : token->fulllen;
2999 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
3000 nameW += len;
3002 heap_free(token);
3004 *nameW = 0;
3007 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
3009 struct name_token stretch_name, weight_name, style_name;
3010 WCHAR familynameW[255], facenameW[255], finalW[255];
3011 WCHAR weightW[32], stretchW[32], styleW[32];
3012 const WCHAR *regular_ptr = NULL;
3013 DWRITE_FONT_STRETCH stretch;
3014 DWRITE_FONT_WEIGHT weight;
3015 struct list tokens;
3016 int len;
3018 /* remove leading and trailing spaces from family and face name */
3019 trim_spaces(familyW, familynameW);
3020 len = trim_spaces(faceW, facenameW);
3022 /* remove rightmost regular variant from face name */
3023 regular_ptr = facename_remove_regular_term(facenameW, len);
3025 /* append face name to family name, FIXME check if face name is a substring of family name */
3026 if (*facenameW) {
3027 strcatW(familynameW, spaceW);
3028 strcatW(familynameW, facenameW);
3031 /* tokenize with " .-_" */
3032 fontname_tokenize(&tokens, familynameW);
3034 /* extract and resolve style */
3035 font->style = font_extract_style(&tokens, font->style, &style_name);
3037 /* extract stretch */
3038 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
3040 /* extract weight */
3041 weight = font_extract_weight(&tokens, font->weight, &weight_name);
3043 /* resolve weight */
3044 if (weight != font->weight) {
3045 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
3046 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
3047 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
3048 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
3049 !(abs(weight - font->weight) <= 150 &&
3050 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
3051 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
3052 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
3054 font->weight = weight;
3058 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
3059 it's leaning in opposite direction from normal comparing to specified stretch or if specified
3060 stretch itself is normal (extracted stretch is never normal). */
3061 if (stretch != font->stretch) {
3062 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
3063 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
3064 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
3066 font->stretch = stretch;
3070 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
3072 /* get final combined string from what's left in token list, list is released */
3073 fontname_tokens_to_str(&tokens, finalW);
3075 if (!strcmpW(familyW, finalW))
3076 return FALSE;
3078 /* construct face name */
3079 strcpyW(familyW, finalW);
3081 /* resolved weight name */
3082 if (weight_name.ptr)
3083 font_name_token_to_str(&weight_name, weightW);
3084 /* ignore normal weight */
3085 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
3086 weightW[0] = 0;
3087 /* for known weight values use appropriate names */
3088 else if (is_known_weight_value(font->weight, weightW)) {
3090 /* use Wnnn format as a fallback in case weight is not one of known values */
3091 else {
3092 static const WCHAR fmtW[] = {'W','%','d',0};
3093 sprintfW(weightW, fmtW, font->weight);
3096 /* resolved stretch name */
3097 if (stretch_name.ptr)
3098 font_name_token_to_str(&stretch_name, stretchW);
3099 /* ignore normal stretch */
3100 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
3101 stretchW[0] = 0;
3102 /* use predefined stretch names */
3103 else {
3104 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3105 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
3106 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
3107 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
3108 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3109 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
3111 static const WCHAR *stretchnamesW[] = {
3112 NULL, /* DWRITE_FONT_STRETCH_UNDEFINED */
3113 ultracondensedW,
3114 extracondensedW,
3115 condensedW,
3116 semicondensedW,
3117 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
3118 semiexpandedW,
3119 expandedW,
3120 extraexpandedW,
3121 ultraexpandedW
3123 strcpyW(stretchW, stretchnamesW[font->stretch]);
3126 /* resolved style name */
3127 if (style_name.ptr)
3128 font_name_token_to_str(&style_name, styleW);
3129 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
3130 styleW[0] = 0;
3131 /* use predefined names */
3132 else {
3133 if (font->style == DWRITE_FONT_STYLE_ITALIC)
3134 strcpyW(styleW, italicW);
3135 else
3136 strcpyW(styleW, obliqueW);
3139 /* use Regular match if it was found initially */
3140 if (!*weightW && !*stretchW && !*styleW)
3141 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
3142 else {
3143 faceW[0] = 0;
3144 if (*stretchW)
3145 strcpyW(faceW, stretchW);
3146 if (*weightW) {
3147 if (*faceW)
3148 strcatW(faceW, spaceW);
3149 strcatW(faceW, weightW);
3151 if (*styleW) {
3152 if (*faceW)
3153 strcatW(faceW, spaceW);
3154 strcatW(faceW, styleW);
3158 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
3159 return TRUE;
3162 static HRESULT init_font_data(const struct fontface_desc *desc, IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
3164 struct file_stream_desc stream_desc;
3165 struct dwrite_font_props props;
3166 struct dwrite_font_data *data;
3167 IDWriteFontFileStream *stream;
3168 WCHAR familyW[255], faceW[255];
3169 HRESULT hr;
3171 *ret = NULL;
3172 data = heap_alloc_zero(sizeof(*data));
3173 if (!data)
3174 return E_OUTOFMEMORY;
3176 hr = get_filestream_from_file(desc->files[0], &stream);
3177 if (FAILED(hr)) {
3178 heap_free(data);
3179 return hr;
3182 data->ref = 1;
3183 data->factory = desc->factory;
3184 data->file = desc->files[0];
3185 data->face_index = desc->index;
3186 data->face_type = desc->face_type;
3187 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
3188 data->bold_sim_tested = 0;
3189 data->oblique_sim_tested = 0;
3190 IDWriteFontFile_AddRef(data->file);
3191 IDWriteFactory3_AddRef(data->factory);
3193 stream_desc.stream = stream;
3194 stream_desc.face_type = desc->face_type;
3195 stream_desc.face_index = desc->index;
3196 opentype_get_font_properties(&stream_desc, &props);
3197 opentype_get_font_metrics(&stream_desc, &data->metrics, NULL);
3198 opentype_get_font_facename(&stream_desc, &data->names);
3200 /* get family name from font file */
3201 hr = opentype_get_font_familyname(&stream_desc, family_name);
3202 IDWriteFontFileStream_Release(stream);
3203 if (FAILED(hr)) {
3204 WARN("unable to get family name from font\n");
3205 release_font_data(data);
3206 return hr;
3209 data->style = props.style;
3210 data->stretch = props.stretch;
3211 data->weight = props.weight;
3212 data->panose = props.panose;
3214 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3215 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
3216 if (font_apply_differentiation_rules(data, familyW, faceW)) {
3217 set_en_localizedstring(*family_name, familyW);
3218 set_en_localizedstring(data->names, faceW);
3221 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3223 *ret = data;
3224 return S_OK;
3227 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
3228 struct dwrite_font_data **ret)
3230 struct dwrite_font_data *data;
3232 *ret = NULL;
3233 data = heap_alloc_zero(sizeof(*data));
3234 if (!data)
3235 return E_OUTOFMEMORY;
3237 *data = *src;
3238 data->ref = 1;
3239 data->simulations |= sim;
3240 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
3241 data->weight = DWRITE_FONT_WEIGHT_BOLD;
3242 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
3243 data->style = DWRITE_FONT_STYLE_OBLIQUE;
3244 memset(data->info_strings, 0, sizeof(data->info_strings));
3245 data->names = NULL;
3246 IDWriteFactory3_AddRef(data->factory);
3247 IDWriteFontFile_AddRef(data->file);
3249 create_localizedstrings(&data->names);
3250 add_localizedstring(data->names, enusW, facenameW);
3252 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
3254 *ret = data;
3255 return S_OK;
3258 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
3260 struct dwrite_fontfamily_data *data;
3262 data = heap_alloc(sizeof(*data));
3263 if (!data)
3264 return E_OUTOFMEMORY;
3266 data->ref = 1;
3267 data->font_count = 0;
3268 data->font_alloc = 2;
3269 data->has_normal_face = 0;
3270 data->has_oblique_face = 0;
3271 data->has_italic_face = 0;
3273 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
3274 if (!data->fonts) {
3275 heap_free(data);
3276 return E_OUTOFMEMORY;
3279 data->familyname = familyname;
3280 IDWriteLocalizedStrings_AddRef(familyname);
3282 *ret = data;
3283 return S_OK;
3286 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
3288 UINT32 i, j, heaviest;
3290 for (i = 0; i < family->font_count; i++) {
3291 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
3292 heaviest = i;
3294 if (family->fonts[i]->bold_sim_tested)
3295 continue;
3297 family->fonts[i]->bold_sim_tested = 1;
3298 for (j = i; j < family->font_count; j++) {
3299 if (family->fonts[j]->bold_sim_tested)
3300 continue;
3302 if ((family->fonts[i]->style == family->fonts[j]->style) &&
3303 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3304 if (family->fonts[j]->weight > weight) {
3305 weight = family->fonts[j]->weight;
3306 heaviest = j;
3308 family->fonts[j]->bold_sim_tested = 1;
3312 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
3313 static const struct name_pattern weightsim_patterns[] = {
3314 { extraW, lightW },
3315 { extW, lightW },
3316 { ultraW, lightW },
3317 { semiW, lightW },
3318 { semiW, boldW },
3319 { demiW, boldW },
3320 { boldW },
3321 { thinW },
3322 { lightW },
3323 { mediumW },
3324 { demiW },
3325 { NULL }
3328 WCHAR facenameW[255], initialW[255];
3329 struct dwrite_font_data *boldface;
3330 struct list tokens;
3332 /* add Bold simulation based on heaviest face data */
3334 /* Simulated face name should only contain Bold as weight term,
3335 so remove existing regular and weight terms. */
3336 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
3337 facename_remove_regular_term(initialW, -1);
3339 /* remove current weight pattern */
3340 fontname_tokenize(&tokens, initialW);
3341 match_pattern_list(&tokens, weightsim_patterns, NULL);
3342 fontname_tokens_to_str(&tokens, facenameW);
3344 /* Bold suffix for new name */
3345 if (*facenameW)
3346 strcatW(facenameW, spaceW);
3347 strcatW(facenameW, boldW);
3349 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
3350 boldface->bold_sim_tested = 1;
3351 fontfamily_add_font(family, boldface);
3357 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3359 UINT32 i, j;
3361 for (i = 0; i < family->font_count; i++) {
3362 UINT32 regular = ~0u, oblique = ~0u;
3363 struct dwrite_font_data *obliqueface;
3364 WCHAR facenameW[255];
3366 if (family->fonts[i]->oblique_sim_tested)
3367 continue;
3369 family->fonts[i]->oblique_sim_tested = 1;
3370 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3371 regular = i;
3372 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3373 oblique = i;
3375 /* find regular style with same weight/stretch values */
3376 for (j = i; j < family->font_count; j++) {
3377 if (family->fonts[j]->oblique_sim_tested)
3378 continue;
3380 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3381 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3383 family->fonts[j]->oblique_sim_tested = 1;
3384 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3385 regular = j;
3387 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3388 oblique = j;
3391 if (regular != ~0u && oblique != ~0u)
3392 break;
3395 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3396 if (regular == ~0u)
3397 continue;
3399 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3400 if (oblique != ~0u)
3401 continue;
3403 /* add oblique simulation based on this regular face */
3405 /* remove regular term if any, append 'Oblique' */
3406 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3407 facename_remove_regular_term(facenameW, -1);
3409 if (*facenameW)
3410 strcatW(facenameW, spaceW);
3411 strcatW(facenameW, obliqueW);
3413 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3414 obliqueface->oblique_sim_tested = 1;
3415 fontfamily_add_font(family, obliqueface);
3420 static BOOL fontcollection_add_replacement(struct dwrite_fontcollection *collection, const WCHAR *target_name,
3421 const WCHAR *replacement_name)
3423 UINT32 i = collection_find_family(collection, replacement_name);
3424 struct dwrite_fontfamily_data *target;
3425 IDWriteLocalizedStrings *strings;
3426 HRESULT hr;
3428 /* replacement does not exist */
3429 if (i == ~0u)
3430 return FALSE;
3432 hr = create_localizedstrings(&strings);
3433 if (FAILED(hr))
3434 return FALSE;
3436 /* add a new family with target name, reuse font data from replacement */
3437 add_localizedstring(strings, enusW, target_name);
3438 hr = init_fontfamily_data(strings, &target);
3439 if (hr == S_OK) {
3440 struct dwrite_fontfamily_data *replacement = collection->family_data[i];
3441 WCHAR nameW[255];
3443 for (i = 0; i < replacement->font_count; i++)
3444 fontfamily_add_font(target, replacement->fonts[i]);
3446 fontcollection_add_family(collection, target);
3447 fontstrings_get_en_string(replacement->familyname, nameW, sizeof(nameW)/sizeof(WCHAR));
3448 TRACE("replacement %s -> %s\n", debugstr_w(target_name), debugstr_w(nameW));
3450 IDWriteLocalizedStrings_Release(strings);
3451 return TRUE;
3454 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3455 system font collections. */
3456 static void fontcollection_add_replacements(struct dwrite_fontcollection *collection)
3458 DWORD max_namelen, max_datalen, i = 0, type, datalen, namelen;
3459 WCHAR *name;
3460 void *data;
3461 HKEY hkey;
3463 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Fonts\\Replacements", &hkey))
3464 return;
3466 if (RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_namelen, &max_datalen, NULL, NULL)) {
3467 RegCloseKey(hkey);
3468 return;
3471 max_namelen++; /* returned value doesn't include room for '\0' */
3472 name = heap_alloc(max_namelen * sizeof(WCHAR));
3473 data = heap_alloc(max_datalen);
3475 datalen = max_datalen;
3476 namelen = max_namelen;
3477 while (RegEnumValueW(hkey, i++, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS) {
3478 if (collection_find_family(collection, name) == ~0u) {
3479 if (type == REG_MULTI_SZ) {
3480 WCHAR *replacement = data;
3481 while (*replacement) {
3482 if (fontcollection_add_replacement(collection, name, replacement))
3483 break;
3484 replacement += strlenW(replacement) + 1;
3487 else if (type == REG_SZ)
3488 fontcollection_add_replacement(collection, name, data);
3490 else
3491 TRACE("%s is available, won't be replaced.\n", debugstr_w(name));
3493 datalen = max_datalen;
3494 namelen = max_namelen;
3497 heap_free(data);
3498 heap_free(name);
3499 RegCloseKey(hkey);
3502 HRESULT create_font_collection(IDWriteFactory3 *factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system,
3503 IDWriteFontCollection1 **ret)
3505 struct fontfile_enum {
3506 struct list entry;
3507 IDWriteFontFile *file;
3509 struct fontfile_enum *fileenum, *fileenum2;
3510 struct dwrite_fontcollection *collection;
3511 struct list scannedfiles;
3512 BOOL current = FALSE;
3513 HRESULT hr = S_OK;
3514 UINT32 i;
3516 *ret = NULL;
3518 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3519 if (!collection) return E_OUTOFMEMORY;
3521 hr = init_font_collection(collection, is_system);
3522 if (FAILED(hr)) {
3523 heap_free(collection);
3524 return hr;
3527 *ret = &collection->IDWriteFontCollection1_iface;
3529 TRACE("building font collection:\n");
3531 list_init(&scannedfiles);
3532 while (hr == S_OK) {
3533 DWRITE_FONT_FACE_TYPE face_type;
3534 DWRITE_FONT_FILE_TYPE file_type;
3535 BOOL supported, same = FALSE;
3536 IDWriteFontFile *file;
3537 UINT32 face_count;
3539 current = FALSE;
3540 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3541 if (FAILED(hr) || !current)
3542 break;
3544 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3545 if (FAILED(hr))
3546 break;
3548 /* check if we've scanned this file already */
3549 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3550 if ((same = is_same_fontfile(fileenum->file, file)))
3551 break;
3554 if (same) {
3555 IDWriteFontFile_Release(file);
3556 continue;
3559 /* failed font files are skipped */
3560 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3561 if (FAILED(hr) || !supported || face_count == 0) {
3562 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3563 IDWriteFontFile_Release(file);
3564 hr = S_OK;
3565 continue;
3568 /* add to scanned list */
3569 fileenum = heap_alloc(sizeof(*fileenum));
3570 fileenum->file = file;
3571 list_add_tail(&scannedfiles, &fileenum->entry);
3573 for (i = 0; i < face_count; i++) {
3574 IDWriteLocalizedStrings *family_name = NULL;
3575 struct dwrite_font_data *font_data;
3576 struct fontface_desc desc;
3577 WCHAR familyW[255];
3578 UINT32 index;
3580 desc.factory = factory;
3581 desc.face_type = face_type;
3582 desc.files = &file;
3583 desc.files_number = 1;
3584 desc.index = i;
3585 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3586 desc.font_data = NULL;
3588 /* alloc and init new font data structure */
3589 hr = init_font_data(&desc, &family_name, &font_data);
3590 if (FAILED(hr)) {
3591 /* move to next one */
3592 hr = S_OK;
3593 continue;
3596 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3598 /* ignore dot named faces */
3599 if (familyW[0] == '.') {
3600 WARN("Ignoring face %s\n", debugstr_w(familyW));
3601 IDWriteLocalizedStrings_Release(family_name);
3602 release_font_data(font_data);
3603 continue;
3606 index = collection_find_family(collection, familyW);
3607 if (index != ~0u)
3608 hr = fontfamily_add_font(collection->family_data[index], font_data);
3609 else {
3610 struct dwrite_fontfamily_data *family_data;
3612 /* create and init new family */
3613 hr = init_fontfamily_data(family_name, &family_data);
3614 if (hr == S_OK) {
3615 /* add font to family, family - to collection */
3616 hr = fontfamily_add_font(family_data, font_data);
3617 if (hr == S_OK)
3618 hr = fontcollection_add_family(collection, family_data);
3620 if (FAILED(hr))
3621 release_fontfamily_data(family_data);
3625 IDWriteLocalizedStrings_Release(family_name);
3627 if (FAILED(hr))
3628 break;
3632 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3633 IDWriteFontFile_Release(fileenum->file);
3634 list_remove(&fileenum->entry);
3635 heap_free(fileenum);
3638 for (i = 0; i < collection->family_count; i++) {
3639 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3640 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3643 if (is_system)
3644 fontcollection_add_replacements(collection);
3646 return hr;
3649 struct system_fontfile_enumerator
3651 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3652 LONG ref;
3654 IDWriteFactory3 *factory;
3655 HKEY hkey;
3656 int index;
3659 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3661 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3664 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3666 *obj = NULL;
3668 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3669 IDWriteFontFileEnumerator_AddRef(iface);
3670 *obj = iface;
3671 return S_OK;
3674 return E_NOINTERFACE;
3677 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3679 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3680 return InterlockedIncrement(&enumerator->ref);
3683 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3685 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3686 ULONG ref = InterlockedDecrement(&enumerator->ref);
3688 if (!ref) {
3689 IDWriteFactory3_Release(enumerator->factory);
3690 RegCloseKey(enumerator->hkey);
3691 heap_free(enumerator);
3694 return ref;
3697 static HRESULT create_local_file_reference(IDWriteFactory3 *factory, const WCHAR *filename, IDWriteFontFile **file)
3699 HRESULT hr;
3701 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3702 if (!strchrW(filename, '\\')) {
3703 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3704 WCHAR fullpathW[MAX_PATH];
3706 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3707 strcatW(fullpathW, fontsW);
3708 strcatW(fullpathW, filename);
3710 hr = IDWriteFactory3_CreateFontFileReference(factory, fullpathW, NULL, file);
3712 else
3713 hr = IDWriteFactory3_CreateFontFileReference(factory, filename, NULL, file);
3715 return hr;
3718 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3720 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3721 DWORD ret, type, val_count, count;
3722 WCHAR *value, *filename;
3723 HRESULT hr;
3725 *file = NULL;
3727 if (enumerator->index < 0)
3728 return E_FAIL;
3730 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3731 if (ret != ERROR_SUCCESS)
3732 return E_FAIL;
3734 val_count++;
3735 value = heap_alloc( val_count * sizeof(value[0]) );
3736 filename = heap_alloc(count);
3737 if (!value || !filename) {
3738 heap_free(value);
3739 heap_free(filename);
3740 return E_OUTOFMEMORY;
3743 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3744 if (ret) {
3745 heap_free(value);
3746 heap_free(filename);
3747 return E_FAIL;
3750 hr = create_local_file_reference(enumerator->factory, filename, file);
3752 heap_free(value);
3753 heap_free(filename);
3754 return hr;
3757 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3759 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3760 DWORD ret, max_val_count;
3761 WCHAR *value;
3763 *current = FALSE;
3764 enumerator->index++;
3766 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3767 if (ret != ERROR_SUCCESS)
3768 return E_FAIL;
3770 max_val_count++;
3771 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3772 return E_OUTOFMEMORY;
3774 /* iterate until we find next string value */
3775 while (1) {
3776 DWORD type = 0, count, val_count;
3777 val_count = max_val_count;
3778 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3779 break;
3780 if (type == REG_SZ) {
3781 *current = TRUE;
3782 break;
3784 enumerator->index++;
3787 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3788 heap_free(value);
3789 return S_OK;
3792 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3794 systemfontfileenumerator_QueryInterface,
3795 systemfontfileenumerator_AddRef,
3796 systemfontfileenumerator_Release,
3797 systemfontfileenumerator_MoveNext,
3798 systemfontfileenumerator_GetCurrentFontFile
3801 static HRESULT create_system_fontfile_enumerator(IDWriteFactory3 *factory, IDWriteFontFileEnumerator **ret)
3803 struct system_fontfile_enumerator *enumerator;
3804 static const WCHAR fontslistW[] = {
3805 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3806 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3807 'F','o','n','t','s',0
3810 *ret = NULL;
3812 enumerator = heap_alloc(sizeof(*enumerator));
3813 if (!enumerator)
3814 return E_OUTOFMEMORY;
3816 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3817 enumerator->ref = 1;
3818 enumerator->factory = factory;
3819 enumerator->index = -1;
3820 IDWriteFactory3_AddRef(factory);
3822 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3823 ERR("failed to open fonts list key\n");
3824 IDWriteFactory3_Release(factory);
3825 heap_free(enumerator);
3826 return E_FAIL;
3829 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3831 return S_OK;
3834 HRESULT get_system_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection1 **collection)
3836 IDWriteFontFileEnumerator *enumerator;
3837 HRESULT hr;
3839 *collection = NULL;
3841 hr = create_system_fontfile_enumerator(factory, &enumerator);
3842 if (FAILED(hr))
3843 return hr;
3845 TRACE("building system font collection for factory %p\n", factory);
3846 hr = create_font_collection(factory, enumerator, TRUE, collection);
3847 IDWriteFontFileEnumerator_Release(enumerator);
3848 return hr;
3851 static HRESULT eudc_collection_add_family(IDWriteFactory3 *factory, struct dwrite_fontcollection *collection,
3852 const WCHAR *keynameW, const WCHAR *pathW)
3854 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};
3855 static const WCHAR emptyW[] = {0};
3856 IDWriteLocalizedStrings *names;
3857 DWRITE_FONT_FACE_TYPE face_type;
3858 DWRITE_FONT_FILE_TYPE file_type;
3859 BOOL supported;
3860 UINT32 face_count, i;
3861 IDWriteFontFile *file;
3862 HRESULT hr;
3863 struct dwrite_fontfamily_data *family_data;
3865 /* create font file from this path */
3866 hr = create_local_file_reference(factory, pathW, &file);
3867 if (FAILED(hr))
3868 return S_FALSE;
3870 /* failed font files are skipped */
3871 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3872 if (FAILED(hr) || !supported || face_count == 0) {
3873 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3874 IDWriteFontFile_Release(file);
3875 return S_FALSE;
3878 /* create and init new family */
3880 /* Family names are added for non-specific locale, represented with empty string.
3881 Default family appears with empty family name. */
3882 create_localizedstrings(&names);
3883 if (!strcmpiW(keynameW, defaultfontW))
3884 add_localizedstring(names, emptyW, emptyW);
3885 else
3886 add_localizedstring(names, emptyW, keynameW);
3888 hr = init_fontfamily_data(names, &family_data);
3889 IDWriteLocalizedStrings_Release(names);
3890 if (hr != S_OK) {
3891 IDWriteFontFile_Release(file);
3892 return hr;
3895 /* fill with faces */
3896 for (i = 0; i < face_count; i++) {
3897 struct dwrite_font_data *font_data;
3898 struct fontface_desc desc;
3900 /* alloc and init new font data structure */
3901 desc.factory = factory;
3902 desc.face_type = face_type;
3903 desc.index = i;
3904 desc.files = &file;
3905 desc.files_number = 1;
3906 desc.simulations = DWRITE_FONT_SIMULATIONS_NONE;
3907 desc.font_data = NULL;
3909 hr = init_font_data(&desc, &names, &font_data);
3910 if (FAILED(hr))
3911 continue;
3913 IDWriteLocalizedStrings_Release(names);
3915 /* add font to family */
3916 hr = fontfamily_add_font(family_data, font_data);
3917 if (hr != S_OK)
3918 release_font_data(font_data);
3921 /* add family to collection */
3922 hr = fontcollection_add_family(collection, family_data);
3923 if (FAILED(hr))
3924 release_fontfamily_data(family_data);
3925 IDWriteFontFile_Release(file);
3927 return hr;
3930 HRESULT get_eudc_fontcollection(IDWriteFactory3 *factory, IDWriteFontCollection **ret)
3932 static const WCHAR eudckeyfmtW[] = {'E','U','D','C','\\','%','u',0};
3933 struct dwrite_fontcollection *collection;
3934 static const WCHAR emptyW[] = {0};
3935 WCHAR eudckeypathW[16];
3936 HKEY eudckey;
3937 DWORD index;
3938 BOOL exists;
3939 LONG retval;
3940 HRESULT hr;
3941 UINT32 i;
3943 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory, GetACP());
3945 *ret = NULL;
3947 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3948 if (!collection) return E_OUTOFMEMORY;
3950 hr = init_font_collection(collection, FALSE);
3951 if (FAILED(hr)) {
3952 heap_free(collection);
3953 return hr;
3956 *ret = (IDWriteFontCollection*)&collection->IDWriteFontCollection1_iface;
3958 /* return empty collection if EUDC fonts are not configured */
3959 sprintfW(eudckeypathW, eudckeyfmtW, GetACP());
3960 if (RegOpenKeyExW(HKEY_CURRENT_USER, eudckeypathW, 0, GENERIC_READ, &eudckey))
3961 return S_OK;
3963 retval = ERROR_SUCCESS;
3964 index = 0;
3965 while (retval != ERROR_NO_MORE_ITEMS) {
3966 WCHAR keynameW[64], pathW[MAX_PATH];
3967 DWORD type, path_len, name_len;
3969 path_len = sizeof(pathW)/sizeof(*pathW);
3970 name_len = sizeof(keynameW)/sizeof(*keynameW);
3971 retval = RegEnumValueW(eudckey, index++, keynameW, &name_len, NULL, &type, (BYTE*)pathW, &path_len);
3972 if (retval || type != REG_SZ)
3973 continue;
3975 hr = eudc_collection_add_family(factory, collection, keynameW, pathW);
3976 if (hr != S_OK)
3977 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW), debugstr_w(pathW));
3979 RegCloseKey(eudckey);
3981 /* try to add global default if not defined for specific codepage */
3982 exists = FALSE;
3983 hr = IDWriteFontCollection1_FindFamilyName(&collection->IDWriteFontCollection1_iface, emptyW,
3984 &index, &exists);
3985 if (FAILED(hr) || !exists) {
3986 const WCHAR globaldefaultW[] = {'E','U','D','C','.','T','T','E',0};
3987 hr = eudc_collection_add_family(factory, collection, emptyW, globaldefaultW);
3988 if (hr != S_OK)
3989 WARN("failed to add global default EUDC font, 0x%08x\n", hr);
3992 /* EUDC collection offers simulated faces too */
3993 for (i = 0; i < collection->family_count; i++) {
3994 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3995 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3998 return S_OK;
4001 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
4003 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4005 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4007 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
4009 *obj = iface;
4010 IDWriteFontFile_AddRef(iface);
4011 return S_OK;
4014 *obj = NULL;
4015 return E_NOINTERFACE;
4018 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
4020 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4021 ULONG ref = InterlockedIncrement(&This->ref);
4022 TRACE("(%p)->(%d)\n", This, ref);
4023 return ref;
4026 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
4028 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4029 ULONG ref = InterlockedDecrement(&This->ref);
4031 TRACE("(%p)->(%d)\n", This, ref);
4033 if (!ref)
4035 IDWriteFontFileLoader_Release(This->loader);
4036 if (This->stream) IDWriteFontFileStream_Release(This->stream);
4037 heap_free(This->reference_key);
4038 heap_free(This);
4041 return ref;
4044 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
4046 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4047 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
4048 *fontFileReferenceKey = This->reference_key;
4049 *fontFileReferenceKeySize = This->key_size;
4051 return S_OK;
4054 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
4056 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4057 TRACE("(%p)->(%p)\n", This, fontFileLoader);
4058 *fontFileLoader = This->loader;
4059 IDWriteFontFileLoader_AddRef(This->loader);
4061 return S_OK;
4064 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType,
4065 DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
4067 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
4068 IDWriteFontFileStream *stream;
4069 HRESULT hr;
4071 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
4073 *isSupportedFontType = FALSE;
4074 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
4075 if (fontFaceType)
4076 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
4077 *numberOfFaces = 0;
4079 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
4080 if (FAILED(hr))
4081 return hr;
4083 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
4085 /* TODO: Further Analysis */
4086 IDWriteFontFileStream_Release(stream);
4087 return S_OK;
4090 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
4091 dwritefontfile_QueryInterface,
4092 dwritefontfile_AddRef,
4093 dwritefontfile_Release,
4094 dwritefontfile_GetReferenceKey,
4095 dwritefontfile_GetLoader,
4096 dwritefontfile_Analyze,
4099 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
4101 struct dwrite_fontfile *This;
4103 This = heap_alloc(sizeof(struct dwrite_fontfile));
4104 if (!This) return E_OUTOFMEMORY;
4106 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
4107 This->ref = 1;
4108 IDWriteFontFileLoader_AddRef(loader);
4109 This->loader = loader;
4110 This->stream = NULL;
4111 This->reference_key = heap_alloc(key_size);
4112 memcpy(This->reference_key, reference_key, key_size);
4113 This->key_size = key_size;
4115 *font_file = &This->IDWriteFontFile_iface;
4117 return S_OK;
4120 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
4122 IDWriteFontFileLoader *loader;
4123 UINT32 key_size;
4124 const void *key;
4125 HRESULT hr;
4127 *stream = NULL;
4128 hr = IDWriteFontFile_GetLoader(file, &loader);
4129 if (FAILED(hr))
4130 return hr;
4132 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
4133 if (FAILED(hr)) {
4134 IDWriteFontFileLoader_Release(loader);
4135 return hr;
4138 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
4139 IDWriteFontFileLoader_Release(loader);
4141 return hr;
4144 HRESULT create_fontface(const struct fontface_desc *desc, IDWriteFontFace3 **ret)
4146 struct file_stream_desc stream_desc;
4147 struct dwrite_fontface *fontface;
4148 HRESULT hr = S_OK;
4149 BOOL is_symbol;
4150 int i;
4152 *ret = NULL;
4154 fontface = heap_alloc(sizeof(struct dwrite_fontface));
4155 if (!fontface)
4156 return E_OUTOFMEMORY;
4158 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * desc->files_number);
4159 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * desc->files_number);
4161 if (!fontface->files || !fontface->streams) {
4162 heap_free(fontface->files);
4163 heap_free(fontface->streams);
4164 heap_free(fontface);
4165 return E_OUTOFMEMORY;
4168 fontface->IDWriteFontFace3_iface.lpVtbl = &dwritefontfacevtbl;
4169 fontface->ref = 1;
4170 fontface->type = desc->face_type;
4171 fontface->file_count = desc->files_number;
4172 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
4173 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
4174 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
4175 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
4176 memset(&fontface->colr, 0, sizeof(fontface->colr));
4177 fontface->cmap.exists = TRUE;
4178 fontface->vdmx.exists = TRUE;
4179 fontface->gasp.exists = TRUE;
4180 fontface->cpal.exists = TRUE;
4181 fontface->colr.exists = TRUE;
4182 fontface->index = desc->index;
4183 fontface->simulations = desc->simulations;
4184 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
4186 for (i = 0; i < fontface->file_count; i++) {
4187 hr = get_stream_from_file(desc->files[i], &fontface->streams[i]);
4188 if (FAILED(hr)) {
4189 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
4190 return hr;
4193 fontface->files[i] = desc->files[i];
4194 IDWriteFontFile_AddRef(fontface->files[i]);
4197 stream_desc.stream = fontface->streams[0];
4198 stream_desc.face_type = desc->face_type;
4199 stream_desc.face_index = desc->index;
4200 opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret);
4201 if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
4202 /* TODO: test what happens if caret is already slanted */
4203 if (fontface->caret.slopeRise == 1) {
4204 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
4205 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
4209 fontface->flags = 0;
4210 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace3_iface, &is_symbol);
4211 if (is_symbol)
4212 fontface->flags |= FONTFACE_IS_SYMBOL;
4213 if (freetype_has_kerning_pairs(&fontface->IDWriteFontFace3_iface))
4214 fontface->flags |= FONTFACE_HAS_KERN_PAIRS;
4215 if (freetype_is_monospaced(&fontface->IDWriteFontFace3_iface))
4216 fontface->flags |= FONTFACE_IS_MONOSPACED;
4217 if (opentype_has_vertical_variants(&fontface->IDWriteFontFace3_iface))
4218 fontface->flags |= FONTFACE_HAS_VERTICAL_VARIANTS;
4220 /* Font properties are reused from font object when 'normal' face creation path is used:
4221 collection -> family -> matching font -> fontface.
4223 If face is created directly from factory we have to go through properties resolution.
4225 if (desc->font_data) {
4226 fontface->weight = desc->font_data->weight;
4227 fontface->style = desc->font_data->style;
4228 fontface->stretch = desc->font_data->stretch;
4229 fontface->panose = desc->font_data->panose;
4231 else {
4232 IDWriteLocalizedStrings *names;
4233 struct dwrite_font_data *data;
4235 hr = init_font_data(desc, &names, &data);
4236 if (FAILED(hr)) {
4237 IDWriteFontFace3_Release(&fontface->IDWriteFontFace3_iface);
4238 return hr;
4241 fontface->weight = data->weight;
4242 fontface->style = data->style;
4243 fontface->stretch = data->stretch;
4244 fontface->panose = data->panose;
4246 IDWriteLocalizedStrings_Release(names);
4247 release_font_data(data);
4250 *ret = &fontface->IDWriteFontFace3_iface;
4251 return S_OK;
4254 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
4255 struct local_refkey
4257 FILETIME writetime;
4258 WCHAR name[1];
4261 struct local_cached_stream
4263 struct list entry;
4264 IDWriteFontFileStream *stream;
4265 struct local_refkey *key;
4266 UINT32 key_size;
4269 struct dwrite_localfontfilestream
4271 IDWriteFontFileStream IDWriteFontFileStream_iface;
4272 LONG ref;
4274 struct local_cached_stream *entry;
4275 const void *file_ptr;
4276 UINT64 size;
4279 struct dwrite_localfontfileloader {
4280 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
4281 LONG ref;
4283 struct list streams;
4286 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
4288 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
4291 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
4293 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
4296 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
4298 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4299 TRACE_(dwrite_file)("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4300 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
4302 *obj = iface;
4303 IDWriteFontFileStream_AddRef(iface);
4304 return S_OK;
4307 *obj = NULL;
4308 return E_NOINTERFACE;
4311 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
4313 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4314 ULONG ref = InterlockedIncrement(&This->ref);
4315 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4316 return ref;
4319 static inline void release_cached_stream(struct local_cached_stream *stream)
4321 list_remove(&stream->entry);
4322 heap_free(stream->key);
4323 heap_free(stream);
4326 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
4328 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4329 ULONG ref = InterlockedDecrement(&This->ref);
4331 TRACE_(dwrite_file)("(%p)->(%d)\n", This, ref);
4333 if (!ref) {
4334 UnmapViewOfFile(This->file_ptr);
4335 release_cached_stream(This->entry);
4336 heap_free(This);
4339 return ref;
4342 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
4344 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4346 TRACE_(dwrite_file)("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
4347 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
4349 *fragment_context = NULL;
4351 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
4352 *fragment_start = NULL;
4353 return E_FAIL;
4356 *fragment_start = (char*)This->file_ptr + offset;
4357 return S_OK;
4360 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
4362 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4363 TRACE_(dwrite_file)("(%p)->(%p)\n", This, fragment_context);
4366 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
4368 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4369 TRACE_(dwrite_file)("(%p)->(%p)\n", This, size);
4370 *size = This->size;
4371 return S_OK;
4374 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
4376 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
4377 ULARGE_INTEGER li;
4379 TRACE_(dwrite_file)("(%p)->(%p)\n", This, last_writetime);
4381 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
4382 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
4383 *last_writetime = li.QuadPart;
4385 return S_OK;
4388 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
4390 localfontfilestream_QueryInterface,
4391 localfontfilestream_AddRef,
4392 localfontfilestream_Release,
4393 localfontfilestream_ReadFileFragment,
4394 localfontfilestream_ReleaseFileFragment,
4395 localfontfilestream_GetFileSize,
4396 localfontfilestream_GetLastWriteTime
4399 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream **ret)
4401 struct dwrite_localfontfilestream *This;
4403 *ret = NULL;
4405 This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
4406 if (!This)
4407 return E_OUTOFMEMORY;
4409 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
4410 This->ref = 1;
4412 This->file_ptr = file_ptr;
4413 This->size = size;
4414 This->entry = entry;
4416 *ret = &This->IDWriteFontFileStream_iface;
4417 return S_OK;
4420 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
4422 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4424 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
4426 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
4428 *obj = iface;
4429 IDWriteLocalFontFileLoader_AddRef(iface);
4430 return S_OK;
4433 *obj = NULL;
4434 return E_NOINTERFACE;
4437 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
4439 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4440 ULONG ref = InterlockedIncrement(&This->ref);
4441 TRACE("(%p)->(%d)\n", This, ref);
4442 return ref;
4445 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
4447 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4448 ULONG ref = InterlockedDecrement(&This->ref);
4450 TRACE("(%p)->(%d)\n", This, ref);
4452 if (!ref) {
4453 struct local_cached_stream *stream, *stream2;
4455 /* This will detach all entries from cache. Entries are released together with streams,
4456 so stream controls cache entry lifetime. */
4457 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
4458 list_init(&stream->entry);
4460 heap_free(This);
4463 return ref;
4466 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
4468 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4469 const struct local_refkey *refkey = key;
4470 struct local_cached_stream *stream;
4471 IDWriteFontFileStream *filestream;
4472 HANDLE file, mapping;
4473 LARGE_INTEGER size;
4474 void *file_ptr;
4475 HRESULT hr;
4477 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
4478 TRACE("name: %s\n", debugstr_w(refkey->name));
4480 /* search cache first */
4481 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
4482 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
4483 *ret = stream->stream;
4484 IDWriteFontFileStream_AddRef(*ret);
4485 return S_OK;
4489 *ret = NULL;
4491 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
4492 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
4493 if (file == INVALID_HANDLE_VALUE)
4494 return E_FAIL;
4496 GetFileSizeEx(file, &size);
4497 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
4498 CloseHandle(file);
4499 if (!mapping)
4500 return E_FAIL;
4502 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4503 CloseHandle(mapping);
4504 if (!file_ptr) {
4505 ERR("mapping failed, file size %s, error %d\n", wine_dbgstr_longlong(size.QuadPart), GetLastError());
4506 return E_FAIL;
4509 stream = heap_alloc(sizeof(*stream));
4510 if (!stream) {
4511 UnmapViewOfFile(file_ptr);
4512 return E_OUTOFMEMORY;
4515 stream->key = heap_alloc(key_size);
4516 if (!stream->key) {
4517 UnmapViewOfFile(file_ptr);
4518 heap_free(stream);
4519 return E_OUTOFMEMORY;
4522 stream->key_size = key_size;
4523 memcpy(stream->key, key, key_size);
4525 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
4526 if (FAILED(hr)) {
4527 UnmapViewOfFile(file_ptr);
4528 heap_free(stream->key);
4529 heap_free(stream);
4530 return hr;
4533 stream->stream = filestream;
4534 list_add_head(&This->streams, &stream->entry);
4536 *ret = stream->stream;
4538 return S_OK;
4541 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
4543 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4544 const struct local_refkey *refkey = key;
4546 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
4548 *length = strlenW(refkey->name);
4549 return S_OK;
4552 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
4554 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4555 const struct local_refkey *refkey = key;
4557 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
4559 if (length < strlenW(refkey->name))
4560 return E_INVALIDARG;
4562 strcpyW(path, refkey->name);
4563 return S_OK;
4566 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
4568 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
4569 const struct local_refkey *refkey = key;
4571 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
4573 *writetime = refkey->writetime;
4574 return S_OK;
4577 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
4578 localfontfileloader_QueryInterface,
4579 localfontfileloader_AddRef,
4580 localfontfileloader_Release,
4581 localfontfileloader_CreateStreamFromKey,
4582 localfontfileloader_GetFilePathLengthFromKey,
4583 localfontfileloader_GetFilePathFromKey,
4584 localfontfileloader_GetLastWriteTimeFromKey
4587 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader **ret)
4589 struct dwrite_localfontfileloader *This;
4591 *ret = NULL;
4593 This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
4594 if (!This)
4595 return E_OUTOFMEMORY;
4597 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
4598 This->ref = 1;
4599 list_init(&This->streams);
4601 *ret = &This->IDWriteLocalFontFileLoader_iface;
4602 return S_OK;
4605 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
4607 struct local_refkey *refkey;
4609 if (!path)
4610 return E_INVALIDARG;
4612 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
4613 *key = NULL;
4615 refkey = heap_alloc(*size);
4616 if (!refkey)
4617 return E_OUTOFMEMORY;
4619 if (writetime)
4620 refkey->writetime = *writetime;
4621 else {
4622 WIN32_FILE_ATTRIBUTE_DATA info;
4624 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
4625 refkey->writetime = info.ftLastWriteTime;
4626 else
4627 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4629 strcpyW(refkey->name, path);
4631 *key = refkey;
4633 return S_OK;
4636 /* IDWriteGlyphRunAnalysis */
4637 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4639 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4641 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4643 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4644 IsEqualIID(riid, &IID_IUnknown))
4646 *ppv = iface;
4647 IDWriteGlyphRunAnalysis_AddRef(iface);
4648 return S_OK;
4651 *ppv = NULL;
4652 return E_NOINTERFACE;
4655 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4657 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4658 ULONG ref = InterlockedIncrement(&This->ref);
4659 TRACE("(%p)->(%u)\n", This, ref);
4660 return ref;
4663 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4665 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4666 ULONG ref = InterlockedDecrement(&This->ref);
4668 TRACE("(%p)->(%u)\n", This, ref);
4670 if (!ref) {
4671 if (This->run.fontFace)
4672 IDWriteFontFace_Release(This->run.fontFace);
4673 heap_free(This->glyphs);
4674 heap_free(This->advances);
4675 heap_free(This->advanceoffsets);
4676 heap_free(This->ascenderoffsets);
4677 heap_free(This->bitmap);
4678 heap_free(This);
4681 return ref;
4684 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4686 struct dwrite_glyphbitmap glyph_bitmap;
4687 IDWriteFontFace3 *fontface3;
4688 D2D_POINT_2F origin;
4689 BOOL is_rtl;
4690 HRESULT hr;
4691 UINT32 i;
4693 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4694 *bounds = analysis->bounds;
4695 return;
4698 if (analysis->run.isSideways)
4699 FIXME("sideways runs are not supported.\n");
4701 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
4702 if (FAILED(hr))
4703 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4705 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4706 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4707 for any non-zero glyph ascender */
4708 origin.x = origin.y = 0.0f;
4709 is_rtl = analysis->run.bidiLevel & 1;
4711 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4712 glyph_bitmap.fontface = fontface3;
4713 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4714 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4715 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4716 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4717 glyph_bitmap.m = &analysis->m;
4719 for (i = 0; i < analysis->run.glyphCount; i++) {
4720 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4721 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4722 const D2D_POINT_2F *advance = analysis->advances + i;
4723 RECT *bbox = &glyph_bitmap.bbox;
4725 glyph_bitmap.index = analysis->run.glyphIndices[i];
4726 freetype_get_glyph_bbox(&glyph_bitmap);
4728 if (is_rtl)
4729 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4730 else
4731 OffsetRect(bbox, origin.x, origin.y);
4733 if (advanceoffset)
4734 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4736 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4737 origin.x += advance->x;
4738 origin.y += advance->y;
4741 IDWriteFontFace3_Release(fontface3);
4743 /* translate to given run origin */
4744 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4745 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4746 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4748 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4749 *bounds = analysis->bounds;
4752 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4754 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4756 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4758 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4759 memset(bounds, 0, sizeof(*bounds));
4760 return E_INVALIDARG;
4763 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4764 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4765 memset(bounds, 0, sizeof(*bounds));
4766 return S_OK;
4769 glyphrunanalysis_get_texturebounds(This, bounds);
4770 return S_OK;
4773 static inline int get_dib_stride( int width, int bpp )
4775 return ((width * bpp + 31) >> 3) & ~3;
4778 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4780 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4781 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4782 (runbounds->left - bounds->left) * 3;
4783 else
4784 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4785 runbounds->left - bounds->left;
4788 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4790 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4791 struct dwrite_glyphbitmap glyph_bitmap;
4792 IDWriteFontFace3 *fontface2;
4793 D2D_POINT_2F origin;
4794 UINT32 i, size;
4795 BOOL is_rtl;
4796 HRESULT hr;
4797 RECT *bbox;
4799 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace3, (void**)&fontface2);
4800 if (FAILED(hr)) {
4801 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
4802 return;
4805 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4806 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4807 size *= 3;
4808 analysis->bitmap = heap_alloc_zero(size);
4810 origin.x = origin.y = 0.0f;
4811 is_rtl = analysis->run.bidiLevel & 1;
4813 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4814 glyph_bitmap.fontface = fontface2;
4815 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4816 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4817 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4818 glyph_bitmap.type = type;
4819 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4820 glyph_bitmap.m = &analysis->m;
4821 bbox = &glyph_bitmap.bbox;
4823 for (i = 0; i < analysis->run.glyphCount; i++) {
4824 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4825 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4826 const D2D_POINT_2F *advance = analysis->advances + i;
4827 int x, y, width, height;
4828 BYTE *src, *dst;
4829 BOOL is_1bpp;
4831 glyph_bitmap.index = analysis->run.glyphIndices[i];
4832 freetype_get_glyph_bbox(&glyph_bitmap);
4834 if (IsRectEmpty(bbox)) {
4835 origin.x += advance->x;
4836 origin.y += advance->y;
4837 continue;
4840 width = bbox->right - bbox->left;
4841 height = bbox->bottom - bbox->top;
4843 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4844 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4845 else
4846 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4848 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4849 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4851 if (is_rtl)
4852 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4853 else
4854 OffsetRect(bbox, origin.x, origin.y);
4856 if (advanceoffset)
4857 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4859 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4860 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4861 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4863 /* blit to analysis bitmap */
4864 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4866 if (is_1bpp) {
4867 /* convert 1bpp to 8bpp/24bpp */
4868 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4869 for (y = 0; y < height; y++) {
4870 for (x = 0; x < width; x++)
4871 if (src[x / 8] & masks[x % 8])
4872 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4873 src += glyph_bitmap.pitch;
4874 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4877 else {
4878 for (y = 0; y < height; y++) {
4879 for (x = 0; x < width; x++)
4880 if (src[x / 8] & masks[x % 8])
4881 dst[x] = DWRITE_ALPHA_MAX;
4882 src += get_dib_stride(width, 1);
4883 dst += analysis->bounds.right - analysis->bounds.left;
4887 else {
4888 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4889 for (y = 0; y < height; y++) {
4890 for (x = 0; x < width; x++)
4891 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4892 src += glyph_bitmap.pitch;
4893 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4897 heap_free(glyph_bitmap.buf);
4899 origin.x += advance->x;
4900 origin.y += advance->y;
4903 IDWriteFontFace3_Release(fontface2);
4905 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4907 /* we don't need this anymore */
4908 heap_free(analysis->glyphs);
4909 heap_free(analysis->advances);
4910 heap_free(analysis->advanceoffsets);
4911 heap_free(analysis->ascenderoffsets);
4912 IDWriteFontFace_Release(analysis->run.fontFace);
4914 analysis->glyphs = NULL;
4915 analysis->advances = NULL;
4916 analysis->advanceoffsets = NULL;
4917 analysis->ascenderoffsets = NULL;
4918 analysis->run.glyphIndices = NULL;
4919 analysis->run.fontFace = NULL;
4922 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4923 RECT const *bounds, BYTE *bitmap, UINT32 size)
4925 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4926 UINT32 required;
4927 RECT runbounds;
4929 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4931 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4932 return E_INVALIDARG;
4934 /* make sure buffer is large enough for requested texture type */
4935 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4936 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4937 required *= 3;
4939 if (size < required)
4940 return E_NOT_SUFFICIENT_BUFFER;
4942 /* validate requested texture type with rendering mode */
4943 switch (This->rendering_mode)
4945 case DWRITE_RENDERING_MODE_ALIASED:
4946 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4947 return DWRITE_E_UNSUPPORTEDOPERATION;
4948 break;
4949 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4950 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4951 case DWRITE_RENDERING_MODE_NATURAL:
4952 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4953 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4954 return DWRITE_E_UNSUPPORTEDOPERATION;
4955 break;
4956 default:
4960 memset(bitmap, 0, size);
4961 glyphrunanalysis_get_texturebounds(This, &runbounds);
4962 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4963 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4964 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4965 int dst_width = (bounds->right - bounds->left) * pixel_size;
4966 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4967 BYTE *src, *dst;
4968 int y;
4970 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4971 glyphrunanalysis_render(This, type);
4973 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4974 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4976 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4977 memcpy(dst, src, draw_width);
4978 src += src_width;
4979 dst += dst_width;
4983 return S_OK;
4986 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4987 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4989 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4991 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4993 if (!params)
4994 return E_INVALIDARG;
4996 switch (This->rendering_mode)
4998 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4999 case DWRITE_RENDERING_MODE_GDI_NATURAL:
5001 UINT value = 0;
5002 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5003 *gamma = (FLOAT)value / 1000.0f;
5004 *contrast = 0.0f;
5005 *cleartypelevel = 1.0f;
5006 break;
5008 case DWRITE_RENDERING_MODE_ALIASED:
5009 case DWRITE_RENDERING_MODE_NATURAL:
5010 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
5011 *gamma = IDWriteRenderingParams_GetGamma(params);
5012 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
5013 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
5014 break;
5015 default:
5019 return S_OK;
5022 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
5023 glyphrunanalysis_QueryInterface,
5024 glyphrunanalysis_AddRef,
5025 glyphrunanalysis_Release,
5026 glyphrunanalysis_GetAlphaTextureBounds,
5027 glyphrunanalysis_CreateAlphaTexture,
5028 glyphrunanalysis_GetAlphaBlendParams
5031 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
5033 if (is_vertical) {
5034 vec->x = 0.0f;
5035 vec->y = length;
5037 else {
5038 vec->x = length;
5039 vec->y = 0.0f;
5043 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
5045 D2D_POINT_2F ret;
5046 ret.x = vec->x * m->m11 + vec->y * m->m21;
5047 ret.y = vec->x * m->m12 + vec->y * m->m22;
5048 *vec = ret;
5051 HRESULT create_glyphrunanalysis(const struct glyphrunanalysis_desc *desc, IDWriteGlyphRunAnalysis **ret)
5053 struct dwrite_glyphrunanalysis *analysis;
5054 FLOAT rtl_factor;
5055 UINT32 i;
5057 *ret = NULL;
5059 /* check for valid rendering mode */
5060 if ((UINT32)desc->rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || desc->rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
5061 return E_INVALIDARG;
5063 analysis = heap_alloc(sizeof(*analysis));
5064 if (!analysis)
5065 return E_OUTOFMEMORY;
5067 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
5068 analysis->ref = 1;
5069 analysis->rendering_mode = desc->rendering_mode;
5070 analysis->flags = 0;
5071 analysis->bitmap = NULL;
5072 analysis->ppdip = desc->ppdip;
5073 analysis->origin.x = desc->origin_x * desc->ppdip;
5074 analysis->origin.y = desc->origin_y * desc->ppdip;
5075 SetRectEmpty(&analysis->bounds);
5076 analysis->run = *desc->run;
5077 IDWriteFontFace_AddRef(analysis->run.fontFace);
5078 analysis->glyphs = heap_alloc(desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5079 analysis->advances = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advances));
5080 if (desc->run->glyphOffsets) {
5081 analysis->advanceoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->advanceoffsets));
5082 analysis->ascenderoffsets = heap_alloc(desc->run->glyphCount*sizeof(*analysis->ascenderoffsets));
5084 else {
5085 analysis->advanceoffsets = NULL;
5086 analysis->ascenderoffsets = NULL;
5089 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && desc->run->glyphOffsets)) {
5090 heap_free(analysis->glyphs);
5091 heap_free(analysis->advances);
5092 heap_free(analysis->advanceoffsets);
5093 heap_free(analysis->ascenderoffsets);
5095 analysis->glyphs = NULL;
5096 analysis->advances = NULL;
5097 analysis->advanceoffsets = NULL;
5098 analysis->ascenderoffsets = NULL;
5100 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
5101 return E_OUTOFMEMORY;
5104 /* check if transform is usable */
5105 if (desc->transform && memcmp(desc->transform, &identity, sizeof(*desc->transform))) {
5106 analysis->m = *desc->transform;
5107 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
5109 else
5110 memset(&analysis->m, 0, sizeof(analysis->m));
5112 analysis->run.glyphIndices = analysis->glyphs;
5113 analysis->run.glyphAdvances = NULL;
5114 analysis->run.glyphOffsets = NULL;
5116 rtl_factor = desc->run->bidiLevel & 1 ? -1.0f : 1.0f;
5118 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5119 transform_2d_vec(&analysis->origin, &analysis->m);
5121 memcpy(analysis->glyphs, desc->run->glyphIndices, desc->run->glyphCount*sizeof(*desc->run->glyphIndices));
5123 if (desc->run->glyphAdvances) {
5124 for (i = 0; i < desc->run->glyphCount; i++) {
5125 init_2d_vec(analysis->advances + i, rtl_factor * desc->run->glyphAdvances[i] * desc->ppdip, desc->run->isSideways);
5126 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5127 transform_2d_vec(analysis->advances + i, &analysis->m);
5130 else {
5131 DWRITE_FONT_METRICS metrics;
5132 IDWriteFontFace1 *fontface1;
5134 IDWriteFontFace_GetMetrics(desc->run->fontFace, &metrics);
5135 IDWriteFontFace_QueryInterface(desc->run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
5137 for (i = 0; i < desc->run->glyphCount; i++) {
5138 HRESULT hr;
5139 INT32 a;
5141 switch (desc->measuring_mode)
5143 case DWRITE_MEASURING_MODE_NATURAL:
5144 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, desc->run->glyphIndices + i, &a, desc->run->isSideways);
5145 if (FAILED(hr))
5146 a = 0;
5147 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, desc->run->fontEmSize, &metrics) * desc->ppdip,
5148 desc->run->isSideways);
5149 break;
5150 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5151 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5152 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, desc->run->fontEmSize, desc->ppdip, desc->transform,
5153 desc->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, desc->run->isSideways, 1, desc->run->glyphIndices + i, &a);
5154 if (FAILED(hr))
5155 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
5156 else
5157 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * desc->run->fontEmSize * desc->ppdip / metrics.designUnitsPerEm + 0.5f),
5158 desc->run->isSideways);
5159 break;
5160 default:
5164 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
5165 transform_2d_vec(analysis->advances + i, &analysis->m);
5168 IDWriteFontFace1_Release(fontface1);
5171 if (desc->run->glyphOffsets) {
5172 for (i = 0; i < desc->run->glyphCount; i++) {
5173 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * desc->run->glyphOffsets[i].advanceOffset * desc->ppdip, desc->run->isSideways);
5174 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
5175 init_2d_vec(analysis->ascenderoffsets + i, -desc->run->glyphOffsets[i].ascenderOffset * desc->ppdip, !desc->run->isSideways);
5176 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
5177 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
5178 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
5183 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
5184 return S_OK;
5187 /* IDWriteColorGlyphRunEnumerator */
5188 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
5190 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5192 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
5194 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
5195 IsEqualIID(riid, &IID_IUnknown))
5197 *ppv = iface;
5198 IDWriteColorGlyphRunEnumerator_AddRef(iface);
5199 return S_OK;
5202 *ppv = NULL;
5203 return E_NOINTERFACE;
5206 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
5208 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5209 ULONG ref = InterlockedIncrement(&This->ref);
5210 TRACE("(%p)->(%u)\n", This, ref);
5211 return ref;
5214 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
5216 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5217 ULONG ref = InterlockedDecrement(&This->ref);
5219 TRACE("(%p)->(%u)\n", This, ref);
5221 if (!ref) {
5222 heap_free(This->advances);
5223 heap_free(This->color_advances);
5224 heap_free(This->offsets);
5225 heap_free(This->color_offsets);
5226 heap_free(This->glyphindices);
5227 heap_free(This->glyphs);
5228 if (This->colr.context)
5229 IDWriteFontFace3_ReleaseFontTable(This->fontface, This->colr.context);
5230 IDWriteFontFace3_Release(This->fontface);
5231 heap_free(This);
5234 return ref;
5237 static FLOAT get_glyph_origin(const struct dwrite_colorglyphenum *glyphenum, UINT32 g)
5239 BOOL is_rtl = glyphenum->run.bidiLevel & 1;
5240 FLOAT origin = 0.0f;
5242 if (g == 0)
5243 return 0.0f;
5245 while (g--)
5246 origin += is_rtl ? -glyphenum->advances[g] : glyphenum->advances[g];
5247 return origin;
5250 static BOOL colorglyphenum_build_color_run(struct dwrite_colorglyphenum *glyphenum)
5252 DWRITE_COLOR_GLYPH_RUN *colorrun = &glyphenum->colorrun;
5253 FLOAT advance_adj = 0.0f;
5254 BOOL got_palette_index;
5255 UINT32 g;
5257 /* start with regular glyphs */
5258 if (glyphenum->current_layer == 0 && glyphenum->has_regular_glyphs) {
5259 UINT32 first_glyph = 0;
5261 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5262 if (glyphenum->glyphs[g].num_layers == 0) {
5263 glyphenum->glyphindices[g] = glyphenum->glyphs[g].glyph;
5264 first_glyph = min(first_glyph, g);
5266 else
5267 glyphenum->glyphindices[g] = 1;
5268 glyphenum->color_advances[g] = glyphenum->advances[g];
5269 if (glyphenum->color_offsets)
5270 glyphenum->color_offsets[g] = glyphenum->offsets[g];
5273 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, first_glyph);
5274 colorrun->baselineOriginY = glyphenum->origin_y;
5275 colorrun->glyphRun.glyphCount = glyphenum->run.glyphCount;
5276 colorrun->paletteIndex = 0xffff;
5277 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5278 glyphenum->has_regular_glyphs = FALSE;
5279 return TRUE;
5281 else {
5282 colorrun->glyphRun.glyphCount = 0;
5283 got_palette_index = FALSE;
5286 advance_adj = 0.0f;
5287 for (g = 0; g < glyphenum->run.glyphCount; g++) {
5289 glyphenum->glyphindices[g] = 1;
5291 /* all glyph layers were returned */
5292 if (glyphenum->glyphs[g].layer == glyphenum->glyphs[g].num_layers) {
5293 advance_adj += glyphenum->advances[g];
5294 continue;
5297 if (glyphenum->current_layer == glyphenum->glyphs[g].layer && (!got_palette_index || colorrun->paletteIndex == glyphenum->glyphs[g].palette_index)) {
5298 UINT32 index = colorrun->glyphRun.glyphCount;
5299 if (!got_palette_index) {
5300 colorrun->paletteIndex = glyphenum->glyphs[g].palette_index;
5301 /* use foreground color or request one from the font */
5302 memset(&colorrun->runColor, 0, sizeof(colorrun->runColor));
5303 if (colorrun->paletteIndex != 0xffff) {
5304 HRESULT hr = IDWriteFontFace3_GetPaletteEntries(glyphenum->fontface, glyphenum->palette, colorrun->paletteIndex,
5305 1, &colorrun->runColor);
5306 if (FAILED(hr))
5307 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum->fontface,
5308 glyphenum->palette, colorrun->paletteIndex, hr);
5310 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
5311 colorrun->baselineOriginX = glyphenum->origin_x + get_glyph_origin(glyphenum, g);
5312 colorrun->baselineOriginY = glyphenum->origin_y;
5313 glyphenum->color_advances[index] = glyphenum->advances[g];
5314 got_palette_index = TRUE;
5317 glyphenum->glyphindices[index] = glyphenum->glyphs[g].glyph;
5318 /* offsets are relative to glyph origin, nothing to fix up */
5319 if (glyphenum->color_offsets)
5320 glyphenum->color_offsets[index] = glyphenum->offsets[g];
5321 opentype_colr_next_glyph(glyphenum->colr.data, glyphenum->glyphs + g);
5322 if (index)
5323 glyphenum->color_advances[index-1] += advance_adj;
5324 colorrun->glyphRun.glyphCount++;
5325 advance_adj = 0.0f;
5327 else
5328 advance_adj += glyphenum->advances[g];
5331 /* reset last advance */
5332 if (colorrun->glyphRun.glyphCount)
5333 glyphenum->color_advances[colorrun->glyphRun.glyphCount-1] = 0.0f;
5335 return colorrun->glyphRun.glyphCount > 0;
5338 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
5340 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5342 TRACE("(%p)->(%p)\n", This, has_run);
5344 *has_run = FALSE;
5346 This->colorrun.glyphRun.glyphCount = 0;
5347 while (This->current_layer < This->max_layer_num) {
5348 if (colorglyphenum_build_color_run(This))
5349 break;
5350 else
5351 This->current_layer++;
5354 *has_run = This->colorrun.glyphRun.glyphCount > 0;
5356 return S_OK;
5359 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
5361 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
5363 TRACE("(%p)->(%p)\n", This, run);
5365 if (This->colorrun.glyphRun.glyphCount == 0) {
5366 *run = NULL;
5367 return E_NOT_VALID_STATE;
5370 *run = &This->colorrun;
5371 return S_OK;
5374 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
5375 colorglyphenum_QueryInterface,
5376 colorglyphenum_AddRef,
5377 colorglyphenum_Release,
5378 colorglyphenum_MoveNext,
5379 colorglyphenum_GetCurrentRun
5382 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
5383 DWRITE_MEASURING_MODE measuring_mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
5385 struct dwrite_colorglyphenum *colorglyphenum;
5386 BOOL colorfont, has_colored_glyph;
5387 IDWriteFontFace3 *fontface3;
5388 HRESULT hr;
5389 UINT32 i;
5391 *ret = NULL;
5393 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace3, (void**)&fontface3);
5394 if (FAILED(hr)) {
5395 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr);
5396 return hr;
5399 colorfont = IDWriteFontFace3_IsColorFont(fontface3) && IDWriteFontFace3_GetColorPaletteCount(fontface3) > palette;
5400 if (!colorfont) {
5401 hr = DWRITE_E_NOCOLOR;
5402 goto failed;
5405 colorglyphenum = heap_alloc_zero(sizeof(*colorglyphenum));
5406 if (!colorglyphenum) {
5407 hr = E_OUTOFMEMORY;
5408 goto failed;
5411 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
5412 colorglyphenum->ref = 1;
5413 colorglyphenum->origin_x = originX;
5414 colorglyphenum->origin_y = originY;
5415 colorglyphenum->fontface = fontface3;
5416 colorglyphenum->glyphs = NULL;
5417 colorglyphenum->run = *run;
5418 colorglyphenum->run.glyphIndices = NULL;
5419 colorglyphenum->run.glyphAdvances = NULL;
5420 colorglyphenum->run.glyphOffsets = NULL;
5421 colorglyphenum->palette = palette;
5422 memset(&colorglyphenum->colr, 0, sizeof(colorglyphenum->colr));
5423 colorglyphenum->colr.exists = TRUE;
5424 get_fontface_table(fontface3, MS_COLR_TAG, &colorglyphenum->colr);
5425 colorglyphenum->current_layer = 0;
5426 colorglyphenum->max_layer_num = 0;
5428 colorglyphenum->glyphs = heap_alloc_zero(run->glyphCount * sizeof(*colorglyphenum->glyphs));
5430 has_colored_glyph = FALSE;
5431 colorglyphenum->has_regular_glyphs = FALSE;
5432 for (i = 0; i < run->glyphCount; i++) {
5433 if (opentype_get_colr_glyph(colorglyphenum->colr.data, run->glyphIndices[i], colorglyphenum->glyphs + i) == S_OK) {
5434 colorglyphenum->max_layer_num = max(colorglyphenum->max_layer_num, colorglyphenum->glyphs[i].num_layers);
5435 has_colored_glyph = TRUE;
5437 if (colorglyphenum->glyphs[i].num_layers == 0)
5438 colorglyphenum->has_regular_glyphs = TRUE;
5441 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5442 is supposed to proceed normally, like if font had no color info at all. */
5443 if (!has_colored_glyph) {
5444 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum->IDWriteColorGlyphRunEnumerator_iface);
5445 return DWRITE_E_NOCOLOR;
5448 colorglyphenum->advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5449 colorglyphenum->color_advances = heap_alloc(run->glyphCount * sizeof(FLOAT));
5450 colorglyphenum->glyphindices = heap_alloc(run->glyphCount * sizeof(UINT16));
5451 if (run->glyphOffsets) {
5452 colorglyphenum->offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->offsets));
5453 colorglyphenum->color_offsets = heap_alloc(run->glyphCount * sizeof(*colorglyphenum->color_offsets));
5454 memcpy(colorglyphenum->offsets, run->glyphOffsets, run->glyphCount * sizeof(*run->glyphOffsets));
5457 colorglyphenum->colorrun.glyphRun.glyphIndices = colorglyphenum->glyphindices;
5458 colorglyphenum->colorrun.glyphRun.glyphAdvances = colorglyphenum->color_advances;
5459 colorglyphenum->colorrun.glyphRun.glyphOffsets = colorglyphenum->color_offsets;
5460 colorglyphenum->colorrun.glyphRunDescription = NULL; /* FIXME */
5462 if (run->glyphAdvances)
5463 memcpy(colorglyphenum->advances, run->glyphAdvances, run->glyphCount * sizeof(FLOAT));
5464 else {
5465 DWRITE_FONT_METRICS metrics;
5467 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
5468 for (i = 0; i < run->glyphCount; i++) {
5469 HRESULT hr;
5470 INT32 a;
5472 switch (measuring_mode)
5474 case DWRITE_MEASURING_MODE_NATURAL:
5475 hr = IDWriteFontFace3_GetDesignGlyphAdvances(fontface3, 1, run->glyphIndices + i, &a, run->isSideways);
5476 if (FAILED(hr))
5477 a = 0;
5478 colorglyphenum->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
5479 break;
5480 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5481 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5482 hr = IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3, run->fontEmSize, 1.0f, transform,
5483 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
5484 if (FAILED(hr))
5485 colorglyphenum->advances[i] = 0.0f;
5486 else
5487 colorglyphenum->advances[i] = floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f);
5488 break;
5489 default:
5495 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
5496 return S_OK;
5498 failed:
5499 IDWriteFontFace3_Release(fontface3);
5500 return hr;
5503 /* IDWriteFontFaceReference */
5504 static HRESULT WINAPI fontfacereference_QueryInterface(IDWriteFontFaceReference *iface, REFIID riid, void **obj)
5506 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5508 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
5510 if (IsEqualIID(riid, &IID_IDWriteFontFaceReference) || IsEqualIID(riid, &IID_IUnknown)) {
5511 *obj = iface;
5512 IDWriteFontFaceReference_AddRef(iface);
5513 return S_OK;
5516 *obj = NULL;
5518 return E_NOINTERFACE;
5521 static ULONG WINAPI fontfacereference_AddRef(IDWriteFontFaceReference *iface)
5523 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5524 ULONG ref = InterlockedIncrement(&This->ref);
5525 TRACE("(%p)->(%u)\n", This, ref);
5526 return ref;
5529 static ULONG WINAPI fontfacereference_Release(IDWriteFontFaceReference *iface)
5531 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5532 ULONG ref = InterlockedDecrement(&This->ref);
5534 TRACE("(%p)->(%u)\n", This, ref);
5536 if (!ref) {
5537 IDWriteFontFile_Release(This->file);
5538 IDWriteFactory3_Release(This->factory);
5539 heap_free(This);
5542 return ref;
5545 static HRESULT WINAPI fontfacereference_CreateFontFace(IDWriteFontFaceReference *iface, IDWriteFontFace3 **fontface)
5547 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5549 TRACE("(%p)->(%p)\n", This, fontface);
5551 return IDWriteFontFaceReference_CreateFontFaceWithSimulations(iface, This->simulations, fontface);
5554 static HRESULT WINAPI fontfacereference_CreateFontFaceWithSimulations(IDWriteFontFaceReference *iface,
5555 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace3 **ret)
5557 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5558 DWRITE_FONT_FILE_TYPE file_type;
5559 DWRITE_FONT_FACE_TYPE face_type;
5560 IDWriteFontFace *fontface;
5561 BOOL is_supported;
5562 UINT32 face_num;
5563 HRESULT hr;
5565 TRACE("(%p)->(%d %p)\n", This, simulations, ret);
5567 hr = IDWriteFontFile_Analyze(This->file, &is_supported, &file_type, &face_type, &face_num);
5568 if (FAILED(hr))
5569 return hr;
5571 hr = IDWriteFactory3_CreateFontFace(This->factory, face_type, 1, &This->file, This->index, simulations, &fontface);
5572 if (SUCCEEDED(hr)) {
5573 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)ret);
5574 IDWriteFontFace_Release(fontface);
5577 return hr;
5580 static BOOL WINAPI fontfacereference_Equals(IDWriteFontFaceReference *iface, IDWriteFontFaceReference *ref)
5582 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5583 IDWriteFontFile *file;
5584 BOOL ret;
5586 TRACE("(%p)->(%p)\n", This, ref);
5588 if (FAILED(IDWriteFontFaceReference_GetFontFile(ref, &file)))
5589 return FALSE;
5591 ret = is_same_fontfile(This->file, file) &&
5592 This->index == IDWriteFontFaceReference_GetFontFaceIndex(ref) &&
5593 This->simulations == IDWriteFontFaceReference_GetSimulations(ref);
5594 IDWriteFontFile_Release(file);
5596 return ret;
5599 static UINT32 WINAPI fontfacereference_GetFontFaceIndex(IDWriteFontFaceReference *iface)
5601 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5603 TRACE("(%p)\n", This);
5605 return This->index;
5608 static DWRITE_FONT_SIMULATIONS WINAPI fontfacereference_GetSimulations(IDWriteFontFaceReference *iface)
5610 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5612 TRACE("(%p)\n", This);
5614 return This->simulations;
5617 static HRESULT WINAPI fontfacereference_GetFontFile(IDWriteFontFaceReference *iface, IDWriteFontFile **file)
5619 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5620 IDWriteFontFileLoader *loader;
5621 const void *key;
5622 UINT32 key_size;
5623 HRESULT hr;
5625 TRACE("(%p)->(%p)\n", This, file);
5627 hr = IDWriteFontFile_GetReferenceKey(This->file, &key, &key_size);
5628 if (FAILED(hr))
5629 return hr;
5631 hr = IDWriteFontFile_GetLoader(This->file, &loader);
5632 if (FAILED(hr))
5633 return hr;
5635 hr = IDWriteFactory3_CreateCustomFontFileReference(This->factory, key, key_size, loader, file);
5636 IDWriteFontFileLoader_Release(loader);
5638 return hr;
5641 static UINT64 WINAPI fontfacereference_GetLocalFileSize(IDWriteFontFaceReference *iface)
5643 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5645 FIXME("(%p): stub\n", This);
5647 return 0;
5650 static UINT64 WINAPI fontfacereference_GetFileSize(IDWriteFontFaceReference *iface)
5652 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5654 FIXME("(%p): stub\n", This);
5656 return 0;
5659 static HRESULT WINAPI fontfacereference_GetFileTime(IDWriteFontFaceReference *iface, FILETIME *writetime)
5661 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5663 FIXME("(%p)->(%p): stub\n", This, writetime);
5665 return E_NOTIMPL;
5668 static DWRITE_LOCALITY WINAPI fontfacereference_GetLocality(IDWriteFontFaceReference *iface)
5670 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5672 FIXME("(%p): stub\n", This);
5674 return DWRITE_LOCALITY_LOCAL;
5677 static HRESULT WINAPI fontfacereference_EnqueueFontDownloadRequest(IDWriteFontFaceReference *iface)
5679 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5681 FIXME("(%p): stub\n", This);
5683 return E_NOTIMPL;
5686 static HRESULT WINAPI fontfacereference_EnqueueCharacterDownloadRequest(IDWriteFontFaceReference *iface, WCHAR const *chars,
5687 UINT32 count)
5689 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5691 FIXME("(%p)->(%s:%u): stub\n", This, debugstr_wn(chars, count), count);
5693 return E_NOTIMPL;
5696 static HRESULT WINAPI fontfacereference_EnqueueGlyphDownloadRequest(IDWriteFontFaceReference *iface, UINT16 const *glyphs,
5697 UINT32 count)
5699 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5701 FIXME("(%p)->(%p %u): stub\n", This, glyphs, count);
5703 return E_NOTIMPL;
5706 static HRESULT WINAPI fontfacereference_EnqueueFileFragmentDownloadRequest(IDWriteFontFaceReference *iface,
5707 UINT64 offset, UINT64 size)
5709 struct dwrite_fontfacereference *This = impl_from_IDWriteFontFaceReference(iface);
5711 FIXME("(%p)->(%s %s): stub\n", This, wine_dbgstr_longlong(offset), wine_dbgstr_longlong(size));
5713 return E_NOTIMPL;
5716 static const IDWriteFontFaceReferenceVtbl fontfacereferencevtbl = {
5717 fontfacereference_QueryInterface,
5718 fontfacereference_AddRef,
5719 fontfacereference_Release,
5720 fontfacereference_CreateFontFace,
5721 fontfacereference_CreateFontFaceWithSimulations,
5722 fontfacereference_Equals,
5723 fontfacereference_GetFontFaceIndex,
5724 fontfacereference_GetSimulations,
5725 fontfacereference_GetFontFile,
5726 fontfacereference_GetLocalFileSize,
5727 fontfacereference_GetFileSize,
5728 fontfacereference_GetFileTime,
5729 fontfacereference_GetLocality,
5730 fontfacereference_EnqueueFontDownloadRequest,
5731 fontfacereference_EnqueueCharacterDownloadRequest,
5732 fontfacereference_EnqueueGlyphDownloadRequest,
5733 fontfacereference_EnqueueFileFragmentDownloadRequest
5736 HRESULT create_fontfacereference(IDWriteFactory3 *factory, IDWriteFontFile *file, UINT32 index,
5737 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFaceReference **ret)
5739 struct dwrite_fontfacereference *ref;
5741 *ret = NULL;
5743 if (!is_simulation_valid(simulations))
5744 return E_INVALIDARG;
5746 ref = heap_alloc(sizeof(*ref));
5747 if (!ref)
5748 return E_OUTOFMEMORY;
5750 ref->IDWriteFontFaceReference_iface.lpVtbl = &fontfacereferencevtbl;
5751 ref->ref = 1;
5753 ref->factory = factory;
5754 IDWriteFactory3_AddRef(ref->factory);
5755 ref->file = file;
5756 IDWriteFontFile_AddRef(ref->file);
5757 ref->index = index;
5758 ref->simulations = simulations;
5759 *ret = &ref->IDWriteFontFaceReference_iface;
5761 return S_OK;