dwrite: Implement GetRecommendedRenderingMode().
[wine.git] / dlls / dwrite / font.c
blob4fdea6c89637ffc054a3c667c23862f9d02a83e9
1 /*
2 * Font and collections
4 * Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
5 * Copyright 2014 Aric Stewart for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <math.h>
23 #define COBJMACROS
25 #include "wine/list.h"
26 #include "dwrite_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
30 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
31 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
32 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
33 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
34 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
35 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
37 static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
39 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f;
40 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f;
41 static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f;
43 struct dwrite_font_data {
44 LONG ref;
46 DWRITE_FONT_STYLE style;
47 DWRITE_FONT_STRETCH stretch;
48 DWRITE_FONT_WEIGHT weight;
49 DWRITE_PANOSE panose;
50 DWRITE_FONT_METRICS1 metrics;
51 IDWriteLocalizedStrings *info_strings[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1];
53 /* data needed to create fontface instance */
54 IDWriteFactory2 *factory;
55 DWRITE_FONT_FACE_TYPE face_type;
56 IDWriteFontFile *file;
57 UINT32 face_index;
59 WCHAR *facename;
62 struct dwrite_fontfamily_data {
63 LONG ref;
65 IDWriteLocalizedStrings *familyname;
67 struct dwrite_font_data **fonts;
68 UINT32 font_count;
69 UINT32 font_alloc;
72 struct dwrite_fontcollection {
73 IDWriteFontCollection IDWriteFontCollection_iface;
74 LONG ref;
76 struct dwrite_fontfamily_data **family_data;
77 UINT32 family_count;
78 UINT32 family_alloc;
79 BOOL is_system;
82 struct dwrite_fontfamily {
83 IDWriteFontFamily IDWriteFontFamily_iface;
84 LONG ref;
86 struct dwrite_fontfamily_data *data;
88 IDWriteFontCollection* collection;
91 struct dwrite_font {
92 IDWriteFont2 IDWriteFont2_iface;
93 LONG ref;
95 IDWriteFontFamily *family;
97 USHORT simulations;
98 DWRITE_FONT_STYLE style;
99 struct dwrite_font_data *data;
102 struct dwrite_fonttable {
103 void *data;
104 void *context;
105 UINT32 size;
106 BOOL exists;
109 struct dwrite_glyphrunanalysis {
110 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface;
111 LONG ref;
113 DWRITE_RENDERING_MODE rendering_mode;
116 #define GLYPH_BLOCK_SHIFT 8
117 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
118 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
119 #define GLYPH_MAX 65536
121 struct dwrite_fontface {
122 IDWriteFontFace2 IDWriteFontFace2_iface;
123 LONG ref;
125 IDWriteFontFileStream **streams;
126 IDWriteFontFile **files;
127 UINT32 file_count;
128 UINT32 index;
130 USHORT simulations;
131 DWRITE_FONT_FACE_TYPE type;
132 DWRITE_FONT_METRICS1 metrics;
133 DWRITE_CARET_METRICS caret;
135 struct dwrite_fonttable cmap;
136 struct dwrite_fonttable vdmx;
137 struct dwrite_fonttable gasp;
138 DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE];
141 struct dwrite_fontfile {
142 IDWriteFontFile IDWriteFontFile_iface;
143 LONG ref;
145 IDWriteFontFileLoader *loader;
146 void *reference_key;
147 UINT32 key_size;
148 IDWriteFontFileStream *stream;
151 static inline struct dwrite_fontface *impl_from_IDWriteFontFace2(IDWriteFontFace2 *iface)
153 return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace2_iface);
156 static inline struct dwrite_font *impl_from_IDWriteFont2(IDWriteFont2 *iface)
158 return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont2_iface);
161 static inline struct dwrite_fontfile *impl_from_IDWriteFontFile(IDWriteFontFile *iface)
163 return CONTAINING_RECORD(iface, struct dwrite_fontfile, IDWriteFontFile_iface);
166 static inline struct dwrite_fontfamily *impl_from_IDWriteFontFamily(IDWriteFontFamily *iface)
168 return CONTAINING_RECORD(iface, struct dwrite_fontfamily, IDWriteFontFamily_iface);
171 static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection(IDWriteFontCollection *iface)
173 return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection_iface);
176 static inline struct dwrite_glyphrunanalysis *impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis *iface)
178 return CONTAINING_RECORD(iface, struct dwrite_glyphrunanalysis, IDWriteGlyphRunAnalysis_iface);
181 static inline const char *debugstr_tag(UINT32 tag)
183 return wine_dbg_sprintf("%c%c%c%c", tag >> 24, (tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff);
186 static HRESULT get_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
188 static const DWRITE_GLYPH_METRICS nil;
189 DWRITE_GLYPH_METRICS *block = fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
191 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(DWRITE_GLYPH_METRICS))) return S_FALSE;
192 memcpy(metrics, &block[glyph & GLYPH_BLOCK_MASK], sizeof(*metrics));
193 return S_OK;
196 static HRESULT set_cached_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *metrics)
198 DWRITE_GLYPH_METRICS **block = &fontface->glyphs[glyph >> GLYPH_BLOCK_SHIFT];
200 if (!*block) {
201 /* start new block */
202 *block = heap_alloc_zero(sizeof(*metrics) * GLYPH_BLOCK_SIZE);
203 if (!*block)
204 return E_OUTOFMEMORY;
207 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], metrics, sizeof(*metrics));
208 return S_OK;
211 static void* get_fontface_table(struct dwrite_fontface *fontface, UINT32 tag, struct dwrite_fonttable *table)
213 HRESULT hr;
215 if (table->data || !table->exists)
216 return table->data;
218 table->exists = FALSE;
219 hr = IDWriteFontFace2_TryGetFontTable(&fontface->IDWriteFontFace2_iface, tag, (const void**)&table->data,
220 &table->size, &table->context, &table->exists);
221 if (FAILED(hr) || !table->exists) {
222 WARN("Font does not have a %s table\n", debugstr_tag(tag));
223 return NULL;
226 return table->data;
229 static inline void* get_fontface_cmap(struct dwrite_fontface *fontface)
231 return get_fontface_table(fontface, MS_CMAP_TAG, &fontface->cmap);
234 static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface)
236 return get_fontface_table(fontface, MS_VDMX_TAG, &fontface->vdmx);
239 static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size)
241 void *ptr = get_fontface_table(fontface, MS_GASP_TAG, &fontface->gasp);
242 *size = fontface->gasp.size;
243 return ptr;
246 static void release_font_data(struct dwrite_font_data *data)
248 int i;
250 if (InterlockedDecrement(&data->ref) > 0)
251 return;
253 for (i = DWRITE_INFORMATIONAL_STRING_NONE; i < sizeof(data->info_strings)/sizeof(data->info_strings[0]); i++) {
254 if (data->info_strings[i])
255 IDWriteLocalizedStrings_Release(data->info_strings[i]);
258 IDWriteFontFile_Release(data->file);
259 IDWriteFactory2_Release(data->factory);
260 heap_free(data->facename);
261 heap_free(data);
264 static void release_fontfamily_data(struct dwrite_fontfamily_data *data)
266 int i;
268 if (InterlockedDecrement(&data->ref) > 0)
269 return;
271 for (i = 0; i < data->font_count; i++)
272 release_font_data(data->fonts[i]);
273 heap_free(data->fonts);
274 IDWriteLocalizedStrings_Release(data->familyname);
275 heap_free(data);
278 static HRESULT WINAPI dwritefontface_QueryInterface(IDWriteFontFace2 *iface, REFIID riid, void **obj)
280 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
282 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
284 if (IsEqualIID(riid, &IID_IDWriteFontFace2) ||
285 IsEqualIID(riid, &IID_IDWriteFontFace1) ||
286 IsEqualIID(riid, &IID_IDWriteFontFace) ||
287 IsEqualIID(riid, &IID_IUnknown))
289 *obj = iface;
290 IDWriteFontFace2_AddRef(iface);
291 return S_OK;
294 *obj = NULL;
295 return E_NOINTERFACE;
298 static ULONG WINAPI dwritefontface_AddRef(IDWriteFontFace2 *iface)
300 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
301 ULONG ref = InterlockedIncrement(&This->ref);
302 TRACE("(%p)->(%d)\n", This, ref);
303 return ref;
306 static ULONG WINAPI dwritefontface_Release(IDWriteFontFace2 *iface)
308 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
309 ULONG ref = InterlockedDecrement(&This->ref);
311 TRACE("(%p)->(%d)\n", This, ref);
313 if (!ref) {
314 UINT32 i;
316 if (This->cmap.context)
317 IDWriteFontFace2_ReleaseFontTable(iface, This->cmap.context);
318 if (This->vdmx.context)
319 IDWriteFontFace2_ReleaseFontTable(iface, This->vdmx.context);
320 if (This->gasp.context)
321 IDWriteFontFace2_ReleaseFontTable(iface, This->gasp.context);
322 for (i = 0; i < This->file_count; i++) {
323 if (This->streams[i])
324 IDWriteFontFileStream_Release(This->streams[i]);
325 if (This->files[i])
326 IDWriteFontFile_Release(This->files[i]);
329 for (i = 0; i < sizeof(This->glyphs)/sizeof(This->glyphs[0]); i++)
330 heap_free(This->glyphs[i]);
332 freetype_notify_cacheremove(iface);
333 heap_free(This);
336 return ref;
339 static DWRITE_FONT_FACE_TYPE WINAPI dwritefontface_GetType(IDWriteFontFace2 *iface)
341 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
342 TRACE("(%p)\n", This);
343 return This->type;
346 static HRESULT WINAPI dwritefontface_GetFiles(IDWriteFontFace2 *iface, UINT32 *number_of_files,
347 IDWriteFontFile **fontfiles)
349 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
350 int i;
352 TRACE("(%p)->(%p %p)\n", This, number_of_files, fontfiles);
353 if (fontfiles == NULL)
355 *number_of_files = This->file_count;
356 return S_OK;
358 if (*number_of_files < This->file_count)
359 return E_INVALIDARG;
361 for (i = 0; i < This->file_count; i++)
363 IDWriteFontFile_AddRef(This->files[i]);
364 fontfiles[i] = This->files[i];
367 return S_OK;
370 static UINT32 WINAPI dwritefontface_GetIndex(IDWriteFontFace2 *iface)
372 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
373 TRACE("(%p)\n", This);
374 return This->index;
377 static DWRITE_FONT_SIMULATIONS WINAPI dwritefontface_GetSimulations(IDWriteFontFace2 *iface)
379 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
380 TRACE("(%p)\n", This);
381 return This->simulations;
384 static BOOL WINAPI dwritefontface_IsSymbolFont(IDWriteFontFace2 *iface)
386 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
387 FIXME("(%p): stub\n", This);
388 return FALSE;
391 static void WINAPI dwritefontface_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS *metrics)
393 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
394 TRACE("(%p)->(%p)\n", This, metrics);
395 memcpy(metrics, &This->metrics, sizeof(*metrics));
398 static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace2 *iface)
400 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
401 TRACE("(%p)\n", This);
402 return freetype_get_glyphcount(iface);
405 static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace2 *iface,
406 UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways)
408 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
409 HRESULT hr;
410 UINT32 i;
412 TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways);
414 if (!glyphs)
415 return E_INVALIDARG;
417 if (is_sideways)
418 FIXME("sideways metrics are not supported.\n");
420 for (i = 0; i < glyph_count; i++) {
421 DWRITE_GLYPH_METRICS metrics;
423 hr = get_cached_glyph_metrics(This, glyphs[i], &metrics);
424 if (hr != S_OK) {
425 freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics);
426 hr = set_cached_glyph_metrics(This, glyphs[i], &metrics);
427 if (FAILED(hr))
428 return hr;
430 ret[i] = metrics;
433 return S_OK;
436 static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace2 *iface, UINT32 const *codepoints,
437 UINT32 count, UINT16 *glyph_indices)
439 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
440 UINT32 i;
442 TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
444 if (!glyph_indices)
445 return E_INVALIDARG;
447 if (!codepoints) {
448 memset(glyph_indices, 0, count*sizeof(UINT16));
449 return E_INVALIDARG;
452 for (i = 0; i < count; i++)
453 glyph_indices[i] = freetype_get_glyphindex(iface, codepoints[i]);
455 return S_OK;
458 static HRESULT WINAPI dwritefontface_TryGetFontTable(IDWriteFontFace2 *iface, UINT32 table_tag,
459 const void **table_data, UINT32 *table_size, void **context, BOOL *exists)
461 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
463 TRACE("(%p)->(%u %p %p %p %p)\n", This, table_tag, table_data, table_size, context, exists);
465 return opentype_get_font_table(This->streams[0], This->type, This->index, table_tag, table_data, context, table_size, exists);
468 static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace2 *iface, void *table_context)
470 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
472 TRACE("(%p)->(%p)\n", This, table_context);
474 IDWriteFontFileStream_ReleaseFileFragment(This->streams[0], table_context);
477 HRESULT new_glyph_outline(UINT32 count, struct glyph_outline **ret)
479 struct glyph_outline *outline;
480 D2D1_POINT_2F *points;
481 UINT8 *tags;
483 *ret = NULL;
485 outline = heap_alloc(sizeof(*outline));
486 if (!outline)
487 return E_OUTOFMEMORY;
489 points = heap_alloc(count*sizeof(D2D1_POINT_2F));
490 tags = heap_alloc_zero(count*sizeof(UINT8));
491 if (!points || !tags) {
492 heap_free(points);
493 heap_free(tags);
494 heap_free(outline);
495 return E_OUTOFMEMORY;
498 outline->points = points;
499 outline->tags = tags;
500 outline->count = count;
501 outline->advance = 0.0;
503 *ret = outline;
504 return S_OK;
507 static void free_glyph_outline(struct glyph_outline *outline)
509 heap_free(outline->points);
510 heap_free(outline->tags);
511 heap_free(outline);
514 static void report_glyph_outline(const struct glyph_outline *outline, IDWriteGeometrySink *sink)
516 UINT16 p;
518 for (p = 0; p < outline->count; p++) {
519 if (outline->tags[p] & OUTLINE_POINT_START) {
520 ID2D1SimplifiedGeometrySink_BeginFigure(sink, outline->points[p], D2D1_FIGURE_BEGIN_FILLED);
521 continue;
524 if (outline->tags[p] & OUTLINE_POINT_LINE)
525 ID2D1SimplifiedGeometrySink_AddLines(sink, outline->points+p, 1);
526 else if (outline->tags[p] & OUTLINE_POINT_BEZIER) {
527 static const UINT16 segment_length = 3;
528 ID2D1SimplifiedGeometrySink_AddBeziers(sink, (D2D1_BEZIER_SEGMENT*)&outline->points[p], 1);
529 p += segment_length - 1;
532 if (outline->tags[p] & OUTLINE_POINT_END)
533 ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
537 static inline void translate_glyph_outline(struct glyph_outline *outline, FLOAT xoffset, FLOAT yoffset)
539 UINT16 p;
541 for (p = 0; p < outline->count; p++) {
542 outline->points[p].x += xoffset;
543 outline->points[p].y += yoffset;
547 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace2 *iface, FLOAT emSize,
548 UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
549 UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
551 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
552 FLOAT advance = 0.0;
553 HRESULT hr;
554 UINT32 g;
556 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This, emSize, glyphs, advances, offsets,
557 count, is_sideways, is_rtl, sink);
559 if (!glyphs || !sink)
560 return E_INVALIDARG;
562 if (is_sideways)
563 FIXME("sideways mode is not supported.\n");
565 if (count)
566 ID2D1SimplifiedGeometrySink_SetFillMode(sink, D2D1_FILL_MODE_WINDING);
568 for (g = 0; g < count; g++) {
569 FLOAT xoffset = 0.0, yoffset = 0.0;
570 struct glyph_outline *outline;
572 /* FIXME: cache outlines */
574 hr = freetype_get_glyph_outline(iface, emSize, glyphs[g], This->simulations, &outline);
575 if (FAILED(hr))
576 return hr;
578 /* glyph offsets act as current glyph adjustment */
579 if (offsets) {
580 xoffset += is_rtl ? -offsets[g].advanceOffset : offsets[g].advanceOffset;
581 yoffset -= offsets[g].ascenderOffset;
584 if (g == 0)
585 advance = is_rtl ? -outline->advance : 0.0;
587 xoffset += advance;
588 translate_glyph_outline(outline, xoffset, yoffset);
590 /* update advance to next glyph */
591 if (advances)
592 advance += is_rtl ? -advances[g] : advances[g];
593 else
594 advance += is_rtl ? -outline->advance : outline->advance;
596 report_glyph_outline(outline, sink);
597 free_glyph_outline(outline);
600 return S_OK;
603 static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring,
604 FLOAT ppem, WORD gasp)
606 DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT;
608 switch (measuring)
610 case DWRITE_MEASURING_MODE_NATURAL:
612 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM))
613 mode = DWRITE_RENDERING_MODE_NATURAL;
614 else
615 mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
616 break;
618 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
619 mode = DWRITE_RENDERING_MODE_GDI_CLASSIC;
620 break;
621 case DWRITE_MEASURING_MODE_GDI_NATURAL:
622 mode = DWRITE_RENDERING_MODE_GDI_NATURAL;
623 break;
624 default:
628 return mode;
631 static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
632 FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode)
634 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
635 WORD gasp, *ptr;
636 UINT32 size;
637 FLOAT ppem;
639 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode);
641 if (!params) {
642 *mode = DWRITE_RENDERING_MODE_DEFAULT;
643 return E_INVALIDARG;
646 *mode = IDWriteRenderingParams_GetRenderingMode(params);
647 if (*mode != DWRITE_RENDERING_MODE_DEFAULT)
648 return S_OK;
650 ppem = emSize * ppdip;
652 if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) {
653 *mode = DWRITE_RENDERING_MODE_OUTLINE;
654 return S_OK;
657 ptr = get_fontface_gasp(This, &size);
658 gasp = opentype_get_gasp_flags(ptr, size, ppem);
659 *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp);
660 return S_OK;
663 static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT pixels_per_dip,
664 DWRITE_MATRIX const *transform, DWRITE_FONT_METRICS *metrics)
666 DWRITE_FONT_METRICS1 metrics1;
667 HRESULT hr = IDWriteFontFace2_GetGdiCompatibleMetrics(iface, emSize, pixels_per_dip, transform, &metrics1);
668 memcpy(metrics, &metrics1, sizeof(*metrics));
669 return hr;
672 static inline int round_metric(FLOAT metric)
674 return (int)floorf(metric + 0.5f);
677 static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT ppdip,
678 DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count,
679 DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways)
681 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
682 FLOAT scale;
683 HRESULT hr;
684 UINT32 i;
686 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This, emSize, ppdip, m, use_gdi_natural, glyphs,
687 glyph_count, metrics, is_sideways);
689 if (m && memcmp(m, &identity, sizeof(*m)))
690 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
692 scale = emSize * ppdip / This->metrics.designUnitsPerEm;
694 for (i = 0; i < glyph_count; i++) {
695 DWRITE_GLYPH_METRICS *ret = metrics + i;
696 DWRITE_GLYPH_METRICS design;
698 hr = IDWriteFontFace2_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways);
699 if (FAILED(hr))
700 return hr;
702 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
703 SCALE_METRIC(leftSideBearing);
704 SCALE_METRIC(advanceWidth);
705 SCALE_METRIC(rightSideBearing);
706 SCALE_METRIC(topSideBearing);
707 SCALE_METRIC(advanceHeight);
708 SCALE_METRIC(bottomSideBearing);
709 SCALE_METRIC(verticalOriginY);
710 #undef SCALE_METRIC
713 return S_OK;
716 static void WINAPI dwritefontface1_GetMetrics(IDWriteFontFace2 *iface, DWRITE_FONT_METRICS1 *metrics)
718 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
719 TRACE("(%p)->(%p)\n", This, metrics);
720 *metrics = This->metrics;
723 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT em_size, FLOAT pixels_per_dip,
724 const DWRITE_MATRIX *m, DWRITE_FONT_METRICS1 *metrics)
726 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
727 const DWRITE_FONT_METRICS1 *design = &This->metrics;
728 UINT16 ascent, descent;
729 FLOAT scale;
731 TRACE("(%p)->(%.2f %.2f %p %p)\n", This, em_size, pixels_per_dip, m, metrics);
733 if (em_size <= 0.0 || pixels_per_dip <= 0.0) {
734 memset(metrics, 0, sizeof(*metrics));
735 return E_INVALIDARG;
738 em_size *= pixels_per_dip;
739 if (m && m->m22 != 0.0)
740 em_size *= fabs(m->m22);
742 scale = em_size / design->designUnitsPerEm;
743 if (!opentype_get_vdmx_size(get_fontface_vdmx(This), em_size, &ascent, &descent)) {
744 ascent = round_metric(design->ascent * scale);
745 descent = round_metric(design->descent * scale);
748 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
749 metrics->designUnitsPerEm = design->designUnitsPerEm;
750 metrics->ascent = round_metric(ascent / scale);
751 metrics->descent = round_metric(descent / scale);
753 SCALE_METRIC(lineGap);
754 SCALE_METRIC(capHeight);
755 SCALE_METRIC(xHeight);
756 SCALE_METRIC(underlinePosition);
757 SCALE_METRIC(underlineThickness);
758 SCALE_METRIC(strikethroughPosition);
759 SCALE_METRIC(strikethroughThickness);
760 SCALE_METRIC(glyphBoxLeft);
761 SCALE_METRIC(glyphBoxTop);
762 SCALE_METRIC(glyphBoxRight);
763 SCALE_METRIC(glyphBoxBottom);
764 SCALE_METRIC(subscriptPositionX);
765 SCALE_METRIC(subscriptPositionY);
766 SCALE_METRIC(subscriptSizeX);
767 SCALE_METRIC(subscriptSizeY);
768 SCALE_METRIC(superscriptPositionX);
769 SCALE_METRIC(superscriptPositionY);
770 SCALE_METRIC(superscriptSizeX);
771 SCALE_METRIC(superscriptSizeY);
773 metrics->hasTypographicMetrics = design->hasTypographicMetrics;
774 #undef SCALE_METRIC
776 return S_OK;
779 static void WINAPI dwritefontface1_GetCaretMetrics(IDWriteFontFace2 *iface, DWRITE_CARET_METRICS *metrics)
781 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
782 TRACE("(%p)->(%p)\n", This, metrics);
783 *metrics = This->caret;
786 static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace2 *iface, UINT32 max_count,
787 DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
789 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
791 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
793 *count = 0;
794 if (max_count && !ranges)
795 return E_INVALIDARG;
797 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count);
800 static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace2 *iface)
802 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
803 TRACE("(%p)\n", This);
804 return freetype_is_monospaced(iface);
807 static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace2 *iface,
808 UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways)
810 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
811 UINT32 i;
813 TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways);
815 for (i = 0; i < glyph_count; i++) {
816 DWRITE_GLYPH_METRICS metrics = { 0 };
817 HRESULT hr;
819 hr = IDWriteFontFace2_GetDesignGlyphMetrics(iface, glyphs + i, 1, &metrics, is_sideways);
820 if (FAILED(hr))
821 return hr;
823 advances[i] = is_sideways ? metrics.advanceHeight : metrics.advanceWidth;
826 return S_OK;
829 static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace2 *iface,
830 FLOAT em_size, FLOAT ppdip, const DWRITE_MATRIX *m, BOOL use_gdi_natural,
831 BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances)
833 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
834 FLOAT scale;
835 HRESULT hr;
836 UINT32 i;
838 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This, em_size, ppdip, m,
839 use_gdi_natural, is_sideways, glyph_count, glyphs, advances);
841 if (em_size < 0.0 || ppdip <= 0.0) {
842 memset(advances, 0, sizeof(*advances) * glyph_count);
843 return E_INVALIDARG;
846 scale = em_size * ppdip / This->metrics.designUnitsPerEm;
847 if (scale == 0.0) {
848 memset(advances, 0, sizeof(*advances) * glyph_count);
849 return S_OK;
852 if (m && memcmp(m, &identity, sizeof(*m)))
853 FIXME("transform is not supported, %s\n", debugstr_matrix(m));
855 for (i = 0; i < glyph_count; i++) {
856 hr = IDWriteFontFace2_GetDesignGlyphAdvances(iface, 1, glyphs + i, advances + i, is_sideways);
857 if (FAILED(hr))
858 return hr;
860 #define SCALE_METRIC(x) x = round_metric(round_metric((x) * scale) / scale)
861 SCALE_METRIC(advances[i]);
862 #undef SCALE_METRIC
865 return S_OK;
868 static HRESULT WINAPI dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace2 *iface, UINT32 count,
869 const UINT16 *indices, INT32 *adjustments)
871 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
872 UINT32 i;
874 TRACE("(%p)->(%u %p %p)\n", This, count, indices, adjustments);
876 if (!(indices || adjustments) || !count)
877 return E_INVALIDARG;
879 if (!indices || count == 1) {
880 memset(adjustments, 0, count*sizeof(INT32));
881 return E_INVALIDARG;
884 for (i = 0; i < count-1; i++)
885 adjustments[i] = freetype_get_kerning_pair_adjustment(iface, indices[i], indices[i+1]);
886 adjustments[count-1] = 0;
888 return S_OK;
891 static BOOL WINAPI dwritefontface1_HasKerningPairs(IDWriteFontFace2 *iface)
893 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
894 TRACE("(%p)\n", This);
895 return freetype_has_kerning_pairs(iface);
898 static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace2 *iface,
899 FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways,
900 DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode)
902 DWRITE_GRID_FIT_MODE gridfitmode;
903 return IDWriteFontFace2_GetRecommendedRenderingMode(iface, font_emsize, dpiX, dpiY, transform, is_sideways,
904 threshold, measuring_mode, NULL, rendering_mode, &gridfitmode);
907 static HRESULT WINAPI dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace2 *iface, UINT32 glyph_count,
908 const UINT16 *nominal_indices, UINT16 *vertical_indices)
910 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
911 FIXME("(%p)->(%u %p %p): stub\n", This, glyph_count, nominal_indices, vertical_indices);
912 return E_NOTIMPL;
915 static BOOL WINAPI dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace2 *iface)
917 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
918 FIXME("(%p): stub\n", This);
919 return FALSE;
922 static BOOL WINAPI dwritefontface2_IsColorFont(IDWriteFontFace2 *iface)
924 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
925 FIXME("(%p): stub\n", This);
926 return FALSE;
929 static UINT32 WINAPI dwritefontface2_GetColorPaletteCount(IDWriteFontFace2 *iface)
931 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
932 FIXME("(%p): stub\n", This);
933 return 0;
936 static UINT32 WINAPI dwritefontface2_GetPaletteEntryCount(IDWriteFontFace2 *iface)
938 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
939 FIXME("(%p): stub\n", This);
940 return 0;
943 static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace2 *iface, UINT32 palette_index,
944 UINT32 first_entry_index, UINT32 entry_count, DWRITE_COLOR_F *entries)
946 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
947 FIXME("(%p)->(%u %u %u %p): stub\n", This, palette_index, first_entry_index, entry_count, entries);
948 return E_NOTIMPL;
951 static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize,
952 FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold,
953 DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode,
954 DWRITE_GRID_FIT_MODE *gridfitmode)
956 struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface);
957 FLOAT emthreshold;
958 WORD gasp, *ptr;
959 UINT32 size;
961 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold,
962 measuringmode, params, renderingmode, gridfitmode);
964 if (m)
965 FIXME("transform not supported %s\n", debugstr_matrix(m));
967 if (is_sideways)
968 FIXME("sideways mode not supported\n");
970 *renderingmode = DWRITE_RENDERING_MODE_DEFAULT;
971 *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT;
972 if (params) {
973 IDWriteRenderingParams2 *params2;
974 HRESULT hr;
976 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
977 if (hr == S_OK) {
978 *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2);
979 *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2);
980 IDWriteRenderingParams2_Release(params2);
982 else
983 *renderingmode = IDWriteRenderingParams_GetRenderingMode(params);
986 emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD;
988 ptr = get_fontface_gasp(This, &size);
989 gasp = opentype_get_gasp_flags(ptr, size, emSize);
991 if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) {
992 if (emSize >= emthreshold)
993 *renderingmode = DWRITE_RENDERING_MODE_OUTLINE;
994 else
995 *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp);
998 if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) {
999 if (emSize >= emthreshold)
1000 *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED;
1001 else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL)
1002 *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED;
1003 else
1004 *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
1007 return S_OK;
1010 static const IDWriteFontFace2Vtbl dwritefontfacevtbl = {
1011 dwritefontface_QueryInterface,
1012 dwritefontface_AddRef,
1013 dwritefontface_Release,
1014 dwritefontface_GetType,
1015 dwritefontface_GetFiles,
1016 dwritefontface_GetIndex,
1017 dwritefontface_GetSimulations,
1018 dwritefontface_IsSymbolFont,
1019 dwritefontface_GetMetrics,
1020 dwritefontface_GetGlyphCount,
1021 dwritefontface_GetDesignGlyphMetrics,
1022 dwritefontface_GetGlyphIndices,
1023 dwritefontface_TryGetFontTable,
1024 dwritefontface_ReleaseFontTable,
1025 dwritefontface_GetGlyphRunOutline,
1026 dwritefontface_GetRecommendedRenderingMode,
1027 dwritefontface_GetGdiCompatibleMetrics,
1028 dwritefontface_GetGdiCompatibleGlyphMetrics,
1029 dwritefontface1_GetMetrics,
1030 dwritefontface1_GetGdiCompatibleMetrics,
1031 dwritefontface1_GetCaretMetrics,
1032 dwritefontface1_GetUnicodeRanges,
1033 dwritefontface1_IsMonospacedFont,
1034 dwritefontface1_GetDesignGlyphAdvances,
1035 dwritefontface1_GetGdiCompatibleGlyphAdvances,
1036 dwritefontface1_GetKerningPairAdjustments,
1037 dwritefontface1_HasKerningPairs,
1038 dwritefontface1_GetRecommendedRenderingMode,
1039 dwritefontface1_GetVerticalGlyphVariants,
1040 dwritefontface1_HasVerticalGlyphVariants,
1041 dwritefontface2_IsColorFont,
1042 dwritefontface2_GetColorPaletteCount,
1043 dwritefontface2_GetPaletteEntryCount,
1044 dwritefontface2_GetPaletteEntries,
1045 dwritefontface2_GetRecommendedRenderingMode
1048 HRESULT get_family_names_from_stream(IDWriteFontFileStream *stream, UINT32 index, DWRITE_FONT_FACE_TYPE facetype,
1049 IDWriteLocalizedStrings **names)
1051 const void *name_table = NULL;
1052 void *name_context;
1053 HRESULT hr = E_FAIL;
1055 opentype_get_font_table(stream, facetype, index, MS_NAME_TAG, &name_table, &name_context, NULL, NULL);
1056 if (name_table) {
1057 hr = opentype_get_font_strings_from_id(name_table, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, names);
1058 IDWriteFontFileStream_ReleaseFileFragment(stream, name_context);
1060 else
1061 *names = NULL;
1063 return hr;
1066 static HRESULT get_fontface_from_font(struct dwrite_font *font, IDWriteFontFace2 **fontface)
1068 struct dwrite_font_data *data = font->data;
1069 IDWriteFontFace *face;
1070 HRESULT hr;
1072 *fontface = NULL;
1074 hr = IDWriteFactory2_CreateFontFace(data->factory, data->face_type, 1, &data->file,
1075 data->face_index, font->simulations, &face);
1076 if (FAILED(hr))
1077 return hr;
1079 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace2, (void**)fontface);
1080 IDWriteFontFace_Release(face);
1082 return hr;
1085 static HRESULT WINAPI dwritefont_QueryInterface(IDWriteFont2 *iface, REFIID riid, void **obj)
1087 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1089 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1091 if (IsEqualIID(riid, &IID_IDWriteFont2) ||
1092 IsEqualIID(riid, &IID_IDWriteFont1) ||
1093 IsEqualIID(riid, &IID_IDWriteFont) ||
1094 IsEqualIID(riid, &IID_IUnknown))
1096 *obj = iface;
1097 IDWriteFont2_AddRef(iface);
1098 return S_OK;
1101 *obj = NULL;
1102 return E_NOINTERFACE;
1105 static ULONG WINAPI dwritefont_AddRef(IDWriteFont2 *iface)
1107 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1108 ULONG ref = InterlockedIncrement(&This->ref);
1109 TRACE("(%p)->(%d)\n", This, ref);
1110 return ref;
1113 static ULONG WINAPI dwritefont_Release(IDWriteFont2 *iface)
1115 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1116 ULONG ref = InterlockedDecrement(&This->ref);
1118 TRACE("(%p)->(%d)\n", This, ref);
1120 if (!ref) {
1121 IDWriteFontFamily_Release(This->family);
1122 release_font_data(This->data);
1123 heap_free(This);
1126 return ref;
1129 static HRESULT WINAPI dwritefont_GetFontFamily(IDWriteFont2 *iface, IDWriteFontFamily **family)
1131 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1132 TRACE("(%p)->(%p)\n", This, family);
1134 *family = This->family;
1135 IDWriteFontFamily_AddRef(*family);
1136 return S_OK;
1139 static DWRITE_FONT_WEIGHT WINAPI dwritefont_GetWeight(IDWriteFont2 *iface)
1141 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1142 TRACE("(%p)\n", This);
1143 return This->data->weight;
1146 static DWRITE_FONT_STRETCH WINAPI dwritefont_GetStretch(IDWriteFont2 *iface)
1148 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1149 TRACE("(%p)\n", This);
1150 return This->data->stretch;
1153 static DWRITE_FONT_STYLE WINAPI dwritefont_GetStyle(IDWriteFont2 *iface)
1155 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1156 TRACE("(%p)\n", This);
1157 return This->style;
1160 static BOOL WINAPI dwritefont_IsSymbolFont(IDWriteFont2 *iface)
1162 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1163 IDWriteFontFace2 *fontface;
1164 HRESULT hr;
1166 TRACE("(%p)\n", This);
1168 hr = get_fontface_from_font(This, &fontface);
1169 if (FAILED(hr))
1170 return hr;
1172 return IDWriteFontFace2_IsSymbolFont(fontface);
1175 static HRESULT WINAPI dwritefont_GetFaceNames(IDWriteFont2 *iface, IDWriteLocalizedStrings **names)
1177 static const WCHAR boldobliqueW[] = {'B','o','l','d',' ','O','b','l','i','q','u','e',0};
1178 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
1179 static const WCHAR boldW[] = {'B','o','l','d',0};
1180 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1182 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1183 IDWriteLocalizedStrings *strings;
1184 const WCHAR *name;
1185 HRESULT hr;
1187 TRACE("(%p)->(%p)\n", This, names);
1189 *names = NULL;
1191 if (This->simulations == DWRITE_FONT_SIMULATIONS_NONE) {
1192 BOOL exists;
1193 return IDWriteFont2_GetInformationalStrings(iface, DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES,
1194 names, &exists);
1197 switch (This->simulations) {
1198 case DWRITE_FONT_SIMULATIONS_BOLD|DWRITE_FONT_SIMULATIONS_OBLIQUE:
1199 name = boldobliqueW;
1200 break;
1201 case DWRITE_FONT_SIMULATIONS_BOLD:
1202 name = boldW;
1203 break;
1204 case DWRITE_FONT_SIMULATIONS_OBLIQUE:
1205 name = obliqueW;
1206 break;
1207 default:
1208 ERR("unknown simulations %d\n", This->simulations);
1209 return E_FAIL;
1212 hr = create_localizedstrings(&strings);
1213 if (FAILED(hr)) return hr;
1215 hr = add_localizedstring(strings, enusW, name);
1216 if (FAILED(hr)) {
1217 IDWriteLocalizedStrings_Release(strings);
1218 return hr;
1221 *names = strings;
1223 return S_OK;
1226 static HRESULT WINAPI dwritefont_GetInformationalStrings(IDWriteFont2 *iface,
1227 DWRITE_INFORMATIONAL_STRING_ID stringid, IDWriteLocalizedStrings **strings, BOOL *exists)
1229 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1230 struct dwrite_font_data *data = This->data;
1231 HRESULT hr;
1233 TRACE("(%p)->(%d %p %p)\n", This, stringid, strings, exists);
1235 *exists = FALSE;
1236 *strings = NULL;
1238 if (stringid > DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME || stringid == DWRITE_INFORMATIONAL_STRING_NONE)
1239 return S_OK;
1241 if (!data->info_strings[stringid]) {
1242 IDWriteFontFace2 *fontface;
1243 const void *table_data;
1244 BOOL table_exists;
1245 void *context;
1246 UINT32 size;
1248 hr = get_fontface_from_font(This, &fontface);
1249 if (FAILED(hr))
1250 return hr;
1252 table_exists = FALSE;
1253 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_NAME_TAG, &table_data, &size, &context, &table_exists);
1254 if (FAILED(hr) || !table_exists)
1255 WARN("no NAME table found.\n");
1257 if (table_exists) {
1258 hr = opentype_get_font_strings_from_id(table_data, stringid, &data->info_strings[stringid]);
1259 if (FAILED(hr) || !data->info_strings[stringid])
1260 return hr;
1261 IDWriteFontFace2_ReleaseFontTable(fontface, context);
1265 hr = clone_localizedstring(data->info_strings[stringid], strings);
1266 if (FAILED(hr))
1267 return hr;
1269 *exists = TRUE;
1270 return S_OK;
1273 static DWRITE_FONT_SIMULATIONS WINAPI dwritefont_GetSimulations(IDWriteFont2 *iface)
1275 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1276 TRACE("(%p)\n", This);
1277 return This->simulations;
1280 static void WINAPI dwritefont_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS *metrics)
1282 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1284 TRACE("(%p)->(%p)\n", This, metrics);
1285 memcpy(metrics, &This->data->metrics, sizeof(*metrics));
1288 static HRESULT WINAPI dwritefont_HasCharacter(IDWriteFont2 *iface, UINT32 value, BOOL *exists)
1290 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1291 IDWriteFontFace2 *fontface;
1292 UINT16 index;
1293 HRESULT hr;
1295 TRACE("(%p)->(0x%08x %p)\n", This, value, exists);
1297 *exists = FALSE;
1299 hr = get_fontface_from_font(This, &fontface);
1300 if (FAILED(hr))
1301 return hr;
1303 index = 0;
1304 hr = IDWriteFontFace2_GetGlyphIndices(fontface, &value, 1, &index);
1305 if (FAILED(hr))
1306 return hr;
1308 *exists = index != 0;
1309 return S_OK;
1312 static HRESULT WINAPI dwritefont_CreateFontFace(IDWriteFont2 *iface, IDWriteFontFace **face)
1314 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1315 HRESULT hr;
1317 TRACE("(%p)->(%p)\n", This, face);
1319 hr = get_fontface_from_font(This, (IDWriteFontFace2**)face);
1320 if (hr == S_OK)
1321 IDWriteFontFace_AddRef(*face);
1323 return hr;
1326 static void WINAPI dwritefont1_GetMetrics(IDWriteFont2 *iface, DWRITE_FONT_METRICS1 *metrics)
1328 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1329 TRACE("(%p)->(%p)\n", This, metrics);
1330 *metrics = This->data->metrics;
1333 static void WINAPI dwritefont1_GetPanose(IDWriteFont2 *iface, DWRITE_PANOSE *panose)
1335 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1336 TRACE("(%p)->(%p)\n", This, panose);
1337 *panose = This->data->panose;
1340 static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont2 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count)
1342 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1343 IDWriteFontFace2 *fontface;
1344 HRESULT hr;
1346 TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count);
1348 hr = get_fontface_from_font(This, &fontface);
1349 if (FAILED(hr))
1350 return hr;
1352 return IDWriteFontFace2_GetUnicodeRanges(fontface, max_count, ranges, count);
1355 static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont2 *iface)
1357 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1358 IDWriteFontFace2 *fontface;
1359 HRESULT hr;
1361 TRACE("(%p)\n", This);
1363 hr = get_fontface_from_font(This, &fontface);
1364 if (FAILED(hr))
1365 return hr;
1367 return IDWriteFontFace2_IsMonospacedFont(fontface);
1370 static HRESULT WINAPI dwritefont2_IsColorFont(IDWriteFont2 *iface)
1372 struct dwrite_font *This = impl_from_IDWriteFont2(iface);
1373 IDWriteFontFace2 *fontface;
1374 HRESULT hr;
1376 TRACE("(%p)\n", This);
1378 hr = get_fontface_from_font(This, &fontface);
1379 if (FAILED(hr))
1380 return hr;
1382 return IDWriteFontFace2_IsColorFont(fontface);
1385 static const IDWriteFont2Vtbl dwritefontvtbl = {
1386 dwritefont_QueryInterface,
1387 dwritefont_AddRef,
1388 dwritefont_Release,
1389 dwritefont_GetFontFamily,
1390 dwritefont_GetWeight,
1391 dwritefont_GetStretch,
1392 dwritefont_GetStyle,
1393 dwritefont_IsSymbolFont,
1394 dwritefont_GetFaceNames,
1395 dwritefont_GetInformationalStrings,
1396 dwritefont_GetSimulations,
1397 dwritefont_GetMetrics,
1398 dwritefont_HasCharacter,
1399 dwritefont_CreateFontFace,
1400 dwritefont1_GetMetrics,
1401 dwritefont1_GetPanose,
1402 dwritefont1_GetUnicodeRanges,
1403 dwritefont1_IsMonospacedFont,
1404 dwritefont2_IsColorFont
1407 static HRESULT create_font(struct dwrite_font_data *data, IDWriteFontFamily *family, DWRITE_FONT_SIMULATIONS simulations,
1408 IDWriteFont **font)
1410 struct dwrite_font *This;
1411 *font = NULL;
1413 This = heap_alloc(sizeof(struct dwrite_font));
1414 if (!This) return E_OUTOFMEMORY;
1416 This->IDWriteFont2_iface.lpVtbl = &dwritefontvtbl;
1417 This->ref = 1;
1418 This->family = family;
1419 IDWriteFontFamily_AddRef(family);
1420 This->simulations = simulations;
1421 This->style = data->style;
1422 This->data = data;
1423 InterlockedIncrement(&This->data->ref);
1425 /* set oblique style from requested simulation */
1426 if ((simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) && data->style == DWRITE_FONT_STYLE_NORMAL)
1427 This->style = DWRITE_FONT_STYLE_OBLIQUE;
1429 *font = (IDWriteFont*)&This->IDWriteFont2_iface;
1431 return S_OK;
1434 static HRESULT WINAPI dwritefontfamily_QueryInterface(IDWriteFontFamily *iface, REFIID riid, void **obj)
1436 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1437 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1439 if (IsEqualIID(riid, &IID_IUnknown) ||
1440 IsEqualIID(riid, &IID_IDWriteFontList) ||
1441 IsEqualIID(riid, &IID_IDWriteFontFamily))
1443 *obj = iface;
1444 IDWriteFontFamily_AddRef(iface);
1445 return S_OK;
1448 *obj = NULL;
1449 return E_NOINTERFACE;
1452 static ULONG WINAPI dwritefontfamily_AddRef(IDWriteFontFamily *iface)
1454 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1455 ULONG ref = InterlockedIncrement(&This->ref);
1456 TRACE("(%p)->(%d)\n", This, ref);
1457 return ref;
1460 static ULONG WINAPI dwritefontfamily_Release(IDWriteFontFamily *iface)
1462 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1463 ULONG ref = InterlockedDecrement(&This->ref);
1465 TRACE("(%p)->(%d)\n", This, ref);
1467 if (!ref)
1469 IDWriteFontCollection_Release(This->collection);
1470 release_fontfamily_data(This->data);
1471 heap_free(This);
1474 return ref;
1477 static HRESULT WINAPI dwritefontfamily_GetFontCollection(IDWriteFontFamily *iface, IDWriteFontCollection **collection)
1479 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1480 TRACE("(%p)->(%p)\n", This, collection);
1482 *collection = This->collection;
1483 IDWriteFontCollection_AddRef(This->collection);
1484 return S_OK;
1487 static UINT32 WINAPI dwritefontfamily_GetFontCount(IDWriteFontFamily *iface)
1489 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1490 TRACE("(%p)\n", This);
1491 return This->data->font_count;
1494 static HRESULT WINAPI dwritefontfamily_GetFont(IDWriteFontFamily *iface, UINT32 index, IDWriteFont **font)
1496 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1498 TRACE("(%p)->(%u %p)\n", This, index, font);
1500 *font = NULL;
1502 if (This->data->font_count == 0)
1503 return S_FALSE;
1505 if (index >= This->data->font_count)
1506 return E_INVALIDARG;
1508 return create_font(This->data->fonts[index], iface, DWRITE_FONT_SIMULATIONS_NONE, font);
1511 static HRESULT WINAPI dwritefontfamily_GetFamilyNames(IDWriteFontFamily *iface, IDWriteLocalizedStrings **names)
1513 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1514 return clone_localizedstring(This->data->familyname, names);
1517 static inline BOOL is_matching_font_style(DWRITE_FONT_STYLE style, DWRITE_FONT_STYLE font_style)
1519 if (style == font_style)
1520 return TRUE;
1522 if (((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE)) && font_style == DWRITE_FONT_STYLE_NORMAL)
1523 return TRUE;
1525 return FALSE;
1528 static HRESULT WINAPI dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1529 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont **font)
1531 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1532 UINT32 min_weight_diff = ~0u;
1533 int found = -1, i;
1535 TRACE("(%p)->(%d %d %d %p)\n", This, weight, stretch, style, font);
1537 for (i = 0; i < This->data->font_count; i++) {
1538 if (is_matching_font_style(style, This->data->fonts[i]->style) && stretch == This->data->fonts[i]->stretch) {
1539 DWRITE_FONT_WEIGHT font_weight = This->data->fonts[i]->weight;
1540 UINT32 weight_diff = abs(font_weight - weight);
1541 if (weight_diff < min_weight_diff) {
1542 min_weight_diff = weight_diff;
1543 found = i;
1548 if (found != -1) {
1549 DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
1551 if (((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE)) &&
1552 This->data->fonts[found]->style == DWRITE_FONT_STYLE_NORMAL) {
1553 simulations = DWRITE_FONT_SIMULATIONS_OBLIQUE;
1555 return create_font(This->data->fonts[found], iface, simulations, font);
1557 else {
1558 *font = NULL;
1559 return DWRITE_E_NOFONT;
1563 static HRESULT WINAPI dwritefontfamily_GetMatchingFonts(IDWriteFontFamily *iface, DWRITE_FONT_WEIGHT weight,
1564 DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontList **fonts)
1566 struct dwrite_fontfamily *This = impl_from_IDWriteFontFamily(iface);
1567 FIXME("(%p)->(%d %d %d %p): stub\n", This, weight, stretch, style, fonts);
1568 return E_NOTIMPL;
1571 static const IDWriteFontFamilyVtbl fontfamilyvtbl = {
1572 dwritefontfamily_QueryInterface,
1573 dwritefontfamily_AddRef,
1574 dwritefontfamily_Release,
1575 dwritefontfamily_GetFontCollection,
1576 dwritefontfamily_GetFontCount,
1577 dwritefontfamily_GetFont,
1578 dwritefontfamily_GetFamilyNames,
1579 dwritefontfamily_GetFirstMatchingFont,
1580 dwritefontfamily_GetMatchingFonts
1583 static HRESULT create_fontfamily(struct dwrite_fontfamily_data *data, IDWriteFontCollection *collection, IDWriteFontFamily **family)
1585 struct dwrite_fontfamily *This;
1587 *family = NULL;
1589 This = heap_alloc(sizeof(struct dwrite_fontfamily));
1590 if (!This) return E_OUTOFMEMORY;
1592 This->IDWriteFontFamily_iface.lpVtbl = &fontfamilyvtbl;
1593 This->ref = 1;
1594 This->collection = collection;
1595 IDWriteFontCollection_AddRef(collection);
1596 This->data = data;
1597 InterlockedIncrement(&This->data->ref);
1599 *family = &This->IDWriteFontFamily_iface;
1601 return S_OK;
1604 BOOL is_system_collection(IDWriteFontCollection *collection)
1606 void *obj;
1607 return IDWriteFontCollection_QueryInterface(collection, &IID_issystemcollection, (void**)&obj) == S_OK;
1610 static HRESULT WINAPI dwritefontcollection_QueryInterface(IDWriteFontCollection *iface, REFIID riid, void **obj)
1612 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1613 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
1615 if (IsEqualIID(riid, &IID_IUnknown) ||
1616 IsEqualIID(riid, &IID_IDWriteFontCollection))
1618 *obj = iface;
1619 IDWriteFontCollection_AddRef(iface);
1620 return S_OK;
1623 *obj = NULL;
1625 if (This->is_system && IsEqualIID(riid, &IID_issystemcollection))
1626 return S_OK;
1628 return E_NOINTERFACE;
1631 static ULONG WINAPI dwritefontcollection_AddRef(IDWriteFontCollection *iface)
1633 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1634 ULONG ref = InterlockedIncrement(&This->ref);
1635 TRACE("(%p)->(%d)\n", This, ref);
1636 return ref;
1639 static ULONG WINAPI dwritefontcollection_Release(IDWriteFontCollection *iface)
1641 unsigned int i;
1642 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1643 ULONG ref = InterlockedDecrement(&This->ref);
1644 TRACE("(%p)->(%d)\n", This, ref);
1646 if (!ref) {
1647 for (i = 0; i < This->family_count; i++)
1648 release_fontfamily_data(This->family_data[i]);
1649 heap_free(This->family_data);
1650 heap_free(This);
1653 return ref;
1656 static UINT32 WINAPI dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
1658 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1659 TRACE("(%p)\n", This);
1660 return This->family_count;
1663 static HRESULT WINAPI dwritefontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
1665 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1667 TRACE("(%p)->(%u %p)\n", This, index, family);
1669 if (index >= This->family_count) {
1670 *family = NULL;
1671 return E_FAIL;
1674 return create_fontfamily(This->family_data[index], iface, family);
1677 static UINT32 collection_find_family(struct dwrite_fontcollection *collection, const WCHAR *name)
1679 UINT32 i;
1681 for (i = 0; i < collection->family_count; i++) {
1682 IDWriteLocalizedStrings *family_name = collection->family_data[i]->familyname;
1683 UINT32 j, count = IDWriteLocalizedStrings_GetCount(family_name);
1684 HRESULT hr;
1686 for (j = 0; j < count; j++) {
1687 WCHAR buffer[255];
1688 hr = IDWriteLocalizedStrings_GetString(family_name, j, buffer, 255);
1689 if (SUCCEEDED(hr) && !strcmpiW(buffer, name))
1690 return i;
1694 return ~0u;
1697 static HRESULT WINAPI dwritefontcollection_FindFamilyName(IDWriteFontCollection *iface, const WCHAR *name, UINT32 *index, BOOL *exists)
1699 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1700 TRACE("(%p)->(%s %p %p)\n", This, debugstr_w(name), index, exists);
1701 *index = collection_find_family(This, name);
1702 *exists = *index != ~0u;
1703 return S_OK;
1706 static BOOL is_same_fontfile(IDWriteFontFile *left, IDWriteFontFile *right)
1708 UINT32 left_key_size, right_key_size;
1709 const void *left_key, *right_key;
1710 HRESULT hr;
1712 if (left == right)
1713 return TRUE;
1715 hr = IDWriteFontFile_GetReferenceKey(left, &left_key, &left_key_size);
1716 if (FAILED(hr))
1717 return FALSE;
1719 hr = IDWriteFontFile_GetReferenceKey(right, &right_key, &right_key_size);
1720 if (FAILED(hr))
1721 return FALSE;
1723 if (left_key_size != right_key_size)
1724 return FALSE;
1726 return !memcmp(left_key, right_key, left_key_size);
1729 static HRESULT WINAPI dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
1731 struct dwrite_fontcollection *This = impl_from_IDWriteFontCollection(iface);
1732 struct dwrite_fontfamily_data *found_family = NULL;
1733 struct dwrite_font_data *found_font = NULL;
1734 DWRITE_FONT_SIMULATIONS simulations;
1735 IDWriteFontFamily *family;
1736 UINT32 i, j, face_index;
1737 IDWriteFontFile *file;
1738 HRESULT hr;
1740 TRACE("(%p)->(%p %p)\n", This, face, font);
1742 *font = NULL;
1744 if (!face)
1745 return E_INVALIDARG;
1747 i = 1;
1748 hr = IDWriteFontFace_GetFiles(face, &i, &file);
1749 if (FAILED(hr))
1750 return hr;
1751 face_index = IDWriteFontFace_GetIndex(face);
1753 for (i = 0; i < This->family_count; i++) {
1754 struct dwrite_fontfamily_data *family_data = This->family_data[i];
1755 for (j = 0; j < family_data->font_count; j++) {
1756 struct dwrite_font_data *font_data = family_data->fonts[j];
1758 if (face_index == font_data->face_index && is_same_fontfile(file, font_data->file)) {
1759 found_font = font_data;
1760 found_family = family_data;
1761 break;
1766 if (!found_font)
1767 return DWRITE_E_NOFONT;
1769 hr = create_fontfamily(found_family, iface, &family);
1770 if (FAILED(hr))
1771 return hr;
1773 simulations = IDWriteFontFace_GetSimulations(face);
1774 hr = create_font(found_font, family, simulations, font);
1775 IDWriteFontFamily_Release(family);
1776 return hr;
1779 static const IDWriteFontCollectionVtbl fontcollectionvtbl = {
1780 dwritefontcollection_QueryInterface,
1781 dwritefontcollection_AddRef,
1782 dwritefontcollection_Release,
1783 dwritefontcollection_GetFontFamilyCount,
1784 dwritefontcollection_GetFontFamily,
1785 dwritefontcollection_FindFamilyName,
1786 dwritefontcollection_GetFontFromFontFace
1789 static HRESULT fontfamily_add_font(struct dwrite_fontfamily_data *family_data, struct dwrite_font_data *font_data)
1791 if (family_data->font_count + 1 >= family_data->font_alloc) {
1792 struct dwrite_font_data **new_list;
1793 UINT32 new_alloc;
1795 new_alloc = family_data->font_alloc * 2;
1796 new_list = heap_realloc(family_data->fonts, sizeof(*family_data->fonts) * new_alloc);
1797 if (!new_list)
1798 return E_OUTOFMEMORY;
1799 family_data->fonts = new_list;
1800 family_data->font_alloc = new_alloc;
1803 family_data->fonts[family_data->font_count] = font_data;
1804 family_data->font_count++;
1805 return S_OK;
1808 static HRESULT fontcollection_add_family(struct dwrite_fontcollection *collection, struct dwrite_fontfamily_data *family)
1810 if (collection->family_alloc < collection->family_count + 1) {
1811 struct dwrite_fontfamily_data **new_list;
1812 UINT32 new_alloc;
1814 new_alloc = collection->family_alloc * 2;
1815 new_list = heap_realloc(collection->family_data, sizeof(*new_list) * new_alloc);
1816 if (!new_list)
1817 return E_OUTOFMEMORY;
1819 collection->family_alloc = new_alloc;
1820 collection->family_data = new_list;
1823 collection->family_data[collection->family_count] = family;
1824 collection->family_count++;
1826 return S_OK;
1829 static HRESULT init_font_collection(struct dwrite_fontcollection *collection, BOOL is_system)
1831 collection->IDWriteFontCollection_iface.lpVtbl = &fontcollectionvtbl;
1832 collection->ref = 1;
1833 collection->family_count = 0;
1834 collection->family_alloc = 2;
1835 collection->is_system = is_system;
1837 collection->family_data = heap_alloc(sizeof(*collection->family_data)*2);
1838 if (!collection->family_data)
1839 return E_OUTOFMEMORY;
1841 return S_OK;
1844 HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
1846 IDWriteFontFileLoader *loader;
1847 const void *key;
1848 UINT32 key_size;
1849 HRESULT hr;
1851 *stream = NULL;
1853 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
1854 if (FAILED(hr))
1855 return hr;
1857 hr = IDWriteFontFile_GetLoader(file, &loader);
1858 if (FAILED(hr))
1859 return hr;
1861 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
1862 IDWriteFontFileLoader_Release(loader);
1863 if (FAILED(hr))
1864 return hr;
1866 return hr;
1869 static HRESULT init_font_data(IDWriteFactory2 *factory, IDWriteFontFile *file, UINT32 face_index, DWRITE_FONT_FACE_TYPE face_type,
1870 IDWriteFontFileStream **stream, struct dwrite_font_data **ret)
1872 void *os2_context, *head_context;
1873 const void *tt_os2 = NULL, *tt_head = NULL;
1874 struct dwrite_font_props props;
1875 struct dwrite_font_data *data;
1876 HRESULT hr;
1878 data = heap_alloc_zero(sizeof(*data));
1879 if (!data)
1880 return E_OUTOFMEMORY;
1882 hr = get_filestream_from_file(file, stream);
1883 if (FAILED(hr)) {
1884 heap_free(data);
1885 return hr;
1888 data->ref = 1;
1889 data->factory = factory;
1890 data->file = file;
1891 data->face_index = face_index;
1892 data->face_type = face_type;
1893 IDWriteFontFile_AddRef(file);
1894 IDWriteFactory2_AddRef(factory);
1896 opentype_get_font_table(*stream, face_type, face_index, MS_OS2_TAG, &tt_os2, &os2_context, NULL, NULL);
1897 opentype_get_font_table(*stream, face_type, face_index, MS_HEAD_TAG, &tt_head, &head_context, NULL, NULL);
1899 opentype_get_font_properties(*stream, face_type, face_index, &props);
1900 opentype_get_font_metrics(*stream, face_type, face_index, &data->metrics, NULL);
1902 data->style = props.style;
1903 data->stretch = props.stretch;
1904 data->weight = props.weight;
1905 data->panose = props.panose;
1907 if (tt_os2)
1908 IDWriteFontFileStream_ReleaseFileFragment(*stream, os2_context);
1909 if (tt_head)
1910 IDWriteFontFileStream_ReleaseFileFragment(*stream, head_context);
1912 *ret = data;
1913 return S_OK;
1916 static HRESULT init_fontfamily_data(IDWriteLocalizedStrings *familyname, struct dwrite_fontfamily_data **ret)
1918 struct dwrite_fontfamily_data *data;
1920 data = heap_alloc(sizeof(*data));
1921 if (!data)
1922 return E_OUTOFMEMORY;
1924 data->ref = 1;
1925 data->font_count = 0;
1926 data->font_alloc = 2;
1928 data->fonts = heap_alloc(sizeof(*data->fonts)*data->font_alloc);
1929 if (!data->fonts) {
1930 heap_free(data);
1931 return E_OUTOFMEMORY;
1934 data->familyname = familyname;
1935 IDWriteLocalizedStrings_AddRef(familyname);
1937 *ret = data;
1938 return S_OK;
1941 HRESULT create_font_collection(IDWriteFactory2* factory, IDWriteFontFileEnumerator *enumerator, BOOL is_system, IDWriteFontCollection **ret)
1943 struct dwrite_fontcollection *collection;
1944 BOOL current = FALSE;
1945 HRESULT hr = S_OK;
1947 *ret = NULL;
1949 collection = heap_alloc(sizeof(struct dwrite_fontcollection));
1950 if (!collection) return E_OUTOFMEMORY;
1952 hr = init_font_collection(collection, is_system);
1953 if (FAILED(hr)) {
1954 heap_free(collection);
1955 return hr;
1958 *ret = &collection->IDWriteFontCollection_iface;
1960 TRACE("building font collection:\n");
1962 while (hr == S_OK) {
1963 DWRITE_FONT_FACE_TYPE face_type;
1964 DWRITE_FONT_FILE_TYPE file_type;
1965 IDWriteFontFile *file;
1966 UINT32 face_count;
1967 BOOL supported;
1968 int i;
1970 current = FALSE;
1971 hr = IDWriteFontFileEnumerator_MoveNext(enumerator, &current);
1972 if (FAILED(hr) || !current)
1973 break;
1975 hr = IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator, &file);
1976 if (FAILED(hr))
1977 break;
1979 /* failed font files are skipped */
1980 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &face_count);
1981 if (FAILED(hr) || !supported || face_count == 0) {
1982 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file, hr, supported, face_count);
1983 IDWriteFontFile_Release(file);
1984 hr = S_OK;
1985 continue;
1988 for (i = 0; i < face_count; i++) {
1989 IDWriteLocalizedStrings *family_name = NULL;
1990 struct dwrite_font_data *font_data;
1991 IDWriteFontFileStream *stream;
1992 WCHAR buffer[255];
1993 UINT32 index;
1995 /* alloc and init new font data structure */
1996 hr = init_font_data(factory, file, i, face_type, &stream, &font_data);
1997 if (FAILED(hr))
1998 break;
2000 /* get family name from font file */
2001 hr = get_family_names_from_stream(stream, i, face_type, &family_name);
2002 IDWriteFontFileStream_Release(stream);
2003 if (FAILED(hr)) {
2004 WARN("unable to get family name from font\n");
2005 release_font_data(font_data);
2006 continue;
2009 buffer[0] = 0;
2010 IDWriteLocalizedStrings_GetString(family_name, 0, buffer, sizeof(buffer)/sizeof(WCHAR));
2012 index = collection_find_family(collection, buffer);
2013 if (index != ~0u)
2014 hr = fontfamily_add_font(collection->family_data[index], font_data);
2015 else {
2016 struct dwrite_fontfamily_data *family_data;
2018 /* create and init new family */
2019 hr = init_fontfamily_data(family_name, &family_data);
2020 if (hr == S_OK) {
2021 /* add font to family, family - to collection */
2022 hr = fontfamily_add_font(family_data, font_data);
2023 if (hr == S_OK)
2024 hr = fontcollection_add_family(collection, family_data);
2026 if (FAILED(hr))
2027 release_fontfamily_data(family_data);
2031 IDWriteLocalizedStrings_Release(family_name);
2033 if (FAILED(hr))
2034 break;
2037 IDWriteFontFile_Release(file);
2040 return hr;
2043 struct system_fontfile_enumerator
2045 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
2046 LONG ref;
2048 IDWriteFactory2 *factory;
2049 HKEY hkey;
2050 int index;
2053 static inline struct system_fontfile_enumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
2055 return CONTAINING_RECORD(iface, struct system_fontfile_enumerator, IDWriteFontFileEnumerator_iface);
2058 static HRESULT WINAPI systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2060 *obj = NULL;
2062 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
2063 IDWriteFontFileEnumerator_AddRef(iface);
2064 *obj = iface;
2065 return S_OK;
2068 return E_NOINTERFACE;
2071 static ULONG WINAPI systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2073 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
2074 return InterlockedIncrement(&enumerator->ref);
2077 static ULONG WINAPI systemfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2079 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
2080 ULONG ref = InterlockedDecrement(&enumerator->ref);
2082 if (!ref) {
2083 IDWriteFactory2_Release(enumerator->factory);
2084 RegCloseKey(enumerator->hkey);
2085 heap_free(enumerator);
2088 return ref;
2091 static HRESULT WINAPI systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2093 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
2094 DWORD ret, type, val_count, count;
2095 WCHAR *value, *filename;
2096 HRESULT hr;
2098 *file = NULL;
2100 if (enumerator->index < 0)
2101 return E_FAIL;
2103 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &val_count, &count, NULL, NULL);
2104 if (ret != ERROR_SUCCESS)
2105 return E_FAIL;
2107 val_count++;
2108 value = heap_alloc( val_count * sizeof(value[0]) );
2109 filename = heap_alloc(count);
2110 if (!value || !filename) {
2111 heap_free(value);
2112 heap_free(filename);
2113 return E_OUTOFMEMORY;
2116 ret = RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, (BYTE*)filename, &count);
2117 if (ret) {
2118 heap_free(value);
2119 heap_free(filename);
2120 return E_FAIL;
2123 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
2124 if (!strchrW(filename, '\\')) {
2125 static const WCHAR fontsW[] = {'\\','f','o','n','t','s','\\',0};
2126 WCHAR fullpathW[MAX_PATH];
2128 GetWindowsDirectoryW(fullpathW, sizeof(fullpathW)/sizeof(WCHAR));
2129 strcatW(fullpathW, fontsW);
2130 strcatW(fullpathW, filename);
2132 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, fullpathW, NULL, file);
2134 else
2135 hr = IDWriteFactory2_CreateFontFileReference(enumerator->factory, filename, NULL, file);
2137 heap_free(value);
2138 heap_free(filename);
2139 return hr;
2142 static HRESULT WINAPI systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2144 struct system_fontfile_enumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
2145 DWORD ret, max_val_count;
2146 WCHAR *value;
2148 *current = FALSE;
2149 enumerator->index++;
2151 ret = RegQueryInfoKeyW(enumerator->hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_val_count, NULL, NULL, NULL);
2152 if (ret != ERROR_SUCCESS)
2153 return E_FAIL;
2155 max_val_count++;
2156 if (!(value = heap_alloc( max_val_count * sizeof(value[0]) )))
2157 return E_OUTOFMEMORY;
2159 /* iterate until we find next string value */
2160 while (1) {
2161 DWORD type = 0, count, val_count;
2162 val_count = max_val_count;
2163 if (RegEnumValueW(enumerator->hkey, enumerator->index, value, &val_count, NULL, &type, NULL, &count))
2164 break;
2165 if (type == REG_SZ) {
2166 *current = TRUE;
2167 break;
2169 enumerator->index++;
2172 TRACE("index = %d, current = %d\n", enumerator->index, *current);
2173 heap_free(value);
2174 return S_OK;
2177 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl =
2179 systemfontfileenumerator_QueryInterface,
2180 systemfontfileenumerator_AddRef,
2181 systemfontfileenumerator_Release,
2182 systemfontfileenumerator_MoveNext,
2183 systemfontfileenumerator_GetCurrentFontFile
2186 static HRESULT create_system_fontfile_enumerator(IDWriteFactory2 *factory, IDWriteFontFileEnumerator **ret)
2188 struct system_fontfile_enumerator *enumerator;
2189 static const WCHAR fontslistW[] = {
2190 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
2191 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2192 'F','o','n','t','s',0
2195 *ret = NULL;
2197 enumerator = heap_alloc(sizeof(*enumerator));
2198 if (!enumerator)
2199 return E_OUTOFMEMORY;
2201 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &systemfontfileenumeratorvtbl;
2202 enumerator->ref = 1;
2203 enumerator->factory = factory;
2204 enumerator->index = -1;
2205 IDWriteFactory2_AddRef(factory);
2207 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, fontslistW, 0, GENERIC_READ, &enumerator->hkey)) {
2208 ERR("failed to open fonts list key\n");
2209 IDWriteFactory2_Release(factory);
2210 heap_free(enumerator);
2211 return E_FAIL;
2214 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
2216 return S_OK;
2219 HRESULT get_system_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
2221 IDWriteFontFileEnumerator *enumerator;
2222 HRESULT hr;
2224 *collection = NULL;
2226 hr = create_system_fontfile_enumerator(factory, &enumerator);
2227 if (FAILED(hr))
2228 return hr;
2230 TRACE("building system font collection for factory %p\n", factory);
2231 hr = create_font_collection(factory, enumerator, TRUE, collection);
2232 IDWriteFontFileEnumerator_Release(enumerator);
2233 return hr;
2236 static HRESULT WINAPI eudcfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2238 *obj = NULL;
2240 if (IsEqualIID(riid, &IID_IDWriteFontFileEnumerator) || IsEqualIID(riid, &IID_IUnknown)) {
2241 IDWriteFontFileEnumerator_AddRef(iface);
2242 *obj = iface;
2243 return S_OK;
2246 return E_NOINTERFACE;
2249 static ULONG WINAPI eudcfontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2251 return 2;
2254 static ULONG WINAPI eudcfontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2256 return 1;
2259 static HRESULT WINAPI eudcfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2261 *file = NULL;
2262 return E_FAIL;
2265 static HRESULT WINAPI eudcfontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2267 *current = FALSE;
2268 return S_OK;
2271 static const struct IDWriteFontFileEnumeratorVtbl eudcfontfileenumeratorvtbl =
2273 eudcfontfileenumerator_QueryInterface,
2274 eudcfontfileenumerator_AddRef,
2275 eudcfontfileenumerator_Release,
2276 eudcfontfileenumerator_MoveNext,
2277 eudcfontfileenumerator_GetCurrentFontFile
2280 static IDWriteFontFileEnumerator eudc_fontfile_enumerator = { &eudcfontfileenumeratorvtbl };
2282 HRESULT get_eudc_fontcollection(IDWriteFactory2 *factory, IDWriteFontCollection **collection)
2284 TRACE("building EUDC font collection for factory %p\n", factory);
2285 return create_font_collection(factory, &eudc_fontfile_enumerator, FALSE, collection);
2288 static HRESULT WINAPI dwritefontfile_QueryInterface(IDWriteFontFile *iface, REFIID riid, void **obj)
2290 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2292 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2294 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFile))
2296 *obj = iface;
2297 IDWriteFontFile_AddRef(iface);
2298 return S_OK;
2301 *obj = NULL;
2302 return E_NOINTERFACE;
2305 static ULONG WINAPI dwritefontfile_AddRef(IDWriteFontFile *iface)
2307 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2308 ULONG ref = InterlockedIncrement(&This->ref);
2309 TRACE("(%p)->(%d)\n", This, ref);
2310 return ref;
2313 static ULONG WINAPI dwritefontfile_Release(IDWriteFontFile *iface)
2315 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2316 ULONG ref = InterlockedDecrement(&This->ref);
2318 TRACE("(%p)->(%d)\n", This, ref);
2320 if (!ref)
2322 IDWriteFontFileLoader_Release(This->loader);
2323 if (This->stream) IDWriteFontFileStream_Release(This->stream);
2324 heap_free(This->reference_key);
2325 heap_free(This);
2328 return ref;
2331 static HRESULT WINAPI dwritefontfile_GetReferenceKey(IDWriteFontFile *iface, const void **fontFileReferenceKey, UINT32 *fontFileReferenceKeySize)
2333 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2334 TRACE("(%p)->(%p, %p)\n", This, fontFileReferenceKey, fontFileReferenceKeySize);
2335 *fontFileReferenceKey = This->reference_key;
2336 *fontFileReferenceKeySize = This->key_size;
2338 return S_OK;
2341 static HRESULT WINAPI dwritefontfile_GetLoader(IDWriteFontFile *iface, IDWriteFontFileLoader **fontFileLoader)
2343 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2344 TRACE("(%p)->(%p)\n", This, fontFileLoader);
2345 *fontFileLoader = This->loader;
2346 IDWriteFontFileLoader_AddRef(This->loader);
2348 return S_OK;
2351 static HRESULT WINAPI dwritefontfile_Analyze(IDWriteFontFile *iface, BOOL *isSupportedFontType, DWRITE_FONT_FILE_TYPE *fontFileType, DWRITE_FONT_FACE_TYPE *fontFaceType, UINT32 *numberOfFaces)
2353 struct dwrite_fontfile *This = impl_from_IDWriteFontFile(iface);
2354 IDWriteFontFileStream *stream;
2355 HRESULT hr;
2357 TRACE("(%p)->(%p, %p, %p, %p)\n", This, isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
2359 *isSupportedFontType = FALSE;
2360 *fontFileType = DWRITE_FONT_FILE_TYPE_UNKNOWN;
2361 if (fontFaceType)
2362 *fontFaceType = DWRITE_FONT_FACE_TYPE_UNKNOWN;
2363 *numberOfFaces = 0;
2365 hr = IDWriteFontFileLoader_CreateStreamFromKey(This->loader, This->reference_key, This->key_size, &stream);
2366 if (FAILED(hr))
2367 return hr;
2369 hr = opentype_analyze_font(stream, numberOfFaces, fontFileType, fontFaceType, isSupportedFontType);
2371 /* TODO: Further Analysis */
2372 IDWriteFontFileStream_Release(stream);
2373 return S_OK;
2376 static const IDWriteFontFileVtbl dwritefontfilevtbl = {
2377 dwritefontfile_QueryInterface,
2378 dwritefontfile_AddRef,
2379 dwritefontfile_Release,
2380 dwritefontfile_GetReferenceKey,
2381 dwritefontfile_GetLoader,
2382 dwritefontfile_Analyze,
2385 HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *reference_key, UINT32 key_size, IDWriteFontFile **font_file)
2387 struct dwrite_fontfile *This;
2389 This = heap_alloc(sizeof(struct dwrite_fontfile));
2390 if (!This) return E_OUTOFMEMORY;
2392 This->IDWriteFontFile_iface.lpVtbl = &dwritefontfilevtbl;
2393 This->ref = 1;
2394 IDWriteFontFileLoader_AddRef(loader);
2395 This->loader = loader;
2396 This->stream = NULL;
2397 This->reference_key = heap_alloc(key_size);
2398 memcpy(This->reference_key, reference_key, key_size);
2399 This->key_size = key_size;
2401 *font_file = &This->IDWriteFontFile_iface;
2403 return S_OK;
2406 static HRESULT get_stream_from_file(IDWriteFontFile *file, IDWriteFontFileStream **stream)
2408 IDWriteFontFileLoader *loader;
2409 UINT32 key_size;
2410 const void *key;
2411 HRESULT hr;
2413 *stream = NULL;
2414 hr = IDWriteFontFile_GetLoader(file, &loader);
2415 if (FAILED(hr))
2416 return hr;
2418 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2419 if (FAILED(hr)) {
2420 IDWriteFontFileLoader_Release(loader);
2421 return hr;
2424 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, stream);
2425 IDWriteFontFileLoader_Release(loader);
2427 return hr;
2430 HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDWriteFontFile* const* font_files, UINT32 index,
2431 DWRITE_FONT_SIMULATIONS simulations, IDWriteFontFace2 **ret)
2433 struct dwrite_fontface *fontface;
2434 HRESULT hr = S_OK;
2435 int i;
2437 *ret = NULL;
2439 fontface = heap_alloc(sizeof(struct dwrite_fontface));
2440 if (!fontface)
2441 return E_OUTOFMEMORY;
2443 fontface->files = heap_alloc_zero(sizeof(*fontface->files) * files_number);
2444 fontface->streams = heap_alloc_zero(sizeof(*fontface->streams) * files_number);
2446 if (!fontface->files || !fontface->streams) {
2447 heap_free(fontface->files);
2448 heap_free(fontface->streams);
2449 heap_free(fontface);
2450 return E_OUTOFMEMORY;
2453 fontface->IDWriteFontFace2_iface.lpVtbl = &dwritefontfacevtbl;
2454 fontface->ref = 1;
2455 fontface->type = facetype;
2456 fontface->file_count = files_number;
2457 memset(&fontface->cmap, 0, sizeof(fontface->cmap));
2458 memset(&fontface->vdmx, 0, sizeof(fontface->vdmx));
2459 memset(&fontface->gasp, 0, sizeof(fontface->gasp));
2460 fontface->cmap.exists = TRUE;
2461 fontface->vdmx.exists = TRUE;
2462 fontface->gasp.exists = TRUE;
2463 fontface->index = index;
2464 fontface->simulations = simulations;
2465 memset(fontface->glyphs, 0, sizeof(fontface->glyphs));
2467 for (i = 0; i < fontface->file_count; i++) {
2468 hr = get_stream_from_file(font_files[i], &fontface->streams[i]);
2469 if (FAILED(hr)) {
2470 IDWriteFontFace2_Release(&fontface->IDWriteFontFace2_iface);
2471 return hr;
2474 fontface->files[i] = font_files[i];
2475 IDWriteFontFile_AddRef(font_files[i]);
2478 opentype_get_font_metrics(fontface->streams[0], facetype, index, &fontface->metrics, &fontface->caret);
2479 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) {
2480 /* TODO: test what happens if caret is already slanted */
2481 if (fontface->caret.slopeRise == 1) {
2482 fontface->caret.slopeRise = fontface->metrics.designUnitsPerEm;
2483 fontface->caret.slopeRun = fontface->caret.slopeRise / 3;
2487 *ret = &fontface->IDWriteFontFace2_iface;
2488 return S_OK;
2491 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
2492 struct local_refkey
2494 FILETIME writetime;
2495 WCHAR name[1];
2498 struct local_cached_stream
2500 struct list entry;
2501 IDWriteFontFileStream *stream;
2502 struct local_refkey *key;
2503 UINT32 key_size;
2506 struct dwrite_localfontfilestream
2508 IDWriteFontFileStream IDWriteFontFileStream_iface;
2509 LONG ref;
2511 struct local_cached_stream *entry;
2512 const void *file_ptr;
2513 UINT64 size;
2516 struct dwrite_localfontfileloader {
2517 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface;
2518 LONG ref;
2520 struct list streams;
2523 static inline struct dwrite_localfontfileloader *impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader *iface)
2525 return CONTAINING_RECORD(iface, struct dwrite_localfontfileloader, IDWriteLocalFontFileLoader_iface);
2528 static inline struct dwrite_localfontfilestream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream *iface)
2530 return CONTAINING_RECORD(iface, struct dwrite_localfontfilestream, IDWriteFontFileStream_iface);
2533 static HRESULT WINAPI localfontfilestream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
2535 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2536 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2537 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
2539 *obj = iface;
2540 IDWriteFontFileStream_AddRef(iface);
2541 return S_OK;
2544 *obj = NULL;
2545 return E_NOINTERFACE;
2548 static ULONG WINAPI localfontfilestream_AddRef(IDWriteFontFileStream *iface)
2550 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2551 ULONG ref = InterlockedIncrement(&This->ref);
2552 TRACE("(%p)->(%d)\n", This, ref);
2553 return ref;
2556 static inline void release_cached_stream(struct local_cached_stream *stream)
2558 list_remove(&stream->entry);
2559 heap_free(stream->key);
2560 heap_free(stream);
2563 static ULONG WINAPI localfontfilestream_Release(IDWriteFontFileStream *iface)
2565 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2566 ULONG ref = InterlockedDecrement(&This->ref);
2568 TRACE("(%p)->(%d)\n", This, ref);
2570 if (!ref) {
2571 UnmapViewOfFile(This->file_ptr);
2572 release_cached_stream(This->entry);
2573 heap_free(This);
2576 return ref;
2579 static HRESULT WINAPI localfontfilestream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
2581 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2583 TRACE("(%p)->(%p, %s, %s, %p)\n",This, fragment_start,
2584 wine_dbgstr_longlong(offset), wine_dbgstr_longlong(fragment_size), fragment_context);
2586 *fragment_context = NULL;
2588 if ((offset >= This->size - 1) || (fragment_size > This->size - offset)) {
2589 *fragment_start = NULL;
2590 return E_FAIL;
2593 *fragment_start = (char*)This->file_ptr + offset;
2594 return S_OK;
2597 static void WINAPI localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
2599 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2600 TRACE("(%p)->(%p)\n", This, fragment_context);
2603 static HRESULT WINAPI localfontfilestream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
2605 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2606 TRACE("(%p)->(%p)\n", This, size);
2607 *size = This->size;
2608 return S_OK;
2611 static HRESULT WINAPI localfontfilestream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
2613 struct dwrite_localfontfilestream *This = impl_from_IDWriteFontFileStream(iface);
2614 ULARGE_INTEGER li;
2616 TRACE("(%p)->(%p)\n", This, last_writetime);
2618 li.u.LowPart = This->entry->key->writetime.dwLowDateTime;
2619 li.u.HighPart = This->entry->key->writetime.dwHighDateTime;
2620 *last_writetime = li.QuadPart;
2622 return S_OK;
2625 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl =
2627 localfontfilestream_QueryInterface,
2628 localfontfilestream_AddRef,
2629 localfontfilestream_Release,
2630 localfontfilestream_ReadFileFragment,
2631 localfontfilestream_ReleaseFileFragment,
2632 localfontfilestream_GetFileSize,
2633 localfontfilestream_GetLastWriteTime
2636 static HRESULT create_localfontfilestream(const void *file_ptr, UINT64 size, struct local_cached_stream *entry, IDWriteFontFileStream** iface)
2638 struct dwrite_localfontfilestream *This = heap_alloc(sizeof(struct dwrite_localfontfilestream));
2639 if (!This)
2640 return E_OUTOFMEMORY;
2642 This->IDWriteFontFileStream_iface.lpVtbl = &localfontfilestreamvtbl;
2643 This->ref = 1;
2645 This->file_ptr = file_ptr;
2646 This->size = size;
2647 This->entry = entry;
2649 *iface = &This->IDWriteFontFileStream_iface;
2650 return S_OK;
2653 static HRESULT WINAPI localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader *iface, REFIID riid, void **obj)
2655 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2657 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj);
2659 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader) || IsEqualIID(riid, &IID_IDWriteLocalFontFileLoader))
2661 *obj = iface;
2662 IDWriteLocalFontFileLoader_AddRef(iface);
2663 return S_OK;
2666 *obj = NULL;
2667 return E_NOINTERFACE;
2670 static ULONG WINAPI localfontfileloader_AddRef(IDWriteLocalFontFileLoader *iface)
2672 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2673 ULONG ref = InterlockedIncrement(&This->ref);
2674 TRACE("(%p)->(%d)\n", This, ref);
2675 return ref;
2678 static ULONG WINAPI localfontfileloader_Release(IDWriteLocalFontFileLoader *iface)
2680 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2681 ULONG ref = InterlockedDecrement(&This->ref);
2683 TRACE("(%p)->(%d)\n", This, ref);
2685 if (!ref) {
2686 struct local_cached_stream *stream, *stream2;
2688 /* This will detach all entries from cache. Entries are released together with streams,
2689 so stream controls its lifetime. */
2690 LIST_FOR_EACH_ENTRY_SAFE(stream, stream2, &This->streams, struct local_cached_stream, entry)
2691 list_init(&stream->entry);
2693 heap_free(This);
2696 return ref;
2699 static HRESULT WINAPI localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader *iface, const void *key, UINT32 key_size, IDWriteFontFileStream **ret)
2701 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2702 const struct local_refkey *refkey = key;
2703 struct local_cached_stream *stream;
2704 IDWriteFontFileStream *filestream;
2705 HANDLE file, mapping;
2706 LARGE_INTEGER size;
2707 void *file_ptr;
2708 HRESULT hr;
2710 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, ret);
2711 TRACE("name: %s\n", debugstr_w(refkey->name));
2713 /* search cache first */
2714 LIST_FOR_EACH_ENTRY(stream, &This->streams, struct local_cached_stream, entry) {
2715 if (key_size == stream->key_size && !memcmp(stream->key, key, key_size)) {
2716 *ret = stream->stream;
2717 IDWriteFontFileStream_AddRef(*ret);
2718 return S_OK;
2722 *ret = NULL;
2724 file = CreateFileW(refkey->name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
2725 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2726 if (file == INVALID_HANDLE_VALUE)
2727 return E_FAIL;
2729 GetFileSizeEx(file, &size);
2730 mapping = CreateFileMappingW(file, NULL, PAGE_READONLY, 0, 0, NULL);
2731 CloseHandle(file);
2732 if (!mapping)
2733 return E_FAIL;
2735 file_ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
2736 CloseHandle(mapping);
2738 stream = heap_alloc(sizeof(*stream));
2739 if (!stream) {
2740 UnmapViewOfFile(file_ptr);
2741 return E_OUTOFMEMORY;
2744 stream->key = heap_alloc(key_size);
2745 if (!stream->key) {
2746 UnmapViewOfFile(file_ptr);
2747 heap_free(stream);
2748 return E_OUTOFMEMORY;
2751 stream->key_size = key_size;
2752 memcpy(stream->key, key, key_size);
2754 hr = create_localfontfilestream(file_ptr, size.QuadPart, stream, &filestream);
2755 if (FAILED(hr)) {
2756 UnmapViewOfFile(file_ptr);
2757 heap_free(stream->key);
2758 heap_free(stream);
2759 return hr;
2762 stream->stream = filestream;
2763 list_add_head(&This->streams, &stream->entry);
2765 *ret = stream->stream;
2767 return S_OK;
2770 static HRESULT WINAPI localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, UINT32 *length)
2772 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2773 const struct local_refkey *refkey = key;
2775 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, length);
2777 *length = strlenW(refkey->name);
2778 return S_OK;
2781 static HRESULT WINAPI localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, WCHAR *path, UINT32 length)
2783 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2784 const struct local_refkey *refkey = key;
2786 TRACE("(%p)->(%p, %i, %p, %i)\n", This, key, key_size, path, length);
2788 if (length < strlenW(refkey->name))
2789 return E_INVALIDARG;
2791 strcpyW(path, refkey->name);
2792 return S_OK;
2795 static HRESULT WINAPI localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader *iface, void const *key, UINT32 key_size, FILETIME *writetime)
2797 struct dwrite_localfontfileloader *This = impl_from_IDWriteLocalFontFileLoader(iface);
2798 const struct local_refkey *refkey = key;
2800 TRACE("(%p)->(%p, %i, %p)\n", This, key, key_size, writetime);
2802 *writetime = refkey->writetime;
2803 return S_OK;
2806 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl = {
2807 localfontfileloader_QueryInterface,
2808 localfontfileloader_AddRef,
2809 localfontfileloader_Release,
2810 localfontfileloader_CreateStreamFromKey,
2811 localfontfileloader_GetFilePathLengthFromKey,
2812 localfontfileloader_GetFilePathFromKey,
2813 localfontfileloader_GetLastWriteTimeFromKey
2816 HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface)
2818 struct dwrite_localfontfileloader *This = heap_alloc(sizeof(struct dwrite_localfontfileloader));
2819 if (!This)
2820 return E_OUTOFMEMORY;
2822 This->IDWriteLocalFontFileLoader_iface.lpVtbl = &localfontfileloadervtbl;
2823 This->ref = 1;
2824 list_init(&This->streams);
2826 *iface = &This->IDWriteLocalFontFileLoader_iface;
2827 return S_OK;
2830 HRESULT get_local_refkey(const WCHAR *path, const FILETIME *writetime, void **key, UINT32 *size)
2832 struct local_refkey *refkey;
2834 *size = FIELD_OFFSET(struct local_refkey, name) + (strlenW(path)+1)*sizeof(WCHAR);
2835 *key = NULL;
2837 refkey = heap_alloc(*size);
2838 if (!refkey)
2839 return E_OUTOFMEMORY;
2841 if (writetime)
2842 refkey->writetime = *writetime;
2843 else {
2844 WIN32_FILE_ATTRIBUTE_DATA info;
2846 if (GetFileAttributesExW(path, GetFileExInfoStandard, &info))
2847 refkey->writetime = info.ftLastWriteTime;
2848 else
2849 memset(&refkey->writetime, 0, sizeof(refkey->writetime));
2851 strcpyW(refkey->name, path);
2853 *key = refkey;
2855 return S_OK;
2858 /* IDWriteGlyphRunAnalysis */
2859 static HRESULT WINAPI glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis *iface, REFIID riid, void **ppv)
2861 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2863 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
2865 if (IsEqualIID(riid, &IID_IDWriteGlyphRunAnalysis) ||
2866 IsEqualIID(riid, &IID_IUnknown))
2868 *ppv = iface;
2869 IDWriteGlyphRunAnalysis_AddRef(iface);
2870 return S_OK;
2873 *ppv = NULL;
2874 return E_NOINTERFACE;
2877 static ULONG WINAPI glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis *iface)
2879 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2880 ULONG ref = InterlockedIncrement(&This->ref);
2881 TRACE("(%p)->(%u)\n", This, ref);
2882 return ref;
2885 static ULONG WINAPI glyphrunanalysis_Release(IDWriteGlyphRunAnalysis *iface)
2887 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2888 ULONG ref = InterlockedDecrement(&This->ref);
2890 TRACE("(%p)->(%u)\n", This, ref);
2892 if (!ref) {
2893 heap_free(This);
2896 return ref;
2899 static HRESULT WINAPI glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type, RECT* bounds)
2901 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2903 FIXME("(%p)->(%d %p): stub\n", This, type, bounds);
2905 if ((UINT32)type > DWRITE_TEXTURE_CLEARTYPE_3x1) {
2906 memset(bounds, 0, sizeof(*bounds));
2907 return E_INVALIDARG;
2910 if ((type == DWRITE_TEXTURE_ALIASED_1x1 && This->rendering_mode != DWRITE_RENDERING_MODE_ALIASED) ||
2911 (type == DWRITE_TEXTURE_CLEARTYPE_3x1 && This->rendering_mode == DWRITE_RENDERING_MODE_ALIASED)) {
2912 memset(bounds, 0, sizeof(*bounds));
2913 return S_OK;
2916 return E_NOTIMPL;
2919 static HRESULT WINAPI glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis *iface, DWRITE_TEXTURE_TYPE type,
2920 RECT const* bounds, BYTE* alphaValues, UINT32 bufferSize)
2922 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2923 FIXME("(%p)->(%d %p %p %u): stub\n", This, type, bounds, alphaValues, bufferSize);
2924 return E_NOTIMPL;
2927 static HRESULT WINAPI glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis *iface, IDWriteRenderingParams *params,
2928 FLOAT *blendGamma, FLOAT *blendEnhancedContrast, FLOAT *blendClearTypeLevel)
2930 struct dwrite_glyphrunanalysis *This = impl_from_IDWriteGlyphRunAnalysis(iface);
2931 FIXME("(%p)->(%p %p %p %p): stub\n", This, params, blendGamma, blendEnhancedContrast, blendClearTypeLevel);
2932 return E_NOTIMPL;
2935 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = {
2936 glyphrunanalysis_QueryInterface,
2937 glyphrunanalysis_AddRef,
2938 glyphrunanalysis_Release,
2939 glyphrunanalysis_GetAlphaTextureBounds,
2940 glyphrunanalysis_CreateAlphaTexture,
2941 glyphrunanalysis_GetAlphaBlendParams
2944 HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, IDWriteGlyphRunAnalysis **ret)
2946 struct dwrite_glyphrunanalysis *analysis;
2948 *ret = NULL;
2950 /* check for valid rendering mode */
2951 if ((UINT32)rendering_mode >= DWRITE_RENDERING_MODE_OUTLINE || rendering_mode == DWRITE_RENDERING_MODE_DEFAULT)
2952 return E_INVALIDARG;
2954 analysis = heap_alloc(sizeof(*analysis));
2955 if (!analysis)
2956 return E_OUTOFMEMORY;
2958 analysis->IDWriteGlyphRunAnalysis_iface.lpVtbl = &glyphrunanalysisvtbl;
2959 analysis->ref = 1;
2960 analysis->rendering_mode = rendering_mode;
2962 *ret = &analysis->IDWriteGlyphRunAnalysis_iface;
2963 return S_OK;