tools: Allow running installed builtin apps even when the 32-bit loader is missing.
[wine.git] / dlls / dwrite / font.c
blob92449781243578814b4deffe6920f33581bef9fe
1 /*
2 * Font and collections
4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <math.h>
24 #define COBJMACROS
26 #include "wine/list.h"
27 #include "dwrite_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
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')
39 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
41 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
42 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
43 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
45 static const WCHAR extraW[] = {'e','x','t','r','a',0};
46 static const WCHAR ultraW[] = {'u','l','t','r','a',0};
47 static const WCHAR semiW[] = {'s','e','m','i',0};
48 static const WCHAR extW[] = {'e','x','t',0};
49 static const WCHAR thinW[] = {'t','h','i','n',0};
50 static const WCHAR lightW[] = {'l','i','g','h','t',0};
51 static const WCHAR mediumW[] = {'m','e','d','i','u','m',0};
52 static const WCHAR blackW[] = {'b','l','a','c','k',0};
53 static const WCHAR condensedW[] = {'c','o','n','d','e','n','s','e','d',0};
54 static const WCHAR expandedW[] = {'e','x','p','a','n','d','e','d',0};
55 static const WCHAR italicW[] = {'i','t','a','l','i','c',0};
56 static const WCHAR boldW[] = {'B','o','l','d',0};
57 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
58 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
59 static const WCHAR demiW[] = {'d','e','m','i',0};
60 static const WCHAR spaceW[] = {' ',0};
61 static const WCHAR enusW[] = {'e','n','-','u','s',0};
63 struct dwrite_font_propvec {
64 FLOAT stretch;
65 FLOAT style;
66 FLOAT weight;
69 struct dwrite_font_data {
70 LONG ref;
72 DWRITE_FONT_STYLE style;
73 DWRITE_FONT_STRETCH stretch;
74 DWRITE_FONT_WEIGHT weight;
75 DWRITE_PANOSE panose;
76 struct dwrite_font_propvec propvec;
78 DWRITE_FONT_METRICS1 metrics;
79 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
80 IDWriteLocalizedStrings *names;
82 /* data needed to create fontface instance */
83 IDWriteFactory2 *factory;
84 DWRITE_FONT_FACE_TYPE face_type;
85 IDWriteFontFile *file;
86 UINT32 face_index;
88 WCHAR *facename;
90 USHORT simulations;
92 /* used to mark font as tested when scanning for simulation candidate */
93 BOOL bold_sim_tested : 1;
94 BOOL oblique_sim_tested : 1;
97 struct dwrite_fontlist {
98 IDWriteFontList IDWriteFontList_iface;
99 LONG ref;
101 IDWriteFontFamily *family;
102 struct dwrite_font_data **fonts;
103 UINT32 font_count;
106 struct dwrite_fontfamily_data {
107 LONG ref;
109 IDWriteLocalizedStrings *familyname;
111 struct dwrite_font_data **fonts;
112 UINT32 font_count;
113 UINT32 font_alloc;
114 BOOL has_normal_face : 1;
115 BOOL has_oblique_face : 1;
116 BOOL has_italic_face : 1;
119 struct dwrite_fontcollection {
120 IDWriteFontCollection IDWriteFontCollection_iface;
121 LONG ref;
123 struct dwrite_fontfamily_data **family_data;
124 UINT32 family_count;
125 UINT32 family_alloc;
126 BOOL is_system;
129 struct dwrite_fontfamily {
130 IDWriteFontFamily IDWriteFontFamily_iface;
131 LONG ref;
133 struct dwrite_fontfamily_data *data;
135 IDWriteFontCollection* collection;
138 struct dwrite_font {
139 IDWriteFont2 IDWriteFont2_iface;
140 LONG ref;
142 IDWriteFontFamily *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;
185 #define GLYPH_BLOCK_SHIFT 8
186 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
187 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
188 #define GLYPH_MAX 65536
190 struct dwrite_fontface {
191 IDWriteFontFace2 IDWriteFontFace2_iface;
192 LONG ref;
194 IDWriteFontFileStream **streams;
195 IDWriteFontFile **files;
196 UINT32 file_count;
197 UINT32 index;
199 USHORT simulations;
200 DWRITE_FONT_FACE_TYPE type;
201 DWRITE_FONT_METRICS1 metrics;
202 DWRITE_CARET_METRICS caret;
203 INT charmap;
204 BOOL is_symbol;
206 struct dwrite_fonttable cmap;
207 struct dwrite_fonttable vdmx;
208 struct dwrite_fonttable gasp;
209 struct dwrite_fonttable cpal;
210 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
213 struct dwrite_fontfile {
214 IDWriteFontFile IDWriteFontFile_iface;
215 LONG ref;
217 IDWriteFontFileLoader *loader;
218 void *reference_key;
219 UINT32 key_size;
220 IDWriteFontFileStream *stream;
223 static inline struct dwrite_fontface *impl_from_IDWriteFontFace2(IDWriteFontFace2 *iface)
225 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace2_iface);
228 static inline struct dwrite_font *impl_from_IDWriteFont2(IDWriteFont2 *iface)
230 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont2_iface);
233 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
235 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
238 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily(IDWriteFontFamily *iface)
240 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily_iface);
243 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection(IDWriteFontCollection *iface)
245 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection_iface);
248 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
250 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
253 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
255 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
258 static inline struct dwrite_fontlist *impl_from_IDWriteFontList(IDWriteFontList *iface)
260 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList_iface);
263 static inline const char *debugstr_tag(UINT32 tag)
265 return debugstr_an((char*)&tag, 4);
268 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
270 static const DWRITE_GLYPH_METRICS nil;
271 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
273 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
274 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
275 return S_OK;
278 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
280 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
282 if (!*block) {
283 /* start new block */
284 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
285 if (!*block)
286 return E_OUTOFMEMORY;
289 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
290 return S_OK;
293 static void* get_fontface_table(struct dwrite_fontface *fontface, UINT32 tag, struct dwrite_fonttable *table)
295 HRESULT hr;
297 if (table->data || !table->exists)
298 return table->data;
300 table->exists = FALSE;
301 hr = IDWriteFontFace2_TryGetFontTable(&fontface->IDWriteFontFace2_iface, tag, (const void**)&table->data,
302 &table->size, &table->context, &table->exists);
303 if (FAILED(hr) || !table->exists) {
304 WARN("Font does not have a %s table\n", debugstr_tag(tag));
305 return NULL;
308 return table->data;
311 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
312 struct dwrite_font_propvec *vec)
314 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
315 vec->style = style * 7.0f;
316 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
319 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
321 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
324 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
326 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
329 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
331 return get_fontface_table(fontface, MS_CMAP_TAG, &fontface->cmap);
334 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
336 return get_fontface_table(fontface, MS_VDMX_TAG, &fontface->vdmx);
339 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
341 void *ptr = get_fontface_table(fontface, MS_GASP_TAG, &fontface->gasp);
342 *size = fontface->gasp.size;
343 return ptr;
346 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
348 return get_fontface_table(fontface, MS_CPAL_TAG, &fontface->cpal);
351 static void release_font_data(struct dwrite_font_data *data)
353 int i;
355 if (InterlockedDecrement(&data->ref) > 0)
356 return;
358 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
359 if (data->info_strings[i])
360 IDWriteLocalizedStrings_Release(data->info_strings[i]);
362 IDWriteLocalizedStrings_Release(data->names);
364 IDWriteFontFile_Release(data->file);
365 IDWriteFactory2_Release(data->factory);
366 heap_free(data->facename);
367 heap_free(data);
370 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
372 int i;
374 if (InterlockedDecrement(&data->ref) > 0)
375 return;
377 for (i = 0; i < data->font_count; i++)
378 release_font_data(data->fonts[i]);
379 heap_free(data->fonts);
380 IDWriteLocalizedStrings_Release(data->familyname);
381 heap_free(data);
384 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace2 *iface, REFIID riid, void **obj)
386 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
388 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
390 if (IsEqualIID(riid, &IID_IDWriteFontFace2) ||
391 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
392 IsEqualIID(riid, &IID_IDWriteFontFace) ||
393 IsEqualIID(riid, &IID_IUnknown))
395 *obj = iface;
396 IDWriteFontFace2_AddRef(iface);
397 return S_OK;
400 *obj = NULL;
401 return E_NOINTERFACE;
404 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace2 *iface)
406 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
407 ULONG ref = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(%d)\n", This, ref);
409 return ref;
412 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace2 *iface)
414 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
415 ULONG ref = InterlockedDecrement(&This->ref);
417 TRACE("(%p)->(%d)\n", This, ref);
419 if (!ref) {
420 UINT32 i;
422 if (This->cmap.context)
423 IDWriteFontFace2_ReleaseFontTable(iface, This->cmap.context);
424 if (This->vdmx.context)
425 IDWriteFontFace2_ReleaseFontTable(iface, This->vdmx.context);
426 if (This->gasp.context)
427 IDWriteFontFace2_ReleaseFontTable(iface, This->gasp.context);
428 if (This->cpal.context)
429 IDWriteFontFace2_ReleaseFontTable(iface, This->cpal.context);
430 for (i = 0; i < This->file_count; i++) {
431 if (This->streams[i])
432 IDWriteFontFileStream_Release(This->streams[i]);
433 if (This->files[i])
434 IDWriteFontFile_Release(This->files[i]);
436 heap_free(This->streams);
437 heap_free(This->files);
439 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
440 heap_free(This->glyphs[i]);
442 freetype_notify_cacheremove(iface);
443 heap_free(This);
446 return ref;
449 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace2 *iface)
451 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
452 TRACE("(%p)\n", This);
453 return This->type;
456 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace2 *iface, UINT32 *number_of_files,
457 IDWriteFontFile **fontfiles)
459 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
460 int i;
462 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
463 if (fontfiles == NULL)
465 *number_of_files = This->file_count;
466 return S_OK;
468 if (*number_of_files < This->file_count)
469 return E_INVALIDARG;
471 for (i = 0; i < This->file_count; i++)
473 IDWriteFontFile_AddRef(This->files[i]);
474 fontfiles[i] = This->files[i];
477 return S_OK;
480 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace2 *iface)
482 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
483 TRACE("(%p)\n", This);
484 return This->index;
487 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace2 *iface)
489 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
490 TRACE("(%p)\n", This);
491 return This->simulations;
494 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace2 *iface)
496 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
497 TRACE("(%p)\n", This);
498 return This->is_symbol;
501 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS *metrics)
503 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
504 TRACE("(%p)->(%p)\n", This, metrics);
505 memcpy(metrics, &This->metrics, sizeof(*metrics));
508 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace2 *iface)
510 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
511 TRACE("(%p)\n", This);
512 return freetype_get_glyphcount(iface);
515 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace2 *iface,
516 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
518 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
519 HRESULT hr;
520 UINT32 i;
522 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
524 if (!glyphs)
525 return E_INVALIDARG;
527 if (is_sideways)
528 FIXME("sideways metrics are not supported.\n");
530 for (i = 0; i < glyph_count; i++) {
531 DWRITE_GLYPH_METRICS metrics;
533 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
534 if (hr != S_OK) {
535 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
536 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
537 if (FAILED(hr))
538 return hr;
540 ret[i] = metrics;
543 return S_OK;
546 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace2 *iface, UINT32 const *codepoints,
547 UINT32 count, UINT16 *glyph_indices)
549 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
550 UINT32 i;
552 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
554 if (!glyph_indices)
555 return E_INVALIDARG;
557 if (!codepoints) {
558 memset(glyph_indices, 0, count*sizeof(UINT16));
559 return E_INVALIDARG;
562 for (i = 0; i < count; i++)
563 glyph_indices[i] = freetype_get_glyphindex(iface, codepoints[i], This->charmap);
565 return S_OK;
568 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace2 *iface, UINT32 table_tag,
569 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
571 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
573 TRACE("(%p)->(%s %p %p %p %p)\n", This, debugstr_tag(table_tag), table_data, table_size, context, exists);
575 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
578 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace2 *iface, void *table_context)
580 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
582 TRACE("(%p)->(%p)\n", This, table_context);
584 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
587 HRESULT new_glyph_outline(UINT32 count, struct glyph_outline **ret)
589 struct glyph_outline *outline;
590 D2D1_POINT_2F *points;
591 UINT8 *tags;
593 *ret = NULL;
595 outline = heap_alloc(sizeof(*outline));
596 if (!outline)
597 return E_OUTOFMEMORY;
599 points = heap_alloc(count*sizeof(D2D1_POINT_2F));
600 tags = heap_alloc_zero(count*sizeof(UINT8));
601 if (!points || !tags) {
602 heap_free(points);
603 heap_free(tags);
604 heap_free(outline);
605 return E_OUTOFMEMORY;
608 outline->points = points;
609 outline->tags = tags;
610 outline->count = count;
611 outline->advance = 0.0;
613 *ret = outline;
614 return S_OK;
617 static void free_glyph_outline(struct glyph_outline *outline)
619 heap_free(outline->points);
620 heap_free(outline->tags);
621 heap_free(outline);
624 static void report_glyph_outline(const struct glyph_outline *outline, IDWriteGeometrySink *sink)
626 UINT16 p;
628 for (p = 0; p < outline->count; p++) {
629 if (outline->tags[p] & OUTLINE_POINT_START) {
630 ID2D1SimplifiedGeometrySink_BeginFigure(sink, outline->points[p], D2D1_FIGURE_BEGIN_FILLED);
631 continue;
634 if (outline->tags[p] & OUTLINE_POINT_LINE)
635 ID2D1SimplifiedGeometrySink_AddLines(sink, outline->points+p, 1);
636 else if (outline->tags[p] & OUTLINE_POINT_BEZIER) {
637 static const UINT16 segment_length = 3;
638 ID2D1SimplifiedGeometrySink_AddBeziers(sink, (D2D1_BEZIER_SEGMENT*)&outline->points[p], 1);
639 p += segment_length - 1;
642 if (outline->tags[p] & OUTLINE_POINT_END)
643 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
647 static inline void translate_glyph_outline(struct glyph_outline *outline, FLOAT xoffset, FLOAT yoffset)
649 UINT16 p;
651 for (p = 0; p < outline->count; p++) {
652 outline->points[p].x += xoffset;
653 outline->points[p].y += yoffset;
657 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace2 *iface, FLOAT emSize,
658 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
659 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
661 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
662 FLOAT advance = 0.0;
663 HRESULT hr;
664 UINT32 g;
666 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
667 count, is_sideways, is_rtl, sink);
669 if (!glyphs || !sink)
670 return E_INVALIDARG;
672 if (is_sideways)
673 FIXME("sideways mode is not supported.\n");
675 if (count)
676 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
678 for (g = 0; g < count; g++) {
679 FLOAT xoffset = 0.0, yoffset = 0.0;
680 struct glyph_outline *outline;
682 /* FIXME: cache outlines */
684 hr = freetype_get_glyph_outline(iface, emSize, glyphs[g], This->simulations, &outline);
685 if (FAILED(hr))
686 return hr;
688 /* glyph offsets act as current glyph adjustment */
689 if (offsets) {
690 xoffset += is_rtl ? -offsets[g].advanceOffset : offsets[g].advanceOffset;
691 yoffset -= offsets[g].ascenderOffset;
694 if (g == 0)
695 advance = is_rtl ? -outline->advance : 0.0;
697 xoffset += advance;
698 translate_glyph_outline(outline, xoffset, yoffset);
700 /* update advance to next glyph */
701 if (advances)
702 advance += is_rtl ? -advances[g] : advances[g];
703 else
704 advance += is_rtl ? -outline->advance : outline->advance;
706 report_glyph_outline(outline, sink);
707 free_glyph_outline(outline);
710 return S_OK;
713 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
714 FLOAT ppem, WORD gasp)
716 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
718 switch (measuring)
720 case DWRITE_MEASURING_MODE_NATURAL:
722 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
723 mode = DWRITE_RENDERING_MODE_NATURAL;
724 else
725 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
726 break;
728 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
729 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
730 break;
731 case DWRITE_MEASURING_MODE_GDI_NATURAL:
732 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
733 break;
734 default:
738 return mode;
741 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
742 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
744 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
745 WORD gasp, *ptr;
746 UINT32 size;
747 FLOAT ppem;
749 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
751 if (!params) {
752 *mode = DWRITE_RENDERING_MODE_DEFAULT;
753 return E_INVALIDARG;
756 *mode = IDWriteRenderingParams_GetRenderingMode(params);
757 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
758 return S_OK;
760 ppem = emSize * ppdip;
762 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
763 *mode = DWRITE_RENDERING_MODE_OUTLINE;
764 return S_OK;
767 ptr = get_fontface_gasp(This, &size);
768 gasp = opentype_get_gasp_flags(ptr, size, ppem);
769 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
770 return S_OK;
773 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT pixels_per_dip,
774 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
776 DWRITE_FONT_METRICS1 metrics1;
777 HRESULT hr = IDWriteFontFace2_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
778 memcpy(metrics, &metrics1, sizeof(*metrics));
779 return hr;
782 static inline int round_metric(FLOAT metric)
784 return (int)floorf(metric + 0.5f);
787 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT ppdip,
788 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
789 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
791 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
792 DWRITE_MEASURING_MODE mode;
793 FLOAT scale, size;
794 HRESULT hr;
795 UINT32 i;
797 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
798 glyph_count, metrics, is_sideways);
800 if (m && memcmp(m, &identity, sizeof(*m)))
801 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
803 size = emSize * ppdip;
804 scale = size / This->metrics.designUnitsPerEm;
805 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
807 for (i = 0; i < glyph_count; i++) {
808 DWRITE_GLYPH_METRICS *ret = metrics + i;
809 DWRITE_GLYPH_METRICS design;
811 hr = IDWriteFontFace2_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
812 if (FAILED(hr))
813 return hr;
815 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
816 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
818 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
819 SCALE_METRIC(leftSideBearing);
820 SCALE_METRIC(rightSideBearing);
821 SCALE_METRIC(topSideBearing);
822 SCALE_METRIC(advanceHeight);
823 SCALE_METRIC(bottomSideBearing);
824 SCALE_METRIC(verticalOriginY);
825 #undef SCALE_METRIC
828 return S_OK;
831 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS1 *metrics)
833 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
834 TRACE("(%p)->(%p)\n", This, metrics);
835 *metrics = This->metrics;
838 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT em_size, FLOAT pixels_per_dip,
839 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
841 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
842 const DWRITE_FONT_METRICS1 *design = &This->metrics;
843 UINT16 ascent, descent;
844 FLOAT scale;
846 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
848 if (em_size <= 0.0 || pixels_per_dip <= 0.0) {
849 memset(metrics, 0, sizeof(*metrics));
850 return E_INVALIDARG;
853 em_size *= pixels_per_dip;
854 if (m && m->m22 != 0.0)
855 em_size *= fabs(m->m22);
857 scale = em_size / design->designUnitsPerEm;
858 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
859 ascent = round_metric(design->ascent * scale);
860 descent = round_metric(design->descent * scale);
863 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
864 metrics->designUnitsPerEm = design->designUnitsPerEm;
865 metrics->ascent = round_metric(ascent / scale);
866 metrics->descent = round_metric(descent / scale);
868 SCALE_METRIC(lineGap);
869 SCALE_METRIC(capHeight);
870 SCALE_METRIC(xHeight);
871 SCALE_METRIC(underlinePosition);
872 SCALE_METRIC(underlineThickness);
873 SCALE_METRIC(strikethroughPosition);
874 SCALE_METRIC(strikethroughThickness);
875 SCALE_METRIC(glyphBoxLeft);
876 SCALE_METRIC(glyphBoxTop);
877 SCALE_METRIC(glyphBoxRight);
878 SCALE_METRIC(glyphBoxBottom);
879 SCALE_METRIC(subscriptPositionX);
880 SCALE_METRIC(subscriptPositionY);
881 SCALE_METRIC(subscriptSizeX);
882 SCALE_METRIC(subscriptSizeY);
883 SCALE_METRIC(superscriptPositionX);
884 SCALE_METRIC(superscriptPositionY);
885 SCALE_METRIC(superscriptSizeX);
886 SCALE_METRIC(superscriptSizeY);
888 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
889 #undef SCALE_METRIC
891 return S_OK;
894 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace2 *iface, DWRITE_CARET_METRICS *metrics)
896 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
897 TRACE("(%p)->(%p)\n", This, metrics);
898 *metrics = This->caret;
901 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace2 *iface, UINT32 max_count,
902 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
904 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
906 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
908 *count = 0;
909 if (max_count && !ranges)
910 return E_INVALIDARG;
912 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
915 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace2 *iface)
917 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
918 TRACE("(%p)\n", This);
919 return freetype_is_monospaced(iface);
922 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace2 *iface,
923 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
925 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
926 UINT32 i;
928 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
930 if (is_sideways)
931 FIXME("sideways mode not supported\n");
933 for (i = 0; i < glyph_count; i++)
934 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
936 return S_OK;
939 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace2 *iface,
940 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
941 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
943 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
944 DWRITE_MEASURING_MODE mode;
945 UINT32 i;
947 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
948 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
950 if (em_size < 0.0 || ppdip <= 0.0) {
951 memset(advances, 0, sizeof(*advances) * glyph_count);
952 return E_INVALIDARG;
955 em_size *= ppdip;
956 if (em_size == 0.0) {
957 memset(advances, 0, sizeof(*advances) * glyph_count);
958 return S_OK;
961 if (m && memcmp(m, &identity, sizeof(*m)))
962 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
964 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
965 for (i = 0; i < glyph_count; i++) {
966 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
967 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
970 return S_OK;
973 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace2 *iface, UINT32 count,
974 const UINT16 *indices, INT32 *adjustments)
976 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
977 UINT32 i;
979 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
981 if (!(indices || adjustments) || !count)
982 return E_INVALIDARG;
984 if (!indices || count == 1) {
985 memset(adjustments, 0, count*sizeof(INT32));
986 return E_INVALIDARG;
989 for (i = 0; i < count-1; i++)
990 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
991 adjustments[count-1] = 0;
993 return S_OK;
996 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace2 *iface)
998 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
999 TRACE("(%p)\n", This);
1000 return freetype_has_kerning_pairs(iface);
1003 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace2 *iface,
1004 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1005 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1007 DWRITE_GRID_FIT_MODE gridfitmode;
1008 return IDWriteFontFace2_GetRecommendedRenderingMode(iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1009 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1012 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace2 *iface, UINT32 glyph_count,
1013 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1015 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1016 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1017 return E_NOTIMPL;
1020 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace2 *iface)
1022 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1023 FIXME("(%p): stub\n", This);
1024 return FALSE;
1027 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace2 *iface)
1029 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1030 FIXME("(%p): stub\n", This);
1031 return FALSE;
1034 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace2 *iface)
1036 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1037 TRACE("(%p)\n", This);
1038 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1041 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace2 *iface)
1043 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1044 TRACE("(%p)\n", This);
1045 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1048 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace2 *iface, UINT32 palette_index,
1049 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1051 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1052 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1053 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1056 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
1057 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1058 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1059 DWRITE_GRID_FIT_MODE *gridfitmode)
1061 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1062 FLOAT emthreshold;
1063 WORD gasp, *ptr;
1064 UINT32 size;
1066 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1067 measuringmode, params, renderingmode, gridfitmode);
1069 if (m)
1070 FIXME("transform not supported %s\n", debugstr_matrix(m));
1072 if (is_sideways)
1073 FIXME("sideways mode not supported\n");
1075 emSize *= max(dpiX, dpiY) / 96.0f;
1077 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1078 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1079 if (params) {
1080 IDWriteRenderingParams2 *params2;
1081 HRESULT hr;
1083 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1084 if (hr == S_OK) {
1085 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1086 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1087 IDWriteRenderingParams2_Release(params2);
1089 else
1090 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1093 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1095 ptr = get_fontface_gasp(This, &size);
1096 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1098 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1099 if (emSize >= emthreshold)
1100 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1101 else
1102 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1105 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1106 if (emSize >= emthreshold)
1107 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1108 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1109 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1110 else
1111 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1114 return S_OK;
1117 static const IDWriteFontFace2Vtbl dwritefontfacevtbl = {
1118 dwritefontface_QueryInterface,
1119 dwritefontface_AddRef,
1120 dwritefontface_Release,
1121 dwritefontface_GetType,
1122 dwritefontface_GetFiles,
1123 dwritefontface_GetIndex,
1124 dwritefontface_GetSimulations,
1125 dwritefontface_IsSymbolFont,
1126 dwritefontface_GetMetrics,
1127 dwritefontface_GetGlyphCount,
1128 dwritefontface_GetDesignGlyphMetrics,
1129 dwritefontface_GetGlyphIndices,
1130 dwritefontface_TryGetFontTable,
1131 dwritefontface_ReleaseFontTable,
1132 dwritefontface_GetGlyphRunOutline,
1133 dwritefontface_GetRecommendedRenderingMode,
1134 dwritefontface_GetGdiCompatibleMetrics,
1135 dwritefontface_GetGdiCompatibleGlyphMetrics,
1136 dwritefontface1_GetMetrics,
1137 dwritefontface1_GetGdiCompatibleMetrics,
1138 dwritefontface1_GetCaretMetrics,
1139 dwritefontface1_GetUnicodeRanges,
1140 dwritefontface1_IsMonospacedFont,
1141 dwritefontface1_GetDesignGlyphAdvances,
1142 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1143 dwritefontface1_GetKerningPairAdjustments,
1144 dwritefontface1_HasKerningPairs,
1145 dwritefontface1_GetRecommendedRenderingMode,
1146 dwritefontface1_GetVerticalGlyphVariants,
1147 dwritefontface1_HasVerticalGlyphVariants,
1148 dwritefontface2_IsColorFont,
1149 dwritefontface2_GetColorPaletteCount,
1150 dwritefontface2_GetPaletteEntryCount,
1151 dwritefontface2_GetPaletteEntries,
1152 dwritefontface2_GetRecommendedRenderingMode
1155 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace2 **fontface)
1157 struct dwrite_font_data *data = font->data;
1158 IDWriteFontFace *face;
1159 HRESULT hr;
1161 *fontface = NULL;
1163 hr = IDWriteFactory2_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1164 data->face_index, font->data->simulations, &face);
1165 if (FAILED(hr))
1166 return hr;
1168 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace2, (void**)fontface);
1169 IDWriteFontFace_Release(face);
1171 return hr;
1174 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont2 *iface, REFIID riid, void **obj)
1176 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1178 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1180 if (IsEqualIID(riid, &IID_IDWriteFont2) ||
1181 IsEqualIID(riid, &IID_IDWriteFont1) ||
1182 IsEqualIID(riid, &IID_IDWriteFont) ||
1183 IsEqualIID(riid, &IID_IUnknown))
1185 *obj = iface;
1186 IDWriteFont2_AddRef(iface);
1187 return S_OK;
1190 *obj = NULL;
1191 return E_NOINTERFACE;
1194 static ULONG WINAPI dwritefont_AddRef(IDWriteFont2 *iface)
1196 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1197 ULONG ref = InterlockedIncrement(&This->ref);
1198 TRACE("(%p)->(%d)\n", This, ref);
1199 return ref;
1202 static ULONG WINAPI dwritefont_Release(IDWriteFont2 *iface)
1204 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1205 ULONG ref = InterlockedDecrement(&This->ref);
1207 TRACE("(%p)->(%d)\n", This, ref);
1209 if (!ref) {
1210 IDWriteFontFamily_Release(This->family);
1211 release_font_data(This->data);
1212 heap_free(This);
1215 return ref;
1218 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont2 *iface, IDWriteFontFamily **family)
1220 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1221 TRACE("(%p)->(%p)\n", This, family);
1223 *family = This->family;
1224 IDWriteFontFamily_AddRef(*family);
1225 return S_OK;
1228 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont2 *iface)
1230 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1231 TRACE("(%p)\n", This);
1232 return This->data->weight;
1235 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont2 *iface)
1237 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1238 TRACE("(%p)\n", This);
1239 return This->data->stretch;
1242 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont2 *iface)
1244 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1245 TRACE("(%p)\n", This);
1246 return This->style;
1249 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont2 *iface)
1251 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1252 IDWriteFontFace2 *fontface;
1253 HRESULT hr;
1255 TRACE("(%p)\n", This);
1257 hr = get_fontface_from_font(This, &fontface);
1258 if (FAILED(hr))
1259 return FALSE;
1261 return IDWriteFontFace2_IsSymbolFont(fontface);
1264 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont2 *iface, IDWriteLocalizedStrings **names)
1266 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1267 TRACE("(%p)->(%p)\n", This, names);
1268 return clone_localizedstring(This->data->names, names);
1271 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont2 *iface,
1272 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1274 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1275 struct dwrite_font_data *data = This->data;
1276 HRESULT hr;
1278 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1280 *exists = FALSE;
1281 *strings = NULL;
1283 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1284 return S_OK;
1286 if (!data->info_strings[stringid]) {
1287 IDWriteFontFace2 *fontface;
1288 const void *table_data;
1289 BOOL table_exists;
1290 void *context;
1291 UINT32 size;
1293 hr = get_fontface_from_font(This, &fontface);
1294 if (FAILED(hr))
1295 return hr;
1297 table_exists = FALSE;
1298 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1299 if (FAILED(hr) || !table_exists)
1300 WARN("no NAME table found.\n");
1302 if (table_exists) {
1303 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1304 if (FAILED(hr) || !data->info_strings[stringid])
1305 return hr;
1306 IDWriteFontFace2_ReleaseFontTable(fontface, context);
1310 hr = clone_localizedstring(data->info_strings[stringid], strings);
1311 if (FAILED(hr))
1312 return hr;
1314 *exists = TRUE;
1315 return S_OK;
1318 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont2 *iface)
1320 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1321 TRACE("(%p)\n", This);
1322 return This->data->simulations;
1325 static void WINAPI dwritefont_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS *metrics)
1327 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1329 TRACE("(%p)->(%p)\n", This, metrics);
1330 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1333 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont2 *iface, UINT32 value, BOOL *exists)
1335 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1336 IDWriteFontFace2 *fontface;
1337 UINT16 index;
1338 HRESULT hr;
1340 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1342 *exists = FALSE;
1344 hr = get_fontface_from_font(This, &fontface);
1345 if (FAILED(hr))
1346 return hr;
1348 index = 0;
1349 hr = IDWriteFontFace2_GetGlyphIndices(fontface, &value, 1, &index);
1350 if (FAILED(hr))
1351 return hr;
1353 *exists = index != 0;
1354 return S_OK;
1357 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont2 *iface, IDWriteFontFace **face)
1359 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1360 HRESULT hr;
1362 TRACE("(%p)->(%p)\n", This, face);
1364 hr = get_fontface_from_font(This, (IDWriteFontFace2**)face);
1365 if (hr == S_OK)
1366 IDWriteFontFace_AddRef(*face);
1368 return hr;
1371 static void WINAPI dwritefont1_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS1 *metrics)
1373 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1374 TRACE("(%p)->(%p)\n", This, metrics);
1375 *metrics = This->data->metrics;
1378 static void WINAPI dwritefont1_GetPanose(IDWriteFont2 *iface, DWRITE_PANOSE *panose)
1380 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1381 TRACE("(%p)->(%p)\n", This, panose);
1382 *panose = This->data->panose;
1385 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont2 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1387 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1388 IDWriteFontFace2 *fontface;
1389 HRESULT hr;
1391 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1393 hr = get_fontface_from_font(This, &fontface);
1394 if (FAILED(hr))
1395 return hr;
1397 return IDWriteFontFace2_GetUnicodeRanges(fontface, max_count, ranges, count);
1400 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont2 *iface)
1402 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1403 IDWriteFontFace2 *fontface;
1404 HRESULT hr;
1406 TRACE("(%p)\n", This);
1408 hr = get_fontface_from_font(This, &fontface);
1409 if (FAILED(hr))
1410 return FALSE;
1412 return IDWriteFontFace2_IsMonospacedFont(fontface);
1415 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont2 *iface)
1417 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1418 IDWriteFontFace2 *fontface;
1419 HRESULT hr;
1421 TRACE("(%p)\n", This);
1423 hr = get_fontface_from_font(This, &fontface);
1424 if (FAILED(hr))
1425 return FALSE;
1427 return IDWriteFontFace2_IsColorFont(fontface);
1430 static const IDWriteFont2Vtbl dwritefontvtbl = {
1431 dwritefont_QueryInterface,
1432 dwritefont_AddRef,
1433 dwritefont_Release,
1434 dwritefont_GetFontFamily,
1435 dwritefont_GetWeight,
1436 dwritefont_GetStretch,
1437 dwritefont_GetStyle,
1438 dwritefont_IsSymbolFont,
1439 dwritefont_GetFaceNames,
1440 dwritefont_GetInformationalStrings,
1441 dwritefont_GetSimulations,
1442 dwritefont_GetMetrics,
1443 dwritefont_HasCharacter,
1444 dwritefont_CreateFontFace,
1445 dwritefont1_GetMetrics,
1446 dwritefont1_GetPanose,
1447 dwritefont1_GetUnicodeRanges,
1448 dwritefont1_IsMonospacedFont,
1449 dwritefont2_IsColorFont
1452 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily *family, IDWriteFont **font)
1454 struct dwrite_font *This;
1455 *font = NULL;
1457 This = heap_alloc(sizeof(struct dwrite_font));
1458 if (!This) return E_OUTOFMEMORY;
1460 This->IDWriteFont2_iface.lpVtbl = &dwritefontvtbl;
1461 This->ref = 1;
1462 This->family = family;
1463 IDWriteFontFamily_AddRef(family);
1464 This->style = data->style;
1465 This->data = data;
1466 InterlockedIncrement(&This->data->ref);
1468 *font = (IDWriteFont*)&This->IDWriteFont2_iface;
1470 return S_OK;
1473 /* IDWriteFontList */
1474 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList *iface, REFIID riid, void **obj)
1476 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1478 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1480 if (IsEqualIID(riid, &IID_IDWriteFontList) ||
1481 IsEqualIID(riid, &IID_IUnknown))
1483 *obj = iface;
1484 IDWriteFontList_AddRef(iface);
1485 return S_OK;
1488 *obj = NULL;
1489 return E_NOINTERFACE;
1492 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList *iface)
1494 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1495 ULONG ref = InterlockedIncrement(&This->ref);
1496 TRACE("(%p)->(%d)\n", This, ref);
1497 return ref;
1500 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList *iface)
1502 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1503 ULONG ref = InterlockedDecrement(&This->ref);
1505 TRACE("(%p)->(%d)\n", This, ref);
1507 if (!ref) {
1508 UINT32 i;
1510 for (i = 0; i < This->font_count; i++)
1511 release_font_data(This->fonts[i]);
1512 IDWriteFontFamily_Release(This->family);
1513 heap_free(This);
1516 return ref;
1519 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList *iface, IDWriteFontCollection **collection)
1521 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1522 return IDWriteFontFamily_GetFontCollection(This->family, collection);
1525 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList *iface)
1527 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1528 TRACE("(%p)\n", This);
1529 return This->font_count;
1532 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList *iface, UINT32 index, IDWriteFont **font)
1534 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1536 TRACE("(%p)->(%u %p)\n", This, index, font);
1538 *font = NULL;
1540 if (This->font_count == 0)
1541 return S_FALSE;
1543 if (index >= This->font_count)
1544 return E_INVALIDARG;
1546 return create_font(This->fonts[index], This->family, font);
1549 static const IDWriteFontListVtbl dwritefontlistvtbl = {
1550 dwritefontlist_QueryInterface,
1551 dwritefontlist_AddRef,
1552 dwritefontlist_Release,
1553 dwritefontlist_GetFontCollection,
1554 dwritefontlist_GetFontCount,
1555 dwritefontlist_GetFont
1558 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily *iface, REFIID riid, void **obj)
1560 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1561 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1563 if (IsEqualIID(riid, &IID_IUnknown) ||
1564 IsEqualIID(riid, &IID_IDWriteFontList) ||
1565 IsEqualIID(riid, &IID_IDWriteFontFamily))
1567 *obj = iface;
1568 IDWriteFontFamily_AddRef(iface);
1569 return S_OK;
1572 *obj = NULL;
1573 return E_NOINTERFACE;
1576 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily *iface)
1578 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1579 ULONG ref = InterlockedIncrement(&This->ref);
1580 TRACE("(%p)->(%d)\n", This, ref);
1581 return ref;
1584 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily *iface)
1586 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1587 ULONG ref = InterlockedDecrement(&This->ref);
1589 TRACE("(%p)->(%d)\n", This, ref);
1591 if (!ref)
1593 IDWriteFontCollection_Release(This->collection);
1594 release_fontfamily_data(This->data);
1595 heap_free(This);
1598 return ref;
1601 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily *iface, IDWriteFontCollection **collection)
1603 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1604 TRACE("(%p)->(%p)\n", This, collection);
1606 *collection = This->collection;
1607 IDWriteFontCollection_AddRef(This->collection);
1608 return S_OK;
1611 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily *iface)
1613 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1614 TRACE("(%p)\n", This);
1615 return This->data->font_count;
1618 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily *iface, UINT32 index, IDWriteFont **font)
1620 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1622 TRACE("(%p)->(%u %p)\n", This, index, font);
1624 *font = NULL;
1626 if (This->data->font_count == 0)
1627 return S_FALSE;
1629 if (index >= This->data->font_count)
1630 return E_INVALIDARG;
1632 return create_font(This->data->fonts[index], iface, font);
1635 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface, IDWriteLocalizedStrings **names)
1637 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1638 return clone_localizedstring(This->data->familyname, names);
1641 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1642 const struct dwrite_font_propvec *req)
1644 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1645 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1646 FLOAT cur_req_prod, next_req_prod;
1648 if (next_to_req < cur_to_req)
1649 return TRUE;
1651 if (next_to_req > cur_to_req)
1652 return FALSE;
1654 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1655 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1657 if (next_req_prod > cur_req_prod)
1658 return TRUE;
1660 if (next_req_prod < cur_req_prod)
1661 return FALSE;
1663 if (next->stretch > cur->stretch)
1664 return TRUE;
1665 if (next->stretch < cur->stretch)
1666 return FALSE;
1668 if (next->style > cur->style)
1669 return TRUE;
1670 if (next->style < cur->style)
1671 return FALSE;
1673 if (next->weight > cur->weight)
1674 return TRUE;
1675 if (next->weight < cur->weight)
1676 return FALSE;
1678 /* full match, no reason to prefer new variant */
1679 return FALSE;
1682 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1683 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1685 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1686 struct dwrite_font_propvec req;
1687 struct dwrite_font_data *match;
1688 UINT32 i;
1690 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1692 if (This->data->font_count == 0) {
1693 *font = NULL;
1694 return DWRITE_E_NOFONT;
1697 init_font_prop_vec(weight, stretch, style, &req);
1698 match = This->data->fonts[0];
1700 for (i = 1; i < This->data->font_count; i++) {
1701 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1702 match = This->data->fonts[i];
1705 return create_font(match, iface, font);
1708 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1710 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1712 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1715 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1717 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1720 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1722 UINT32 b = fonts->font_count - 1, j, t;
1724 while (1) {
1725 t = b;
1727 for (j = 0; j < b; j++) {
1728 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1729 struct dwrite_font_data *s = fonts->fonts[j];
1730 fonts->fonts[j] = fonts->fonts[j+1];
1731 fonts->fonts[j+1] = s;
1732 t = j;
1736 if (t == b)
1737 break;
1738 b = t;
1742 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1743 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1745 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1746 matching_filter_func func = NULL;
1747 struct dwrite_font_propvec req;
1748 struct dwrite_fontlist *fonts;
1749 UINT32 i;
1751 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1753 *ret = NULL;
1755 fonts = heap_alloc(sizeof(*fonts));
1756 if (!fonts)
1757 return E_OUTOFMEMORY;
1759 /* Allocate as many as family has, not all of them will be necessary used. */
1760 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1761 if (!fonts->fonts) {
1762 heap_free(fonts);
1763 return E_OUTOFMEMORY;
1766 fonts->IDWriteFontList_iface.lpVtbl = &dwritefontlistvtbl;
1767 fonts->ref = 1;
1768 fonts->family = iface;
1769 IDWriteFontFamily_AddRef(fonts->family);
1770 fonts->font_count = 0;
1772 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1773 if (style == DWRITE_FONT_STYLE_NORMAL) {
1774 if (This->data->has_normal_face || This->data->has_italic_face)
1775 func = is_font_acceptable_for_normal;
1777 else /* requested oblique or italic */ {
1778 if (This->data->has_oblique_face || This->data->has_italic_face)
1779 func = is_font_acceptable_for_oblique_italic;
1782 for (i = 0; i < This->data->font_count; i++) {
1783 if (!func || func(This->data->fonts[i])) {
1784 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1785 InterlockedIncrement(&This->data->fonts[i]->ref);
1786 fonts->font_count++;
1790 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1791 init_font_prop_vec(weight, stretch, style, &req);
1792 matchingfonts_sort(fonts, &req);
1794 *ret = &fonts->IDWriteFontList_iface;
1795 return S_OK;
1798 static const IDWriteFontFamilyVtbl fontfamilyvtbl = {
1799 dwritefontfamily_QueryInterface,
1800 dwritefontfamily_AddRef,
1801 dwritefontfamily_Release,
1802 dwritefontfamily_GetFontCollection,
1803 dwritefontfamily_GetFontCount,
1804 dwritefontfamily_GetFont,
1805 dwritefontfamily_GetFamilyNames,
1806 dwritefontfamily_GetFirstMatchingFont,
1807 dwritefontfamily_GetMatchingFonts
1810 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily **family)
1812 struct dwrite_fontfamily *This;
1814 *family = NULL;
1816 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1817 if (!This) return E_OUTOFMEMORY;
1819 This->IDWriteFontFamily_iface.lpVtbl = &fontfamilyvtbl;
1820 This->ref = 1;
1821 This->collection = collection;
1822 IDWriteFontCollection_AddRef(collection);
1823 This->data = data;
1824 InterlockedIncrement(&This->data->ref);
1826 *family = &This->IDWriteFontFamily_iface;
1828 return S_OK;
1831 BOOL is_system_collection(IDWriteFontCollection *collection)
1833 void *obj;
1834 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1837 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection *iface, REFIID riid, void **obj)
1839 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1840 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1842 if (IsEqualIID(riid, &IID_IUnknown) ||
1843 IsEqualIID(riid, &IID_IDWriteFontCollection))
1845 *obj = iface;
1846 IDWriteFontCollection_AddRef(iface);
1847 return S_OK;
1850 *obj = NULL;
1852 if (This->is_system && IsEqualIID(riid, &IID_issystemcollection))
1853 return S_OK;
1855 return E_NOINTERFACE;
1858 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection *iface)
1860 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1861 ULONG ref = InterlockedIncrement(&This->ref);
1862 TRACE("(%p)->(%d)\n", This, ref);
1863 return ref;
1866 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection *iface)
1868 unsigned int i;
1869 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1870 ULONG ref = InterlockedDecrement(&This->ref);
1871 TRACE("(%p)->(%d)\n", This, ref);
1873 if (!ref) {
1874 for (i = 0; i < This->family_count; i++)
1875 release_fontfamily_data(This->family_data[i]);
1876 heap_free(This->family_data);
1877 heap_free(This);
1880 return ref;
1883 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
1885 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1886 TRACE("(%p)\n", This);
1887 return This->family_count;
1890 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
1892 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1894 TRACE("(%p)->(%u %p)\n", This, index, family);
1896 if (index >= This->family_count) {
1897 *family = NULL;
1898 return E_FAIL;
1901 return create_fontfamily(This->family_data[index], iface, family);
1904 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
1906 UINT32 i;
1908 for (i = 0; i < collection->family_count; i++) {
1909 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
1910 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
1911 HRESULT hr;
1913 for (j = 0; j < count; j++) {
1914 WCHAR buffer[255];
1915 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
1916 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
1917 return i;
1921 return ~0u;
1924 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
1926 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1927 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
1928 *index = collection_find_family(This, name);
1929 *exists = *index != ~0u;
1930 return S_OK;
1933 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
1935 UINT32 left_key_size, right_key_size;
1936 const void *left_key, *right_key;
1937 HRESULT hr;
1939 if (left == right)
1940 return TRUE;
1942 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
1943 if (FAILED(hr))
1944 return FALSE;
1946 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
1947 if (FAILED(hr))
1948 return FALSE;
1950 if (left_key_size != right_key_size)
1951 return FALSE;
1953 return !memcmp(left_key, right_key, left_key_size);
1956 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
1958 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1959 struct dwrite_fontfamily_data *found_family = NULL;
1960 struct dwrite_font_data *found_font = NULL;
1961 IDWriteFontFamily *family;
1962 UINT32 i, j, face_index;
1963 IDWriteFontFile *file;
1964 HRESULT hr;
1966 TRACE("(%p)->(%p %p)\n", This, face, font);
1968 *font = NULL;
1970 if (!face)
1971 return E_INVALIDARG;
1973 i = 1;
1974 hr = IDWriteFontFace_GetFiles(face, &i, &file);
1975 if (FAILED(hr))
1976 return hr;
1977 face_index = IDWriteFontFace_GetIndex(face);
1979 for (i = 0; i < This->family_count; i++) {
1980 struct dwrite_fontfamily_data *family_data = This->family_data[i];
1981 for (j = 0; j < family_data->font_count; j++) {
1982 struct dwrite_font_data *font_data = family_data->fonts[j];
1984 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
1985 found_font = font_data;
1986 found_family = family_data;
1987 break;
1992 if (!found_font)
1993 return DWRITE_E_NOFONT;
1995 hr = create_fontfamily(found_family, iface, &family);
1996 if (FAILED(hr))
1997 return hr;
1999 hr = create_font(found_font, family, font);
2000 IDWriteFontFamily_Release(family);
2001 return hr;
2004 static const IDWriteFontCollectionVtbl fontcollectionvtbl = {
2005 dwritefontcollection_QueryInterface,
2006 dwritefontcollection_AddRef,
2007 dwritefontcollection_Release,
2008 dwritefontcollection_GetFontFamilyCount,
2009 dwritefontcollection_GetFontFamily,
2010 dwritefontcollection_FindFamilyName,
2011 dwritefontcollection_GetFontFromFontFace
2014 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2016 if (family_data->font_count + 1 >= family_data->font_alloc) {
2017 struct dwrite_font_data **new_list;
2018 UINT32 new_alloc;
2020 new_alloc = family_data->font_alloc * 2;
2021 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2022 if (!new_list)
2023 return E_OUTOFMEMORY;
2024 family_data->fonts = new_list;
2025 family_data->font_alloc = new_alloc;
2028 family_data->fonts[family_data->font_count] = font_data;
2029 family_data->font_count++;
2030 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2031 family_data->has_normal_face = TRUE;
2032 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2033 family_data->has_oblique_face = TRUE;
2034 else
2035 family_data->has_italic_face = TRUE;
2036 return S_OK;
2039 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2041 if (collection->family_alloc < collection->family_count + 1) {
2042 struct dwrite_fontfamily_data **new_list;
2043 UINT32 new_alloc;
2045 new_alloc = collection->family_alloc * 2;
2046 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2047 if (!new_list)
2048 return E_OUTOFMEMORY;
2050 collection->family_alloc = new_alloc;
2051 collection->family_data = new_list;
2054 collection->family_data[collection->family_count] = family;
2055 collection->family_count++;
2057 return S_OK;
2060 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2062 collection->IDWriteFontCollection_iface.lpVtbl = &fontcollectionvtbl;
2063 collection->ref = 1;
2064 collection->family_count = 0;
2065 collection->family_alloc = is_system ? 30 : 5;
2066 collection->is_system = is_system;
2068 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2069 if (!collection->family_data)
2070 return E_OUTOFMEMORY;
2072 return S_OK;
2075 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2077 IDWriteFontFileLoader *loader;
2078 const void *key;
2079 UINT32 key_size;
2080 HRESULT hr;
2082 *stream = NULL;
2084 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2085 if (FAILED(hr))
2086 return hr;
2088 hr = IDWriteFontFile_GetLoader(file, &loader);
2089 if (FAILED(hr))
2090 return hr;
2092 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2093 IDWriteFontFileLoader_Release(loader);
2094 if (FAILED(hr))
2095 return hr;
2097 return hr;
2100 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2102 BOOL exists = FALSE;
2103 UINT32 index;
2104 HRESULT hr;
2106 buffer[0] = 0;
2107 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2108 if (FAILED(hr) || !exists)
2109 return;
2111 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2114 static int trim_spaces(WCHAR *in, WCHAR *ret)
2116 int len;
2118 while (isspaceW(*in))
2119 in++;
2121 ret[0] = 0;
2122 if (!(len = strlenW(in)))
2123 return 0;
2125 while (isspaceW(in[len-1]))
2126 len--;
2128 memcpy(ret, in, len*sizeof(WCHAR));
2129 ret[len] = 0;
2131 return len;
2134 struct name_token {
2135 struct list entry;
2136 const WCHAR *ptr;
2137 INT len; /* token length */
2138 INT fulllen; /* full length including following separators */
2141 static inline BOOL is_name_separator_char(WCHAR ch)
2143 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2146 struct name_pattern {
2147 const WCHAR *part1; /* NULL indicates end of list */
2148 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2151 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2153 const struct name_pattern *pattern;
2154 struct name_token *token;
2155 int i = 0;
2157 while ((pattern = &patterns[i++])->part1) {
2158 int len_part1 = strlenW(pattern->part1);
2159 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2161 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2162 if (len_part2 == 0) {
2163 /* simple case with single part pattern */
2164 if (token->len != len_part1)
2165 continue;
2167 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2168 if (match) *match = *token;
2169 list_remove(&token->entry);
2170 heap_free(token);
2171 return TRUE;
2174 else {
2175 struct name_token *next_token;
2176 struct list *next_entry;
2178 /* pattern parts are stored in reading order, tokens list is reversed */
2179 if (token->len < len_part2)
2180 continue;
2182 /* it's possible to have combined string as a token, like ExtraCondensed */
2183 if (token->len == len_part1 + len_part2) {
2184 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2185 continue;
2187 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2188 continue;
2190 /* combined string match */
2191 if (match) *match = *token;
2192 list_remove(&token->entry);
2193 heap_free(token);
2194 return TRUE;
2197 /* now it's only possible to have two tokens matched to respective pattern parts */
2198 if (token->len != len_part2)
2199 continue;
2201 next_entry = list_next(tokens, &token->entry);
2202 if (next_entry) {
2203 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2204 if (next_token->len != len_part1)
2205 continue;
2207 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2208 continue;
2210 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2211 continue;
2213 /* both parts matched, remove tokens */
2214 if (match) {
2215 match->ptr = next_token->ptr;
2216 match->len = (token->ptr - next_token->ptr) + token->len;
2218 list_remove(&token->entry);
2219 list_remove(&next_token->entry);
2220 heap_free(next_token);
2221 heap_free(token);
2222 return TRUE;
2228 if (match) {
2229 match->ptr = NULL;
2230 match->len = 0;
2232 return FALSE;
2235 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2237 static const WCHAR itaW[] = {'i','t','a',0};
2238 static const WCHAR italW[] = {'i','t','a','l',0};
2239 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2240 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2242 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2243 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2244 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2245 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2247 static const struct name_pattern italic_patterns[] = {
2248 { itaW },
2249 { italW },
2250 { italicW },
2251 { cursiveW },
2252 { kursivW },
2253 { NULL }
2256 static const struct name_pattern oblique_patterns[] = {
2257 { inclinedW },
2258 { obliqueW },
2259 { backslantedW },
2260 { backslantW },
2261 { slantedW },
2262 { NULL }
2265 /* italic patterns first */
2266 if (match_pattern_list(tokens, italic_patterns, match))
2267 return DWRITE_FONT_STYLE_ITALIC;
2269 /* oblique patterns */
2270 if (match_pattern_list(tokens, oblique_patterns, match))
2271 return DWRITE_FONT_STYLE_OBLIQUE;
2273 return style;
2276 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2277 struct name_token *match)
2279 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2280 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2281 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2282 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2283 static const WCHAR wideW[] = {'w','i','d','e',0};
2284 static const WCHAR condW[] = {'c','o','n','d',0};
2286 static const struct name_pattern ultracondensed_patterns[] = {
2287 { extraW, compressedW },
2288 { extW, compressedW },
2289 { ultraW, compressedW },
2290 { ultraW, condensedW },
2291 { ultraW, condW },
2292 { NULL }
2295 static const struct name_pattern extracondensed_patterns[] = {
2296 { compressedW },
2297 { extraW, condensedW },
2298 { extW, condensedW },
2299 { extraW, condW },
2300 { extW, condW },
2301 { NULL }
2304 static const struct name_pattern semicondensed_patterns[] = {
2305 { narrowW },
2306 { compactW },
2307 { semiW, condensedW },
2308 { semiW, condW },
2309 { NULL }
2312 static const struct name_pattern semiexpanded_patterns[] = {
2313 { wideW },
2314 { semiW, expandedW },
2315 { semiW, extendedW },
2316 { NULL }
2319 static const struct name_pattern extraexpanded_patterns[] = {
2320 { extraW, expandedW },
2321 { extW, expandedW },
2322 { extraW, extendedW },
2323 { extW, extendedW },
2324 { NULL }
2327 static const struct name_pattern ultraexpanded_patterns[] = {
2328 { ultraW, expandedW },
2329 { ultraW, extendedW },
2330 { NULL }
2333 static const struct name_pattern condensed_patterns[] = {
2334 { condensedW },
2335 { condW },
2336 { NULL }
2339 static const struct name_pattern expanded_patterns[] = {
2340 { expandedW },
2341 { extendedW },
2342 { NULL }
2345 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2346 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2348 if (match_pattern_list(tokens, extracondensed_patterns, match))
2349 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2351 if (match_pattern_list(tokens, semicondensed_patterns, match))
2352 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2354 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2355 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2357 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2358 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2360 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2361 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2363 if (match_pattern_list(tokens, condensed_patterns, match))
2364 return DWRITE_FONT_STRETCH_CONDENSED;
2366 if (match_pattern_list(tokens, expanded_patterns, match))
2367 return DWRITE_FONT_STRETCH_EXPANDED;
2369 return stretch;
2372 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2373 struct name_token *match)
2375 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2376 static const WCHAR nordW[] = {'n','o','r','d',0};
2378 static const struct name_pattern thin_patterns[] = {
2379 { extraW, thinW },
2380 { extW, thinW },
2381 { ultraW, thinW },
2382 { NULL }
2385 static const struct name_pattern extralight_patterns[] = {
2386 { extraW, lightW },
2387 { extW, lightW },
2388 { ultraW, lightW },
2389 { NULL }
2392 static const struct name_pattern semilight_patterns[] = {
2393 { semiW, lightW },
2394 { NULL }
2397 static const struct name_pattern demibold_patterns[] = {
2398 { semiW, boldW },
2399 { demiW, boldW },
2400 { NULL }
2403 static const struct name_pattern extrabold_patterns[] = {
2404 { extraW, boldW },
2405 { extW, boldW },
2406 { ultraW, boldW },
2407 { NULL }
2410 static const struct name_pattern extrablack_patterns[] = {
2411 { extraW, blackW },
2412 { extW, blackW },
2413 { ultraW, blackW },
2414 { NULL }
2417 static const struct name_pattern bold_patterns[] = {
2418 { boldW },
2419 { NULL }
2422 static const struct name_pattern thin2_patterns[] = {
2423 { thinW },
2424 { NULL }
2427 static const struct name_pattern light_patterns[] = {
2428 { lightW },
2429 { NULL }
2432 static const struct name_pattern medium_patterns[] = {
2433 { mediumW },
2434 { NULL }
2437 static const struct name_pattern black_patterns[] = {
2438 { blackW },
2439 { heavyW },
2440 { nordW },
2441 { NULL }
2444 static const struct name_pattern demibold2_patterns[] = {
2445 { demiW },
2446 { NULL }
2449 static const struct name_pattern extrabold2_patterns[] = {
2450 { ultraW },
2451 { NULL }
2454 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2455 matching pattern. */
2457 if (match_pattern_list(tokens, thin_patterns, match))
2458 return DWRITE_FONT_WEIGHT_THIN;
2460 if (match_pattern_list(tokens, extralight_patterns, match))
2461 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2463 if (match_pattern_list(tokens, semilight_patterns, match))
2464 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2466 if (match_pattern_list(tokens, demibold_patterns, match))
2467 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2469 if (match_pattern_list(tokens, extrabold_patterns, match))
2470 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2472 if (match_pattern_list(tokens, extrablack_patterns, match))
2473 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2475 if (match_pattern_list(tokens, bold_patterns, match))
2476 return DWRITE_FONT_WEIGHT_BOLD;
2478 if (match_pattern_list(tokens, thin2_patterns, match))
2479 return DWRITE_FONT_WEIGHT_THIN;
2481 if (match_pattern_list(tokens, light_patterns, match))
2482 return DWRITE_FONT_WEIGHT_LIGHT;
2484 if (match_pattern_list(tokens, medium_patterns, match))
2485 return DWRITE_FONT_WEIGHT_MEDIUM;
2487 if (match_pattern_list(tokens, black_patterns, match))
2488 return DWRITE_FONT_WEIGHT_BLACK;
2490 if (match_pattern_list(tokens, black_patterns, match))
2491 return DWRITE_FONT_WEIGHT_BLACK;
2493 if (match_pattern_list(tokens, demibold2_patterns, match))
2494 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2496 if (match_pattern_list(tokens, extrabold2_patterns, match))
2497 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2499 /* FIXME: use abbreviated names to extract weight */
2501 return weight;
2504 struct knownweight_entry {
2505 const WCHAR *nameW;
2506 DWRITE_FONT_WEIGHT weight;
2509 static int compare_knownweights(const void *a, const void* b)
2511 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2512 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2513 int ret = 0;
2515 if (target > entry->weight)
2516 ret = 1;
2517 else if (target < entry->weight)
2518 ret = -1;
2520 return ret;
2523 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2525 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2526 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2527 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2528 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2529 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2530 const struct knownweight_entry *ptr;
2532 static const struct knownweight_entry knownweights[] = {
2533 { thinW, DWRITE_FONT_WEIGHT_THIN },
2534 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2535 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2536 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2537 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2538 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2539 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2540 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2541 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2542 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2545 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2546 compare_knownweights);
2547 if (!ptr) {
2548 nameW[0] = 0;
2549 return FALSE;
2552 strcpyW(nameW, ptr->nameW);
2553 return TRUE;
2556 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2558 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2559 strW[name->len] = 0;
2562 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2563 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2565 static const WCHAR bookW[] = {'B','o','o','k',0};
2566 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2567 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2568 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2569 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2571 static const WCHAR *regular_patterns[] = {
2572 bookW,
2573 normalW,
2574 regularW,
2575 romanW,
2576 uprightW,
2577 NULL
2580 const WCHAR *regular_ptr = NULL, *ptr;
2581 int i = 0;
2583 if (len == -1)
2584 len = strlenW(facenameW);
2586 /* remove rightmost regular variant from face name */
2587 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2588 int pattern_len = strlenW(ptr);
2589 WCHAR *src;
2591 if (pattern_len > len)
2592 continue;
2594 src = facenameW + len - pattern_len;
2595 while (src >= facenameW) {
2596 if (!strncmpiW(src, ptr, pattern_len)) {
2597 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2598 len = strlenW(facenameW);
2599 regular_ptr = ptr;
2600 break;
2602 else
2603 src--;
2607 return regular_ptr;
2610 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2612 const WCHAR *ptr;
2614 list_init(tokens);
2615 ptr = nameW;
2617 while (*ptr) {
2618 struct name_token *token = heap_alloc(sizeof(*token));
2619 token->ptr = ptr;
2620 token->len = 0;
2621 token->fulllen = 0;
2623 while (*ptr && !is_name_separator_char(*ptr)) {
2624 token->len++;
2625 token->fulllen++;
2626 ptr++;
2629 /* skip separators */
2630 while (is_name_separator_char(*ptr)) {
2631 token->fulllen++;
2632 ptr++;
2635 list_add_head(tokens, &token->entry);
2639 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2641 struct name_token *token, *token2;
2642 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2643 int len;
2645 list_remove(&token->entry);
2647 /* don't include last separator */
2648 len = list_empty(tokens) ? token->len : token->fulllen;
2649 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2650 nameW += len;
2652 heap_free(token);
2654 *nameW = 0;
2657 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2659 struct name_token stretch_name, weight_name, style_name;
2660 WCHAR familynameW[255], facenameW[255], finalW[255];
2661 WCHAR weightW[32], stretchW[32], styleW[32];
2662 const WCHAR *regular_ptr = NULL;
2663 DWRITE_FONT_STRETCH stretch;
2664 DWRITE_FONT_WEIGHT weight;
2665 struct list tokens;
2666 int len;
2668 /* remove leading and trailing spaces from family and face name */
2669 trim_spaces(familyW, familynameW);
2670 len = trim_spaces(faceW, facenameW);
2672 /* remove rightmost regular variant from face name */
2673 regular_ptr = facename_remove_regular_term(facenameW, len);
2675 /* append face name to family name, FIXME check if face name is a substring of family name */
2676 if (*facenameW) {
2677 strcatW(familynameW, spaceW);
2678 strcatW(familynameW, facenameW);
2681 /* tokenize with " .-_" */
2682 fontname_tokenize(&tokens, familynameW);
2684 /* extract and resolve style */
2685 font->style = font_extract_style(&tokens, font->style, &style_name);
2687 /* extract stretch */
2688 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2690 /* extract weight */
2691 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2693 /* resolve weight */
2694 if (weight != font->weight) {
2695 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2696 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2697 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2698 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2699 !(abs(weight - font->weight) <= 150 &&
2700 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2701 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2702 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2704 font->weight = weight;
2708 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2709 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2710 stretch itself is normal (extracted stretch is never normal). */
2711 if (stretch != font->stretch) {
2712 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2713 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2714 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2716 font->stretch = stretch;
2720 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2722 /* get final combined string from what's left in token list, list is released */
2723 fontname_tokens_to_str(&tokens, finalW);
2725 if (!strcmpW(familyW, finalW))
2726 return FALSE;
2728 /* construct face name */
2729 strcpyW(familyW, finalW);
2731 /* resolved weight name */
2732 if (weight_name.ptr)
2733 font_name_token_to_str(&weight_name, weightW);
2734 /* ignore normal weight */
2735 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2736 weightW[0] = 0;
2737 /* for known weight values use appropriate names */
2738 else if (is_known_weight_value(font->weight, weightW)) {
2740 /* use Wnnn format as a fallback in case weight is not one of defined values */
2741 else {
2742 static const WCHAR fmtW[] = {'W','%','d',0};
2743 sprintfW(weightW, fmtW, font->weight);
2746 /* resolved stretch name */
2747 if (stretch_name.ptr)
2748 font_name_token_to_str(&stretch_name, stretchW);
2749 /* ignore normal stretch */
2750 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2751 stretchW[0] = 0;
2752 /* use predefined stretch names */
2753 else {
2754 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2755 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2756 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2757 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2758 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2759 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2761 static const WCHAR *stretchnamesW[] = {
2762 ultracondensedW,
2763 extracondensedW,
2764 condensedW,
2765 semicondensedW,
2766 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
2767 semiexpandedW,
2768 expandedW,
2769 extraexpandedW,
2770 ultraexpandedW
2772 strcpyW(stretchW, stretchnamesW[font->stretch]);
2775 /* resolved style name */
2776 if (style_name.ptr)
2777 font_name_token_to_str(&style_name, styleW);
2778 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
2779 styleW[0] = 0;
2780 /* use predefined names */
2781 else {
2782 if (font->style == DWRITE_FONT_STYLE_ITALIC)
2783 strcpyW(styleW, italicW);
2784 else
2785 strcpyW(styleW, obliqueW);
2788 /* use Regular match if it was found initially */
2789 if (!*weightW && !*stretchW && !*styleW)
2790 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
2791 else {
2792 faceW[0] = 0;
2793 if (*stretchW)
2794 strcpyW(faceW, stretchW);
2795 if (*weightW) {
2796 if (*faceW)
2797 strcatW(faceW, spaceW);
2798 strcatW(faceW, weightW);
2800 if (*styleW) {
2801 if (*faceW)
2802 strcatW(faceW, spaceW);
2803 strcatW(faceW, styleW);
2807 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
2808 return TRUE;
2811 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
2812 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
2814 struct dwrite_font_props props;
2815 struct dwrite_font_data *data;
2816 IDWriteFontFileStream *stream;
2817 WCHAR familyW[255], faceW[255];
2818 HRESULT hr;
2820 *ret = NULL;
2821 data = heap_alloc_zero(sizeof(*data));
2822 if (!data)
2823 return E_OUTOFMEMORY;
2825 hr = get_filestream_from_file(file, &stream);
2826 if (FAILED(hr)) {
2827 heap_free(data);
2828 return hr;
2831 data->ref = 1;
2832 data->factory = factory;
2833 data->file = file;
2834 data->face_index = face_index;
2835 data->face_type = face_type;
2836 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
2837 data->bold_sim_tested = FALSE;
2838 data->oblique_sim_tested = FALSE;
2839 IDWriteFontFile_AddRef(file);
2840 IDWriteFactory2_AddRef(factory);
2842 opentype_get_font_properties(stream, face_type, face_index, &props);
2843 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
2844 opentype_get_font_facename(stream, face_type, face_index, &data->names);
2846 /* get family name from font file */
2847 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
2848 IDWriteFontFileStream_Release(stream);
2849 if (FAILED(hr)) {
2850 WARN("unable to get family name from font\n");
2851 release_font_data(data);
2852 return hr;
2855 data->style = props.style;
2856 data->stretch = props.stretch;
2857 data->weight = props.weight;
2858 data->panose = props.panose;
2860 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
2861 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
2862 if (font_apply_differentiation_rules(data, familyW, faceW)) {
2863 set_en_localizedstring(*family_name, familyW);
2864 set_en_localizedstring(data->names, faceW);
2867 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2869 *ret = data;
2870 return S_OK;
2873 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
2874 struct dwrite_font_data **ret)
2876 struct dwrite_font_data *data;
2878 *ret = NULL;
2879 data = heap_alloc_zero(sizeof(*data));
2880 if (!data)
2881 return E_OUTOFMEMORY;
2883 *data = *src;
2884 data->ref = 1;
2885 data->simulations |= sim;
2886 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
2887 data->weight = DWRITE_FONT_WEIGHT_BOLD;
2888 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
2889 data->style = DWRITE_FONT_STYLE_OBLIQUE;
2890 memset(data->info_strings, 0, sizeof(data->info_strings));
2891 data->names = NULL;
2892 IDWriteFactory2_AddRef(data->factory);
2893 IDWriteFontFile_AddRef(data->file);
2895 create_localizedstrings(&data->names);
2896 add_localizedstring(data->names, enusW, facenameW);
2898 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2900 *ret = data;
2901 return S_OK;
2904 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
2906 struct dwrite_fontfamily_data *data;
2908 data = heap_alloc(sizeof(*data));
2909 if (!data)
2910 return E_OUTOFMEMORY;
2912 data->ref = 1;
2913 data->font_count = 0;
2914 data->font_alloc = 2;
2915 data->has_normal_face = FALSE;
2916 data->has_oblique_face = FALSE;
2917 data->has_italic_face = FALSE;
2919 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
2920 if (!data->fonts) {
2921 heap_free(data);
2922 return E_OUTOFMEMORY;
2925 data->familyname = familyname;
2926 IDWriteLocalizedStrings_AddRef(familyname);
2928 *ret = data;
2929 return S_OK;
2932 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
2934 UINT32 i, j, heaviest;
2936 for (i = 0; i < family->font_count; i++) {
2937 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
2938 heaviest = i;
2940 if (family->fonts[i]->bold_sim_tested)
2941 continue;
2943 family->fonts[i]->bold_sim_tested = TRUE;
2944 for (j = i; j < family->font_count; j++) {
2945 if (family->fonts[j]->bold_sim_tested)
2946 continue;
2948 if ((family->fonts[i]->style == family->fonts[j]->style) &&
2949 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
2950 if (family->fonts[j]->weight > weight) {
2951 weight = family->fonts[j]->weight;
2952 heaviest = j;
2954 family->fonts[j]->bold_sim_tested = TRUE;
2958 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
2959 static const struct name_pattern weightsim_patterns[] = {
2960 { extraW, lightW },
2961 { extW, lightW },
2962 { ultraW, lightW },
2963 { semiW, lightW },
2964 { semiW, boldW },
2965 { demiW, boldW },
2966 { boldW },
2967 { thinW },
2968 { lightW },
2969 { mediumW },
2970 { demiW },
2971 { NULL }
2974 WCHAR facenameW[255], initialW[255];
2975 struct dwrite_font_data *boldface;
2976 struct list tokens;
2978 /* add Bold simulation based on heaviest face data */
2980 /* Simulated face name should only contain Bold as weight term,
2981 so remove existing regular and weight terms. */
2982 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
2983 facename_remove_regular_term(initialW, -1);
2985 /* remove current weight pattern */
2986 fontname_tokenize(&tokens, initialW);
2987 match_pattern_list(&tokens, weightsim_patterns, NULL);
2988 fontname_tokens_to_str(&tokens, facenameW);
2990 /* Bold suffix for new name */
2991 if (*facenameW)
2992 strcatW(facenameW, spaceW);
2993 strcatW(facenameW, boldW);
2995 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
2996 boldface->bold_sim_tested = TRUE;
2997 fontfamily_add_font(family, boldface);
3003 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3005 UINT32 i, j;
3007 for (i = 0; i < family->font_count; i++) {
3008 UINT32 regular = ~0u, oblique = ~0u;
3009 struct dwrite_font_data *obliqueface;
3010 WCHAR facenameW[255];
3012 if (family->fonts[i]->oblique_sim_tested)
3013 continue;
3015 family->fonts[i]->oblique_sim_tested = TRUE;
3016 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3017 regular = i;
3018 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3019 oblique = i;
3021 /* find regular style with same weight/stretch values */
3022 for (j = i; j < family->font_count; j++) {
3023 if (family->fonts[j]->oblique_sim_tested)
3024 continue;
3026 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3027 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3029 family->fonts[j]->oblique_sim_tested = TRUE;
3030 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3031 regular = j;
3033 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3034 oblique = j;
3037 if (regular != ~0u && oblique != ~0u)
3038 break;
3041 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3042 if (regular == ~0u)
3043 continue;
3045 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3046 if (oblique != ~0u)
3047 continue;
3049 /* add oblique simulation based on this regular face */
3051 /* remove regular term if any, append 'Oblique' */
3052 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3053 facename_remove_regular_term(facenameW, -1);
3055 if (*facenameW)
3056 strcatW(facenameW, spaceW);
3057 strcatW(facenameW, obliqueW);
3059 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3060 obliqueface->oblique_sim_tested = TRUE;
3061 fontfamily_add_font(family, obliqueface);
3066 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3068 struct fontfile_enum {
3069 struct list entry;
3070 IDWriteFontFile *file;
3072 struct fontfile_enum *fileenum, *fileenum2;
3073 struct dwrite_fontcollection *collection;
3074 struct list scannedfiles;
3075 BOOL current = FALSE;
3076 HRESULT hr = S_OK;
3077 UINT32 i;
3079 *ret = NULL;
3081 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3082 if (!collection) return E_OUTOFMEMORY;
3084 hr = init_font_collection(collection, is_system);
3085 if (FAILED(hr)) {
3086 heap_free(collection);
3087 return hr;
3090 *ret = &collection->IDWriteFontCollection_iface;
3092 TRACE("building font collection:\n");
3094 list_init(&scannedfiles);
3095 while (hr == S_OK) {
3096 DWRITE_FONT_FACE_TYPE face_type;
3097 DWRITE_FONT_FILE_TYPE file_type;
3098 BOOL supported, same = FALSE;
3099 IDWriteFontFile *file;
3100 UINT32 face_count;
3102 current = FALSE;
3103 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3104 if (FAILED(hr) || !current)
3105 break;
3107 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3108 if (FAILED(hr))
3109 break;
3111 /* check if we've scanned this file already */
3112 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3113 if ((same = is_same_fontfile(fileenum->file, file)))
3114 break;
3117 if (same) {
3118 IDWriteFontFile_Release(file);
3119 continue;
3122 /* failed font files are skipped */
3123 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3124 if (FAILED(hr) || !supported || face_count == 0) {
3125 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3126 IDWriteFontFile_Release(file);
3127 hr = S_OK;
3128 continue;
3131 /* add to scanned list */
3132 fileenum = heap_alloc(sizeof(*fileenum));
3133 fileenum->file = file;
3134 list_add_tail(&scannedfiles, &fileenum->entry);
3136 for (i = 0; i < face_count; i++) {
3137 IDWriteLocalizedStrings *family_name = NULL;
3138 struct dwrite_font_data *font_data;
3139 WCHAR familyW[255];
3140 UINT32 index;
3142 /* alloc and init new font data structure */
3143 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3144 if (FAILED(hr))
3145 continue;
3147 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3149 index = collection_find_family(collection, familyW);
3150 if (index != ~0u)
3151 hr = fontfamily_add_font(collection->family_data[index], font_data);
3152 else {
3153 struct dwrite_fontfamily_data *family_data;
3155 /* create and init new family */
3156 hr = init_fontfamily_data(family_name, &family_data);
3157 if (hr == S_OK) {
3158 /* add font to family, family - to collection */
3159 hr = fontfamily_add_font(family_data, font_data);
3160 if (hr == S_OK)
3161 hr = fontcollection_add_family(collection, family_data);
3163 if (FAILED(hr))
3164 release_fontfamily_data(family_data);
3168 IDWriteLocalizedStrings_Release(family_name);
3170 if (FAILED(hr))
3171 break;
3175 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3176 IDWriteFontFile_Release(fileenum->file);
3177 list_remove(&fileenum->entry);
3178 heap_free(fileenum);
3181 for (i = 0; i < collection->family_count; i++) {
3182 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3183 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3186 return hr;
3189 struct system_fontfile_enumerator
3191 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3192 LONG ref;
3194 IDWriteFactory2 *factory;
3195 HKEY hkey;
3196 int index;
3199 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3201 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3204 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3206 *obj = NULL;
3208 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3209 IDWriteFontFileEnumerator_AddRef(iface);
3210 *obj = iface;
3211 return S_OK;
3214 return E_NOINTERFACE;
3217 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3219 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3220 return InterlockedIncrement(&enumerator->ref);
3223 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3225 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3226 ULONG ref = InterlockedDecrement(&enumerator->ref);
3228 if (!ref) {
3229 IDWriteFactory2_Release(enumerator->factory);
3230 RegCloseKey(enumerator->hkey);
3231 heap_free(enumerator);
3234 return ref;
3237 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3239 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3240 DWORD ret, type, val_count, count;
3241 WCHAR *value, *filename;
3242 HRESULT hr;
3244 *file = NULL;
3246 if (enumerator->index < 0)
3247 return E_FAIL;
3249 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3250 if (ret != ERROR_SUCCESS)
3251 return E_FAIL;
3253 val_count++;
3254 value = heap_alloc( val_count * sizeof(value[0]) );
3255 filename = heap_alloc(count);
3256 if (!value || !filename) {
3257 heap_free(value);
3258 heap_free(filename);
3259 return E_OUTOFMEMORY;
3262 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3263 if (ret) {
3264 heap_free(value);
3265 heap_free(filename);
3266 return E_FAIL;
3269 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3270 if (!strchrW(filename, '\\')) {
3271 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3272 WCHAR fullpathW[MAX_PATH];
3274 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3275 strcatW(fullpathW, fontsW);
3276 strcatW(fullpathW, filename);
3278 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, fullpathW, NULL, file);
3280 else
3281 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, filename, NULL, file);
3283 heap_free(value);
3284 heap_free(filename);
3285 return hr;
3288 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3290 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3291 DWORD ret, max_val_count;
3292 WCHAR *value;
3294 *current = FALSE;
3295 enumerator->index++;
3297 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3298 if (ret != ERROR_SUCCESS)
3299 return E_FAIL;
3301 max_val_count++;
3302 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3303 return E_OUTOFMEMORY;
3305 /* iterate until we find next string value */
3306 while (1) {
3307 DWORD type = 0, count, val_count;
3308 val_count = max_val_count;
3309 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3310 break;
3311 if (type == REG_SZ) {
3312 *current = TRUE;
3313 break;
3315 enumerator->index++;
3318 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3319 heap_free(value);
3320 return S_OK;
3323 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3325 systemfontfileenumerator_QueryInterface,
3326 systemfontfileenumerator_AddRef,
3327 systemfontfileenumerator_Release,
3328 systemfontfileenumerator_MoveNext,
3329 systemfontfileenumerator_GetCurrentFontFile
3332 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
3334 struct system_fontfile_enumerator *enumerator;
3335 static const WCHAR fontslistW[] = {
3336 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3337 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3338 'F','o','n','t','s',0
3341 *ret = NULL;
3343 enumerator = heap_alloc(sizeof(*enumerator));
3344 if (!enumerator)
3345 return E_OUTOFMEMORY;
3347 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3348 enumerator->ref = 1;
3349 enumerator->factory = factory;
3350 enumerator->index = -1;
3351 IDWriteFactory2_AddRef(factory);
3353 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3354 ERR("failed to open fonts list key\n");
3355 IDWriteFactory2_Release(factory);
3356 heap_free(enumerator);
3357 return E_FAIL;
3360 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3362 return S_OK;
3365 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3367 IDWriteFontFileEnumerator *enumerator;
3368 HRESULT hr;
3370 *collection = NULL;
3372 hr = create_system_fontfile_enumerator(factory, &enumerator);
3373 if (FAILED(hr))
3374 return hr;
3376 TRACE("building system font collection for factory %p\n", factory);
3377 hr = create_font_collection(factory, enumerator, TRUE, collection);
3378 IDWriteFontFileEnumerator_Release(enumerator);
3379 return hr;
3382 static HRESULT WINAPI eudcfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3384 *obj = NULL;
3386 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3387 IDWriteFontFileEnumerator_AddRef(iface);
3388 *obj = iface;
3389 return S_OK;
3392 return E_NOINTERFACE;
3395 static ULONG WINAPI eudcfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3397 return 2;
3400 static ULONG WINAPI eudcfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3402 return 1;
3405 static HRESULT WINAPI eudcfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3407 *file = NULL;
3408 return E_FAIL;
3411 static HRESULT WINAPI eudcfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3413 *current = FALSE;
3414 return S_OK;
3417 static const struct IDWriteFontFileEnumeratorVtbl eudcfontfileenumeratorvtbl =
3419 eudcfontfileenumerator_QueryInterface,
3420 eudcfontfileenumerator_AddRef,
3421 eudcfontfileenumerator_Release,
3422 eudcfontfileenumerator_MoveNext,
3423 eudcfontfileenumerator_GetCurrentFontFile
3426 static IDWriteFontFileEnumerator eudc_fontfile_enumerator = { &eudcfontfileenumeratorvtbl };
3428 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3430 TRACE("building EUDC font collection for factory %p\n", factory);
3431 return create_font_collection(factory, &eudc_fontfile_enumerator, FALSE, collection);
3434 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3436 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3438 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3440 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3442 *obj = iface;
3443 IDWriteFontFile_AddRef(iface);
3444 return S_OK;
3447 *obj = NULL;
3448 return E_NOINTERFACE;
3451 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3453 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3454 ULONG ref = InterlockedIncrement(&This->ref);
3455 TRACE("(%p)->(%d)\n", This, ref);
3456 return ref;
3459 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3461 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3462 ULONG ref = InterlockedDecrement(&This->ref);
3464 TRACE("(%p)->(%d)\n", This, ref);
3466 if (!ref)
3468 IDWriteFontFileLoader_Release(This->loader);
3469 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3470 heap_free(This->reference_key);
3471 heap_free(This);
3474 return ref;
3477 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3479 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3480 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3481 *fontFileReferenceKey = This->reference_key;
3482 *fontFileReferenceKeySize = This->key_size;
3484 return S_OK;
3487 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3489 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3490 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3491 *fontFileLoader = This->loader;
3492 IDWriteFontFileLoader_AddRef(This->loader);
3494 return S_OK;
3497 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType, DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3499 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3500 IDWriteFontFileStream *stream;
3501 HRESULT hr;
3503 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3505 *isSupportedFontType = FALSE;
3506 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3507 if (fontFaceType)
3508 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3509 *numberOfFaces = 0;
3511 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3512 if (FAILED(hr))
3513 return hr;
3515 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3517 /* TODO: Further Analysis */
3518 IDWriteFontFileStream_Release(stream);
3519 return S_OK;
3522 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3523 dwritefontfile_QueryInterface,
3524 dwritefontfile_AddRef,
3525 dwritefontfile_Release,
3526 dwritefontfile_GetReferenceKey,
3527 dwritefontfile_GetLoader,
3528 dwritefontfile_Analyze,
3531 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3533 struct dwrite_fontfile *This;
3535 This = heap_alloc(sizeof(struct dwrite_fontfile));
3536 if (!This) return E_OUTOFMEMORY;
3538 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3539 This->ref = 1;
3540 IDWriteFontFileLoader_AddRef(loader);
3541 This->loader = loader;
3542 This->stream = NULL;
3543 This->reference_key = heap_alloc(key_size);
3544 memcpy(This->reference_key, reference_key, key_size);
3545 This->key_size = key_size;
3547 *font_file = &This->IDWriteFontFile_iface;
3549 return S_OK;
3552 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3554 IDWriteFontFileLoader *loader;
3555 UINT32 key_size;
3556 const void *key;
3557 HRESULT hr;
3559 *stream = NULL;
3560 hr = IDWriteFontFile_GetLoader(file, &loader);
3561 if (FAILED(hr))
3562 return hr;
3564 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3565 if (FAILED(hr)) {
3566 IDWriteFontFileLoader_Release(loader);
3567 return hr;
3570 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3571 IDWriteFontFileLoader_Release(loader);
3573 return hr;
3576 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
3577 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace2 **ret)
3579 struct dwrite_fontface *fontface;
3580 HRESULT hr = S_OK;
3581 int i;
3583 *ret = NULL;
3585 fontface = heap_alloc(sizeof(struct dwrite_fontface));
3586 if (!fontface)
3587 return E_OUTOFMEMORY;
3589 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
3590 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
3592 if (!fontface->files || !fontface->streams) {
3593 heap_free(fontface->files);
3594 heap_free(fontface->streams);
3595 heap_free(fontface);
3596 return E_OUTOFMEMORY;
3599 fontface->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl;
3600 fontface->ref = 1;
3601 fontface->type = facetype;
3602 fontface->file_count = files_number;
3603 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
3604 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
3605 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
3606 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
3607 fontface->cmap.exists = TRUE;
3608 fontface->vdmx.exists = TRUE;
3609 fontface->gasp.exists = TRUE;
3610 fontface->cpal.exists = TRUE;
3611 fontface->index = index;
3612 fontface->simulations = simulations;
3613 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
3615 for (i = 0; i < fontface->file_count; i++) {
3616 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
3617 if (FAILED(hr)) {
3618 IDWriteFontFace2_Release(&fontface->IDWriteFontFace2_iface);
3619 return hr;
3622 fontface->files[i] = font_files[i];
3623 IDWriteFontFile_AddRef(font_files[i]);
3626 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
3627 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
3628 /* TODO: test what happens if caret is already slanted */
3629 if (fontface->caret.slopeRise == 1) {
3630 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
3631 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
3634 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace2_iface, &fontface->is_symbol);
3636 *ret = &fontface->IDWriteFontFace2_iface;
3637 return S_OK;
3640 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3641 struct local_refkey
3643 FILETIME writetime;
3644 WCHAR name[1];
3647 struct local_cached_stream
3649 struct list entry;
3650 IDWriteFontFileStream *stream;
3651 struct local_refkey *key;
3652 UINT32 key_size;
3655 struct dwrite_localfontfilestream
3657 IDWriteFontFileStream IDWriteFontFileStream_iface;
3658 LONG ref;
3660 struct local_cached_stream *entry;
3661 const void *file_ptr;
3662 UINT64 size;
3665 struct dwrite_localfontfileloader {
3666 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
3667 LONG ref;
3669 struct list streams;
3672 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
3674 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
3677 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
3679 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
3682 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
3684 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3685 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3686 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
3688 *obj = iface;
3689 IDWriteFontFileStream_AddRef(iface);
3690 return S_OK;
3693 *obj = NULL;
3694 return E_NOINTERFACE;
3697 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
3699 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3700 ULONG ref = InterlockedIncrement(&This->ref);
3701 TRACE("(%p)->(%d)\n", This, ref);
3702 return ref;
3705 static inline void release_cached_stream(struct local_cached_stream *stream)
3707 list_remove(&stream->entry);
3708 heap_free(stream->key);
3709 heap_free(stream);
3712 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
3714 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3715 ULONG ref = InterlockedDecrement(&This->ref);
3717 TRACE("(%p)->(%d)\n", This, ref);
3719 if (!ref) {
3720 UnmapViewOfFile(This->file_ptr);
3721 release_cached_stream(This->entry);
3722 heap_free(This);
3725 return ref;
3728 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
3730 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3732 TRACE("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
3733 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
3735 *fragment_context = NULL;
3737 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
3738 *fragment_start = NULL;
3739 return E_FAIL;
3742 *fragment_start = (char*)This->file_ptr + offset;
3743 return S_OK;
3746 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
3748 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3749 TRACE("(%p)->(%p)\n", This, fragment_context);
3752 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
3754 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3755 TRACE("(%p)->(%p)\n", This, size);
3756 *size = This->size;
3757 return S_OK;
3760 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
3762 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3763 ULARGE_INTEGER li;
3765 TRACE("(%p)->(%p)\n", This, last_writetime);
3767 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
3768 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
3769 *last_writetime = li.QuadPart;
3771 return S_OK;
3774 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
3776 localfontfilestream_QueryInterface,
3777 localfontfilestream_AddRef,
3778 localfontfilestream_Release,
3779 localfontfilestream_ReadFileFragment,
3780 localfontfilestream_ReleaseFileFragment,
3781 localfontfilestream_GetFileSize,
3782 localfontfilestream_GetLastWriteTime
3785 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream** iface)
3787 struct dwrite_localfontfilestream *This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
3788 if (!This)
3789 return E_OUTOFMEMORY;
3791 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
3792 This->ref = 1;
3794 This->file_ptr = file_ptr;
3795 This->size = size;
3796 This->entry = entry;
3798 *iface = &This->IDWriteFontFileStream_iface;
3799 return S_OK;
3802 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
3804 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3806 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3808 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
3810 *obj = iface;
3811 IDWriteLocalFontFileLoader_AddRef(iface);
3812 return S_OK;
3815 *obj = NULL;
3816 return E_NOINTERFACE;
3819 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
3821 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3822 ULONG ref = InterlockedIncrement(&This->ref);
3823 TRACE("(%p)->(%d)\n", This, ref);
3824 return ref;
3827 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
3829 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3830 ULONG ref = InterlockedDecrement(&This->ref);
3832 TRACE("(%p)->(%d)\n", This, ref);
3834 if (!ref) {
3835 struct local_cached_stream *stream, *stream2;
3837 /* This will detach all entries from cache. Entries are released together with streams,
3838 so stream controls its lifetime. */
3839 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
3840 list_init(&stream->entry);
3842 heap_free(This);
3845 return ref;
3848 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
3850 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3851 const struct local_refkey *refkey = key;
3852 struct local_cached_stream *stream;
3853 IDWriteFontFileStream *filestream;
3854 HANDLE file, mapping;
3855 LARGE_INTEGER size;
3856 void *file_ptr;
3857 HRESULT hr;
3859 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
3860 TRACE("name: %s\n", debugstr_w(refkey->name));
3862 /* search cache first */
3863 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
3864 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
3865 *ret = stream->stream;
3866 IDWriteFontFileStream_AddRef(*ret);
3867 return S_OK;
3871 *ret = NULL;
3873 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
3874 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3875 if (file == INVALID_HANDLE_VALUE)
3876 return E_FAIL;
3878 GetFileSizeEx(file, &size);
3879 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
3880 CloseHandle(file);
3881 if (!mapping)
3882 return E_FAIL;
3884 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3885 CloseHandle(mapping);
3887 stream = heap_alloc(sizeof(*stream));
3888 if (!stream) {
3889 UnmapViewOfFile(file_ptr);
3890 return E_OUTOFMEMORY;
3893 stream->key = heap_alloc(key_size);
3894 if (!stream->key) {
3895 UnmapViewOfFile(file_ptr);
3896 heap_free(stream);
3897 return E_OUTOFMEMORY;
3900 stream->key_size = key_size;
3901 memcpy(stream->key, key, key_size);
3903 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
3904 if (FAILED(hr)) {
3905 UnmapViewOfFile(file_ptr);
3906 heap_free(stream->key);
3907 heap_free(stream);
3908 return hr;
3911 stream->stream = filestream;
3912 list_add_head(&This->streams, &stream->entry);
3914 *ret = stream->stream;
3916 return S_OK;
3919 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
3921 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3922 const struct local_refkey *refkey = key;
3924 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
3926 *length = strlenW(refkey->name);
3927 return S_OK;
3930 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
3932 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3933 const struct local_refkey *refkey = key;
3935 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
3937 if (length < strlenW(refkey->name))
3938 return E_INVALIDARG;
3940 strcpyW(path, refkey->name);
3941 return S_OK;
3944 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
3946 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3947 const struct local_refkey *refkey = key;
3949 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
3951 *writetime = refkey->writetime;
3952 return S_OK;
3955 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
3956 localfontfileloader_QueryInterface,
3957 localfontfileloader_AddRef,
3958 localfontfileloader_Release,
3959 localfontfileloader_CreateStreamFromKey,
3960 localfontfileloader_GetFilePathLengthFromKey,
3961 localfontfileloader_GetFilePathFromKey,
3962 localfontfileloader_GetLastWriteTimeFromKey
3965 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface)
3967 struct dwrite_localfontfileloader *This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
3968 if (!This)
3969 return E_OUTOFMEMORY;
3971 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
3972 This->ref = 1;
3973 list_init(&This->streams);
3975 *iface = &This->IDWriteLocalFontFileLoader_iface;
3976 return S_OK;
3979 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
3981 struct local_refkey *refkey;
3983 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
3984 *key = NULL;
3986 refkey = heap_alloc(*size);
3987 if (!refkey)
3988 return E_OUTOFMEMORY;
3990 if (writetime)
3991 refkey->writetime = *writetime;
3992 else {
3993 WIN32_FILE_ATTRIBUTE_DATA info;
3995 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
3996 refkey->writetime = info.ftLastWriteTime;
3997 else
3998 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
4000 strcpyW(refkey->name, path);
4002 *key = refkey;
4004 return S_OK;
4007 /* IDWriteGlyphRunAnalysis */
4008 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4010 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4012 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4014 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4015 IsEqualIID(riid, &IID_IUnknown))
4017 *ppv = iface;
4018 IDWriteGlyphRunAnalysis_AddRef(iface);
4019 return S_OK;
4022 *ppv = NULL;
4023 return E_NOINTERFACE;
4026 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4028 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4029 ULONG ref = InterlockedIncrement(&This->ref);
4030 TRACE("(%p)->(%u)\n", This, ref);
4031 return ref;
4034 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4036 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4037 ULONG ref = InterlockedDecrement(&This->ref);
4039 TRACE("(%p)->(%u)\n", This, ref);
4041 if (!ref) {
4042 if (This->run.fontFace)
4043 IDWriteFontFace_Release(This->run.fontFace);
4044 heap_free(This->glyphs);
4045 heap_free(This->advances);
4046 heap_free(This->advanceoffsets);
4047 heap_free(This->ascenderoffsets);
4048 heap_free(This->bitmap);
4049 heap_free(This);
4052 return ref;
4055 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4057 struct dwrite_glyphbitmap glyph_bitmap;
4058 IDWriteFontFace2 *fontface2;
4059 D2D_POINT_2F origin;
4060 BOOL is_rtl;
4061 HRESULT hr;
4062 UINT32 i;
4064 if (analysis->flags & RUNANALYSIS_BOUNDS_READY) {
4065 *bounds = analysis->bounds;
4066 return;
4069 if (analysis->run.isSideways)
4070 FIXME("sideways runs are not supported.\n");
4072 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
4073 if (FAILED(hr))
4074 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
4076 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4077 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4078 for any non-zero glyph ascender */
4079 origin.x = origin.y = 0.0f;
4080 is_rtl = analysis->run.bidiLevel & 1;
4082 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4083 glyph_bitmap.fontface = fontface2;
4084 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4085 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4086 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4087 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4088 glyph_bitmap.m = &analysis->m;
4090 for (i = 0; i < analysis->run.glyphCount; i++) {
4091 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4092 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4093 const D2D_POINT_2F *advance = analysis->advances + i;
4094 RECT *bbox = &glyph_bitmap.bbox;
4096 glyph_bitmap.index = analysis->run.glyphIndices[i];
4097 freetype_get_glyph_bbox(&glyph_bitmap);
4099 if (is_rtl)
4100 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4101 else
4102 OffsetRect(bbox, origin.x, origin.y);
4104 if (advanceoffset)
4105 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4107 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4108 origin.x += advance->x;
4109 origin.y += advance->y;
4112 IDWriteFontFace2_Release(fontface2);
4114 /* translate to given run origin */
4115 OffsetRect(&analysis->bounds, analysis->origin.x, analysis->origin.y);
4116 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4117 OffsetRect(&analysis->bounds, analysis->m.dx, analysis->m.dy);
4119 analysis->flags |= RUNANALYSIS_BOUNDS_READY;
4120 *bounds = analysis->bounds;
4123 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4125 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4127 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4129 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4130 memset(bounds, 0, sizeof(*bounds));
4131 return E_INVALIDARG;
4134 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4135 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4136 memset(bounds, 0, sizeof(*bounds));
4137 return S_OK;
4140 glyphrunanalysis_get_texturebounds(This, bounds);
4141 return S_OK;
4144 static inline int get_dib_stride( int width, int bpp )
4146 return ((width * bpp + 31) >> 3) & ~3;
4149 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4151 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4152 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4153 (runbounds->left - bounds->left) * 3;
4154 else
4155 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4156 runbounds->left - bounds->left;
4159 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4161 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4162 struct dwrite_glyphbitmap glyph_bitmap;
4163 IDWriteFontFace2 *fontface2;
4164 D2D_POINT_2F origin;
4165 UINT32 i, size;
4166 BOOL is_rtl;
4167 HRESULT hr;
4168 RECT *bbox;
4170 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
4171 if (FAILED(hr)) {
4172 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
4173 return;
4176 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4177 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4178 size *= 3;
4179 analysis->bitmap = heap_alloc_zero(size);
4181 origin.x = origin.y = 0.0f;
4182 is_rtl = analysis->run.bidiLevel & 1;
4184 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4185 glyph_bitmap.fontface = fontface2;
4186 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4187 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4188 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4189 glyph_bitmap.type = type;
4190 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4191 glyph_bitmap.m = &analysis->m;
4192 bbox = &glyph_bitmap.bbox;
4194 for (i = 0; i < analysis->run.glyphCount; i++) {
4195 const D2D_POINT_2F *advanceoffset = analysis->advanceoffsets ? analysis->advanceoffsets + i : NULL;
4196 const D2D_POINT_2F *ascenderoffset = analysis->ascenderoffsets ? analysis->ascenderoffsets + i : NULL;
4197 const D2D_POINT_2F *advance = analysis->advances + i;
4198 int x, y, width, height;
4199 BYTE *src, *dst;
4200 BOOL is_1bpp;
4202 glyph_bitmap.index = analysis->run.glyphIndices[i];
4203 freetype_get_glyph_bbox(&glyph_bitmap);
4205 if (IsRectEmpty(bbox)) {
4206 origin.x += advance->x;
4207 origin.y += advance->y;
4208 continue;
4211 width = bbox->right - bbox->left;
4212 height = bbox->bottom - bbox->top;
4214 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4215 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4216 else
4217 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4219 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4220 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4222 if (is_rtl)
4223 OffsetRect(bbox, origin.x + advance->x, origin.y + advance->y);
4224 else
4225 OffsetRect(bbox, origin.x, origin.y);
4227 if (advanceoffset)
4228 OffsetRect(bbox, advanceoffset->x + ascenderoffset->x, advanceoffset->y + ascenderoffset->y);
4230 OffsetRect(bbox, analysis->origin.x, analysis->origin.y);
4231 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4232 OffsetRect(bbox, analysis->m.dx, analysis->m.dy);
4234 /* blit to analysis bitmap */
4235 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4237 if (is_1bpp) {
4238 /* convert 1bpp to 8bpp/24bpp */
4239 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4240 for (y = 0; y < height; y++) {
4241 for (x = 0; x < width; x++)
4242 if (src[x / 8] & masks[x % 8])
4243 dst[3*x] = dst[3*x+1] = dst[3*x+2] = DWRITE_ALPHA_MAX;
4244 src += glyph_bitmap.pitch;
4245 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4248 else {
4249 for (y = 0; y < height; y++) {
4250 for (x = 0; x < width; x++)
4251 if (src[x / 8] & masks[x % 8])
4252 dst[x] = DWRITE_ALPHA_MAX;
4253 src += get_dib_stride(width, 1);
4254 dst += analysis->bounds.right - analysis->bounds.left;
4258 else {
4259 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4260 for (y = 0; y < height; y++) {
4261 for (x = 0; x < width; x++)
4262 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x] | dst[3*x];
4263 src += glyph_bitmap.pitch;
4264 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4268 heap_free(glyph_bitmap.buf);
4270 origin.x += advance->x;
4271 origin.y += advance->y;
4274 IDWriteFontFace2_Release(fontface2);
4276 analysis->flags |= RUNANALYSIS_BITMAP_READY;
4278 /* we don't need this anymore */
4279 heap_free(analysis->glyphs);
4280 heap_free(analysis->advances);
4281 heap_free(analysis->advanceoffsets);
4282 heap_free(analysis->ascenderoffsets);
4283 IDWriteFontFace_Release(analysis->run.fontFace);
4285 analysis->glyphs = NULL;
4286 analysis->advances = NULL;
4287 analysis->advanceoffsets = NULL;
4288 analysis->ascenderoffsets = NULL;
4289 analysis->run.glyphIndices = NULL;
4290 analysis->run.fontFace = NULL;
4293 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4294 RECT const *bounds, BYTE *bitmap, UINT32 size)
4296 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4297 UINT32 required;
4298 RECT runbounds;
4300 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4302 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4303 return E_INVALIDARG;
4305 /* make sure buffer is large enough for requested texture type */
4306 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4307 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4308 required *= 3;
4310 if (size < required)
4311 return E_NOT_SUFFICIENT_BUFFER;
4313 /* validate requested texture type with rendering mode */
4314 switch (This->rendering_mode)
4316 case DWRITE_RENDERING_MODE_ALIASED:
4317 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4318 return DWRITE_E_UNSUPPORTEDOPERATION;
4319 break;
4320 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4321 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4322 case DWRITE_RENDERING_MODE_NATURAL:
4323 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4324 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4325 return DWRITE_E_UNSUPPORTEDOPERATION;
4326 break;
4327 default:
4331 memset(bitmap, 0, size);
4332 glyphrunanalysis_get_texturebounds(This, &runbounds);
4333 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4334 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4335 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4336 int dst_width = (bounds->right - bounds->left) * pixel_size;
4337 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4338 BYTE *src, *dst;
4339 int y;
4341 if (!(This->flags & RUNANALYSIS_BITMAP_READY))
4342 glyphrunanalysis_render(This, type);
4344 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4345 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4347 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4348 memcpy(dst, src, draw_width);
4349 src += src_width;
4350 dst += dst_width;
4354 return S_OK;
4357 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4358 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4360 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4362 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4364 if (!params)
4365 return E_INVALIDARG;
4367 switch (This->rendering_mode)
4369 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4370 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4372 UINT value = 0;
4373 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4374 *gamma = (FLOAT)value / 1000.0f;
4375 *contrast = 0.0f;
4376 *cleartypelevel = 1.0f;
4377 break;
4379 case DWRITE_RENDERING_MODE_ALIASED:
4380 case DWRITE_RENDERING_MODE_NATURAL:
4381 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4382 *gamma = IDWriteRenderingParams_GetGamma(params);
4383 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4384 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4385 break;
4386 default:
4390 return S_OK;
4393 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4394 glyphrunanalysis_QueryInterface,
4395 glyphrunanalysis_AddRef,
4396 glyphrunanalysis_Release,
4397 glyphrunanalysis_GetAlphaTextureBounds,
4398 glyphrunanalysis_CreateAlphaTexture,
4399 glyphrunanalysis_GetAlphaBlendParams
4402 static inline void init_2d_vec(D2D_POINT_2F *vec, FLOAT length, BOOL is_vertical)
4404 if (is_vertical) {
4405 vec->x = 0.0f;
4406 vec->y = length;
4408 else {
4409 vec->x = length;
4410 vec->y = 0.0f;
4414 static inline void transform_2d_vec(D2D_POINT_2F *vec, const DWRITE_MATRIX *m)
4416 D2D_POINT_2F ret;
4417 ret.x = vec->x * m->m11 + vec->y * m->m21;
4418 ret.y = vec->x * m->m12 + vec->y * m->m22;
4419 *vec = ret;
4422 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4423 FLOAT ppdip, const DWRITE_MATRIX *transform, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode,
4424 FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4426 struct dwrite_glyphrunanalysis *analysis;
4427 FLOAT rtl_factor;
4428 UINT32 i;
4430 *ret = NULL;
4432 /* check for valid rendering mode */
4433 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4434 return E_INVALIDARG;
4436 analysis = heap_alloc(sizeof(*analysis));
4437 if (!analysis)
4438 return E_OUTOFMEMORY;
4440 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4441 analysis->ref = 1;
4442 analysis->rendering_mode = rendering_mode;
4443 analysis->flags = 0;
4444 analysis->bitmap = NULL;
4445 analysis->ppdip = ppdip;
4446 analysis->origin.x = originX * ppdip;
4447 analysis->origin.y = originY * ppdip;
4448 SetRectEmpty(&analysis->bounds);
4449 analysis->run = *run;
4450 IDWriteFontFace_AddRef(analysis->run.fontFace);
4451 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4452 analysis->advances = heap_alloc(run->glyphCount*sizeof(*analysis->advances));
4453 if (run->glyphOffsets) {
4454 analysis->advanceoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->advanceoffsets));
4455 analysis->ascenderoffsets = heap_alloc(run->glyphCount*sizeof(*analysis->ascenderoffsets));
4457 else {
4458 analysis->advanceoffsets = NULL;
4459 analysis->ascenderoffsets = NULL;
4462 if (!analysis->glyphs || !analysis->advances || ((!analysis->advanceoffsets || !analysis->ascenderoffsets) && run->glyphOffsets)) {
4463 heap_free(analysis->glyphs);
4464 heap_free(analysis->advances);
4465 heap_free(analysis->advanceoffsets);
4466 heap_free(analysis->ascenderoffsets);
4468 analysis->glyphs = NULL;
4469 analysis->advances = NULL;
4470 analysis->advanceoffsets = NULL;
4471 analysis->ascenderoffsets = NULL;
4473 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4474 return E_OUTOFMEMORY;
4477 /* check if transform is usable */
4478 if (transform && memcmp(transform, &identity, sizeof(*transform))) {
4479 analysis->m = *transform;
4480 analysis->flags |= RUNANALYSIS_USE_TRANSFORM;
4482 else
4483 memset(&analysis->m, 0, sizeof(analysis->m));
4485 analysis->run.glyphIndices = analysis->glyphs;
4486 analysis->run.glyphAdvances = NULL;
4487 analysis->run.glyphOffsets = NULL;
4489 rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f;
4491 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4492 transform_2d_vec(&analysis->origin, &analysis->m);
4494 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4496 if (run->glyphAdvances) {
4497 for (i = 0; i < run->glyphCount; i++) {
4498 init_2d_vec(analysis->advances + i, rtl_factor * run->glyphAdvances[i] * ppdip, run->isSideways);
4499 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4500 transform_2d_vec(analysis->advances + i, &analysis->m);
4503 else {
4504 DWRITE_FONT_METRICS metrics;
4505 IDWriteFontFace1 *fontface1;
4507 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4508 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4510 for (i = 0; i < run->glyphCount; i++) {
4511 HRESULT hr;
4512 INT32 a;
4514 switch (measuring_mode)
4516 case DWRITE_MEASURING_MODE_NATURAL:
4517 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4518 if (FAILED(hr))
4519 a = 0;
4520 init_2d_vec(analysis->advances + i, rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics) * ppdip,
4521 run->isSideways);
4522 break;
4523 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4524 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4525 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, transform,
4526 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4527 if (FAILED(hr))
4528 init_2d_vec(analysis->advances + i, 0.0f, FALSE);
4529 else
4530 init_2d_vec(analysis->advances + i, rtl_factor * floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f),
4531 run->isSideways);
4532 break;
4533 default:
4537 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM)
4538 transform_2d_vec(analysis->advances + i, &analysis->m);
4541 IDWriteFontFace1_Release(fontface1);
4544 if (run->glyphOffsets) {
4545 for (i = 0; i < run->glyphCount; i++) {
4546 init_2d_vec(analysis->advanceoffsets + i, rtl_factor * run->glyphOffsets[i].advanceOffset * ppdip, run->isSideways);
4547 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4548 init_2d_vec(analysis->ascenderoffsets + i, -run->glyphOffsets[i].ascenderOffset * ppdip, !run->isSideways);
4549 if (analysis->flags & RUNANALYSIS_USE_TRANSFORM) {
4550 transform_2d_vec(analysis->advanceoffsets + i, &analysis->m);
4551 transform_2d_vec(analysis->ascenderoffsets + i, &analysis->m);
4556 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
4557 return S_OK;
4560 /* IDWriteColorGlyphRunEnumerator */
4561 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
4563 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4565 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4567 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
4568 IsEqualIID(riid, &IID_IUnknown))
4570 *ppv = iface;
4571 IDWriteColorGlyphRunEnumerator_AddRef(iface);
4572 return S_OK;
4575 *ppv = NULL;
4576 return E_NOINTERFACE;
4579 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
4581 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4582 ULONG ref = InterlockedIncrement(&This->ref);
4583 TRACE("(%p)->(%u)\n", This, ref);
4584 return ref;
4587 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
4589 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4590 ULONG ref = InterlockedDecrement(&This->ref);
4592 TRACE("(%p)->(%u)\n", This, ref);
4594 if (!ref)
4595 heap_free(This);
4597 return ref;
4600 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
4602 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4603 FIXME("(%p)->(%p): stub\n", This, has_run);
4604 return E_NOTIMPL;
4607 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
4609 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4610 FIXME("(%p)->(%p): stub\n", This, run);
4611 return E_NOTIMPL;
4614 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
4615 colorglyphenum_QueryInterface,
4616 colorglyphenum_AddRef,
4617 colorglyphenum_Release,
4618 colorglyphenum_MoveNext,
4619 colorglyphenum_GetCurrentRun
4622 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
4623 DWRITE_MEASURING_MODE mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
4625 struct dwrite_colorglyphenum *colorglyphenum;
4626 IDWriteFontFace2 *fontface2;
4627 BOOL colorfont;
4628 HRESULT hr;
4630 *ret = NULL;
4632 hr = IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
4633 if (FAILED(hr)) {
4634 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
4635 return hr;
4638 colorfont = IDWriteFontFace2_IsColorFont(fontface2);
4639 IDWriteFontFace2_Release(fontface2);
4640 if (!colorfont)
4641 return DWRITE_E_NOCOLOR;
4643 colorglyphenum = heap_alloc(sizeof(*colorglyphenum));
4644 if (!colorglyphenum)
4645 return E_OUTOFMEMORY;
4647 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
4648 colorglyphenum->ref = 1;
4650 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
4651 return S_OK;