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
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
{
69 struct dwrite_font_data
{
72 DWRITE_FONT_STYLE style
;
73 DWRITE_FONT_STRETCH stretch
;
74 DWRITE_FONT_WEIGHT weight
;
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
;
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
;
101 IDWriteFontFamily
*family
;
102 struct dwrite_font_data
**fonts
;
106 struct dwrite_fontfamily_data
{
109 IDWriteLocalizedStrings
*familyname
;
111 struct dwrite_font_data
**fonts
;
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
;
123 struct dwrite_fontfamily_data
**family_data
;
129 struct dwrite_fontfamily
{
130 IDWriteFontFamily IDWriteFontFamily_iface
;
133 struct dwrite_fontfamily_data
*data
;
135 IDWriteFontCollection
* collection
;
139 IDWriteFont2 IDWriteFont2_iface
;
142 IDWriteFontFamily
*family
;
144 DWRITE_FONT_STYLE style
;
145 struct dwrite_font_data
*data
;
148 struct dwrite_fonttable
{
155 enum runanalysis_readystate
{
156 RUNANALYSIS_BOUNDS
= 1 << 0,
157 RUNANALYSIS_BITMAP
= 1 << 1,
160 struct dwrite_glyphrunanalysis
{
161 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface
;
164 DWRITE_RENDERING_MODE rendering_mode
;
165 DWRITE_GLYPH_RUN run
;
171 DWRITE_GLYPH_OFFSET
*offsets
;
178 struct dwrite_colorglyphenum
{
179 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface
;
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
;
192 IDWriteFontFileStream
**streams
;
193 IDWriteFontFile
**files
;
198 DWRITE_FONT_FACE_TYPE type
;
199 DWRITE_FONT_METRICS1 metrics
;
200 DWRITE_CARET_METRICS caret
;
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
;
215 IDWriteFontFileLoader
*loader
;
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
));
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
];
281 /* start new block */
282 *block
= heap_alloc_zero(sizeof(*metrics
) * GLYPH_BLOCK_SIZE
);
284 return E_OUTOFMEMORY
;
287 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], metrics
, sizeof(*metrics
));
291 static void* get_fontface_table(struct dwrite_fontface
*fontface
, UINT32 tag
, struct dwrite_fonttable
*table
)
295 if (table
->data
|| !table
->exists
)
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
));
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
;
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
)
353 if (InterlockedDecrement(&data
->ref
) > 0)
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
);
368 static void release_fontfamily_data(struct dwrite_fontfamily_data
*data
)
372 if (InterlockedDecrement(&data
->ref
) > 0)
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
);
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
))
394 IDWriteFontFace2_AddRef(iface
);
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
);
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
);
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
]);
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
);
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
);
452 static HRESULT WINAPI
dwritefontface_GetFiles(IDWriteFontFace2
*iface
, UINT32
*number_of_files
,
453 IDWriteFontFile
**fontfiles
)
455 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace2(iface
);
458 TRACE("(%p)->(%p %p)\n", This
, number_of_files
, fontfiles
);
459 if (fontfiles
== NULL
)
461 *number_of_files
= This
->file_count
;
464 if (*number_of_files
< This
->file_count
)
467 for (i
= 0; i
< This
->file_count
; i
++)
469 IDWriteFontFile_AddRef(This
->files
[i
]);
470 fontfiles
[i
] = This
->files
[i
];
476 static UINT32 WINAPI
dwritefontface_GetIndex(IDWriteFontFace2
*iface
)
478 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace2(iface
);
479 TRACE("(%p)\n", This
);
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
);
518 TRACE("(%p)->(%p %u %p %d)\n", This
, glyphs
, glyph_count
, ret
, 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
);
531 freetype_get_design_glyph_metrics(iface
, This
->metrics
.designUnitsPerEm
, glyphs
[i
], &metrics
);
532 hr
= set_cached_glyph_metrics(This
, glyphs
[i
], &metrics
);
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
);
548 TRACE("(%p)->(%p %u %p)\n", This
, codepoints
, count
, glyph_indices
);
554 memset(glyph_indices
, 0, count
*sizeof(UINT16
));
558 for (i
= 0; i
< count
; i
++)
559 glyph_indices
[i
] = freetype_get_glyphindex(iface
, codepoints
[i
], This
->charmap
);
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
;
591 outline
= heap_alloc(sizeof(*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
) {
601 return E_OUTOFMEMORY
;
604 outline
->points
= points
;
605 outline
->tags
= tags
;
606 outline
->count
= count
;
607 outline
->advance
= 0.0;
613 static void free_glyph_outline(struct glyph_outline
*outline
)
615 heap_free(outline
->points
);
616 heap_free(outline
->tags
);
620 static void report_glyph_outline(const struct glyph_outline
*outline
, IDWriteGeometrySink
*sink
)
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
);
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
)
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
);
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
)
669 FIXME("sideways mode is not supported.\n");
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
);
684 /* glyph offsets act as current glyph adjustment */
686 xoffset
+= is_rtl
? -offsets
[g
].advanceOffset
: offsets
[g
].advanceOffset
;
687 yoffset
-= offsets
[g
].ascenderOffset
;
691 advance
= is_rtl
? -outline
->advance
: 0.0;
694 translate_glyph_outline(outline
, xoffset
, yoffset
);
696 /* update advance to next glyph */
698 advance
+= is_rtl
? -advances
[g
] : advances
[g
];
700 advance
+= is_rtl
? -outline
->advance
: outline
->advance
;
702 report_glyph_outline(outline
, sink
);
703 free_glyph_outline(outline
);
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
;
716 case DWRITE_MEASURING_MODE_NATURAL
:
718 if (!(gasp
& GASP_SYMMETRIC_SMOOTHING
) && (ppem
<= RECOMMENDED_NATURAL_PPEM
))
719 mode
= DWRITE_RENDERING_MODE_NATURAL
;
721 mode
= DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
;
724 case DWRITE_MEASURING_MODE_GDI_CLASSIC
:
725 mode
= DWRITE_RENDERING_MODE_GDI_CLASSIC
;
727 case DWRITE_MEASURING_MODE_GDI_NATURAL
:
728 mode
= DWRITE_RENDERING_MODE_GDI_NATURAL
;
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
);
745 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This
, emSize
, ppdip
, measuring
, params
, mode
);
748 *mode
= DWRITE_RENDERING_MODE_DEFAULT
;
752 *mode
= IDWriteRenderingParams_GetRenderingMode(params
);
753 if (*mode
!= DWRITE_RENDERING_MODE_DEFAULT
)
756 ppem
= emSize
* ppdip
;
758 if (ppem
>= RECOMMENDED_OUTLINE_AA_THRESHOLD
) {
759 *mode
= DWRITE_RENDERING_MODE_OUTLINE
;
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
);
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
));
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
;
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
);
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
);
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
;
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
));
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
;
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
);
905 if (max_count
&& !ranges
)
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
);
924 TRACE("(%p)->(%u %p %p %d)\n", This
, glyph_count
, glyphs
, advances
, 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
);
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
;
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
);
952 if (em_size
== 0.0) {
953 memset(advances
, 0, sizeof(*advances
) * glyph_count
);
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
);
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
);
975 TRACE("(%p)->(%u %p %p)\n", This
, count
, indices
, adjustments
);
977 if (!(indices
|| adjustments
) || !count
)
980 if (!indices
|| count
== 1) {
981 memset(adjustments
, 0, count
*sizeof(INT32
));
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;
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
);
1016 static BOOL WINAPI
dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace2
*iface
)
1018 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace2(iface
);
1019 FIXME("(%p): stub\n", This
);
1023 static BOOL WINAPI
dwritefontface2_IsColorFont(IDWriteFontFace2
*iface
)
1025 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace2(iface
);
1026 FIXME("(%p): stub\n", This
);
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
);
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
);
1066 FIXME("transform not supported %s\n", debugstr_matrix(m
));
1069 FIXME("sideways mode not supported\n");
1071 *renderingmode
= DWRITE_RENDERING_MODE_DEFAULT
;
1072 *gridfitmode
= DWRITE_GRID_FIT_MODE_DEFAULT
;
1074 IDWriteRenderingParams2
*params2
;
1077 hr
= IDWriteRenderingParams_QueryInterface(params
, &IID_IDWriteRenderingParams2
, (void**)¶ms2
);
1079 *renderingmode
= IDWriteRenderingParams2_GetRenderingMode(params2
);
1080 *gridfitmode
= IDWriteRenderingParams2_GetGridFitMode(params2
);
1081 IDWriteRenderingParams2_Release(params2
);
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
;
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
;
1105 *gridfitmode
= (gasp
& (GASP_GRIDFIT
|GASP_SYMMETRIC_GRIDFIT
)) ? DWRITE_GRID_FIT_MODE_ENABLED
: DWRITE_GRID_FIT_MODE_DISABLED
;
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
;
1157 hr
= IDWriteFactory2_CreateFontFace(data
->factory
, data
->face_type
, 1, &data
->file
,
1158 data
->face_index
, font
->data
->simulations
, &face
);
1162 hr
= IDWriteFontFace_QueryInterface(face
, &IID_IDWriteFontFace2
, (void**)fontface
);
1163 IDWriteFontFace_Release(face
);
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
))
1180 IDWriteFont2_AddRef(iface
);
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
);
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
);
1204 IDWriteFontFamily_Release(This
->family
);
1205 release_font_data(This
->data
);
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
);
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
);
1243 static BOOL WINAPI
dwritefont_IsSymbolFont(IDWriteFont2
*iface
)
1245 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1246 IDWriteFontFace2
*fontface
;
1249 TRACE("(%p)\n", This
);
1251 hr
= get_fontface_from_font(This
, &fontface
);
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
;
1272 TRACE("(%p)->(%d %p %p)\n", This
, stringid
, strings
, exists
);
1277 if (stringid
> DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
|| stringid
== DWRITE_INFORMATIONAL_STRING_NONE
)
1280 if (!data
->info_strings
[stringid
]) {
1281 IDWriteFontFace2
*fontface
;
1282 const void *table_data
;
1287 hr
= get_fontface_from_font(This
, &fontface
);
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");
1297 hr
= opentype_get_font_info_strings(table_data
, stringid
, &data
->info_strings
[stringid
]);
1298 if (FAILED(hr
) || !data
->info_strings
[stringid
])
1300 IDWriteFontFace2_ReleaseFontTable(fontface
, context
);
1304 hr
= clone_localizedstring(data
->info_strings
[stringid
], strings
);
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
;
1334 TRACE("(%p)->(0x%08x %p)\n", This
, value
, exists
);
1338 hr
= get_fontface_from_font(This
, &fontface
);
1343 hr
= IDWriteFontFace2_GetGlyphIndices(fontface
, &value
, 1, &index
);
1347 *exists
= index
!= 0;
1351 static HRESULT WINAPI
dwritefont_CreateFontFace(IDWriteFont2
*iface
, IDWriteFontFace
**face
)
1353 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1356 TRACE("(%p)->(%p)\n", This
, face
);
1358 hr
= get_fontface_from_font(This
, (IDWriteFontFace2
**)face
);
1360 IDWriteFontFace_AddRef(*face
);
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
;
1385 TRACE("(%p)->(%u %p %p)\n", This
, max_count
, ranges
, count
);
1387 hr
= get_fontface_from_font(This
, &fontface
);
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
;
1400 TRACE("(%p)\n", This
);
1402 hr
= get_fontface_from_font(This
, &fontface
);
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
;
1415 TRACE("(%p)\n", This
);
1417 hr
= get_fontface_from_font(This
, &fontface
);
1421 return IDWriteFontFace2_IsColorFont(fontface
);
1424 static const IDWriteFont2Vtbl dwritefontvtbl
= {
1425 dwritefont_QueryInterface
,
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
;
1451 This
= heap_alloc(sizeof(struct dwrite_font
));
1452 if (!This
) return E_OUTOFMEMORY
;
1454 This
->IDWriteFont2_iface
.lpVtbl
= &dwritefontvtbl
;
1456 This
->family
= family
;
1457 IDWriteFontFamily_AddRef(family
);
1458 This
->style
= data
->style
;
1460 InterlockedIncrement(&This
->data
->ref
);
1462 *font
= (IDWriteFont
*)&This
->IDWriteFont2_iface
;
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
))
1478 IDWriteFontList_AddRef(iface
);
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
);
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
);
1504 for (i
= 0; i
< This
->font_count
; i
++)
1505 release_font_data(This
->fonts
[i
]);
1506 IDWriteFontFamily_Release(This
->family
);
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
);
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
);
1537 if (This
->font_count
== 0)
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
))
1565 IDWriteFontFamily_AddRef(iface
);
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
);
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
);
1590 IDWriteFontCollection_Release(This
->collection
);
1591 release_fontfamily_data(This
->data
);
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
);
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
);
1623 if (This
->data
->font_count
== 0)
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
)
1648 if (next_to_req
> cur_to_req
)
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
)
1657 if (next_req_prod
< cur_req_prod
)
1660 if (next
->stretch
> cur
->stretch
)
1662 if (next
->stretch
< cur
->stretch
)
1665 if (next
->style
> cur
->style
)
1667 if (next
->style
< cur
->style
)
1670 if (next
->weight
> cur
->weight
)
1672 if (next
->weight
< cur
->weight
)
1675 /* full match, no reason to prefer new variant */
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
;
1687 TRACE("(%p)->(%d %d %d %p)\n", This
, weight
, stretch
, style
, font
);
1689 if (This
->data
->font_count
== 0) {
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
;
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
;
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
;
1748 TRACE("(%p)->(%d %d %d %p)\n", This
, weight
, stretch
, style
, ret
);
1752 fonts
= heap_alloc(sizeof(*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
) {
1760 return E_OUTOFMEMORY
;
1763 fonts
->IDWriteFontList_iface
.lpVtbl
= &dwritefontlistvtbl
;
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
;
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
;
1813 This
= heap_alloc(sizeof(struct dwrite_fontfamily
));
1814 if (!This
) return E_OUTOFMEMORY
;
1816 This
->IDWriteFontFamily_iface
.lpVtbl
= &fontfamilyvtbl
;
1818 This
->collection
= collection
;
1819 IDWriteFontCollection_AddRef(collection
);
1821 InterlockedIncrement(&This
->data
->ref
);
1823 *family
= &This
->IDWriteFontFamily_iface
;
1828 BOOL
is_system_collection(IDWriteFontCollection
*collection
)
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
))
1843 IDWriteFontCollection_AddRef(iface
);
1849 if (This
->is_system
&& IsEqualIID(riid
, &IID_issystemcollection
))
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
);
1863 static ULONG WINAPI
dwritefontcollection_Release(IDWriteFontCollection
*iface
)
1866 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1867 ULONG ref
= InterlockedDecrement(&This
->ref
);
1868 TRACE("(%p)->(%d)\n", This
, ref
);
1871 for (i
= 0; i
< This
->family_count
; i
++)
1872 release_fontfamily_data(This
->family_data
[i
]);
1873 heap_free(This
->family_data
);
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
) {
1898 return create_fontfamily(This
->family_data
[index
], iface
, family
);
1901 static UINT32
collection_find_family(struct dwrite_fontcollection
*collection
, const WCHAR
*name
)
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
);
1910 for (j
= 0; j
< count
; j
++) {
1912 hr
= IDWriteLocalizedStrings_GetString(family_name
, j
, buffer
, 255);
1913 if (SUCCEEDED(hr
) && !strcmpiW(buffer
, name
))
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;
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
;
1939 hr
= IDWriteFontFile_GetReferenceKey(left
, &left_key
, &left_key_size
);
1943 hr
= IDWriteFontFile_GetReferenceKey(right
, &right_key
, &right_key_size
);
1947 if (left_key_size
!= right_key_size
)
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
;
1963 TRACE("(%p)->(%p %p)\n", This
, face
, font
);
1968 return E_INVALIDARG
;
1971 hr
= IDWriteFontFace_GetFiles(face
, &i
, &file
);
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
;
1990 return DWRITE_E_NOFONT
;
1992 hr
= create_fontfamily(found_family
, iface
, &family
);
1996 hr
= create_font(found_font
, family
, font
);
1997 IDWriteFontFamily_Release(family
);
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
;
2017 new_alloc
= family_data
->font_alloc
* 2;
2018 new_list
= heap_realloc(family_data
->fonts
, sizeof(*family_data
->fonts
) * new_alloc
);
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
;
2032 family_data
->has_italic_face
= TRUE
;
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
;
2042 new_alloc
= collection
->family_alloc
* 2;
2043 new_list
= heap_realloc(collection
->family_data
, sizeof(*new_list
) * new_alloc
);
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
++;
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
;
2072 HRESULT
get_filestream_from_file(IDWriteFontFile
*file
, IDWriteFontFileStream
**stream
)
2074 IDWriteFontFileLoader
*loader
;
2081 hr
= IDWriteFontFile_GetReferenceKey(file
, &key
, &key_size
);
2085 hr
= IDWriteFontFile_GetLoader(file
, &loader
);
2089 hr
= IDWriteFontFileLoader_CreateStreamFromKey(loader
, key
, key_size
, stream
);
2090 IDWriteFontFileLoader_Release(loader
);
2097 static void fontstrings_get_en_string(IDWriteLocalizedStrings
*strings
, WCHAR
*buffer
, UINT32 size
)
2099 BOOL exists
= FALSE
;
2104 hr
= IDWriteLocalizedStrings_FindLocaleName(strings
, enusW
, &index
, &exists
);
2105 if (FAILED(hr
) || !exists
)
2108 IDWriteLocalizedStrings_GetString(strings
, index
, buffer
, size
);
2111 static int trim_spaces(WCHAR
*in
, WCHAR
*ret
)
2115 while (isspaceW(*in
))
2119 if (!(len
= strlenW(in
)))
2122 while (isspaceW(in
[len
-1]))
2125 memcpy(ret
, in
, len
*sizeof(WCHAR
));
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
;
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
)
2164 if (!strncmpiW(token
->ptr
, pattern
->part1
, len_part1
)) {
2165 if (match
) *match
= *token
;
2166 list_remove(&token
->entry
);
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
)
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
))
2184 if (strncmpiW(&token
->ptr
[len_part1
], pattern
->part2
, len_part2
))
2187 /* combined string match */
2188 if (match
) *match
= *token
;
2189 list_remove(&token
->entry
);
2194 /* now it's only possible to have two tokens matched to respective pattern parts */
2195 if (token
->len
!= len_part2
)
2198 next_entry
= list_next(tokens
, &token
->entry
);
2200 next_token
= LIST_ENTRY(next_entry
, struct name_token
, entry
);
2201 if (next_token
->len
!= len_part1
)
2204 if (strncmpiW(token
->ptr
, pattern
->part2
, len_part2
))
2207 if (strncmpiW(next_token
->ptr
, pattern
->part1
, len_part1
))
2210 /* both parts matched, remove tokens */
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
);
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
[] = {
2253 static const struct name_pattern oblique_patterns
[] = {
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
;
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
},
2292 static const struct name_pattern extracondensed_patterns
[] = {
2294 { extraW
, condensedW
},
2295 { extW
, condensedW
},
2301 static const struct name_pattern semicondensed_patterns
[] = {
2304 { semiW
, condensedW
},
2309 static const struct name_pattern semiexpanded_patterns
[] = {
2311 { semiW
, expandedW
},
2312 { semiW
, extendedW
},
2316 static const struct name_pattern extraexpanded_patterns
[] = {
2317 { extraW
, expandedW
},
2318 { extW
, expandedW
},
2319 { extraW
, extendedW
},
2320 { extW
, extendedW
},
2324 static const struct name_pattern ultraexpanded_patterns
[] = {
2325 { ultraW
, expandedW
},
2326 { ultraW
, extendedW
},
2330 static const struct name_pattern condensed_patterns
[] = {
2336 static const struct name_pattern expanded_patterns
[] = {
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
;
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
[] = {
2382 static const struct name_pattern extralight_patterns
[] = {
2389 static const struct name_pattern semilight_patterns
[] = {
2394 static const struct name_pattern demibold_patterns
[] = {
2400 static const struct name_pattern extrabold_patterns
[] = {
2407 static const struct name_pattern extrablack_patterns
[] = {
2414 static const struct name_pattern bold_patterns
[] = {
2419 static const struct name_pattern thin2_patterns
[] = {
2424 static const struct name_pattern light_patterns
[] = {
2429 static const struct name_pattern medium_patterns
[] = {
2434 static const struct name_pattern black_patterns
[] = {
2441 static const struct name_pattern demibold2_patterns
[] = {
2446 static const struct name_pattern extrabold2_patterns
[] = {
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 */
2501 struct knownweight_entry
{
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
;
2512 if (target
> entry
->weight
)
2514 else if (target
< entry
->weight
)
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
);
2549 strcpyW(nameW
, ptr
->nameW
);
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
[] = {
2577 const WCHAR
*regular_ptr
= NULL
, *ptr
;
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
);
2588 if (pattern_len
> len
)
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
);
2607 static void fontname_tokenize(struct list
*tokens
, const WCHAR
*nameW
)
2615 struct name_token
*token
= heap_alloc(sizeof(*token
));
2620 while (*ptr
&& !is_name_separator_char(*ptr
)) {
2626 /* skip separators */
2627 while (is_name_separator_char(*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
) {
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
));
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
;
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 */
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
))
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
)
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 */
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
)
2749 /* use predefined stretch names */
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
[] = {
2763 NULL
, /* DWRITE_FONT_STRETCH_NORMAL */
2769 strcpyW(stretchW
, stretchnamesW
[font
->stretch
]);
2772 /* resolved style name */
2774 font_name_token_to_str(&style_name
, styleW
);
2775 else if (font
->style
== DWRITE_FONT_STYLE_NORMAL
)
2777 /* use predefined names */
2779 if (font
->style
== DWRITE_FONT_STYLE_ITALIC
)
2780 strcpyW(styleW
, italicW
);
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
);
2791 strcpyW(faceW
, stretchW
);
2794 strcatW(faceW
, spaceW
);
2795 strcatW(faceW
, weightW
);
2799 strcatW(faceW
, spaceW
);
2800 strcatW(faceW
, styleW
);
2804 TRACE("resolved family %s, face %s\n", debugstr_w(familyW
), debugstr_w(faceW
));
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];
2818 data
= heap_alloc_zero(sizeof(*data
));
2820 return E_OUTOFMEMORY
;
2822 hr
= get_filestream_from_file(file
, &stream
);
2829 data
->factory
= factory
;
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
);
2847 WARN("unable to get family name from font\n");
2848 release_font_data(data
);
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
);
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
;
2876 data
= heap_alloc_zero(sizeof(*data
));
2878 return E_OUTOFMEMORY
;
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
));
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
);
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
));
2907 return E_OUTOFMEMORY
;
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
);
2919 return E_OUTOFMEMORY
;
2922 data
->familyname
= familyname
;
2923 IDWriteLocalizedStrings_AddRef(familyname
);
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
;
2937 if (family
->fonts
[i
]->bold_sim_tested
)
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
)
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
;
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
[] = {
2971 WCHAR facenameW
[255], initialW
[255];
2972 struct dwrite_font_data
*boldface
;
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 */
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
)
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
)
3012 family
->fonts
[i
]->oblique_sim_tested
= TRUE
;
3013 if (family
->fonts
[i
]->style
== DWRITE_FONT_STYLE_NORMAL
)
3015 else if (family
->fonts
[i
]->style
== DWRITE_FONT_STYLE_OBLIQUE
)
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
)
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
)
3030 if (oblique
== ~0 && family
->fonts
[j
]->style
== DWRITE_FONT_STYLE_OBLIQUE
)
3034 if (regular
!= ~0u && oblique
!= ~0u)
3038 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3042 /* regular face exists, and corresponding oblique is present as well, nothing to do */
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);
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
{
3067 IDWriteFontFile
*file
;
3069 struct fontfile_enum
*fileenum
, *fileenum2
;
3070 struct dwrite_fontcollection
*collection
;
3071 struct list scannedfiles
;
3072 BOOL current
= FALSE
;
3078 collection
= heap_alloc(sizeof(struct dwrite_fontcollection
));
3079 if (!collection
) return E_OUTOFMEMORY
;
3081 hr
= init_font_collection(collection
, is_system
);
3083 heap_free(collection
);
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
;
3100 hr
= IDWriteFontFileEnumerator_MoveNext(enumerator
, ¤t
);
3101 if (FAILED(hr
) || !current
)
3104 hr
= IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator
, &file
);
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
)))
3115 IDWriteFontFile_Release(file
);
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
);
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
;
3139 /* alloc and init new font data structure */
3140 hr
= init_font_data(factory
, file
, face_type
, i
, &family_name
, &font_data
);
3144 fontstrings_get_en_string(family_name
, familyW
, sizeof(familyW
)/sizeof(WCHAR
));
3146 index
= collection_find_family(collection
, familyW
);
3148 hr
= fontfamily_add_font(collection
->family_data
[index
], font_data
);
3150 struct dwrite_fontfamily_data
*family_data
;
3152 /* create and init new family */
3153 hr
= init_fontfamily_data(family_name
, &family_data
);
3155 /* add font to family, family - to collection */
3156 hr
= fontfamily_add_font(family_data
, font_data
);
3158 hr
= fontcollection_add_family(collection
, family_data
);
3161 release_fontfamily_data(family_data
);
3165 IDWriteLocalizedStrings_Release(family_name
);
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
]);
3186 struct system_fontfile_enumerator
3188 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface
;
3191 IDWriteFactory2
*factory
;
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
)
3205 if (IsEqualIID(riid
, &IID_IDWriteFontFileEnumerator
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3206 IDWriteFontFileEnumerator_AddRef(iface
);
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
);
3226 IDWriteFactory2_Release(enumerator
->factory
);
3227 RegCloseKey(enumerator
->hkey
);
3228 heap_free(enumerator
);
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
;
3243 if (enumerator
->index
< 0)
3246 ret
= RegQueryInfoKeyW(enumerator
->hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &val_count
, &count
, NULL
, NULL
);
3247 if (ret
!= ERROR_SUCCESS
)
3251 value
= heap_alloc( val_count
* sizeof(value
[0]) );
3252 filename
= heap_alloc(count
);
3253 if (!value
|| !filename
) {
3255 heap_free(filename
);
3256 return E_OUTOFMEMORY
;
3259 ret
= RegEnumValueW(enumerator
->hkey
, enumerator
->index
, value
, &val_count
, NULL
, &type
, (BYTE
*)filename
, &count
);
3262 heap_free(filename
);
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
);
3278 hr
= IDWriteFactory2_CreateFontFileReference(enumerator
->factory
, filename
, NULL
, file
);
3281 heap_free(filename
);
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
;
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
)
3299 if (!(value
= heap_alloc( max_val_count
* sizeof(value
[0]) )))
3300 return E_OUTOFMEMORY
;
3302 /* iterate until we find next string value */
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
))
3308 if (type
== REG_SZ
) {
3312 enumerator
->index
++;
3315 TRACE("index = %d, current = %d\n", enumerator
->index
, *current
);
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
3340 enumerator
= heap_alloc(sizeof(*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
);
3357 *ret
= &enumerator
->IDWriteFontFileEnumerator_iface
;
3362 HRESULT
get_system_fontcollection(IDWriteFactory2
*factory
, IDWriteFontCollection
**collection
)
3364 IDWriteFontFileEnumerator
*enumerator
;
3369 hr
= create_system_fontfile_enumerator(factory
, &enumerator
);
3373 TRACE("building system font collection for factory %p\n", factory
);
3374 hr
= create_font_collection(factory
, enumerator
, TRUE
, collection
);
3375 IDWriteFontFileEnumerator_Release(enumerator
);
3379 static HRESULT WINAPI
eudcfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator
*iface
, REFIID riid
, void **obj
)
3383 if (IsEqualIID(riid
, &IID_IDWriteFontFileEnumerator
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3384 IDWriteFontFileEnumerator_AddRef(iface
);
3389 return E_NOINTERFACE
;
3392 static ULONG WINAPI
eudcfontfileenumerator_AddRef(IDWriteFontFileEnumerator
*iface
)
3397 static ULONG WINAPI
eudcfontfileenumerator_Release(IDWriteFontFileEnumerator
*iface
)
3402 static HRESULT WINAPI
eudcfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator
*iface
, IDWriteFontFile
**file
)
3408 static HRESULT WINAPI
eudcfontfileenumerator_MoveNext(IDWriteFontFileEnumerator
*iface
, BOOL
*current
)
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
))
3440 IDWriteFontFile_AddRef(iface
);
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
);
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
);
3465 IDWriteFontFileLoader_Release(This
->loader
);
3466 if (This
->stream
) IDWriteFontFileStream_Release(This
->stream
);
3467 heap_free(This
->reference_key
);
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
;
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
);
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
;
3500 TRACE("(%p)->(%p, %p, %p, %p)\n", This
, isSupportedFontType
, fontFileType
, fontFaceType
, numberOfFaces
);
3502 *isSupportedFontType
= FALSE
;
3503 *fontFileType
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
3505 *fontFaceType
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
3508 hr
= IDWriteFontFileLoader_CreateStreamFromKey(This
->loader
, This
->reference_key
, This
->key_size
, &stream
);
3512 hr
= opentype_analyze_font(stream
, numberOfFaces
, fontFileType
, fontFaceType
, isSupportedFontType
);
3514 /* TODO: Further Analysis */
3515 IDWriteFontFileStream_Release(stream
);
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
;
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
;
3549 static HRESULT
get_stream_from_file(IDWriteFontFile
*file
, IDWriteFontFileStream
**stream
)
3551 IDWriteFontFileLoader
*loader
;
3557 hr
= IDWriteFontFile_GetLoader(file
, &loader
);
3561 hr
= IDWriteFontFile_GetReferenceKey(file
, &key
, &key_size
);
3563 IDWriteFontFileLoader_Release(loader
);
3567 hr
= IDWriteFontFileLoader_CreateStreamFromKey(loader
, key
, key_size
, stream
);
3568 IDWriteFontFileLoader_Release(loader
);
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
;
3582 fontface
= heap_alloc(sizeof(struct dwrite_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
;
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
]);
3615 IDWriteFontFace2_Release(&fontface
->IDWriteFontFace2_iface
);
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
;
3637 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3644 struct local_cached_stream
3647 IDWriteFontFileStream
*stream
;
3648 struct local_refkey
*key
;
3652 struct dwrite_localfontfilestream
3654 IDWriteFontFileStream IDWriteFontFileStream_iface
;
3657 struct local_cached_stream
*entry
;
3658 const void *file_ptr
;
3662 struct dwrite_localfontfileloader
{
3663 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface
;
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
))
3686 IDWriteFontFileStream_AddRef(iface
);
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
);
3702 static inline void release_cached_stream(struct local_cached_stream
*stream
)
3704 list_remove(&stream
->entry
);
3705 heap_free(stream
->key
);
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
);
3717 UnmapViewOfFile(This
->file_ptr
);
3718 release_cached_stream(This
->entry
);
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
;
3739 *fragment_start
= (char*)This
->file_ptr
+ offset
;
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
);
3757 static HRESULT WINAPI
localfontfilestream_GetLastWriteTime(IDWriteFontFileStream
*iface
, UINT64
*last_writetime
)
3759 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
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
;
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
));
3786 return E_OUTOFMEMORY
;
3788 This
->IDWriteFontFileStream_iface
.lpVtbl
= &localfontfilestreamvtbl
;
3791 This
->file_ptr
= file_ptr
;
3793 This
->entry
= entry
;
3795 *iface
= &This
->IDWriteFontFileStream_iface
;
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
))
3808 IDWriteLocalFontFileLoader_AddRef(iface
);
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
);
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
);
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
);
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
;
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
);
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
)
3875 GetFileSizeEx(file
, &size
);
3876 mapping
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3881 file_ptr
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
3882 CloseHandle(mapping
);
3884 stream
= heap_alloc(sizeof(*stream
));
3886 UnmapViewOfFile(file_ptr
);
3887 return E_OUTOFMEMORY
;
3890 stream
->key
= heap_alloc(key_size
);
3892 UnmapViewOfFile(file_ptr
);
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
);
3902 UnmapViewOfFile(file_ptr
);
3903 heap_free(stream
->key
);
3908 stream
->stream
= filestream
;
3909 list_add_head(&This
->streams
, &stream
->entry
);
3911 *ret
= stream
->stream
;
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
);
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
);
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
;
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
));
3966 return E_OUTOFMEMORY
;
3968 This
->IDWriteLocalFontFileLoader_iface
.lpVtbl
= &localfontfileloadervtbl
;
3970 list_init(&This
->streams
);
3972 *iface
= &This
->IDWriteLocalFontFileLoader_iface
;
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
);
3983 refkey
= heap_alloc(*size
);
3985 return E_OUTOFMEMORY
;
3988 refkey
->writetime
= *writetime
;
3990 WIN32_FILE_ATTRIBUTE_DATA info
;
3992 if (GetFileAttributesExW(path
, GetFileExInfoStandard
, &info
))
3993 refkey
->writetime
= info
.ftLastWriteTime
;
3995 memset(&refkey
->writetime
, 0, sizeof(refkey
->writetime
));
3997 strcpyW(refkey
->name
, path
);
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
))
4015 IDWriteGlyphRunAnalysis_AddRef(iface
);
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
);
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
);
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
);
4051 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis
*analysis
, RECT
*bounds
)
4053 struct dwrite_glyphbitmap glyph_bitmap
;
4054 IDWriteFontFace2
*fontface2
;
4060 if (analysis
->ready
& RUNANALYSIS_BOUNDS
) {
4061 *bounds
= analysis
->bounds
;
4065 if (analysis
->run
.isSideways
)
4066 FIXME("sideways runs are not supported.\n");
4068 hr
= IDWriteFontFace_QueryInterface(analysis
->run
.fontFace
, &IID_IDWriteFontFace2
, (void**)&fontface2
);
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 */
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
);
4093 OffsetRect(bbox
, origin_x
- advance
, 0);
4095 OffsetRect(bbox
, origin_x
, 0);
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
));
4130 glyphrunanalysis_get_texturebounds(This
, bounds
);
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;
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
;
4160 hr
= IDWriteFontFace_QueryInterface(analysis
->run
.fontFace
, &IID_IDWriteFontFace2
, (void**)&fontface2
);
4162 WARN("failed to get IDWriteFontFace2, 0x%08x\n", hr
);
4166 size
= (analysis
->bounds
.right
- analysis
->bounds
.left
)*(analysis
->bounds
.bottom
- analysis
->bounds
.top
);
4167 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
)
4169 analysis
->bitmap
= heap_alloc_zero(size
);
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
;
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
;
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;
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
);
4209 OffsetRect(bbox
, origin_x
- advance
, 0);
4211 OffsetRect(bbox
, origin_x
, 0);
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
);
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;
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
;
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
);
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
)
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
;
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
;
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
;
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
);
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
);
4346 return E_INVALIDARG
;
4348 switch (This
->rendering_mode
)
4350 case DWRITE_RENDERING_MODE_GDI_CLASSIC
:
4351 case DWRITE_RENDERING_MODE_GDI_NATURAL
:
4354 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST
, 0, &value
, 0);
4355 *gamma
= (FLOAT
)value
/ 1000.0f
;
4357 *cleartypelevel
= 1.0f
;
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
);
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
;
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
));
4396 return E_OUTOFMEMORY
;
4398 analysis
->IDWriteGlyphRunAnalysis_iface
.lpVtbl
= &glyphrunanalysisvtbl
;
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
));
4434 DWRITE_FONT_METRICS metrics
;
4435 IDWriteFontFace1
*fontface1
;
4438 IDWriteFontFace_GetMetrics(run
->fontFace
, &metrics
);
4439 IDWriteFontFace_QueryInterface(run
->fontFace
, &IID_IDWriteFontFace1
, (void**)&fontface1
);
4441 for (i
= 0; i
< run
->glyphCount
; i
++) {
4445 switch (measuring_mode
)
4447 case DWRITE_MEASURING_MODE_NATURAL
:
4448 hr
= IDWriteFontFace1_GetDesignGlyphAdvances(fontface1
, 1, run
->glyphIndices
+ i
, &a
, run
->isSideways
);
4451 analysis
->advances
[i
] = get_scaled_advance_width(a
, run
->fontEmSize
, &metrics
);
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
);
4458 analysis
->advances
[i
] = 0.0;
4460 analysis
->advances
[i
] = floorf(a
* run
->fontEmSize
* ppdip
/ metrics
.designUnitsPerEm
+ 0.5f
) / ppdip
;
4467 IDWriteFontFace1_Release(fontface1
);
4470 if (run
->glyphOffsets
)
4471 memcpy(analysis
->offsets
, run
->glyphOffsets
, run
->glyphCount
*sizeof(*run
->glyphOffsets
));
4473 *ret
= &analysis
->IDWriteGlyphRunAnalysis_iface
;
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
))
4488 IDWriteColorGlyphRunEnumerator_AddRef(iface
);
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
);
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
);
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
);
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
);
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
;
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
;