dwrite: Implement GetFont() for matching list.
[wine/multimedia.git] / dlls / dwrite / font.c
blobaea35c938115d917f4e9c5c895ee92814d6e474a
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_readystate {
156 RUNANALYSIS_BOUNDS = 1 << 0,
157 RUNANALYSIS_BITMAP = 1 << 1,
160 struct dwrite_glyphrunanalysis {
161 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
162 LONG ref;
164 DWRITE_RENDERING_MODE rendering_mode;
165 DWRITE_GLYPH_RUN run;
166 FLOAT ppdip;
167 FLOAT originX;
168 FLOAT originY;
169 UINT16 *glyphs;
170 FLOAT *advances;
171 DWRITE_GLYPH_OFFSET *offsets;
173 UINT8 ready;
174 RECT bounds;
175 BYTE *bitmap;
178 struct dwrite_colorglyphenum {
179 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface;
180 LONG ref;
183 #define GLYPH_BLOCK_SHIFT 8
184 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
185 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
186 #define GLYPH_MAX 65536
188 struct dwrite_fontface {
189 IDWriteFontFace2 IDWriteFontFace2_iface;
190 LONG ref;
192 IDWriteFontFileStream **streams;
193 IDWriteFontFile **files;
194 UINT32 file_count;
195 UINT32 index;
197 USHORT simulations;
198 DWRITE_FONT_FACE_TYPE type;
199 DWRITE_FONT_METRICS1 metrics;
200 DWRITE_CARET_METRICS caret;
201 INT charmap;
202 BOOL is_symbol;
204 struct dwrite_fonttable cmap;
205 struct dwrite_fonttable vdmx;
206 struct dwrite_fonttable gasp;
207 struct dwrite_fonttable cpal;
208 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
211 struct dwrite_fontfile {
212 IDWriteFontFile IDWriteFontFile_iface;
213 LONG ref;
215 IDWriteFontFileLoader *loader;
216 void *reference_key;
217 UINT32 key_size;
218 IDWriteFontFileStream *stream;
221 static inline struct dwrite_fontface *impl_from_IDWriteFontFace2(IDWriteFontFace2 *iface)
223 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace2_iface);
226 static inline struct dwrite_font *impl_from_IDWriteFont2(IDWriteFont2 *iface)
228 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont2_iface);
231 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
233 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
236 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily(IDWriteFontFamily *iface)
238 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily_iface);
241 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection(IDWriteFontCollection *iface)
243 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection_iface);
246 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
248 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
251 static inline struct dwrite_colorglyphenum *impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator *iface)
253 return CONTAINING_RECORD(iface, struct dwrite_colorglyphenum, IDWriteColorGlyphRunEnumerator_iface);
256 static inline struct dwrite_fontlist *impl_from_IDWriteFontList(IDWriteFontList *iface)
258 return CONTAINING_RECORD(iface, struct dwrite_fontlist, IDWriteFontList_iface);
261 static inline const char *debugstr_tag(UINT32 tag)
263 return wine_dbg_sprintf("%c%c%c%c", tag & 0xff, (tag >> 8) & 0xff, (tag >> 16) & 0xff, tag >> 24);
266 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
268 static const DWRITE_GLYPH_METRICS nil;
269 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
271 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
272 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
273 return S_OK;
276 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
278 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
280 if (!*block) {
281 /* start new block */
282 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
283 if (!*block)
284 return E_OUTOFMEMORY;
287 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
288 return S_OK;
291 static void* get_fontface_table(struct dwrite_fontface *fontface, UINT32 tag, struct dwrite_fonttable *table)
293 HRESULT hr;
295 if (table->data || !table->exists)
296 return table->data;
298 table->exists = FALSE;
299 hr = IDWriteFontFace2_TryGetFontTable(&fontface->IDWriteFontFace2_iface, tag, (const void**)&table->data,
300 &table->size, &table->context, &table->exists);
301 if (FAILED(hr) || !table->exists) {
302 WARN("Font does not have a %s table\n", debugstr_tag(tag));
303 return NULL;
306 return table->data;
309 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style,
310 struct dwrite_font_propvec *vec)
312 vec->stretch = ((INT32)stretch - DWRITE_FONT_STRETCH_NORMAL) * 11.0f;
313 vec->style = style * 7.0f;
314 vec->weight = ((INT32)weight - DWRITE_FONT_WEIGHT_NORMAL) / 100.0f * 5.0f;
317 static FLOAT get_font_prop_vec_distance(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
319 return powf(left->stretch - right->stretch, 2) + powf(left->style - right->style, 2) + powf(left->weight - right->weight, 2);
322 static FLOAT get_font_prop_vec_dotproduct(const struct dwrite_font_propvec *left, const struct dwrite_font_propvec *right)
324 return left->stretch * right->stretch + left->style * right->style + left->weight * right->weight;
327 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
329 return get_fontface_table(fontface, MS_CMAP_TAG, &fontface->cmap);
332 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
334 return get_fontface_table(fontface, MS_VDMX_TAG, &fontface->vdmx);
337 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
339 void *ptr = get_fontface_table(fontface, MS_GASP_TAG, &fontface->gasp);
340 *size = fontface->gasp.size;
341 return ptr;
344 static inline void* get_fontface_cpal(struct dwrite_fontface *fontface)
346 return get_fontface_table(fontface, MS_CPAL_TAG, &fontface->cpal);
349 static void release_font_data(struct dwrite_font_data *data)
351 int i;
353 if (InterlockedDecrement(&data->ref) > 0)
354 return;
356 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
357 if (data->info_strings[i])
358 IDWriteLocalizedStrings_Release(data->info_strings[i]);
360 IDWriteLocalizedStrings_Release(data->names);
362 IDWriteFontFile_Release(data->file);
363 IDWriteFactory2_Release(data->factory);
364 heap_free(data->facename);
365 heap_free(data);
368 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
370 int i;
372 if (InterlockedDecrement(&data->ref) > 0)
373 return;
375 for (i = 0; i < data->font_count; i++)
376 release_font_data(data->fonts[i]);
377 heap_free(data->fonts);
378 IDWriteLocalizedStrings_Release(data->familyname);
379 heap_free(data);
382 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace2 *iface, REFIID riid, void **obj)
384 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
386 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
388 if (IsEqualIID(riid, &IID_IDWriteFontFace2) ||
389 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
390 IsEqualIID(riid, &IID_IDWriteFontFace) ||
391 IsEqualIID(riid, &IID_IUnknown))
393 *obj = iface;
394 IDWriteFontFace2_AddRef(iface);
395 return S_OK;
398 *obj = NULL;
399 return E_NOINTERFACE;
402 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace2 *iface)
404 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
405 ULONG ref = InterlockedIncrement(&This->ref);
406 TRACE("(%p)->(%d)\n", This, ref);
407 return ref;
410 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace2 *iface)
412 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
413 ULONG ref = InterlockedDecrement(&This->ref);
415 TRACE("(%p)->(%d)\n", This, ref);
417 if (!ref) {
418 UINT32 i;
420 if (This->cmap.context)
421 IDWriteFontFace2_ReleaseFontTable(iface, This->cmap.context);
422 if (This->vdmx.context)
423 IDWriteFontFace2_ReleaseFontTable(iface, This->vdmx.context);
424 if (This->gasp.context)
425 IDWriteFontFace2_ReleaseFontTable(iface, This->gasp.context);
426 if (This->cpal.context)
427 IDWriteFontFace2_ReleaseFontTable(iface, This->cpal.context);
428 for (i = 0; i < This->file_count; i++) {
429 if (This->streams[i])
430 IDWriteFontFileStream_Release(This->streams[i]);
431 if (This->files[i])
432 IDWriteFontFile_Release(This->files[i]);
435 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
436 heap_free(This->glyphs[i]);
438 freetype_notify_cacheremove(iface);
439 heap_free(This);
442 return ref;
445 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace2 *iface)
447 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
448 TRACE("(%p)\n", This);
449 return This->type;
452 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace2 *iface, UINT32 *number_of_files,
453 IDWriteFontFile **fontfiles)
455 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
456 int i;
458 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
459 if (fontfiles == NULL)
461 *number_of_files = This->file_count;
462 return S_OK;
464 if (*number_of_files < This->file_count)
465 return E_INVALIDARG;
467 for (i = 0; i < This->file_count; i++)
469 IDWriteFontFile_AddRef(This->files[i]);
470 fontfiles[i] = This->files[i];
473 return S_OK;
476 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace2 *iface)
478 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
479 TRACE("(%p)\n", This);
480 return This->index;
483 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace2 *iface)
485 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
486 TRACE("(%p)\n", This);
487 return This->simulations;
490 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace2 *iface)
492 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
493 TRACE("(%p)\n", This);
494 return This->is_symbol;
497 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS *metrics)
499 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
500 TRACE("(%p)->(%p)\n", This, metrics);
501 memcpy(metrics, &This->metrics, sizeof(*metrics));
504 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace2 *iface)
506 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
507 TRACE("(%p)\n", This);
508 return freetype_get_glyphcount(iface);
511 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace2 *iface,
512 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
514 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
515 HRESULT hr;
516 UINT32 i;
518 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
520 if (!glyphs)
521 return E_INVALIDARG;
523 if (is_sideways)
524 FIXME("sideways metrics are not supported.\n");
526 for (i = 0; i < glyph_count; i++) {
527 DWRITE_GLYPH_METRICS metrics;
529 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
530 if (hr != S_OK) {
531 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
532 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
533 if (FAILED(hr))
534 return hr;
536 ret[i] = metrics;
539 return S_OK;
542 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace2 *iface, UINT32 const *codepoints,
543 UINT32 count, UINT16 *glyph_indices)
545 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
546 UINT32 i;
548 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
550 if (!glyph_indices)
551 return E_INVALIDARG;
553 if (!codepoints) {
554 memset(glyph_indices, 0, count*sizeof(UINT16));
555 return E_INVALIDARG;
558 for (i = 0; i < count; i++)
559 glyph_indices[i] = freetype_get_glyphindex(iface, codepoints[i], This->charmap);
561 return S_OK;
564 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace2 *iface, UINT32 table_tag,
565 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
567 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
569 TRACE("(%p)->(%u %p %p %p %p)\n", This, table_tag, table_data, table_size, context, exists);
571 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
574 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace2 *iface, void *table_context)
576 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
578 TRACE("(%p)->(%p)\n", This, table_context);
580 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
583 HRESULT new_glyph_outline(UINT32 count, struct glyph_outline **ret)
585 struct glyph_outline *outline;
586 D2D1_POINT_2F *points;
587 UINT8 *tags;
589 *ret = NULL;
591 outline = heap_alloc(sizeof(*outline));
592 if (!outline)
593 return E_OUTOFMEMORY;
595 points = heap_alloc(count*sizeof(D2D1_POINT_2F));
596 tags = heap_alloc_zero(count*sizeof(UINT8));
597 if (!points || !tags) {
598 heap_free(points);
599 heap_free(tags);
600 heap_free(outline);
601 return E_OUTOFMEMORY;
604 outline->points = points;
605 outline->tags = tags;
606 outline->count = count;
607 outline->advance = 0.0;
609 *ret = outline;
610 return S_OK;
613 static void free_glyph_outline(struct glyph_outline *outline)
615 heap_free(outline->points);
616 heap_free(outline->tags);
617 heap_free(outline);
620 static void report_glyph_outline(const struct glyph_outline *outline, IDWriteGeometrySink *sink)
622 UINT16 p;
624 for (p = 0; p < outline->count; p++) {
625 if (outline->tags[p] & OUTLINE_POINT_START) {
626 ID2D1SimplifiedGeometrySink_BeginFigure(sink, outline->points[p], D2D1_FIGURE_BEGIN_FILLED);
627 continue;
630 if (outline->tags[p] & OUTLINE_POINT_LINE)
631 ID2D1SimplifiedGeometrySink_AddLines(sink, outline->points+p, 1);
632 else if (outline->tags[p] & OUTLINE_POINT_BEZIER) {
633 static const UINT16 segment_length = 3;
634 ID2D1SimplifiedGeometrySink_AddBeziers(sink, (D2D1_BEZIER_SEGMENT*)&outline->points[p], 1);
635 p += segment_length - 1;
638 if (outline->tags[p] & OUTLINE_POINT_END)
639 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
643 static inline void translate_glyph_outline(struct glyph_outline *outline, FLOAT xoffset, FLOAT yoffset)
645 UINT16 p;
647 for (p = 0; p < outline->count; p++) {
648 outline->points[p].x += xoffset;
649 outline->points[p].y += yoffset;
653 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace2 *iface, FLOAT emSize,
654 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
655 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
657 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
658 FLOAT advance = 0.0;
659 HRESULT hr;
660 UINT32 g;
662 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
663 count, is_sideways, is_rtl, sink);
665 if (!glyphs || !sink)
666 return E_INVALIDARG;
668 if (is_sideways)
669 FIXME("sideways mode is not supported.\n");
671 if (count)
672 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
674 for (g = 0; g < count; g++) {
675 FLOAT xoffset = 0.0, yoffset = 0.0;
676 struct glyph_outline *outline;
678 /* FIXME: cache outlines */
680 hr = freetype_get_glyph_outline(iface, emSize, glyphs[g], This->simulations, &outline);
681 if (FAILED(hr))
682 return hr;
684 /* glyph offsets act as current glyph adjustment */
685 if (offsets) {
686 xoffset += is_rtl ? -offsets[g].advanceOffset : offsets[g].advanceOffset;
687 yoffset -= offsets[g].ascenderOffset;
690 if (g == 0)
691 advance = is_rtl ? -outline->advance : 0.0;
693 xoffset += advance;
694 translate_glyph_outline(outline, xoffset, yoffset);
696 /* update advance to next glyph */
697 if (advances)
698 advance += is_rtl ? -advances[g] : advances[g];
699 else
700 advance += is_rtl ? -outline->advance : outline->advance;
702 report_glyph_outline(outline, sink);
703 free_glyph_outline(outline);
706 return S_OK;
709 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
710 FLOAT ppem, WORD gasp)
712 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
714 switch (measuring)
716 case DWRITE_MEASURING_MODE_NATURAL:
718 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
719 mode = DWRITE_RENDERING_MODE_NATURAL;
720 else
721 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
722 break;
724 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
725 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
726 break;
727 case DWRITE_MEASURING_MODE_GDI_NATURAL:
728 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
729 break;
730 default:
734 return mode;
737 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
738 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
740 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
741 WORD gasp, *ptr;
742 UINT32 size;
743 FLOAT ppem;
745 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
747 if (!params) {
748 *mode = DWRITE_RENDERING_MODE_DEFAULT;
749 return E_INVALIDARG;
752 *mode = IDWriteRenderingParams_GetRenderingMode(params);
753 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
754 return S_OK;
756 ppem = emSize * ppdip;
758 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
759 *mode = DWRITE_RENDERING_MODE_OUTLINE;
760 return S_OK;
763 ptr = get_fontface_gasp(This, &size);
764 gasp = opentype_get_gasp_flags(ptr, size, ppem);
765 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
766 return S_OK;
769 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT pixels_per_dip,
770 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
772 DWRITE_FONT_METRICS1 metrics1;
773 HRESULT hr = IDWriteFontFace2_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
774 memcpy(metrics, &metrics1, sizeof(*metrics));
775 return hr;
778 static inline int round_metric(FLOAT metric)
780 return (int)floorf(metric + 0.5f);
783 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT ppdip,
784 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
785 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
787 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
788 DWRITE_MEASURING_MODE mode;
789 FLOAT scale, size;
790 HRESULT hr;
791 UINT32 i;
793 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
794 glyph_count, metrics, is_sideways);
796 if (m && memcmp(m, &identity, sizeof(*m)))
797 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
799 size = emSize * ppdip;
800 scale = size / This->metrics.designUnitsPerEm;
801 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
803 for (i = 0; i < glyph_count; i++) {
804 DWRITE_GLYPH_METRICS *ret = metrics + i;
805 DWRITE_GLYPH_METRICS design;
807 hr = IDWriteFontFace2_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
808 if (FAILED(hr))
809 return hr;
811 ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode);
812 ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size);
814 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
815 SCALE_METRIC(leftSideBearing);
816 SCALE_METRIC(rightSideBearing);
817 SCALE_METRIC(topSideBearing);
818 SCALE_METRIC(advanceHeight);
819 SCALE_METRIC(bottomSideBearing);
820 SCALE_METRIC(verticalOriginY);
821 #undef SCALE_METRIC
824 return S_OK;
827 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS1 *metrics)
829 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
830 TRACE("(%p)->(%p)\n", This, metrics);
831 *metrics = This->metrics;
834 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT em_size, FLOAT pixels_per_dip,
835 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
837 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
838 const DWRITE_FONT_METRICS1 *design = &This->metrics;
839 UINT16 ascent, descent;
840 FLOAT scale;
842 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
844 if (em_size <= 0.0 || pixels_per_dip <= 0.0) {
845 memset(metrics, 0, sizeof(*metrics));
846 return E_INVALIDARG;
849 em_size *= pixels_per_dip;
850 if (m && m->m22 != 0.0)
851 em_size *= fabs(m->m22);
853 scale = em_size / design->designUnitsPerEm;
854 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
855 ascent = round_metric(design->ascent * scale);
856 descent = round_metric(design->descent * scale);
859 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
860 metrics->designUnitsPerEm = design->designUnitsPerEm;
861 metrics->ascent = round_metric(ascent / scale);
862 metrics->descent = round_metric(descent / scale);
864 SCALE_METRIC(lineGap);
865 SCALE_METRIC(capHeight);
866 SCALE_METRIC(xHeight);
867 SCALE_METRIC(underlinePosition);
868 SCALE_METRIC(underlineThickness);
869 SCALE_METRIC(strikethroughPosition);
870 SCALE_METRIC(strikethroughThickness);
871 SCALE_METRIC(glyphBoxLeft);
872 SCALE_METRIC(glyphBoxTop);
873 SCALE_METRIC(glyphBoxRight);
874 SCALE_METRIC(glyphBoxBottom);
875 SCALE_METRIC(subscriptPositionX);
876 SCALE_METRIC(subscriptPositionY);
877 SCALE_METRIC(subscriptSizeX);
878 SCALE_METRIC(subscriptSizeY);
879 SCALE_METRIC(superscriptPositionX);
880 SCALE_METRIC(superscriptPositionY);
881 SCALE_METRIC(superscriptSizeX);
882 SCALE_METRIC(superscriptSizeY);
884 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
885 #undef SCALE_METRIC
887 return S_OK;
890 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace2 *iface, DWRITE_CARET_METRICS *metrics)
892 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
893 TRACE("(%p)->(%p)\n", This, metrics);
894 *metrics = This->caret;
897 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace2 *iface, UINT32 max_count,
898 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
900 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
902 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
904 *count = 0;
905 if (max_count && !ranges)
906 return E_INVALIDARG;
908 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
911 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace2 *iface)
913 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
914 TRACE("(%p)\n", This);
915 return freetype_is_monospaced(iface);
918 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace2 *iface,
919 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
921 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
922 UINT32 i;
924 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
926 if (is_sideways)
927 FIXME("sideways mode not supported\n");
929 for (i = 0; i < glyph_count; i++)
930 advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL);
932 return S_OK;
935 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace2 *iface,
936 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
937 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
939 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
940 DWRITE_MEASURING_MODE mode;
941 UINT32 i;
943 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
944 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
946 if (em_size < 0.0 || ppdip <= 0.0) {
947 memset(advances, 0, sizeof(*advances) * glyph_count);
948 return E_INVALIDARG;
951 em_size *= ppdip;
952 if (em_size == 0.0) {
953 memset(advances, 0, sizeof(*advances) * glyph_count);
954 return S_OK;
957 if (m && memcmp(m, &identity, sizeof(*m)))
958 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
960 mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
961 for (i = 0; i < glyph_count; i++) {
962 advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode);
963 advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size);
966 return S_OK;
969 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace2 *iface, UINT32 count,
970 const UINT16 *indices, INT32 *adjustments)
972 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
973 UINT32 i;
975 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
977 if (!(indices || adjustments) || !count)
978 return E_INVALIDARG;
980 if (!indices || count == 1) {
981 memset(adjustments, 0, count*sizeof(INT32));
982 return E_INVALIDARG;
985 for (i = 0; i < count-1; i++)
986 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
987 adjustments[count-1] = 0;
989 return S_OK;
992 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace2 *iface)
994 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
995 TRACE("(%p)\n", This);
996 return freetype_has_kerning_pairs(iface);
999 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace2 *iface,
1000 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
1001 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
1003 DWRITE_GRID_FIT_MODE gridfitmode;
1004 return IDWriteFontFace2_GetRecommendedRenderingMode(iface, font_emsize, dpiX, dpiY, transform, is_sideways,
1005 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
1008 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace2 *iface, UINT32 glyph_count,
1009 const UINT16 *nominal_indices, UINT16 *vertical_indices)
1011 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1012 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
1013 return E_NOTIMPL;
1016 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace2 *iface)
1018 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1019 FIXME("(%p): stub\n", This);
1020 return FALSE;
1023 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace2 *iface)
1025 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1026 FIXME("(%p): stub\n", This);
1027 return FALSE;
1030 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace2 *iface)
1032 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1033 TRACE("(%p)\n", This);
1034 return opentype_get_cpal_palettecount(get_fontface_cpal(This));
1037 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace2 *iface)
1039 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1040 TRACE("(%p)\n", This);
1041 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This));
1044 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace2 *iface, UINT32 palette_index,
1045 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
1047 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1048 TRACE("(%p)->(%u %u %u %p)\n", This, palette_index, first_entry_index, entry_count, entries);
1049 return opentype_get_cpal_entries(get_fontface_cpal(This), palette_index, first_entry_index, entry_count, entries);
1052 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
1053 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
1054 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
1055 DWRITE_GRID_FIT_MODE *gridfitmode)
1057 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
1058 FLOAT emthreshold;
1059 WORD gasp, *ptr;
1060 UINT32 size;
1062 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
1063 measuringmode, params, renderingmode, gridfitmode);
1065 if (m)
1066 FIXME("transform not supported %s\n", debugstr_matrix(m));
1068 if (is_sideways)
1069 FIXME("sideways mode not supported\n");
1071 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
1072 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
1073 if (params) {
1074 IDWriteRenderingParams2 *params2;
1075 HRESULT hr;
1077 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
1078 if (hr == S_OK) {
1079 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
1080 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
1081 IDWriteRenderingParams2_Release(params2);
1083 else
1084 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
1087 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
1089 ptr = get_fontface_gasp(This, &size);
1090 gasp = opentype_get_gasp_flags(ptr, size, emSize);
1092 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
1093 if (emSize >= emthreshold)
1094 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
1095 else
1096 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
1099 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
1100 if (emSize >= emthreshold)
1101 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1102 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1103 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1104 else
1105 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1108 return S_OK;
1111 static const IDWriteFontFace2Vtbl dwritefontfacevtbl = {
1112 dwritefontface_QueryInterface,
1113 dwritefontface_AddRef,
1114 dwritefontface_Release,
1115 dwritefontface_GetType,
1116 dwritefontface_GetFiles,
1117 dwritefontface_GetIndex,
1118 dwritefontface_GetSimulations,
1119 dwritefontface_IsSymbolFont,
1120 dwritefontface_GetMetrics,
1121 dwritefontface_GetGlyphCount,
1122 dwritefontface_GetDesignGlyphMetrics,
1123 dwritefontface_GetGlyphIndices,
1124 dwritefontface_TryGetFontTable,
1125 dwritefontface_ReleaseFontTable,
1126 dwritefontface_GetGlyphRunOutline,
1127 dwritefontface_GetRecommendedRenderingMode,
1128 dwritefontface_GetGdiCompatibleMetrics,
1129 dwritefontface_GetGdiCompatibleGlyphMetrics,
1130 dwritefontface1_GetMetrics,
1131 dwritefontface1_GetGdiCompatibleMetrics,
1132 dwritefontface1_GetCaretMetrics,
1133 dwritefontface1_GetUnicodeRanges,
1134 dwritefontface1_IsMonospacedFont,
1135 dwritefontface1_GetDesignGlyphAdvances,
1136 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1137 dwritefontface1_GetKerningPairAdjustments,
1138 dwritefontface1_HasKerningPairs,
1139 dwritefontface1_GetRecommendedRenderingMode,
1140 dwritefontface1_GetVerticalGlyphVariants,
1141 dwritefontface1_HasVerticalGlyphVariants,
1142 dwritefontface2_IsColorFont,
1143 dwritefontface2_GetColorPaletteCount,
1144 dwritefontface2_GetPaletteEntryCount,
1145 dwritefontface2_GetPaletteEntries,
1146 dwritefontface2_GetRecommendedRenderingMode
1149 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace2 **fontface)
1151 struct dwrite_font_data *data = font->data;
1152 IDWriteFontFace *face;
1153 HRESULT hr;
1155 *fontface = NULL;
1157 hr = IDWriteFactory2_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1158 data->face_index, font->data->simulations, &face);
1159 if (FAILED(hr))
1160 return hr;
1162 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace2, (void**)fontface);
1163 IDWriteFontFace_Release(face);
1165 return hr;
1168 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont2 *iface, REFIID riid, void **obj)
1170 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1172 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1174 if (IsEqualIID(riid, &IID_IDWriteFont2) ||
1175 IsEqualIID(riid, &IID_IDWriteFont1) ||
1176 IsEqualIID(riid, &IID_IDWriteFont) ||
1177 IsEqualIID(riid, &IID_IUnknown))
1179 *obj = iface;
1180 IDWriteFont2_AddRef(iface);
1181 return S_OK;
1184 *obj = NULL;
1185 return E_NOINTERFACE;
1188 static ULONG WINAPI dwritefont_AddRef(IDWriteFont2 *iface)
1190 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1191 ULONG ref = InterlockedIncrement(&This->ref);
1192 TRACE("(%p)->(%d)\n", This, ref);
1193 return ref;
1196 static ULONG WINAPI dwritefont_Release(IDWriteFont2 *iface)
1198 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1199 ULONG ref = InterlockedDecrement(&This->ref);
1201 TRACE("(%p)->(%d)\n", This, ref);
1203 if (!ref) {
1204 IDWriteFontFamily_Release(This->family);
1205 release_font_data(This->data);
1206 heap_free(This);
1209 return ref;
1212 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont2 *iface, IDWriteFontFamily **family)
1214 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1215 TRACE("(%p)->(%p)\n", This, family);
1217 *family = This->family;
1218 IDWriteFontFamily_AddRef(*family);
1219 return S_OK;
1222 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont2 *iface)
1224 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1225 TRACE("(%p)\n", This);
1226 return This->data->weight;
1229 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont2 *iface)
1231 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1232 TRACE("(%p)\n", This);
1233 return This->data->stretch;
1236 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont2 *iface)
1238 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1239 TRACE("(%p)\n", This);
1240 return This->style;
1243 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont2 *iface)
1245 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1246 IDWriteFontFace2 *fontface;
1247 HRESULT hr;
1249 TRACE("(%p)\n", This);
1251 hr = get_fontface_from_font(This, &fontface);
1252 if (FAILED(hr))
1253 return hr;
1255 return IDWriteFontFace2_IsSymbolFont(fontface);
1258 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont2 *iface, IDWriteLocalizedStrings **names)
1260 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1261 TRACE("(%p)->(%p)\n", This, names);
1262 return clone_localizedstring(This->data->names, names);
1265 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont2 *iface,
1266 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1268 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1269 struct dwrite_font_data *data = This->data;
1270 HRESULT hr;
1272 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1274 *exists = FALSE;
1275 *strings = NULL;
1277 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1278 return S_OK;
1280 if (!data->info_strings[stringid]) {
1281 IDWriteFontFace2 *fontface;
1282 const void *table_data;
1283 BOOL table_exists;
1284 void *context;
1285 UINT32 size;
1287 hr = get_fontface_from_font(This, &fontface);
1288 if (FAILED(hr))
1289 return hr;
1291 table_exists = FALSE;
1292 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1293 if (FAILED(hr) || !table_exists)
1294 WARN("no NAME table found.\n");
1296 if (table_exists) {
1297 hr = opentype_get_font_info_strings(table_data, stringid, &data->info_strings[stringid]);
1298 if (FAILED(hr) || !data->info_strings[stringid])
1299 return hr;
1300 IDWriteFontFace2_ReleaseFontTable(fontface, context);
1304 hr = clone_localizedstring(data->info_strings[stringid], strings);
1305 if (FAILED(hr))
1306 return hr;
1308 *exists = TRUE;
1309 return S_OK;
1312 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont2 *iface)
1314 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1315 TRACE("(%p)\n", This);
1316 return This->data->simulations;
1319 static void WINAPI dwritefont_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS *metrics)
1321 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1323 TRACE("(%p)->(%p)\n", This, metrics);
1324 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1327 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont2 *iface, UINT32 value, BOOL *exists)
1329 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1330 IDWriteFontFace2 *fontface;
1331 UINT16 index;
1332 HRESULT hr;
1334 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1336 *exists = FALSE;
1338 hr = get_fontface_from_font(This, &fontface);
1339 if (FAILED(hr))
1340 return hr;
1342 index = 0;
1343 hr = IDWriteFontFace2_GetGlyphIndices(fontface, &value, 1, &index);
1344 if (FAILED(hr))
1345 return hr;
1347 *exists = index != 0;
1348 return S_OK;
1351 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont2 *iface, IDWriteFontFace **face)
1353 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1354 HRESULT hr;
1356 TRACE("(%p)->(%p)\n", This, face);
1358 hr = get_fontface_from_font(This, (IDWriteFontFace2**)face);
1359 if (hr == S_OK)
1360 IDWriteFontFace_AddRef(*face);
1362 return hr;
1365 static void WINAPI dwritefont1_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS1 *metrics)
1367 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1368 TRACE("(%p)->(%p)\n", This, metrics);
1369 *metrics = This->data->metrics;
1372 static void WINAPI dwritefont1_GetPanose(IDWriteFont2 *iface, DWRITE_PANOSE *panose)
1374 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1375 TRACE("(%p)->(%p)\n", This, panose);
1376 *panose = This->data->panose;
1379 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont2 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1381 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1382 IDWriteFontFace2 *fontface;
1383 HRESULT hr;
1385 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1387 hr = get_fontface_from_font(This, &fontface);
1388 if (FAILED(hr))
1389 return hr;
1391 return IDWriteFontFace2_GetUnicodeRanges(fontface, max_count, ranges, count);
1394 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont2 *iface)
1396 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1397 IDWriteFontFace2 *fontface;
1398 HRESULT hr;
1400 TRACE("(%p)\n", This);
1402 hr = get_fontface_from_font(This, &fontface);
1403 if (FAILED(hr))
1404 return hr;
1406 return IDWriteFontFace2_IsMonospacedFont(fontface);
1409 static BOOL WINAPI dwritefont2_IsColorFont(IDWriteFont2 *iface)
1411 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1412 IDWriteFontFace2 *fontface;
1413 HRESULT hr;
1415 TRACE("(%p)\n", This);
1417 hr = get_fontface_from_font(This, &fontface);
1418 if (FAILED(hr))
1419 return FALSE;
1421 return IDWriteFontFace2_IsColorFont(fontface);
1424 static const IDWriteFont2Vtbl dwritefontvtbl = {
1425 dwritefont_QueryInterface,
1426 dwritefont_AddRef,
1427 dwritefont_Release,
1428 dwritefont_GetFontFamily,
1429 dwritefont_GetWeight,
1430 dwritefont_GetStretch,
1431 dwritefont_GetStyle,
1432 dwritefont_IsSymbolFont,
1433 dwritefont_GetFaceNames,
1434 dwritefont_GetInformationalStrings,
1435 dwritefont_GetSimulations,
1436 dwritefont_GetMetrics,
1437 dwritefont_HasCharacter,
1438 dwritefont_CreateFontFace,
1439 dwritefont1_GetMetrics,
1440 dwritefont1_GetPanose,
1441 dwritefont1_GetUnicodeRanges,
1442 dwritefont1_IsMonospacedFont,
1443 dwritefont2_IsColorFont
1446 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily *family, IDWriteFont **font)
1448 struct dwrite_font *This;
1449 *font = NULL;
1451 This = heap_alloc(sizeof(struct dwrite_font));
1452 if (!This) return E_OUTOFMEMORY;
1454 This->IDWriteFont2_iface.lpVtbl = &dwritefontvtbl;
1455 This->ref = 1;
1456 This->family = family;
1457 IDWriteFontFamily_AddRef(family);
1458 This->style = data->style;
1459 This->data = data;
1460 InterlockedIncrement(&This->data->ref);
1462 *font = (IDWriteFont*)&This->IDWriteFont2_iface;
1464 return S_OK;
1467 /* IDWriteFontList */
1468 static HRESULT WINAPI dwritefontlist_QueryInterface(IDWriteFontList *iface, REFIID riid, void **obj)
1470 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1472 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1474 if (IsEqualIID(riid, &IID_IDWriteFontList) ||
1475 IsEqualIID(riid, &IID_IUnknown))
1477 *obj = iface;
1478 IDWriteFontList_AddRef(iface);
1479 return S_OK;
1482 *obj = NULL;
1483 return E_NOINTERFACE;
1486 static ULONG WINAPI dwritefontlist_AddRef(IDWriteFontList *iface)
1488 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1489 ULONG ref = InterlockedIncrement(&This->ref);
1490 TRACE("(%p)->(%d)\n", This, ref);
1491 return ref;
1494 static ULONG WINAPI dwritefontlist_Release(IDWriteFontList *iface)
1496 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1497 ULONG ref = InterlockedDecrement(&This->ref);
1499 TRACE("(%p)->(%d)\n", This, ref);
1501 if (!ref) {
1502 UINT32 i;
1504 for (i = 0; i < This->font_count; i++)
1505 release_font_data(This->fonts[i]);
1506 IDWriteFontFamily_Release(This->family);
1507 heap_free(This);
1510 return ref;
1513 static HRESULT WINAPI dwritefontlist_GetFontCollection(IDWriteFontList *iface, IDWriteFontCollection **collection)
1515 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1517 FIXME("(%p)->(%p): stub\n", This, collection);
1519 return E_NOTIMPL;
1522 static UINT32 WINAPI dwritefontlist_GetFontCount(IDWriteFontList *iface)
1524 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1525 TRACE("(%p)\n", This);
1526 return This->font_count;
1529 static HRESULT WINAPI dwritefontlist_GetFont(IDWriteFontList *iface, UINT32 index, IDWriteFont **font)
1531 struct dwrite_fontlist *This = impl_from_IDWriteFontList(iface);
1533 TRACE("(%p)->(%u %p)\n", This, index, font);
1535 *font = NULL;
1537 if (This->font_count == 0)
1538 return S_FALSE;
1540 if (index >= This->font_count)
1541 return E_INVALIDARG;
1543 return create_font(This->fonts[index], This->family, font);
1546 static const IDWriteFontListVtbl dwritefontlistvtbl = {
1547 dwritefontlist_QueryInterface,
1548 dwritefontlist_AddRef,
1549 dwritefontlist_Release,
1550 dwritefontlist_GetFontCollection,
1551 dwritefontlist_GetFontCount,
1552 dwritefontlist_GetFont
1555 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily *iface, REFIID riid, void **obj)
1557 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1558 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1560 if (IsEqualIID(riid, &IID_IUnknown) ||
1561 IsEqualIID(riid, &IID_IDWriteFontList) ||
1562 IsEqualIID(riid, &IID_IDWriteFontFamily))
1564 *obj = iface;
1565 IDWriteFontFamily_AddRef(iface);
1566 return S_OK;
1569 *obj = NULL;
1570 return E_NOINTERFACE;
1573 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily *iface)
1575 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1576 ULONG ref = InterlockedIncrement(&This->ref);
1577 TRACE("(%p)->(%d)\n", This, ref);
1578 return ref;
1581 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily *iface)
1583 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1584 ULONG ref = InterlockedDecrement(&This->ref);
1586 TRACE("(%p)->(%d)\n", This, ref);
1588 if (!ref)
1590 IDWriteFontCollection_Release(This->collection);
1591 release_fontfamily_data(This->data);
1592 heap_free(This);
1595 return ref;
1598 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily *iface, IDWriteFontCollection **collection)
1600 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1601 TRACE("(%p)->(%p)\n", This, collection);
1603 *collection = This->collection;
1604 IDWriteFontCollection_AddRef(This->collection);
1605 return S_OK;
1608 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily *iface)
1610 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1611 TRACE("(%p)\n", This);
1612 return This->data->font_count;
1615 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily *iface, UINT32 index, IDWriteFont **font)
1617 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1619 TRACE("(%p)->(%u %p)\n", This, index, font);
1621 *font = NULL;
1623 if (This->data->font_count == 0)
1624 return S_FALSE;
1626 if (index >= This->data->font_count)
1627 return E_INVALIDARG;
1629 return create_font(This->data->fonts[index], iface, font);
1632 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface, IDWriteLocalizedStrings **names)
1634 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1635 return clone_localizedstring(This->data->familyname, names);
1638 static BOOL is_better_font_match(const struct dwrite_font_propvec *next, const struct dwrite_font_propvec *cur,
1639 const struct dwrite_font_propvec *req)
1641 FLOAT cur_to_req = get_font_prop_vec_distance(cur, req);
1642 FLOAT next_to_req = get_font_prop_vec_distance(next, req);
1643 FLOAT cur_req_prod, next_req_prod;
1645 if (next_to_req < cur_to_req)
1646 return TRUE;
1648 if (next_to_req > cur_to_req)
1649 return FALSE;
1651 cur_req_prod = get_font_prop_vec_dotproduct(cur, req);
1652 next_req_prod = get_font_prop_vec_dotproduct(next, req);
1654 if (next_req_prod > cur_req_prod)
1655 return TRUE;
1657 if (next_req_prod < cur_req_prod)
1658 return FALSE;
1660 if (next->stretch > cur->stretch)
1661 return TRUE;
1662 if (next->stretch < cur->stretch)
1663 return FALSE;
1665 if (next->style > cur->style)
1666 return TRUE;
1667 if (next->style < cur->style)
1668 return FALSE;
1670 if (next->weight > cur->weight)
1671 return TRUE;
1672 if (next->weight < cur->weight)
1673 return FALSE;
1675 /* full match, no reason to prefer new variant */
1676 return FALSE;
1679 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1680 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1682 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1683 struct dwrite_font_propvec req;
1684 struct dwrite_font_data *match;
1685 UINT32 i;
1687 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1689 if (This->data->font_count == 0) {
1690 *font = NULL;
1691 return DWRITE_E_NOFONT;
1694 init_font_prop_vec(weight, stretch, style, &req);
1695 match = This->data->fonts[0];
1697 for (i = 1; i < This->data->font_count; i++) {
1698 if (is_better_font_match(&This->data->fonts[i]->propvec, &match->propvec, &req))
1699 match = This->data->fonts[i];
1702 return create_font(match, iface, font);
1705 typedef BOOL (*matching_filter_func)(const struct dwrite_font_data*);
1707 static BOOL is_font_acceptable_for_normal(const struct dwrite_font_data *font)
1709 return font->style == DWRITE_FONT_STYLE_NORMAL || font->style == DWRITE_FONT_STYLE_ITALIC;
1712 static BOOL is_font_acceptable_for_oblique_italic(const struct dwrite_font_data *font)
1714 return font->style == DWRITE_FONT_STYLE_OBLIQUE || font->style == DWRITE_FONT_STYLE_ITALIC;
1717 static void matchingfonts_sort(struct dwrite_fontlist *fonts, const struct dwrite_font_propvec *req)
1719 UINT32 b = fonts->font_count - 1, j, t;
1721 while (1) {
1722 t = b;
1724 for (j = 0; j < b; j++) {
1725 if (is_better_font_match(&fonts->fonts[j+1]->propvec, &fonts->fonts[j]->propvec, req)) {
1726 struct dwrite_font_data *s = fonts->fonts[j];
1727 fonts->fonts[j] = fonts->fonts[j+1];
1728 fonts->fonts[j+1] = s;
1729 t = j;
1733 if (t == b)
1734 break;
1735 b = t;
1739 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1740 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **ret)
1742 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1743 matching_filter_func func = NULL;
1744 struct dwrite_font_propvec req;
1745 struct dwrite_fontlist *fonts;
1746 UINT32 i;
1748 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, ret);
1750 *ret = NULL;
1752 fonts = heap_alloc(sizeof(*fonts));
1753 if (!fonts)
1754 return E_OUTOFMEMORY;
1756 /* Allocate as many as family has, not all of them will be necessary used. */
1757 fonts->fonts = heap_alloc(sizeof(*fonts->fonts) * This->data->font_count);
1758 if (!fonts->fonts) {
1759 heap_free(fonts);
1760 return E_OUTOFMEMORY;
1763 fonts->IDWriteFontList_iface.lpVtbl = &dwritefontlistvtbl;
1764 fonts->ref = 1;
1765 fonts->family = iface;
1766 IDWriteFontFamily_AddRef(fonts->family);
1767 fonts->font_count = 0;
1769 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1770 if (style == DWRITE_FONT_STYLE_NORMAL) {
1771 if (This->data->has_normal_face || This->data->has_italic_face)
1772 func = is_font_acceptable_for_normal;
1774 else /* requested oblique or italic */ {
1775 if (This->data->has_oblique_face || This->data->has_italic_face)
1776 func = is_font_acceptable_for_oblique_italic;
1779 for (i = 0; i < This->data->font_count; i++) {
1780 if (!func || func(This->data->fonts[i])) {
1781 fonts->fonts[fonts->font_count] = This->data->fonts[i];
1782 InterlockedIncrement(&This->data->fonts[i]->ref);
1783 fonts->font_count++;
1787 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1788 init_font_prop_vec(weight, stretch, style, &req);
1789 matchingfonts_sort(fonts, &req);
1791 *ret = &fonts->IDWriteFontList_iface;
1792 return S_OK;
1795 static const IDWriteFontFamilyVtbl fontfamilyvtbl = {
1796 dwritefontfamily_QueryInterface,
1797 dwritefontfamily_AddRef,
1798 dwritefontfamily_Release,
1799 dwritefontfamily_GetFontCollection,
1800 dwritefontfamily_GetFontCount,
1801 dwritefontfamily_GetFont,
1802 dwritefontfamily_GetFamilyNames,
1803 dwritefontfamily_GetFirstMatchingFont,
1804 dwritefontfamily_GetMatchingFonts
1807 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily **family)
1809 struct dwrite_fontfamily *This;
1811 *family = NULL;
1813 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1814 if (!This) return E_OUTOFMEMORY;
1816 This->IDWriteFontFamily_iface.lpVtbl = &fontfamilyvtbl;
1817 This->ref = 1;
1818 This->collection = collection;
1819 IDWriteFontCollection_AddRef(collection);
1820 This->data = data;
1821 InterlockedIncrement(&This->data->ref);
1823 *family = &This->IDWriteFontFamily_iface;
1825 return S_OK;
1828 BOOL is_system_collection(IDWriteFontCollection *collection)
1830 void *obj;
1831 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1834 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection *iface, REFIID riid, void **obj)
1836 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1837 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1839 if (IsEqualIID(riid, &IID_IUnknown) ||
1840 IsEqualIID(riid, &IID_IDWriteFontCollection))
1842 *obj = iface;
1843 IDWriteFontCollection_AddRef(iface);
1844 return S_OK;
1847 *obj = NULL;
1849 if (This->is_system && IsEqualIID(riid, &IID_issystemcollection))
1850 return S_OK;
1852 return E_NOINTERFACE;
1855 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection *iface)
1857 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1858 ULONG ref = InterlockedIncrement(&This->ref);
1859 TRACE("(%p)->(%d)\n", This, ref);
1860 return ref;
1863 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection *iface)
1865 unsigned int i;
1866 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1867 ULONG ref = InterlockedDecrement(&This->ref);
1868 TRACE("(%p)->(%d)\n", This, ref);
1870 if (!ref) {
1871 for (i = 0; i < This->family_count; i++)
1872 release_fontfamily_data(This->family_data[i]);
1873 heap_free(This->family_data);
1874 heap_free(This);
1877 return ref;
1880 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
1882 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1883 TRACE("(%p)\n", This);
1884 return This->family_count;
1887 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
1889 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1891 TRACE("(%p)->(%u %p)\n", This, index, family);
1893 if (index >= This->family_count) {
1894 *family = NULL;
1895 return E_FAIL;
1898 return create_fontfamily(This->family_data[index], iface, family);
1901 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
1903 UINT32 i;
1905 for (i = 0; i < collection->family_count; i++) {
1906 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
1907 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
1908 HRESULT hr;
1910 for (j = 0; j < count; j++) {
1911 WCHAR buffer[255];
1912 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
1913 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
1914 return i;
1918 return ~0u;
1921 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
1923 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1924 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
1925 *index = collection_find_family(This, name);
1926 *exists = *index != ~0u;
1927 return S_OK;
1930 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
1932 UINT32 left_key_size, right_key_size;
1933 const void *left_key, *right_key;
1934 HRESULT hr;
1936 if (left == right)
1937 return TRUE;
1939 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
1940 if (FAILED(hr))
1941 return FALSE;
1943 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
1944 if (FAILED(hr))
1945 return FALSE;
1947 if (left_key_size != right_key_size)
1948 return FALSE;
1950 return !memcmp(left_key, right_key, left_key_size);
1953 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
1955 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1956 struct dwrite_fontfamily_data *found_family = NULL;
1957 struct dwrite_font_data *found_font = NULL;
1958 IDWriteFontFamily *family;
1959 UINT32 i, j, face_index;
1960 IDWriteFontFile *file;
1961 HRESULT hr;
1963 TRACE("(%p)->(%p %p)\n", This, face, font);
1965 *font = NULL;
1967 if (!face)
1968 return E_INVALIDARG;
1970 i = 1;
1971 hr = IDWriteFontFace_GetFiles(face, &i, &file);
1972 if (FAILED(hr))
1973 return hr;
1974 face_index = IDWriteFontFace_GetIndex(face);
1976 for (i = 0; i < This->family_count; i++) {
1977 struct dwrite_fontfamily_data *family_data = This->family_data[i];
1978 for (j = 0; j < family_data->font_count; j++) {
1979 struct dwrite_font_data *font_data = family_data->fonts[j];
1981 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
1982 found_font = font_data;
1983 found_family = family_data;
1984 break;
1989 if (!found_font)
1990 return DWRITE_E_NOFONT;
1992 hr = create_fontfamily(found_family, iface, &family);
1993 if (FAILED(hr))
1994 return hr;
1996 hr = create_font(found_font, family, font);
1997 IDWriteFontFamily_Release(family);
1998 return hr;
2001 static const IDWriteFontCollectionVtbl fontcollectionvtbl = {
2002 dwritefontcollection_QueryInterface,
2003 dwritefontcollection_AddRef,
2004 dwritefontcollection_Release,
2005 dwritefontcollection_GetFontFamilyCount,
2006 dwritefontcollection_GetFontFamily,
2007 dwritefontcollection_FindFamilyName,
2008 dwritefontcollection_GetFontFromFontFace
2011 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
2013 if (family_data->font_count + 1 >= family_data->font_alloc) {
2014 struct dwrite_font_data **new_list;
2015 UINT32 new_alloc;
2017 new_alloc = family_data->font_alloc * 2;
2018 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
2019 if (!new_list)
2020 return E_OUTOFMEMORY;
2021 family_data->fonts = new_list;
2022 family_data->font_alloc = new_alloc;
2025 family_data->fonts[family_data->font_count] = font_data;
2026 family_data->font_count++;
2027 if (font_data->style == DWRITE_FONT_STYLE_NORMAL)
2028 family_data->has_normal_face = TRUE;
2029 else if (font_data->style == DWRITE_FONT_STYLE_OBLIQUE)
2030 family_data->has_oblique_face = TRUE;
2031 else
2032 family_data->has_italic_face = TRUE;
2033 return S_OK;
2036 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
2038 if (collection->family_alloc < collection->family_count + 1) {
2039 struct dwrite_fontfamily_data **new_list;
2040 UINT32 new_alloc;
2042 new_alloc = collection->family_alloc * 2;
2043 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
2044 if (!new_list)
2045 return E_OUTOFMEMORY;
2047 collection->family_alloc = new_alloc;
2048 collection->family_data = new_list;
2051 collection->family_data[collection->family_count] = family;
2052 collection->family_count++;
2054 return S_OK;
2057 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
2059 collection->IDWriteFontCollection_iface.lpVtbl = &fontcollectionvtbl;
2060 collection->ref = 1;
2061 collection->family_count = 0;
2062 collection->family_alloc = is_system ? 30 : 5;
2063 collection->is_system = is_system;
2065 collection->family_data = heap_alloc(sizeof(*collection->family_data) * collection->family_alloc);
2066 if (!collection->family_data)
2067 return E_OUTOFMEMORY;
2069 return S_OK;
2072 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2074 IDWriteFontFileLoader *loader;
2075 const void *key;
2076 UINT32 key_size;
2077 HRESULT hr;
2079 *stream = NULL;
2081 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2082 if (FAILED(hr))
2083 return hr;
2085 hr = IDWriteFontFile_GetLoader(file, &loader);
2086 if (FAILED(hr))
2087 return hr;
2089 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2090 IDWriteFontFileLoader_Release(loader);
2091 if (FAILED(hr))
2092 return hr;
2094 return hr;
2097 static void fontstrings_get_en_string(IDWriteLocalizedStrings *strings, WCHAR *buffer, UINT32 size)
2099 BOOL exists = FALSE;
2100 UINT32 index;
2101 HRESULT hr;
2103 buffer[0] = 0;
2104 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2105 if (FAILED(hr) || !exists)
2106 return;
2108 IDWriteLocalizedStrings_GetString(strings, index, buffer, size);
2111 static int trim_spaces(WCHAR *in, WCHAR *ret)
2113 int len;
2115 while (isspaceW(*in))
2116 in++;
2118 ret[0] = 0;
2119 if (!(len = strlenW(in)))
2120 return 0;
2122 while (isspaceW(in[len-1]))
2123 len--;
2125 memcpy(ret, in, len*sizeof(WCHAR));
2126 ret[len] = 0;
2128 return len;
2131 struct name_token {
2132 struct list entry;
2133 const WCHAR *ptr;
2134 INT len; /* token length */
2135 INT fulllen; /* full length including following separators */
2138 static inline BOOL is_name_separator_char(WCHAR ch)
2140 return ch == ' ' || ch == '.' || ch == '-' || ch == '_';
2143 struct name_pattern {
2144 const WCHAR *part1; /* NULL indicates end of list */
2145 const WCHAR *part2; /* optional, if not NULL should point to non-empty string */
2148 static BOOL match_pattern_list(struct list *tokens, const struct name_pattern *patterns, struct name_token *match)
2150 const struct name_pattern *pattern;
2151 struct name_token *token;
2152 int i = 0;
2154 while ((pattern = &patterns[i++])->part1) {
2155 int len_part1 = strlenW(pattern->part1);
2156 int len_part2 = pattern->part2 ? strlenW(pattern->part2) : 0;
2158 LIST_FOR_EACH_ENTRY(token, tokens, struct name_token, entry) {
2159 if (len_part2 == 0) {
2160 /* simple case with single part pattern */
2161 if (token->len != len_part1)
2162 continue;
2164 if (!strncmpiW(token->ptr, pattern->part1, len_part1)) {
2165 if (match) *match = *token;
2166 list_remove(&token->entry);
2167 heap_free(token);
2168 return TRUE;
2171 else {
2172 struct name_token *next_token;
2173 struct list *next_entry;
2175 /* pattern parts are stored in reading order, tokens list is reversed */
2176 if (token->len < len_part2)
2177 continue;
2179 /* it's possible to have combined string as a token, like ExtraCondensed */
2180 if (token->len == len_part1 + len_part2) {
2181 if (strncmpiW(token->ptr, pattern->part1, len_part1))
2182 continue;
2184 if (strncmpiW(&token->ptr[len_part1], pattern->part2, len_part2))
2185 continue;
2187 /* combined string match */
2188 if (match) *match = *token;
2189 list_remove(&token->entry);
2190 heap_free(token);
2191 return TRUE;
2194 /* now it's only possible to have two tokens matched to respective pattern parts */
2195 if (token->len != len_part2)
2196 continue;
2198 next_entry = list_next(tokens, &token->entry);
2199 if (next_entry) {
2200 next_token = LIST_ENTRY(next_entry, struct name_token, entry);
2201 if (next_token->len != len_part1)
2202 continue;
2204 if (strncmpiW(token->ptr, pattern->part2, len_part2))
2205 continue;
2207 if (strncmpiW(next_token->ptr, pattern->part1, len_part1))
2208 continue;
2210 /* both parts matched, remove tokens */
2211 if (match) {
2212 match->ptr = next_token->ptr;
2213 match->len = (token->ptr - next_token->ptr) + token->len;
2215 list_remove(&token->entry);
2216 list_remove(&next_token->entry);
2217 heap_free(next_token);
2218 heap_free(token);
2219 return TRUE;
2225 if (match) {
2226 match->ptr = NULL;
2227 match->len = 0;
2229 return FALSE;
2232 static DWRITE_FONT_STYLE font_extract_style(struct list *tokens, DWRITE_FONT_STYLE style, struct name_token *match)
2234 static const WCHAR itaW[] = {'i','t','a',0};
2235 static const WCHAR italW[] = {'i','t','a','l',0};
2236 static const WCHAR cursiveW[] = {'c','u','r','s','i','v','e',0};
2237 static const WCHAR kursivW[] = {'k','u','r','s','i','v',0};
2239 static const WCHAR inclinedW[] = {'i','n','c','l','i','n','e','d',0};
2240 static const WCHAR backslantedW[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2241 static const WCHAR backslantW[] = {'b','a','c','k','s','l','a','n','t',0};
2242 static const WCHAR slantedW[] = {'s','l','a','n','t','e','d',0};
2244 static const struct name_pattern italic_patterns[] = {
2245 { itaW },
2246 { italW },
2247 { italicW },
2248 { cursiveW },
2249 { kursivW },
2250 { NULL }
2253 static const struct name_pattern oblique_patterns[] = {
2254 { inclinedW },
2255 { obliqueW },
2256 { backslantedW },
2257 { backslantW },
2258 { slantedW },
2259 { NULL }
2262 /* italic patterns first */
2263 if (match_pattern_list(tokens, italic_patterns, match))
2264 return DWRITE_FONT_STYLE_ITALIC;
2266 /* oblique patterns */
2267 if (match_pattern_list(tokens, oblique_patterns, match))
2268 return DWRITE_FONT_STYLE_OBLIQUE;
2270 return style;
2273 static DWRITE_FONT_STRETCH font_extract_stretch(struct list *tokens, DWRITE_FONT_STRETCH stretch,
2274 struct name_token *match)
2276 static const WCHAR compressedW[] = {'c','o','m','p','r','e','s','s','e','d',0};
2277 static const WCHAR extendedW[] = {'e','x','t','e','n','d','e','d',0};
2278 static const WCHAR compactW[] = {'c','o','m','p','a','c','t',0};
2279 static const WCHAR narrowW[] = {'n','a','r','r','o','w',0};
2280 static const WCHAR wideW[] = {'w','i','d','e',0};
2281 static const WCHAR condW[] = {'c','o','n','d',0};
2283 static const struct name_pattern ultracondensed_patterns[] = {
2284 { extraW, compressedW },
2285 { extW, compressedW },
2286 { ultraW, compressedW },
2287 { ultraW, condensedW },
2288 { ultraW, condW },
2289 { NULL }
2292 static const struct name_pattern extracondensed_patterns[] = {
2293 { compressedW },
2294 { extraW, condensedW },
2295 { extW, condensedW },
2296 { extraW, condW },
2297 { extW, condW },
2298 { NULL }
2301 static const struct name_pattern semicondensed_patterns[] = {
2302 { narrowW },
2303 { compactW },
2304 { semiW, condensedW },
2305 { semiW, condW },
2306 { NULL }
2309 static const struct name_pattern semiexpanded_patterns[] = {
2310 { wideW },
2311 { semiW, expandedW },
2312 { semiW, extendedW },
2313 { NULL }
2316 static const struct name_pattern extraexpanded_patterns[] = {
2317 { extraW, expandedW },
2318 { extW, expandedW },
2319 { extraW, extendedW },
2320 { extW, extendedW },
2321 { NULL }
2324 static const struct name_pattern ultraexpanded_patterns[] = {
2325 { ultraW, expandedW },
2326 { ultraW, extendedW },
2327 { NULL }
2330 static const struct name_pattern condensed_patterns[] = {
2331 { condensedW },
2332 { condW },
2333 { NULL }
2336 static const struct name_pattern expanded_patterns[] = {
2337 { expandedW },
2338 { extendedW },
2339 { NULL }
2342 if (match_pattern_list(tokens, ultracondensed_patterns, match))
2343 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
2345 if (match_pattern_list(tokens, extracondensed_patterns, match))
2346 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
2348 if (match_pattern_list(tokens, semicondensed_patterns, match))
2349 return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
2351 if (match_pattern_list(tokens, semiexpanded_patterns, match))
2352 return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
2354 if (match_pattern_list(tokens, extraexpanded_patterns, match))
2355 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
2357 if (match_pattern_list(tokens, ultraexpanded_patterns, match))
2358 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
2360 if (match_pattern_list(tokens, condensed_patterns, match))
2361 return DWRITE_FONT_STRETCH_CONDENSED;
2363 if (match_pattern_list(tokens, expanded_patterns, match))
2364 return DWRITE_FONT_STRETCH_EXPANDED;
2366 return stretch;
2369 static DWRITE_FONT_WEIGHT font_extract_weight(struct list *tokens, DWRITE_FONT_WEIGHT weight,
2370 struct name_token *match)
2372 static const WCHAR heavyW[] = {'h','e','a','v','y',0};
2373 static const WCHAR nordW[] = {'n','o','r','d',0};
2375 static const struct name_pattern thin_patterns[] = {
2376 { extraW, thinW },
2377 { extW, thinW },
2378 { ultraW, thinW },
2379 { NULL }
2382 static const struct name_pattern extralight_patterns[] = {
2383 { extraW, lightW },
2384 { extW, lightW },
2385 { ultraW, lightW },
2386 { NULL }
2389 static const struct name_pattern semilight_patterns[] = {
2390 { semiW, lightW },
2391 { NULL }
2394 static const struct name_pattern demibold_patterns[] = {
2395 { semiW, boldW },
2396 { demiW, boldW },
2397 { NULL }
2400 static const struct name_pattern extrabold_patterns[] = {
2401 { extraW, boldW },
2402 { extW, boldW },
2403 { ultraW, boldW },
2404 { NULL }
2407 static const struct name_pattern extrablack_patterns[] = {
2408 { extraW, blackW },
2409 { extW, blackW },
2410 { ultraW, blackW },
2411 { NULL }
2414 static const struct name_pattern bold_patterns[] = {
2415 { boldW },
2416 { NULL }
2419 static const struct name_pattern thin2_patterns[] = {
2420 { thinW },
2421 { NULL }
2424 static const struct name_pattern light_patterns[] = {
2425 { lightW },
2426 { NULL }
2429 static const struct name_pattern medium_patterns[] = {
2430 { mediumW },
2431 { NULL }
2434 static const struct name_pattern black_patterns[] = {
2435 { blackW },
2436 { heavyW },
2437 { nordW },
2438 { NULL }
2441 static const struct name_pattern demibold2_patterns[] = {
2442 { demiW },
2443 { NULL }
2446 static const struct name_pattern extrabold2_patterns[] = {
2447 { ultraW },
2448 { NULL }
2451 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2452 matching pattern. */
2454 if (match_pattern_list(tokens, thin_patterns, match))
2455 return DWRITE_FONT_WEIGHT_THIN;
2457 if (match_pattern_list(tokens, extralight_patterns, match))
2458 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT;
2460 if (match_pattern_list(tokens, semilight_patterns, match))
2461 return DWRITE_FONT_WEIGHT_SEMI_LIGHT;
2463 if (match_pattern_list(tokens, demibold_patterns, match))
2464 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2466 if (match_pattern_list(tokens, extrabold_patterns, match))
2467 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2469 if (match_pattern_list(tokens, extrablack_patterns, match))
2470 return DWRITE_FONT_WEIGHT_EXTRA_BLACK;
2472 if (match_pattern_list(tokens, bold_patterns, match))
2473 return DWRITE_FONT_WEIGHT_BOLD;
2475 if (match_pattern_list(tokens, thin2_patterns, match))
2476 return DWRITE_FONT_WEIGHT_THIN;
2478 if (match_pattern_list(tokens, light_patterns, match))
2479 return DWRITE_FONT_WEIGHT_LIGHT;
2481 if (match_pattern_list(tokens, medium_patterns, match))
2482 return DWRITE_FONT_WEIGHT_MEDIUM;
2484 if (match_pattern_list(tokens, black_patterns, match))
2485 return DWRITE_FONT_WEIGHT_BLACK;
2487 if (match_pattern_list(tokens, black_patterns, match))
2488 return DWRITE_FONT_WEIGHT_BLACK;
2490 if (match_pattern_list(tokens, demibold2_patterns, match))
2491 return DWRITE_FONT_WEIGHT_DEMI_BOLD;
2493 if (match_pattern_list(tokens, extrabold2_patterns, match))
2494 return DWRITE_FONT_WEIGHT_EXTRA_BOLD;
2496 /* FIXME: use abbreviated names to extract weight */
2498 return weight;
2501 struct knownweight_entry {
2502 const WCHAR *nameW;
2503 DWRITE_FONT_WEIGHT weight;
2506 static int compare_knownweights(const void *a, const void* b)
2508 DWRITE_FONT_WEIGHT target = *(DWRITE_FONT_WEIGHT*)a;
2509 const struct knownweight_entry *entry = (struct knownweight_entry*)b;
2510 int ret = 0;
2512 if (target > entry->weight)
2513 ret = 1;
2514 else if (target < entry->weight)
2515 ret = -1;
2517 return ret;
2520 static BOOL is_known_weight_value(DWRITE_FONT_WEIGHT weight, WCHAR *nameW)
2522 static const WCHAR extralightW[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2523 static const WCHAR semilightW[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2524 static const WCHAR extrablackW[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2525 static const WCHAR extraboldW[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2526 static const WCHAR demiboldW[] = {'D','e','m','i',' ','B','o','l','d',0};
2527 const struct knownweight_entry *ptr;
2529 static const struct knownweight_entry knownweights[] = {
2530 { thinW, DWRITE_FONT_WEIGHT_THIN },
2531 { extralightW, DWRITE_FONT_WEIGHT_EXTRA_LIGHT },
2532 { lightW, DWRITE_FONT_WEIGHT_LIGHT },
2533 { semilightW, DWRITE_FONT_WEIGHT_SEMI_LIGHT },
2534 { mediumW, DWRITE_FONT_WEIGHT_MEDIUM },
2535 { demiboldW, DWRITE_FONT_WEIGHT_DEMI_BOLD },
2536 { boldW, DWRITE_FONT_WEIGHT_BOLD },
2537 { extraboldW, DWRITE_FONT_WEIGHT_EXTRA_BOLD },
2538 { blackW, DWRITE_FONT_WEIGHT_BLACK },
2539 { extrablackW, DWRITE_FONT_WEIGHT_EXTRA_BLACK }
2542 ptr = bsearch(&weight, knownweights, sizeof(knownweights)/sizeof(knownweights[0]), sizeof(knownweights[0]),
2543 compare_knownweights);
2544 if (!ptr) {
2545 nameW[0] = 0;
2546 return FALSE;
2549 strcpyW(nameW, ptr->nameW);
2550 return TRUE;
2553 static inline void font_name_token_to_str(const struct name_token *name, WCHAR *strW)
2555 memcpy(strW, name->ptr, name->len * sizeof(WCHAR));
2556 strW[name->len] = 0;
2559 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2560 static const WCHAR *facename_remove_regular_term(WCHAR *facenameW, INT len)
2562 static const WCHAR bookW[] = {'B','o','o','k',0};
2563 static const WCHAR normalW[] = {'N','o','r','m','a','l',0};
2564 static const WCHAR regularW[] = {'R','e','g','u','l','a','r',0};
2565 static const WCHAR romanW[] = {'R','o','m','a','n',0};
2566 static const WCHAR uprightW[] = {'U','p','r','i','g','h','t',0};
2568 static const WCHAR *regular_patterns[] = {
2569 bookW,
2570 normalW,
2571 regularW,
2572 romanW,
2573 uprightW,
2574 NULL
2577 const WCHAR *regular_ptr = NULL, *ptr;
2578 int i = 0;
2580 if (len == -1)
2581 len = strlenW(facenameW);
2583 /* remove rightmost regular variant from face name */
2584 while (!regular_ptr && (ptr = regular_patterns[i++])) {
2585 int pattern_len = strlenW(ptr);
2586 WCHAR *src;
2588 if (pattern_len > len)
2589 continue;
2591 src = facenameW + len - pattern_len;
2592 while (src >= facenameW) {
2593 if (!strncmpiW(src, ptr, pattern_len)) {
2594 memmove(src, src + pattern_len, (len - pattern_len - (src - facenameW) + 1)*sizeof(WCHAR));
2595 len = strlenW(facenameW);
2596 regular_ptr = ptr;
2597 break;
2599 else
2600 src--;
2604 return regular_ptr;
2607 static void fontname_tokenize(struct list *tokens, const WCHAR *nameW)
2609 const WCHAR *ptr;
2611 list_init(tokens);
2612 ptr = nameW;
2614 while (*ptr) {
2615 struct name_token *token = heap_alloc(sizeof(*token));
2616 token->ptr = ptr;
2617 token->len = 0;
2618 token->fulllen = 0;
2620 while (*ptr && !is_name_separator_char(*ptr)) {
2621 token->len++;
2622 token->fulllen++;
2623 ptr++;
2626 /* skip separators */
2627 while (is_name_separator_char(*ptr)) {
2628 token->fulllen++;
2629 ptr++;
2632 list_add_head(tokens, &token->entry);
2636 static void fontname_tokens_to_str(struct list *tokens, WCHAR *nameW)
2638 struct name_token *token, *token2;
2639 LIST_FOR_EACH_ENTRY_SAFE_REV(token, token2, tokens, struct name_token, entry) {
2640 int len;
2642 list_remove(&token->entry);
2644 /* don't include last separator */
2645 len = list_empty(tokens) ? token->len : token->fulllen;
2646 memcpy(nameW, token->ptr, len * sizeof(WCHAR));
2647 nameW += len;
2649 heap_free(token);
2651 *nameW = 0;
2654 static BOOL font_apply_differentiation_rules(struct dwrite_font_data *font, WCHAR *familyW, WCHAR *faceW)
2656 struct name_token stretch_name, weight_name, style_name;
2657 WCHAR familynameW[255], facenameW[255], finalW[255];
2658 WCHAR weightW[32], stretchW[32], styleW[32];
2659 const WCHAR *regular_ptr = NULL;
2660 DWRITE_FONT_STRETCH stretch;
2661 DWRITE_FONT_WEIGHT weight;
2662 struct list tokens;
2663 int len;
2665 /* remove leading and trailing spaces from family and face name */
2666 trim_spaces(familyW, familynameW);
2667 len = trim_spaces(faceW, facenameW);
2669 /* remove rightmost regular variant from face name */
2670 regular_ptr = facename_remove_regular_term(facenameW, len);
2672 /* append face name to family name, FIXME check if face name is a substring of family name */
2673 if (*facenameW) {
2674 strcatW(familynameW, spaceW);
2675 strcatW(familynameW, facenameW);
2678 /* tokenize with " .-_" */
2679 fontname_tokenize(&tokens, familynameW);
2681 /* extract and resolve style */
2682 font->style = font_extract_style(&tokens, font->style, &style_name);
2684 /* extract stretch */
2685 stretch = font_extract_stretch(&tokens, font->stretch, &stretch_name);
2687 /* extract weight */
2688 weight = font_extract_weight(&tokens, font->weight, &weight_name);
2690 /* resolve weight */
2691 if (weight != font->weight) {
2692 if (!(weight < DWRITE_FONT_WEIGHT_NORMAL && font->weight < DWRITE_FONT_WEIGHT_NORMAL) &&
2693 !(weight > DWRITE_FONT_WEIGHT_MEDIUM && font->weight > DWRITE_FONT_WEIGHT_MEDIUM) &&
2694 !((weight == DWRITE_FONT_WEIGHT_NORMAL && font->weight == DWRITE_FONT_WEIGHT_MEDIUM) ||
2695 (weight == DWRITE_FONT_WEIGHT_MEDIUM && font->weight == DWRITE_FONT_WEIGHT_NORMAL)) &&
2696 !(abs(weight - font->weight) <= 150 &&
2697 font->weight != DWRITE_FONT_WEIGHT_NORMAL &&
2698 font->weight != DWRITE_FONT_WEIGHT_MEDIUM &&
2699 font->weight != DWRITE_FONT_WEIGHT_BOLD)) {
2701 font->weight = weight;
2705 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2706 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2707 stretch itself is normal (extracted stretch is never normal). */
2708 if (stretch != font->stretch) {
2709 if ((font->stretch == DWRITE_FONT_STRETCH_NORMAL) ||
2710 (font->stretch < DWRITE_FONT_STRETCH_NORMAL && stretch > DWRITE_FONT_STRETCH_NORMAL) ||
2711 (font->stretch > DWRITE_FONT_STRETCH_NORMAL && stretch < DWRITE_FONT_STRETCH_NORMAL)) {
2713 font->stretch = stretch;
2717 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2719 /* get final combined string from what's left in token list, list is released */
2720 fontname_tokens_to_str(&tokens, finalW);
2722 if (!strcmpW(familyW, finalW))
2723 return FALSE;
2725 /* construct face name */
2726 strcpyW(familyW, finalW);
2728 /* resolved weight name */
2729 if (weight_name.ptr)
2730 font_name_token_to_str(&weight_name, weightW);
2731 /* ignore normal weight */
2732 else if (font->weight == DWRITE_FONT_WEIGHT_NORMAL)
2733 weightW[0] = 0;
2734 /* for known weight values use appropriate names */
2735 else if (is_known_weight_value(font->weight, weightW)) {
2737 /* use Wnnn format as a fallback in case weight is not one of defined values */
2738 else {
2739 static const WCHAR fmtW[] = {'W','%','d',0};
2740 sprintfW(weightW, fmtW, font->weight);
2743 /* resolved stretch name */
2744 if (stretch_name.ptr)
2745 font_name_token_to_str(&stretch_name, stretchW);
2746 /* ignore normal stretch */
2747 else if (font->stretch == DWRITE_FONT_STRETCH_NORMAL)
2748 stretchW[0] = 0;
2749 /* use predefined stretch names */
2750 else {
2751 static const WCHAR ultracondensedW[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2752 static const WCHAR extracondensedW[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2753 static const WCHAR semicondensedW[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2754 static const WCHAR semiexpandedW[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2755 static const WCHAR extraexpandedW[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2756 static const WCHAR ultraexpandedW[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2758 static const WCHAR *stretchnamesW[] = {
2759 ultracondensedW,
2760 extracondensedW,
2761 condensedW,
2762 semicondensedW,
2763 NULL, /* DWRITE_FONT_STRETCH_NORMAL */
2764 semiexpandedW,
2765 expandedW,
2766 extraexpandedW,
2767 ultraexpandedW
2769 strcpyW(stretchW, stretchnamesW[font->stretch]);
2772 /* resolved style name */
2773 if (style_name.ptr)
2774 font_name_token_to_str(&style_name, styleW);
2775 else if (font->style == DWRITE_FONT_STYLE_NORMAL)
2776 styleW[0] = 0;
2777 /* use predefined names */
2778 else {
2779 if (font->style == DWRITE_FONT_STYLE_ITALIC)
2780 strcpyW(styleW, italicW);
2781 else
2782 strcpyW(styleW, obliqueW);
2785 /* use Regular match if it was found initially */
2786 if (!*weightW && !*stretchW && !*styleW)
2787 strcpyW(faceW, regular_ptr ? regular_ptr : regularW);
2788 else {
2789 faceW[0] = 0;
2790 if (*stretchW)
2791 strcpyW(faceW, stretchW);
2792 if (*weightW) {
2793 if (*faceW)
2794 strcatW(faceW, spaceW);
2795 strcatW(faceW, weightW);
2797 if (*styleW) {
2798 if (*faceW)
2799 strcatW(faceW, spaceW);
2800 strcatW(faceW, styleW);
2804 TRACE("resolved family %s, face %s\n", debugstr_w(familyW), debugstr_w(faceW));
2805 return TRUE;
2808 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index,
2809 IDWriteLocalizedStrings **family_name, struct dwrite_font_data **ret)
2811 struct dwrite_font_props props;
2812 struct dwrite_font_data *data;
2813 IDWriteFontFileStream *stream;
2814 WCHAR familyW[255], faceW[255];
2815 HRESULT hr;
2817 *ret = NULL;
2818 data = heap_alloc_zero(sizeof(*data));
2819 if (!data)
2820 return E_OUTOFMEMORY;
2822 hr = get_filestream_from_file(file, &stream);
2823 if (FAILED(hr)) {
2824 heap_free(data);
2825 return hr;
2828 data->ref = 1;
2829 data->factory = factory;
2830 data->file = file;
2831 data->face_index = face_index;
2832 data->face_type = face_type;
2833 data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
2834 data->bold_sim_tested = FALSE;
2835 data->oblique_sim_tested = FALSE;
2836 IDWriteFontFile_AddRef(file);
2837 IDWriteFactory2_AddRef(factory);
2839 opentype_get_font_properties(stream, face_type, face_index, &props);
2840 opentype_get_font_metrics(stream, face_type, face_index, &data->metrics, NULL);
2841 opentype_get_font_facename(stream, face_type, face_index, &data->names);
2843 /* get family name from font file */
2844 hr = opentype_get_font_familyname(stream, face_type, face_index, family_name);
2845 IDWriteFontFileStream_Release(stream);
2846 if (FAILED(hr)) {
2847 WARN("unable to get family name from font\n");
2848 release_font_data(data);
2849 return hr;
2852 data->style = props.style;
2853 data->stretch = props.stretch;
2854 data->weight = props.weight;
2855 data->panose = props.panose;
2857 fontstrings_get_en_string(*family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
2858 fontstrings_get_en_string(data->names, faceW, sizeof(faceW)/sizeof(WCHAR));
2859 if (font_apply_differentiation_rules(data, familyW, faceW)) {
2860 set_en_localizedstring(*family_name, familyW);
2861 set_en_localizedstring(data->names, faceW);
2864 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2866 *ret = data;
2867 return S_OK;
2870 static HRESULT init_font_data_from_font(const struct dwrite_font_data *src, DWRITE_FONT_SIMULATIONS sim, const WCHAR *facenameW,
2871 struct dwrite_font_data **ret)
2873 struct dwrite_font_data *data;
2875 *ret = NULL;
2876 data = heap_alloc_zero(sizeof(*data));
2877 if (!data)
2878 return E_OUTOFMEMORY;
2880 *data = *src;
2881 data->ref = 1;
2882 data->simulations |= sim;
2883 if (sim == DWRITE_FONT_SIMULATIONS_BOLD)
2884 data->weight = DWRITE_FONT_WEIGHT_BOLD;
2885 else if (sim == DWRITE_FONT_SIMULATIONS_OBLIQUE)
2886 data->style = DWRITE_FONT_STYLE_OBLIQUE;
2887 memset(data->info_strings, 0, sizeof(data->info_strings));
2888 data->names = NULL;
2889 IDWriteFactory2_AddRef(data->factory);
2890 IDWriteFontFile_AddRef(data->file);
2892 create_localizedstrings(&data->names);
2893 add_localizedstring(data->names, enusW, facenameW);
2895 init_font_prop_vec(data->weight, data->stretch, data->style, &data->propvec);
2897 *ret = data;
2898 return S_OK;
2901 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
2903 struct dwrite_fontfamily_data *data;
2905 data = heap_alloc(sizeof(*data));
2906 if (!data)
2907 return E_OUTOFMEMORY;
2909 data->ref = 1;
2910 data->font_count = 0;
2911 data->font_alloc = 2;
2912 data->has_normal_face = FALSE;
2913 data->has_oblique_face = FALSE;
2914 data->has_italic_face = FALSE;
2916 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
2917 if (!data->fonts) {
2918 heap_free(data);
2919 return E_OUTOFMEMORY;
2922 data->familyname = familyname;
2923 IDWriteLocalizedStrings_AddRef(familyname);
2925 *ret = data;
2926 return S_OK;
2929 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data *family)
2931 UINT32 i, j, heaviest;
2933 for (i = 0; i < family->font_count; i++) {
2934 DWRITE_FONT_WEIGHT weight = family->fonts[i]->weight;
2935 heaviest = i;
2937 if (family->fonts[i]->bold_sim_tested)
2938 continue;
2940 family->fonts[i]->bold_sim_tested = TRUE;
2941 for (j = i; j < family->font_count; j++) {
2942 if (family->fonts[j]->bold_sim_tested)
2943 continue;
2945 if ((family->fonts[i]->style == family->fonts[j]->style) &&
2946 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
2947 if (family->fonts[j]->weight > weight) {
2948 weight = family->fonts[j]->weight;
2949 heaviest = j;
2951 family->fonts[j]->bold_sim_tested = TRUE;
2955 if (weight >= DWRITE_FONT_WEIGHT_SEMI_LIGHT && weight <= 550) {
2956 static const struct name_pattern weightsim_patterns[] = {
2957 { extraW, lightW },
2958 { extW, lightW },
2959 { ultraW, lightW },
2960 { semiW, lightW },
2961 { semiW, boldW },
2962 { demiW, boldW },
2963 { boldW },
2964 { thinW },
2965 { lightW },
2966 { mediumW },
2967 { demiW },
2968 { NULL }
2971 WCHAR facenameW[255], initialW[255];
2972 struct dwrite_font_data *boldface;
2973 struct list tokens;
2975 /* add Bold simulation based on heaviest face data */
2977 /* Simulated face name should only contain Bold as weight term,
2978 so remove existing regular and weight terms. */
2979 fontstrings_get_en_string(family->fonts[heaviest]->names, initialW, sizeof(initialW)/sizeof(WCHAR));
2980 facename_remove_regular_term(initialW, -1);
2982 /* remove current weight pattern */
2983 fontname_tokenize(&tokens, initialW);
2984 match_pattern_list(&tokens, weightsim_patterns, NULL);
2985 fontname_tokens_to_str(&tokens, facenameW);
2987 /* Bold suffix for new name */
2988 if (*facenameW)
2989 strcatW(facenameW, spaceW);
2990 strcatW(facenameW, boldW);
2992 if (init_font_data_from_font(family->fonts[heaviest], DWRITE_FONT_SIMULATIONS_BOLD, facenameW, &boldface) == S_OK) {
2993 boldface->bold_sim_tested = TRUE;
2994 fontfamily_add_font(family, boldface);
3000 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data *family)
3002 UINT32 i, j;
3004 for (i = 0; i < family->font_count; i++) {
3005 UINT32 regular = ~0u, oblique = ~0u;
3006 struct dwrite_font_data *obliqueface;
3007 WCHAR facenameW[255];
3009 if (family->fonts[i]->oblique_sim_tested)
3010 continue;
3012 family->fonts[i]->oblique_sim_tested = TRUE;
3013 if (family->fonts[i]->style == DWRITE_FONT_STYLE_NORMAL)
3014 regular = i;
3015 else if (family->fonts[i]->style == DWRITE_FONT_STYLE_OBLIQUE)
3016 oblique = i;
3018 /* find regular style with same weight/stretch values */
3019 for (j = i; j < family->font_count; j++) {
3020 if (family->fonts[j]->oblique_sim_tested)
3021 continue;
3023 if ((family->fonts[i]->weight == family->fonts[j]->weight) &&
3024 (family->fonts[i]->stretch == family->fonts[j]->stretch)) {
3026 family->fonts[j]->oblique_sim_tested = TRUE;
3027 if (regular == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_NORMAL)
3028 regular = j;
3030 if (oblique == ~0 && family->fonts[j]->style == DWRITE_FONT_STYLE_OBLIQUE)
3031 oblique = j;
3034 if (regular != ~0u && oblique != ~0u)
3035 break;
3038 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3039 if (regular == ~0u)
3040 continue;
3042 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3043 if (oblique != ~0u)
3044 continue;
3046 /* add oblique simulation based on this regular face */
3048 /* remove regular term if any, append 'Oblique' */
3049 fontstrings_get_en_string(family->fonts[regular]->names, facenameW, sizeof(facenameW)/sizeof(WCHAR));
3050 facename_remove_regular_term(facenameW, -1);
3052 if (*facenameW)
3053 strcatW(facenameW, spaceW);
3054 strcatW(facenameW, obliqueW);
3056 if (init_font_data_from_font(family->fonts[regular], DWRITE_FONT_SIMULATIONS_OBLIQUE, facenameW, &obliqueface) == S_OK) {
3057 obliqueface->oblique_sim_tested = TRUE;
3058 fontfamily_add_font(family, obliqueface);
3063 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
3065 struct fontfile_enum {
3066 struct list entry;
3067 IDWriteFontFile *file;
3069 struct fontfile_enum *fileenum, *fileenum2;
3070 struct dwrite_fontcollection *collection;
3071 struct list scannedfiles;
3072 BOOL current = FALSE;
3073 HRESULT hr = S_OK;
3074 UINT32 i;
3076 *ret = NULL;
3078 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
3079 if (!collection) return E_OUTOFMEMORY;
3081 hr = init_font_collection(collection, is_system);
3082 if (FAILED(hr)) {
3083 heap_free(collection);
3084 return hr;
3087 *ret = &collection->IDWriteFontCollection_iface;
3089 TRACE("building font collection:\n");
3091 list_init(&scannedfiles);
3092 while (hr == S_OK) {
3093 DWRITE_FONT_FACE_TYPE face_type;
3094 DWRITE_FONT_FILE_TYPE file_type;
3095 BOOL supported, same = FALSE;
3096 IDWriteFontFile *file;
3097 UINT32 face_count;
3099 current = FALSE;
3100 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
3101 if (FAILED(hr) || !current)
3102 break;
3104 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
3105 if (FAILED(hr))
3106 break;
3108 /* check if we've scanned this file already */
3109 LIST_FOR_EACH_ENTRY(fileenum, &scannedfiles, struct fontfile_enum, entry) {
3110 if ((same = is_same_fontfile(fileenum->file, file)))
3111 break;
3114 if (same) {
3115 IDWriteFontFile_Release(file);
3116 continue;
3119 /* failed font files are skipped */
3120 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
3121 if (FAILED(hr) || !supported || face_count == 0) {
3122 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
3123 IDWriteFontFile_Release(file);
3124 hr = S_OK;
3125 continue;
3128 /* add to scanned list */
3129 fileenum = heap_alloc(sizeof(*fileenum));
3130 fileenum->file = file;
3131 list_add_tail(&scannedfiles, &fileenum->entry);
3133 for (i = 0; i < face_count; i++) {
3134 IDWriteLocalizedStrings *family_name = NULL;
3135 struct dwrite_font_data *font_data;
3136 WCHAR familyW[255];
3137 UINT32 index;
3139 /* alloc and init new font data structure */
3140 hr = init_font_data(factory, file, face_type, i, &family_name, &font_data);
3141 if (FAILED(hr))
3142 continue;
3144 fontstrings_get_en_string(family_name, familyW, sizeof(familyW)/sizeof(WCHAR));
3146 index = collection_find_family(collection, familyW);
3147 if (index != ~0u)
3148 hr = fontfamily_add_font(collection->family_data[index], font_data);
3149 else {
3150 struct dwrite_fontfamily_data *family_data;
3152 /* create and init new family */
3153 hr = init_fontfamily_data(family_name, &family_data);
3154 if (hr == S_OK) {
3155 /* add font to family, family - to collection */
3156 hr = fontfamily_add_font(family_data, font_data);
3157 if (hr == S_OK)
3158 hr = fontcollection_add_family(collection, family_data);
3160 if (FAILED(hr))
3161 release_fontfamily_data(family_data);
3165 IDWriteLocalizedStrings_Release(family_name);
3167 if (FAILED(hr))
3168 break;
3172 LIST_FOR_EACH_ENTRY_SAFE(fileenum, fileenum2, &scannedfiles, struct fontfile_enum, entry) {
3173 IDWriteFontFile_Release(fileenum->file);
3174 list_remove(&fileenum->entry);
3175 heap_free(fileenum);
3178 for (i = 0; i < collection->family_count; i++) {
3179 fontfamily_add_bold_simulated_face(collection->family_data[i]);
3180 fontfamily_add_oblique_simulated_face(collection->family_data[i]);
3183 return hr;
3186 struct system_fontfile_enumerator
3188 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
3189 LONG ref;
3191 IDWriteFactory2 *factory;
3192 HKEY hkey;
3193 int index;
3196 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
3198 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
3201 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3203 *obj = NULL;
3205 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3206 IDWriteFontFileEnumerator_AddRef(iface);
3207 *obj = iface;
3208 return S_OK;
3211 return E_NOINTERFACE;
3214 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3216 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3217 return InterlockedIncrement(&enumerator->ref);
3220 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3222 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3223 ULONG ref = InterlockedDecrement(&enumerator->ref);
3225 if (!ref) {
3226 IDWriteFactory2_Release(enumerator->factory);
3227 RegCloseKey(enumerator->hkey);
3228 heap_free(enumerator);
3231 return ref;
3234 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3236 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3237 DWORD ret, type, val_count, count;
3238 WCHAR *value, *filename;
3239 HRESULT hr;
3241 *file = NULL;
3243 if (enumerator->index < 0)
3244 return E_FAIL;
3246 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
3247 if (ret != ERROR_SUCCESS)
3248 return E_FAIL;
3250 val_count++;
3251 value = heap_alloc( val_count * sizeof(value[0]) );
3252 filename = heap_alloc(count);
3253 if (!value || !filename) {
3254 heap_free(value);
3255 heap_free(filename);
3256 return E_OUTOFMEMORY;
3259 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
3260 if (ret) {
3261 heap_free(value);
3262 heap_free(filename);
3263 return E_FAIL;
3266 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3267 if (!strchrW(filename, '\\')) {
3268 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
3269 WCHAR fullpathW[MAX_PATH];
3271 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
3272 strcatW(fullpathW, fontsW);
3273 strcatW(fullpathW, filename);
3275 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, fullpathW, NULL, file);
3277 else
3278 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, filename, NULL, file);
3280 heap_free(value);
3281 heap_free(filename);
3282 return hr;
3285 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3287 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
3288 DWORD ret, max_val_count;
3289 WCHAR *value;
3291 *current = FALSE;
3292 enumerator->index++;
3294 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
3295 if (ret != ERROR_SUCCESS)
3296 return E_FAIL;
3298 max_val_count++;
3299 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
3300 return E_OUTOFMEMORY;
3302 /* iterate until we find next string value */
3303 while (1) {
3304 DWORD type = 0, count, val_count;
3305 val_count = max_val_count;
3306 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
3307 break;
3308 if (type == REG_SZ) {
3309 *current = TRUE;
3310 break;
3312 enumerator->index++;
3315 TRACE("index = %d, current = %d\n", enumerator->index, *current);
3316 heap_free(value);
3317 return S_OK;
3320 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
3322 systemfontfileenumerator_QueryInterface,
3323 systemfontfileenumerator_AddRef,
3324 systemfontfileenumerator_Release,
3325 systemfontfileenumerator_MoveNext,
3326 systemfontfileenumerator_GetCurrentFontFile
3329 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
3331 struct system_fontfile_enumerator *enumerator;
3332 static const WCHAR fontslistW[] = {
3333 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3334 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3335 'F','o','n','t','s',0
3338 *ret = NULL;
3340 enumerator = heap_alloc(sizeof(*enumerator));
3341 if (!enumerator)
3342 return E_OUTOFMEMORY;
3344 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
3345 enumerator->ref = 1;
3346 enumerator->factory = factory;
3347 enumerator->index = -1;
3348 IDWriteFactory2_AddRef(factory);
3350 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
3351 ERR("failed to open fonts list key\n");
3352 IDWriteFactory2_Release(factory);
3353 heap_free(enumerator);
3354 return E_FAIL;
3357 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
3359 return S_OK;
3362 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3364 IDWriteFontFileEnumerator *enumerator;
3365 HRESULT hr;
3367 *collection = NULL;
3369 hr = create_system_fontfile_enumerator(factory, &enumerator);
3370 if (FAILED(hr))
3371 return hr;
3373 TRACE("building system font collection for factory %p\n", factory);
3374 hr = create_font_collection(factory, enumerator, TRUE, collection);
3375 IDWriteFontFileEnumerator_Release(enumerator);
3376 return hr;
3379 static HRESULT WINAPI eudcfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
3381 *obj = NULL;
3383 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
3384 IDWriteFontFileEnumerator_AddRef(iface);
3385 *obj = iface;
3386 return S_OK;
3389 return E_NOINTERFACE;
3392 static ULONG WINAPI eudcfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
3394 return 2;
3397 static ULONG WINAPI eudcfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
3399 return 1;
3402 static HRESULT WINAPI eudcfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
3404 *file = NULL;
3405 return E_FAIL;
3408 static HRESULT WINAPI eudcfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
3410 *current = FALSE;
3411 return S_OK;
3414 static const struct IDWriteFontFileEnumeratorVtbl eudcfontfileenumeratorvtbl =
3416 eudcfontfileenumerator_QueryInterface,
3417 eudcfontfileenumerator_AddRef,
3418 eudcfontfileenumerator_Release,
3419 eudcfontfileenumerator_MoveNext,
3420 eudcfontfileenumerator_GetCurrentFontFile
3423 static IDWriteFontFileEnumerator eudc_fontfile_enumerator = { &eudcfontfileenumeratorvtbl };
3425 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
3427 TRACE("building EUDC font collection for factory %p\n", factory);
3428 return create_font_collection(factory, &eudc_fontfile_enumerator, FALSE, collection);
3431 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
3433 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3435 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3437 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
3439 *obj = iface;
3440 IDWriteFontFile_AddRef(iface);
3441 return S_OK;
3444 *obj = NULL;
3445 return E_NOINTERFACE;
3448 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
3450 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3451 ULONG ref = InterlockedIncrement(&This->ref);
3452 TRACE("(%p)->(%d)\n", This, ref);
3453 return ref;
3456 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
3458 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3459 ULONG ref = InterlockedDecrement(&This->ref);
3461 TRACE("(%p)->(%d)\n", This, ref);
3463 if (!ref)
3465 IDWriteFontFileLoader_Release(This->loader);
3466 if (This->stream) IDWriteFontFileStream_Release(This->stream);
3467 heap_free(This->reference_key);
3468 heap_free(This);
3471 return ref;
3474 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
3476 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3477 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
3478 *fontFileReferenceKey = This->reference_key;
3479 *fontFileReferenceKeySize = This->key_size;
3481 return S_OK;
3484 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
3486 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3487 TRACE("(%p)->(%p)\n", This, fontFileLoader);
3488 *fontFileLoader = This->loader;
3489 IDWriteFontFileLoader_AddRef(This->loader);
3491 return S_OK;
3494 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType, DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
3496 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
3497 IDWriteFontFileStream *stream;
3498 HRESULT hr;
3500 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
3502 *isSupportedFontType = FALSE;
3503 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3504 if (fontFaceType)
3505 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3506 *numberOfFaces = 0;
3508 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
3509 if (FAILED(hr))
3510 return hr;
3512 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
3514 /* TODO: Further Analysis */
3515 IDWriteFontFileStream_Release(stream);
3516 return S_OK;
3519 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
3520 dwritefontfile_QueryInterface,
3521 dwritefontfile_AddRef,
3522 dwritefontfile_Release,
3523 dwritefontfile_GetReferenceKey,
3524 dwritefontfile_GetLoader,
3525 dwritefontfile_Analyze,
3528 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
3530 struct dwrite_fontfile *This;
3532 This = heap_alloc(sizeof(struct dwrite_fontfile));
3533 if (!This) return E_OUTOFMEMORY;
3535 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
3536 This->ref = 1;
3537 IDWriteFontFileLoader_AddRef(loader);
3538 This->loader = loader;
3539 This->stream = NULL;
3540 This->reference_key = heap_alloc(key_size);
3541 memcpy(This->reference_key, reference_key, key_size);
3542 This->key_size = key_size;
3544 *font_file = &This->IDWriteFontFile_iface;
3546 return S_OK;
3549 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
3551 IDWriteFontFileLoader *loader;
3552 UINT32 key_size;
3553 const void *key;
3554 HRESULT hr;
3556 *stream = NULL;
3557 hr = IDWriteFontFile_GetLoader(file, &loader);
3558 if (FAILED(hr))
3559 return hr;
3561 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3562 if (FAILED(hr)) {
3563 IDWriteFontFileLoader_Release(loader);
3564 return hr;
3567 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
3568 IDWriteFontFileLoader_Release(loader);
3570 return hr;
3573 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
3574 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace2 **ret)
3576 struct dwrite_fontface *fontface;
3577 HRESULT hr = S_OK;
3578 int i;
3580 *ret = NULL;
3582 fontface = heap_alloc(sizeof(struct dwrite_fontface));
3583 if (!fontface)
3584 return E_OUTOFMEMORY;
3586 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
3587 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
3589 if (!fontface->files || !fontface->streams) {
3590 heap_free(fontface->files);
3591 heap_free(fontface->streams);
3592 heap_free(fontface);
3593 return E_OUTOFMEMORY;
3596 fontface->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl;
3597 fontface->ref = 1;
3598 fontface->type = facetype;
3599 fontface->file_count = files_number;
3600 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
3601 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
3602 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
3603 memset(&fontface->cpal, 0, sizeof(fontface->cpal));
3604 fontface->cmap.exists = TRUE;
3605 fontface->vdmx.exists = TRUE;
3606 fontface->gasp.exists = TRUE;
3607 fontface->cpal.exists = TRUE;
3608 fontface->index = index;
3609 fontface->simulations = simulations;
3610 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
3612 for (i = 0; i < fontface->file_count; i++) {
3613 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
3614 if (FAILED(hr)) {
3615 IDWriteFontFace2_Release(&fontface->IDWriteFontFace2_iface);
3616 return hr;
3619 fontface->files[i] = font_files[i];
3620 IDWriteFontFile_AddRef(font_files[i]);
3623 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
3624 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
3625 /* TODO: test what happens if caret is already slanted */
3626 if (fontface->caret.slopeRise == 1) {
3627 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
3628 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
3631 fontface->charmap = freetype_get_charmap_index(&fontface->IDWriteFontFace2_iface, &fontface->is_symbol);
3633 *ret = &fontface->IDWriteFontFace2_iface;
3634 return S_OK;
3637 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3638 struct local_refkey
3640 FILETIME writetime;
3641 WCHAR name[1];
3644 struct local_cached_stream
3646 struct list entry;
3647 IDWriteFontFileStream *stream;
3648 struct local_refkey *key;
3649 UINT32 key_size;
3652 struct dwrite_localfontfilestream
3654 IDWriteFontFileStream IDWriteFontFileStream_iface;
3655 LONG ref;
3657 struct local_cached_stream *entry;
3658 const void *file_ptr;
3659 UINT64 size;
3662 struct dwrite_localfontfileloader {
3663 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
3664 LONG ref;
3666 struct list streams;
3669 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
3671 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
3674 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
3676 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
3679 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
3681 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3682 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3683 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
3685 *obj = iface;
3686 IDWriteFontFileStream_AddRef(iface);
3687 return S_OK;
3690 *obj = NULL;
3691 return E_NOINTERFACE;
3694 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
3696 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3697 ULONG ref = InterlockedIncrement(&This->ref);
3698 TRACE("(%p)->(%d)\n", This, ref);
3699 return ref;
3702 static inline void release_cached_stream(struct local_cached_stream *stream)
3704 list_remove(&stream->entry);
3705 heap_free(stream->key);
3706 heap_free(stream);
3709 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
3711 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3712 ULONG ref = InterlockedDecrement(&This->ref);
3714 TRACE("(%p)->(%d)\n", This, ref);
3716 if (!ref) {
3717 UnmapViewOfFile(This->file_ptr);
3718 release_cached_stream(This->entry);
3719 heap_free(This);
3722 return ref;
3725 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
3727 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3729 TRACE("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
3730 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
3732 *fragment_context = NULL;
3734 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
3735 *fragment_start = NULL;
3736 return E_FAIL;
3739 *fragment_start = (char*)This->file_ptr + offset;
3740 return S_OK;
3743 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
3745 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3746 TRACE("(%p)->(%p)\n", This, fragment_context);
3749 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
3751 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3752 TRACE("(%p)->(%p)\n", This, size);
3753 *size = This->size;
3754 return S_OK;
3757 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
3759 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
3760 ULARGE_INTEGER li;
3762 TRACE("(%p)->(%p)\n", This, last_writetime);
3764 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
3765 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
3766 *last_writetime = li.QuadPart;
3768 return S_OK;
3771 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
3773 localfontfilestream_QueryInterface,
3774 localfontfilestream_AddRef,
3775 localfontfilestream_Release,
3776 localfontfilestream_ReadFileFragment,
3777 localfontfilestream_ReleaseFileFragment,
3778 localfontfilestream_GetFileSize,
3779 localfontfilestream_GetLastWriteTime
3782 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream** iface)
3784 struct dwrite_localfontfilestream *This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
3785 if (!This)
3786 return E_OUTOFMEMORY;
3788 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
3789 This->ref = 1;
3791 This->file_ptr = file_ptr;
3792 This->size = size;
3793 This->entry = entry;
3795 *iface = &This->IDWriteFontFileStream_iface;
3796 return S_OK;
3799 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
3801 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3803 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
3805 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
3807 *obj = iface;
3808 IDWriteLocalFontFileLoader_AddRef(iface);
3809 return S_OK;
3812 *obj = NULL;
3813 return E_NOINTERFACE;
3816 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
3818 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3819 ULONG ref = InterlockedIncrement(&This->ref);
3820 TRACE("(%p)->(%d)\n", This, ref);
3821 return ref;
3824 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
3826 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3827 ULONG ref = InterlockedDecrement(&This->ref);
3829 TRACE("(%p)->(%d)\n", This, ref);
3831 if (!ref) {
3832 struct local_cached_stream *stream, *stream2;
3834 /* This will detach all entries from cache. Entries are released together with streams,
3835 so stream controls its lifetime. */
3836 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
3837 list_init(&stream->entry);
3839 heap_free(This);
3842 return ref;
3845 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
3847 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3848 const struct local_refkey *refkey = key;
3849 struct local_cached_stream *stream;
3850 IDWriteFontFileStream *filestream;
3851 HANDLE file, mapping;
3852 LARGE_INTEGER size;
3853 void *file_ptr;
3854 HRESULT hr;
3856 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
3857 TRACE("name: %s\n", debugstr_w(refkey->name));
3859 /* search cache first */
3860 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
3861 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
3862 *ret = stream->stream;
3863 IDWriteFontFileStream_AddRef(*ret);
3864 return S_OK;
3868 *ret = NULL;
3870 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
3871 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
3872 if (file == INVALID_HANDLE_VALUE)
3873 return E_FAIL;
3875 GetFileSizeEx(file, &size);
3876 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
3877 CloseHandle(file);
3878 if (!mapping)
3879 return E_FAIL;
3881 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3882 CloseHandle(mapping);
3884 stream = heap_alloc(sizeof(*stream));
3885 if (!stream) {
3886 UnmapViewOfFile(file_ptr);
3887 return E_OUTOFMEMORY;
3890 stream->key = heap_alloc(key_size);
3891 if (!stream->key) {
3892 UnmapViewOfFile(file_ptr);
3893 heap_free(stream);
3894 return E_OUTOFMEMORY;
3897 stream->key_size = key_size;
3898 memcpy(stream->key, key, key_size);
3900 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
3901 if (FAILED(hr)) {
3902 UnmapViewOfFile(file_ptr);
3903 heap_free(stream->key);
3904 heap_free(stream);
3905 return hr;
3908 stream->stream = filestream;
3909 list_add_head(&This->streams, &stream->entry);
3911 *ret = stream->stream;
3913 return S_OK;
3916 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
3918 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3919 const struct local_refkey *refkey = key;
3921 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
3923 *length = strlenW(refkey->name);
3924 return S_OK;
3927 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
3929 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3930 const struct local_refkey *refkey = key;
3932 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
3934 if (length < strlenW(refkey->name))
3935 return E_INVALIDARG;
3937 strcpyW(path, refkey->name);
3938 return S_OK;
3941 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
3943 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
3944 const struct local_refkey *refkey = key;
3946 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
3948 *writetime = refkey->writetime;
3949 return S_OK;
3952 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
3953 localfontfileloader_QueryInterface,
3954 localfontfileloader_AddRef,
3955 localfontfileloader_Release,
3956 localfontfileloader_CreateStreamFromKey,
3957 localfontfileloader_GetFilePathLengthFromKey,
3958 localfontfileloader_GetFilePathFromKey,
3959 localfontfileloader_GetLastWriteTimeFromKey
3962 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface)
3964 struct dwrite_localfontfileloader *This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
3965 if (!This)
3966 return E_OUTOFMEMORY;
3968 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
3969 This->ref = 1;
3970 list_init(&This->streams);
3972 *iface = &This->IDWriteLocalFontFileLoader_iface;
3973 return S_OK;
3976 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
3978 struct local_refkey *refkey;
3980 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
3981 *key = NULL;
3983 refkey = heap_alloc(*size);
3984 if (!refkey)
3985 return E_OUTOFMEMORY;
3987 if (writetime)
3988 refkey->writetime = *writetime;
3989 else {
3990 WIN32_FILE_ATTRIBUTE_DATA info;
3992 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
3993 refkey->writetime = info.ftLastWriteTime;
3994 else
3995 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
3997 strcpyW(refkey->name, path);
3999 *key = refkey;
4001 return S_OK;
4004 /* IDWriteGlyphRunAnalysis */
4005 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
4007 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4009 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4011 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
4012 IsEqualIID(riid, &IID_IUnknown))
4014 *ppv = iface;
4015 IDWriteGlyphRunAnalysis_AddRef(iface);
4016 return S_OK;
4019 *ppv = NULL;
4020 return E_NOINTERFACE;
4023 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
4025 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4026 ULONG ref = InterlockedIncrement(&This->ref);
4027 TRACE("(%p)->(%u)\n", This, ref);
4028 return ref;
4031 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
4033 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4034 ULONG ref = InterlockedDecrement(&This->ref);
4036 TRACE("(%p)->(%u)\n", This, ref);
4038 if (!ref) {
4039 if (This->run.fontFace)
4040 IDWriteFontFace_Release(This->run.fontFace);
4041 heap_free(This->glyphs);
4042 heap_free(This->advances);
4043 heap_free(This->offsets);
4044 heap_free(This->bitmap);
4045 heap_free(This);
4048 return ref;
4051 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *analysis, RECT *bounds)
4053 struct dwrite_glyphbitmap glyph_bitmap;
4054 IDWriteFontFace2 *fontface2;
4055 FLOAT origin_x;
4056 BOOL is_rtl;
4057 HRESULT hr;
4058 UINT32 i;
4060 if (analysis->ready & RUNANALYSIS_BOUNDS) {
4061 *bounds = analysis->bounds;
4062 return;
4065 if (analysis->run.isSideways)
4066 FIXME("sideways runs are not supported.\n");
4068 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
4069 if (FAILED(hr))
4070 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
4072 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4073 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4074 for any non-zero glyph ascender */
4075 origin_x = 0.0;
4076 is_rtl = analysis->run.bidiLevel & 1;
4078 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4079 glyph_bitmap.fontface = fontface2;
4080 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4081 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4082 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4084 for (i = 0; i < analysis->run.glyphCount; i++) {
4085 const DWRITE_GLYPH_OFFSET *offset = analysis->offsets ? &analysis->offsets[i] : NULL;
4086 FLOAT advance = analysis->advances[i];
4087 RECT *bbox = &glyph_bitmap.bbox;
4089 glyph_bitmap.index = analysis->run.glyphIndices[i];
4090 freetype_get_glyph_bbox(&glyph_bitmap);
4092 if (is_rtl)
4093 OffsetRect(bbox, origin_x - advance, 0);
4094 else
4095 OffsetRect(bbox, origin_x, 0);
4097 if (offset)
4098 OffsetRect(bbox, is_rtl ? -offset->advanceOffset : offset->advanceOffset, is_rtl ? -offset->ascenderOffset : offset->ascenderOffset);
4100 UnionRect(&analysis->bounds, &analysis->bounds, bbox);
4101 origin_x += is_rtl ? -advance : advance;
4104 IDWriteFontFace2_Release(fontface2);
4106 /* translate to given run origin */
4107 OffsetRect(&analysis->bounds, analysis->originX, analysis->originY);
4109 analysis->ready |= RUNANALYSIS_BOUNDS;
4110 *bounds = analysis->bounds;
4113 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT *bounds)
4115 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4117 TRACE("(%p)->(%d %p)\n", This, type, bounds);
4119 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
4120 memset(bounds, 0, sizeof(*bounds));
4121 return E_INVALIDARG;
4124 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
4125 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
4126 memset(bounds, 0, sizeof(*bounds));
4127 return S_OK;
4130 glyphrunanalysis_get_texturebounds(This, bounds);
4131 return S_OK;
4134 static inline int get_dib_stride( int width, int bpp )
4136 return ((width * bpp + 31) >> 3) & ~3;
4139 static inline BYTE *get_pixel_ptr(BYTE *ptr, DWRITE_TEXTURE_TYPE type, const RECT *runbounds, const RECT *bounds)
4141 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4142 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) * 3 +
4143 (runbounds->left - bounds->left) * 3;
4144 else
4145 return ptr + (runbounds->top - bounds->top) * (bounds->right - bounds->left) +
4146 runbounds->left - bounds->left;
4149 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DWRITE_TEXTURE_TYPE type)
4151 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4152 struct dwrite_glyphbitmap glyph_bitmap;
4153 IDWriteFontFace2 *fontface2;
4154 FLOAT origin_x;
4155 UINT32 i, size;
4156 BOOL is_rtl;
4157 HRESULT hr;
4158 RECT *bbox;
4160 hr = IDWriteFontFace_QueryInterface(analysis->run.fontFace, &IID_IDWriteFontFace2, (void**)&fontface2);
4161 if (FAILED(hr)) {
4162 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr);
4163 return;
4166 size = (analysis->bounds.right - analysis->bounds.left)*(analysis->bounds.bottom - analysis->bounds.top);
4167 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4168 size *= 3;
4169 analysis->bitmap = heap_alloc_zero(size);
4171 origin_x = 0.0;
4172 is_rtl = analysis->run.bidiLevel & 1;
4174 memset(&glyph_bitmap, 0, sizeof(glyph_bitmap));
4175 glyph_bitmap.fontface = fontface2;
4176 glyph_bitmap.emsize = analysis->run.fontEmSize * analysis->ppdip;
4177 glyph_bitmap.nohint = analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL ||
4178 analysis->rendering_mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4179 glyph_bitmap.type = type;
4180 bbox = &glyph_bitmap.bbox;
4182 for (i = 0; i < analysis->run.glyphCount; i++) {
4183 const DWRITE_GLYPH_OFFSET *offset = analysis->offsets ? &analysis->offsets[i] : NULL;
4184 FLOAT advance = analysis->advances[i];
4185 int x, y, width, height;
4186 BYTE *src, *dst;
4187 BOOL is_1bpp;
4189 glyph_bitmap.index = analysis->run.glyphIndices[i];
4190 freetype_get_glyph_bbox(&glyph_bitmap);
4192 if (IsRectEmpty(bbox)) {
4193 origin_x += is_rtl ? -advance : advance;
4194 continue;
4197 width = bbox->right - bbox->left;
4198 height = bbox->bottom - bbox->top;
4200 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4201 glyph_bitmap.pitch = (width + 3) / 4 * 4;
4202 else
4203 glyph_bitmap.pitch = ((width + 31) >> 5) << 2;
4205 glyph_bitmap.buf = src = heap_alloc_zero(height * glyph_bitmap.pitch);
4206 is_1bpp = freetype_get_glyph_bitmap(&glyph_bitmap);
4208 if (is_rtl)
4209 OffsetRect(bbox, origin_x - advance, 0);
4210 else
4211 OffsetRect(bbox, origin_x, 0);
4213 if (offset)
4214 OffsetRect(bbox, is_rtl ? -offset->advanceOffset : offset->advanceOffset, is_rtl ? -offset->ascenderOffset : offset->ascenderOffset);
4216 OffsetRect(bbox, analysis->originX, analysis->originY);
4218 /* blit to analysis bitmap */
4219 dst = get_pixel_ptr(analysis->bitmap, type, bbox, &analysis->bounds);
4221 if (is_1bpp) {
4222 /* convert 1bpp to 8bpp/24bpp */
4223 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1) {
4224 for (y = 0; y < height; y++) {
4225 for (x = 0; x < width; x++)
4226 dst[3*x] = dst[3*x+1] = dst[3*x+2] = (src[x / 8] & masks[x % 8]) ? DWRITE_ALPHA_MAX : 0;
4227 src += glyph_bitmap.pitch;
4228 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4231 else {
4232 for (y = 0; y < height; y++) {
4233 for (x = 0; x < width; x++)
4234 dst[x] = (src[x / 8] & masks[x % 8]) ? DWRITE_ALPHA_MAX : 0;
4235 src += get_dib_stride(width, 1);
4236 dst += analysis->bounds.right - analysis->bounds.left;
4240 else {
4241 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4242 for (y = 0; y < height; y++) {
4243 for (x = 0; x < width; x++)
4244 dst[3*x] = dst[3*x+1] = dst[3*x+2] = src[x];
4245 src += glyph_bitmap.pitch;
4246 dst += (analysis->bounds.right - analysis->bounds.left) * 3;
4250 heap_free(glyph_bitmap.buf);
4252 origin_x += is_rtl ? -advance : advance;
4255 IDWriteFontFace2_Release(fontface2);
4257 analysis->ready |= RUNANALYSIS_BITMAP;
4259 /* we don't need this anymore */
4260 heap_free(analysis->glyphs);
4261 heap_free(analysis->advances);
4262 heap_free(analysis->offsets);
4263 IDWriteFontFace_Release(analysis->run.fontFace);
4265 analysis->glyphs = NULL;
4266 analysis->advances = NULL;
4267 analysis->offsets = NULL;
4268 analysis->run.glyphIndices = NULL;
4269 analysis->run.glyphAdvances = NULL;
4270 analysis->run.glyphOffsets = NULL;
4271 analysis->run.fontFace = NULL;
4274 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
4275 RECT const *bounds, BYTE *bitmap, UINT32 size)
4277 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4278 UINT32 required;
4279 RECT runbounds;
4281 TRACE("(%p)->(%d %s %p %u)\n", This, type, wine_dbgstr_rect(bounds), bitmap, size);
4283 if (!bounds || !bitmap || (UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1)
4284 return E_INVALIDARG;
4286 /* make sure buffer is large enough for requested texture type */
4287 required = (bounds->right - bounds->left) * (bounds->bottom - bounds->top);
4288 if (type == DWRITE_TEXTURE_CLEARTYPE_3x1)
4289 required *= 3;
4291 if (size < required)
4292 return E_NOT_SUFFICIENT_BUFFER;
4294 /* validate requested texture type with rendering mode */
4295 switch (This->rendering_mode)
4297 case DWRITE_RENDERING_MODE_ALIASED:
4298 if (type != DWRITE_TEXTURE_ALIASED_1x1)
4299 return DWRITE_E_UNSUPPORTEDOPERATION;
4300 break;
4301 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4302 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4303 case DWRITE_RENDERING_MODE_NATURAL:
4304 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4305 if (type != DWRITE_TEXTURE_CLEARTYPE_3x1)
4306 return DWRITE_E_UNSUPPORTEDOPERATION;
4307 break;
4308 default:
4312 memset(bitmap, 0, size);
4313 glyphrunanalysis_get_texturebounds(This, &runbounds);
4314 if (IntersectRect(&runbounds, &runbounds, bounds)) {
4315 int pixel_size = type == DWRITE_TEXTURE_CLEARTYPE_3x1 ? 3 : 1;
4316 int src_width = (This->bounds.right - This->bounds.left) * pixel_size;
4317 int dst_width = (bounds->right - bounds->left) * pixel_size;
4318 int draw_width = (runbounds.right - runbounds.left) * pixel_size;
4319 BYTE *src, *dst;
4320 int y;
4322 if (!(This->ready & RUNANALYSIS_BITMAP))
4323 glyphrunanalysis_render(This, type);
4325 src = get_pixel_ptr(This->bitmap, type, &runbounds, &This->bounds);
4326 dst = get_pixel_ptr(bitmap, type, &runbounds, bounds);
4328 for (y = 0; y < runbounds.bottom - runbounds.top; y++) {
4329 memcpy(dst, src, draw_width);
4330 src += src_width;
4331 dst += dst_width;
4335 return S_OK;
4338 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
4339 FLOAT *gamma, FLOAT *contrast, FLOAT *cleartypelevel)
4341 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
4343 TRACE("(%p)->(%p %p %p %p)\n", This, params, gamma, contrast, cleartypelevel);
4345 if (!params)
4346 return E_INVALIDARG;
4348 switch (This->rendering_mode)
4350 case DWRITE_RENDERING_MODE_GDI_CLASSIC:
4351 case DWRITE_RENDERING_MODE_GDI_NATURAL:
4353 UINT value = 0;
4354 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4355 *gamma = (FLOAT)value / 1000.0f;
4356 *contrast = 0.0f;
4357 *cleartypelevel = 1.0f;
4358 break;
4360 case DWRITE_RENDERING_MODE_ALIASED:
4361 case DWRITE_RENDERING_MODE_NATURAL:
4362 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC:
4363 *gamma = IDWriteRenderingParams_GetGamma(params);
4364 *contrast = IDWriteRenderingParams_GetEnhancedContrast(params);
4365 *cleartypelevel = IDWriteRenderingParams_GetClearTypeLevel(params);
4366 break;
4367 default:
4371 return S_OK;
4374 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
4375 glyphrunanalysis_QueryInterface,
4376 glyphrunanalysis_AddRef,
4377 glyphrunanalysis_Release,
4378 glyphrunanalysis_GetAlphaTextureBounds,
4379 glyphrunanalysis_CreateAlphaTexture,
4380 glyphrunanalysis_GetAlphaBlendParams
4383 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run,
4384 FLOAT ppdip, DWRITE_GRID_FIT_MODE gridfit_mode, DWRITE_TEXT_ANTIALIAS_MODE aa_mode, FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret)
4386 struct dwrite_glyphrunanalysis *analysis;
4388 *ret = NULL;
4390 /* check for valid rendering mode */
4391 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
4392 return E_INVALIDARG;
4394 analysis = heap_alloc(sizeof(*analysis));
4395 if (!analysis)
4396 return E_OUTOFMEMORY;
4398 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
4399 analysis->ref = 1;
4400 analysis->rendering_mode = rendering_mode;
4401 analysis->ready = 0;
4402 analysis->bitmap = NULL;
4403 analysis->ppdip = ppdip;
4404 analysis->originX = originX;
4405 analysis->originY = originY;
4406 SetRectEmpty(&analysis->bounds);
4407 analysis->run = *run;
4408 IDWriteFontFace_AddRef(analysis->run.fontFace);
4409 analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices));
4410 analysis->advances = heap_alloc(run->glyphCount*sizeof(*run->glyphAdvances));
4411 analysis->offsets = run->glyphOffsets ? heap_alloc(run->glyphCount*sizeof(*run->glyphOffsets)) : NULL;
4412 if (!analysis->glyphs || !analysis->advances || (!analysis->offsets && run->glyphOffsets)) {
4413 heap_free(analysis->glyphs);
4414 heap_free(analysis->advances);
4415 heap_free(analysis->offsets);
4417 analysis->glyphs = NULL;
4418 analysis->advances = NULL;
4419 analysis->offsets = NULL;
4421 IDWriteGlyphRunAnalysis_Release(&analysis->IDWriteGlyphRunAnalysis_iface);
4422 return E_OUTOFMEMORY;
4425 analysis->run.glyphIndices = analysis->glyphs;
4426 analysis->run.glyphAdvances = analysis->advances;
4427 analysis->run.glyphOffsets = analysis->offsets;
4429 memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices));
4431 if (run->glyphAdvances)
4432 memcpy(analysis->advances, run->glyphAdvances, run->glyphCount*sizeof(*run->glyphAdvances));
4433 else {
4434 DWRITE_FONT_METRICS metrics;
4435 IDWriteFontFace1 *fontface1;
4436 UINT32 i;
4438 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
4439 IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1);
4441 for (i = 0; i < run->glyphCount; i++) {
4442 HRESULT hr;
4443 INT32 a;
4445 switch (measuring_mode)
4447 case DWRITE_MEASURING_MODE_NATURAL:
4448 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways);
4449 if (FAILED(hr))
4450 a = 0;
4451 analysis->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics);
4452 break;
4453 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4454 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4455 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, NULL /* FIXME */,
4456 measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a);
4457 if (FAILED(hr))
4458 analysis->advances[i] = 0.0;
4459 else
4460 analysis->advances[i] = floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f) / ppdip;
4461 break;
4462 default:
4467 IDWriteFontFace1_Release(fontface1);
4470 if (run->glyphOffsets)
4471 memcpy(analysis->offsets, run->glyphOffsets, run->glyphCount*sizeof(*run->glyphOffsets));
4473 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
4474 return S_OK;
4477 /* IDWriteColorGlyphRunEnumerator */
4478 static HRESULT WINAPI colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator *iface, REFIID riid, void **ppv)
4480 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4482 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
4484 if (IsEqualIID(riid, &IID_IDWriteColorGlyphRunEnumerator) ||
4485 IsEqualIID(riid, &IID_IUnknown))
4487 *ppv = iface;
4488 IDWriteColorGlyphRunEnumerator_AddRef(iface);
4489 return S_OK;
4492 *ppv = NULL;
4493 return E_NOINTERFACE;
4496 static ULONG WINAPI colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator *iface)
4498 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4499 ULONG ref = InterlockedIncrement(&This->ref);
4500 TRACE("(%p)->(%u)\n", This, ref);
4501 return ref;
4504 static ULONG WINAPI colorglyphenum_Release(IDWriteColorGlyphRunEnumerator *iface)
4506 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4507 ULONG ref = InterlockedDecrement(&This->ref);
4509 TRACE("(%p)->(%u)\n", This, ref);
4511 if (!ref)
4512 heap_free(This);
4514 return ref;
4517 static HRESULT WINAPI colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator *iface, BOOL *has_run)
4519 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4520 FIXME("(%p)->(%p): stub\n", This, has_run);
4521 return E_NOTIMPL;
4524 static HRESULT WINAPI colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator *iface, DWRITE_COLOR_GLYPH_RUN const **run)
4526 struct dwrite_colorglyphenum *This = impl_from_IDWriteColorGlyphRunEnumerator(iface);
4527 FIXME("(%p)->(%p): stub\n", This, run);
4528 return E_NOTIMPL;
4531 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl = {
4532 colorglyphenum_QueryInterface,
4533 colorglyphenum_AddRef,
4534 colorglyphenum_Release,
4535 colorglyphenum_MoveNext,
4536 colorglyphenum_GetCurrentRun
4539 HRESULT create_colorglyphenum(FLOAT originX, FLOAT originY, const DWRITE_GLYPH_RUN *run, const DWRITE_GLYPH_RUN_DESCRIPTION *rundescr,
4540 DWRITE_MEASURING_MODE mode, const DWRITE_MATRIX *transform, UINT32 palette, IDWriteColorGlyphRunEnumerator **ret)
4542 struct dwrite_colorglyphenum *colorglyphenum;
4544 *ret = NULL;
4545 colorglyphenum = heap_alloc(sizeof(*colorglyphenum));
4546 if (!colorglyphenum)
4547 return E_OUTOFMEMORY;
4549 colorglyphenum->IDWriteColorGlyphRunEnumerator_iface.lpVtbl = &colorglyphenumvtbl;
4550 colorglyphenum->ref = 1;
4552 *ret = &colorglyphenum->IDWriteColorGlyphRunEnumerator_iface;
4553 return S_OK;