4 * Copyright 2011 Huw Davies
5 * Copyright 2012, 2014-2016 Nikolay Sivov for CodeWeavers
6 * Copyright 2014 Aric Stewart for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/list.h"
27 #include "dwrite_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dwrite
);
30 WINE_DECLARE_DEBUG_CHANNEL(dwrite_file
);
32 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
33 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
34 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
35 #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e')
36 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
37 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
38 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
39 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
41 static const IID IID_issystemcollection
= {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}};
43 static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD
= 100.0f
;
44 static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD
= 350.0f
;
45 static const FLOAT RECOMMENDED_NATURAL_PPEM
= 20.0f
;
47 static const WCHAR extraW
[] = {'e','x','t','r','a',0};
48 static const WCHAR ultraW
[] = {'u','l','t','r','a',0};
49 static const WCHAR semiW
[] = {'s','e','m','i',0};
50 static const WCHAR extW
[] = {'e','x','t',0};
51 static const WCHAR thinW
[] = {'t','h','i','n',0};
52 static const WCHAR lightW
[] = {'l','i','g','h','t',0};
53 static const WCHAR mediumW
[] = {'m','e','d','i','u','m',0};
54 static const WCHAR blackW
[] = {'b','l','a','c','k',0};
55 static const WCHAR condensedW
[] = {'c','o','n','d','e','n','s','e','d',0};
56 static const WCHAR expandedW
[] = {'e','x','p','a','n','d','e','d',0};
57 static const WCHAR italicW
[] = {'i','t','a','l','i','c',0};
58 static const WCHAR boldW
[] = {'B','o','l','d',0};
59 static const WCHAR obliqueW
[] = {'O','b','l','i','q','u','e',0};
60 static const WCHAR regularW
[] = {'R','e','g','u','l','a','r',0};
61 static const WCHAR demiW
[] = {'d','e','m','i',0};
62 static const WCHAR spaceW
[] = {' ',0};
63 static const WCHAR enusW
[] = {'e','n','-','u','s',0};
65 struct dwrite_font_propvec
{
71 struct dwrite_font_data
{
74 DWRITE_FONT_STYLE style
;
75 DWRITE_FONT_STRETCH stretch
;
76 DWRITE_FONT_WEIGHT weight
;
78 struct dwrite_font_propvec propvec
;
80 DWRITE_FONT_METRICS1 metrics
;
81 IDWriteLocalizedStrings
*info_strings
[DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
+1];
82 IDWriteLocalizedStrings
*names
;
84 /* data needed to create fontface instance */
85 IDWriteFactory2
*factory
;
86 DWRITE_FONT_FACE_TYPE face_type
;
87 IDWriteFontFile
*file
;
94 /* used to mark font as tested when scanning for simulation candidate */
95 BOOL bold_sim_tested
: 1;
96 BOOL oblique_sim_tested
: 1;
99 struct dwrite_fontlist
{
100 IDWriteFontList IDWriteFontList_iface
;
103 IDWriteFontFamily
*family
;
104 struct dwrite_font_data
**fonts
;
108 struct dwrite_fontfamily_data
{
111 IDWriteLocalizedStrings
*familyname
;
113 struct dwrite_font_data
**fonts
;
116 BOOL has_normal_face
: 1;
117 BOOL has_oblique_face
: 1;
118 BOOL has_italic_face
: 1;
121 struct dwrite_fontcollection
{
122 IDWriteFontCollection IDWriteFontCollection_iface
;
125 struct dwrite_fontfamily_data
**family_data
;
131 struct dwrite_fontfamily
{
132 IDWriteFontFamily IDWriteFontFamily_iface
;
135 struct dwrite_fontfamily_data
*data
;
137 IDWriteFontCollection
* collection
;
141 IDWriteFont2 IDWriteFont2_iface
;
144 IDWriteFontFamily
*family
;
146 DWRITE_FONT_STYLE style
;
147 struct dwrite_font_data
*data
;
150 struct dwrite_fonttable
{
157 enum runanalysis_flags
{
158 RUNANALYSIS_BOUNDS_READY
= 1 << 0,
159 RUNANALYSIS_BITMAP_READY
= 1 << 1,
160 RUNANALYSIS_USE_TRANSFORM
= 1 << 2
163 struct dwrite_glyphrunanalysis
{
164 IDWriteGlyphRunAnalysis IDWriteGlyphRunAnalysis_iface
;
167 DWRITE_RENDERING_MODE rendering_mode
;
168 DWRITE_GLYPH_RUN run
; /* glyphAdvances and glyphOffsets are not used */
173 D2D_POINT_2F
*advances
;
174 D2D_POINT_2F
*advanceoffsets
;
175 D2D_POINT_2F
*ascenderoffsets
;
182 struct dwrite_colorglyphenum
{
183 IDWriteColorGlyphRunEnumerator IDWriteColorGlyphRunEnumerator_iface
;
186 FLOAT origin_x
; /* original run origin */
189 IDWriteFontFace3
*fontface
; /* for convenience */
190 DWRITE_COLOR_GLYPH_RUN colorrun
; /* returned with GetCurrentRun() */
191 DWRITE_GLYPH_RUN run
; /* base run */
192 UINT32 palette
; /* palette index to get layer color from */
193 FLOAT
*advances
; /* original or measured advances for base glyphs */
194 FLOAT
*color_advances
; /* returned color run points to this */
195 DWRITE_GLYPH_OFFSET
*offsets
; /* original offsets, or NULL */
196 DWRITE_GLYPH_OFFSET
*color_offsets
; /* returned color run offsets, or NULL */
197 UINT16
*glyphindices
; /* returned color run points to this */
198 struct dwrite_colorglyph
*glyphs
; /* current glyph color info */
199 BOOL has_regular_glyphs
; /* TRUE if there's any glyph without a color */
200 UINT16 current_layer
; /* enumerator position, updated with MoveNext */
201 UINT16 max_layer_num
; /* max number of layers for this run */
202 struct dwrite_fonttable colr
; /* used to access layers */
205 #define GLYPH_BLOCK_SHIFT 8
206 #define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT)
207 #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1)
208 #define GLYPH_MAX 65536
210 struct dwrite_fontface
{
211 IDWriteFontFace3 IDWriteFontFace3_iface
;
214 IDWriteFontFileStream
**streams
;
215 IDWriteFontFile
**files
;
220 DWRITE_FONT_FACE_TYPE type
;
221 DWRITE_FONT_METRICS1 metrics
;
222 DWRITE_CARET_METRICS caret
;
225 BOOL has_kerning_pairs
: 1;
226 BOOL is_monospaced
: 1;
228 struct dwrite_fonttable cmap
;
229 struct dwrite_fonttable vdmx
;
230 struct dwrite_fonttable gasp
;
231 struct dwrite_fonttable cpal
;
232 struct dwrite_fonttable colr
;
233 DWRITE_GLYPH_METRICS
*glyphs
[GLYPH_MAX
/GLYPH_BLOCK_SIZE
];
236 struct dwrite_fontfile
{
237 IDWriteFontFile IDWriteFontFile_iface
;
240 IDWriteFontFileLoader
*loader
;
243 IDWriteFontFileStream
*stream
;
246 static inline struct dwrite_fontface
*impl_from_IDWriteFontFace3(IDWriteFontFace3
*iface
)
248 return CONTAINING_RECORD(iface
, struct dwrite_fontface
, IDWriteFontFace3_iface
);
251 static inline struct dwrite_font
*impl_from_IDWriteFont2(IDWriteFont2
*iface
)
253 return CONTAINING_RECORD(iface
, struct dwrite_font
, IDWriteFont2_iface
);
256 static inline struct dwrite_fontfile
*impl_from_IDWriteFontFile(IDWriteFontFile
*iface
)
258 return CONTAINING_RECORD(iface
, struct dwrite_fontfile
, IDWriteFontFile_iface
);
261 static inline struct dwrite_fontfamily
*impl_from_IDWriteFontFamily(IDWriteFontFamily
*iface
)
263 return CONTAINING_RECORD(iface
, struct dwrite_fontfamily
, IDWriteFontFamily_iface
);
266 static inline struct dwrite_fontcollection
*impl_from_IDWriteFontCollection(IDWriteFontCollection
*iface
)
268 return CONTAINING_RECORD(iface
, struct dwrite_fontcollection
, IDWriteFontCollection_iface
);
271 static inline struct dwrite_glyphrunanalysis
*impl_from_IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysis
*iface
)
273 return CONTAINING_RECORD(iface
, struct dwrite_glyphrunanalysis
, IDWriteGlyphRunAnalysis_iface
);
276 static inline struct dwrite_colorglyphenum
*impl_from_IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumerator
*iface
)
278 return CONTAINING_RECORD(iface
, struct dwrite_colorglyphenum
, IDWriteColorGlyphRunEnumerator_iface
);
281 static inline struct dwrite_fontlist
*impl_from_IDWriteFontList(IDWriteFontList
*iface
)
283 return CONTAINING_RECORD(iface
, struct dwrite_fontlist
, IDWriteFontList_iface
);
286 static inline const char *debugstr_tag(UINT32 tag
)
288 return debugstr_an((char*)&tag
, 4);
291 static HRESULT
get_cached_glyph_metrics(struct dwrite_fontface
*fontface
, UINT16 glyph
, DWRITE_GLYPH_METRICS
*metrics
)
293 static const DWRITE_GLYPH_METRICS nil
;
294 DWRITE_GLYPH_METRICS
*block
= fontface
->glyphs
[glyph
>> GLYPH_BLOCK_SHIFT
];
296 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(DWRITE_GLYPH_METRICS
))) return S_FALSE
;
297 memcpy(metrics
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(*metrics
));
301 static HRESULT
set_cached_glyph_metrics(struct dwrite_fontface
*fontface
, UINT16 glyph
, DWRITE_GLYPH_METRICS
*metrics
)
303 DWRITE_GLYPH_METRICS
**block
= &fontface
->glyphs
[glyph
>> GLYPH_BLOCK_SHIFT
];
306 /* start new block */
307 *block
= heap_alloc_zero(sizeof(*metrics
) * GLYPH_BLOCK_SIZE
);
309 return E_OUTOFMEMORY
;
312 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], metrics
, sizeof(*metrics
));
316 static void* get_fontface_table(IDWriteFontFace3
*fontface
, UINT32 tag
, struct dwrite_fonttable
*table
)
320 if (table
->data
|| !table
->exists
)
323 table
->exists
= FALSE
;
324 hr
= IDWriteFontFace3_TryGetFontTable(fontface
, tag
, (const void**)&table
->data
, &table
->size
, &table
->context
,
326 if (FAILED(hr
) || !table
->exists
) {
327 WARN("Font does not have a %s table\n", debugstr_tag(tag
));
334 static void init_font_prop_vec(DWRITE_FONT_WEIGHT weight
, DWRITE_FONT_STRETCH stretch
, DWRITE_FONT_STYLE style
,
335 struct dwrite_font_propvec
*vec
)
337 vec
->stretch
= ((INT32
)stretch
- DWRITE_FONT_STRETCH_NORMAL
) * 11.0f
;
338 vec
->style
= style
* 7.0f
;
339 vec
->weight
= ((INT32
)weight
- DWRITE_FONT_WEIGHT_NORMAL
) / 100.0f
* 5.0f
;
342 static FLOAT
get_font_prop_vec_distance(const struct dwrite_font_propvec
*left
, const struct dwrite_font_propvec
*right
)
344 return powf(left
->stretch
- right
->stretch
, 2) + powf(left
->style
- right
->style
, 2) + powf(left
->weight
- right
->weight
, 2);
347 static FLOAT
get_font_prop_vec_dotproduct(const struct dwrite_font_propvec
*left
, const struct dwrite_font_propvec
*right
)
349 return left
->stretch
* right
->stretch
+ left
->style
* right
->style
+ left
->weight
* right
->weight
;
352 static inline void* get_fontface_cmap(struct dwrite_fontface
*fontface
)
354 return get_fontface_table(&fontface
->IDWriteFontFace3_iface
, MS_CMAP_TAG
, &fontface
->cmap
);
357 static inline void* get_fontface_vdmx(struct dwrite_fontface
*fontface
)
359 return get_fontface_table(&fontface
->IDWriteFontFace3_iface
, MS_VDMX_TAG
, &fontface
->vdmx
);
362 static inline void* get_fontface_gasp(struct dwrite_fontface
*fontface
, UINT32
*size
)
364 void *ptr
= get_fontface_table(&fontface
->IDWriteFontFace3_iface
, MS_GASP_TAG
, &fontface
->gasp
);
365 *size
= fontface
->gasp
.size
;
369 static inline void* get_fontface_cpal(struct dwrite_fontface
*fontface
)
371 return get_fontface_table(&fontface
->IDWriteFontFace3_iface
, MS_CPAL_TAG
, &fontface
->cpal
);
374 static inline void* get_fontface_colr(struct dwrite_fontface
*fontface
)
376 return get_fontface_table(&fontface
->IDWriteFontFace3_iface
, MS_COLR_TAG
, &fontface
->colr
);
379 static void release_font_data(struct dwrite_font_data
*data
)
383 if (InterlockedDecrement(&data
->ref
) > 0)
386 for (i
= DWRITE_INFORMATIONAL_STRING_NONE
; i
< sizeof(data
->info_strings
)/sizeof(data
->info_strings
[0]); i
++) {
387 if (data
->info_strings
[i
])
388 IDWriteLocalizedStrings_Release(data
->info_strings
[i
]);
391 IDWriteLocalizedStrings_Release(data
->names
);
393 IDWriteFontFile_Release(data
->file
);
394 IDWriteFactory2_Release(data
->factory
);
395 heap_free(data
->facename
);
399 static void release_fontfamily_data(struct dwrite_fontfamily_data
*data
)
403 if (InterlockedDecrement(&data
->ref
) > 0)
406 for (i
= 0; i
< data
->font_count
; i
++)
407 release_font_data(data
->fonts
[i
]);
408 heap_free(data
->fonts
);
409 IDWriteLocalizedStrings_Release(data
->familyname
);
413 static HRESULT WINAPI
dwritefontface_QueryInterface(IDWriteFontFace3
*iface
, REFIID riid
, void **obj
)
415 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
417 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
419 if (IsEqualIID(riid
, &IID_IDWriteFontFace3
) ||
420 IsEqualIID(riid
, &IID_IDWriteFontFace2
) ||
421 IsEqualIID(riid
, &IID_IDWriteFontFace1
) ||
422 IsEqualIID(riid
, &IID_IDWriteFontFace
) ||
423 IsEqualIID(riid
, &IID_IUnknown
))
426 IDWriteFontFace3_AddRef(iface
);
431 return E_NOINTERFACE
;
434 static ULONG WINAPI
dwritefontface_AddRef(IDWriteFontFace3
*iface
)
436 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
437 ULONG ref
= InterlockedIncrement(&This
->ref
);
438 TRACE("(%p)->(%d)\n", This
, ref
);
442 static ULONG WINAPI
dwritefontface_Release(IDWriteFontFace3
*iface
)
444 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
445 ULONG ref
= InterlockedDecrement(&This
->ref
);
447 TRACE("(%p)->(%d)\n", This
, ref
);
452 if (This
->cmap
.context
)
453 IDWriteFontFace3_ReleaseFontTable(iface
, This
->cmap
.context
);
454 if (This
->vdmx
.context
)
455 IDWriteFontFace3_ReleaseFontTable(iface
, This
->vdmx
.context
);
456 if (This
->gasp
.context
)
457 IDWriteFontFace3_ReleaseFontTable(iface
, This
->gasp
.context
);
458 if (This
->cpal
.context
)
459 IDWriteFontFace3_ReleaseFontTable(iface
, This
->cpal
.context
);
460 if (This
->colr
.context
)
461 IDWriteFontFace3_ReleaseFontTable(iface
, This
->colr
.context
);
462 for (i
= 0; i
< This
->file_count
; i
++) {
463 if (This
->streams
[i
])
464 IDWriteFontFileStream_Release(This
->streams
[i
]);
466 IDWriteFontFile_Release(This
->files
[i
]);
468 heap_free(This
->streams
);
469 heap_free(This
->files
);
471 for (i
= 0; i
< sizeof(This
->glyphs
)/sizeof(This
->glyphs
[0]); i
++)
472 heap_free(This
->glyphs
[i
]);
474 freetype_notify_cacheremove(iface
);
481 static DWRITE_FONT_FACE_TYPE WINAPI
dwritefontface_GetType(IDWriteFontFace3
*iface
)
483 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
484 TRACE("(%p)\n", This
);
488 static HRESULT WINAPI
dwritefontface_GetFiles(IDWriteFontFace3
*iface
, UINT32
*number_of_files
,
489 IDWriteFontFile
**fontfiles
)
491 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
494 TRACE("(%p)->(%p %p)\n", This
, number_of_files
, fontfiles
);
495 if (fontfiles
== NULL
)
497 *number_of_files
= This
->file_count
;
500 if (*number_of_files
< This
->file_count
)
503 for (i
= 0; i
< This
->file_count
; i
++)
505 IDWriteFontFile_AddRef(This
->files
[i
]);
506 fontfiles
[i
] = This
->files
[i
];
512 static UINT32 WINAPI
dwritefontface_GetIndex(IDWriteFontFace3
*iface
)
514 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
515 TRACE("(%p)\n", This
);
519 static DWRITE_FONT_SIMULATIONS WINAPI
dwritefontface_GetSimulations(IDWriteFontFace3
*iface
)
521 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
522 TRACE("(%p)\n", This
);
523 return This
->simulations
;
526 static BOOL WINAPI
dwritefontface_IsSymbolFont(IDWriteFontFace3
*iface
)
528 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
529 TRACE("(%p)\n", This
);
530 return This
->is_symbol
;
533 static void WINAPI
dwritefontface_GetMetrics(IDWriteFontFace3
*iface
, DWRITE_FONT_METRICS
*metrics
)
535 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
536 TRACE("(%p)->(%p)\n", This
, metrics
);
537 memcpy(metrics
, &This
->metrics
, sizeof(*metrics
));
540 static UINT16 WINAPI
dwritefontface_GetGlyphCount(IDWriteFontFace3
*iface
)
542 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
543 TRACE("(%p)\n", This
);
544 return freetype_get_glyphcount(iface
);
547 static HRESULT WINAPI
dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace3
*iface
,
548 UINT16
const *glyphs
, UINT32 glyph_count
, DWRITE_GLYPH_METRICS
*ret
, BOOL is_sideways
)
550 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
554 TRACE("(%p)->(%p %u %p %d)\n", This
, glyphs
, glyph_count
, ret
, is_sideways
);
560 FIXME("sideways metrics are not supported.\n");
562 for (i
= 0; i
< glyph_count
; i
++) {
563 DWRITE_GLYPH_METRICS metrics
;
565 hr
= get_cached_glyph_metrics(This
, glyphs
[i
], &metrics
);
567 freetype_get_design_glyph_metrics(iface
, This
->metrics
.designUnitsPerEm
, glyphs
[i
], &metrics
);
568 hr
= set_cached_glyph_metrics(This
, glyphs
[i
], &metrics
);
578 static HRESULT WINAPI
dwritefontface_GetGlyphIndices(IDWriteFontFace3
*iface
, UINT32
const *codepoints
,
579 UINT32 count
, UINT16
*glyph_indices
)
581 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
583 TRACE("(%p)->(%p %u %p)\n", This
, codepoints
, count
, glyph_indices
);
589 memset(glyph_indices
, 0, count
*sizeof(UINT16
));
593 freetype_get_glyphs(iface
, This
->charmap
, codepoints
, count
, glyph_indices
);
597 static HRESULT WINAPI
dwritefontface_TryGetFontTable(IDWriteFontFace3
*iface
, UINT32 table_tag
,
598 const void **table_data
, UINT32
*table_size
, void **context
, BOOL
*exists
)
600 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
602 TRACE("(%p)->(%s %p %p %p %p)\n", This
, debugstr_tag(table_tag
), table_data
, table_size
, context
, exists
);
604 return opentype_get_font_table(This
->streams
[0], This
->type
, This
->index
, table_tag
, table_data
, context
, table_size
, exists
);
607 static void WINAPI
dwritefontface_ReleaseFontTable(IDWriteFontFace3
*iface
, void *table_context
)
609 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
611 TRACE("(%p)->(%p)\n", This
, table_context
);
613 IDWriteFontFileStream_ReleaseFileFragment(This
->streams
[0], table_context
);
616 static HRESULT WINAPI
dwritefontface_GetGlyphRunOutline(IDWriteFontFace3
*iface
, FLOAT emSize
,
617 UINT16
const *glyphs
, FLOAT
const* advances
, DWRITE_GLYPH_OFFSET
const *offsets
,
618 UINT32 count
, BOOL is_sideways
, BOOL is_rtl
, IDWriteGeometrySink
*sink
)
620 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
622 TRACE("(%p)->(%.2f %p %p %p %u %d %d %p)\n", This
, emSize
, glyphs
, advances
, offsets
,
623 count
, is_sideways
, is_rtl
, sink
);
625 if (!glyphs
|| !sink
)
629 FIXME("sideways mode is not supported.\n");
631 return freetype_get_glyphrun_outline(iface
, emSize
, glyphs
, advances
, offsets
, count
, is_rtl
, sink
);
634 static DWRITE_RENDERING_MODE
fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring
,
635 FLOAT ppem
, WORD gasp
)
637 DWRITE_RENDERING_MODE mode
= DWRITE_RENDERING_MODE_DEFAULT
;
641 case DWRITE_MEASURING_MODE_NATURAL
:
643 if (!(gasp
& GASP_SYMMETRIC_SMOOTHING
) && (ppem
<= RECOMMENDED_NATURAL_PPEM
))
644 mode
= DWRITE_RENDERING_MODE_NATURAL
;
646 mode
= DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
;
649 case DWRITE_MEASURING_MODE_GDI_CLASSIC
:
650 mode
= DWRITE_RENDERING_MODE_GDI_CLASSIC
;
652 case DWRITE_MEASURING_MODE_GDI_NATURAL
:
653 mode
= DWRITE_RENDERING_MODE_GDI_NATURAL
;
662 static HRESULT WINAPI
dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace3
*iface
, FLOAT emSize
,
663 FLOAT ppdip
, DWRITE_MEASURING_MODE measuring
, IDWriteRenderingParams
*params
, DWRITE_RENDERING_MODE
*mode
)
665 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
670 TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This
, emSize
, ppdip
, measuring
, params
, mode
);
673 *mode
= DWRITE_RENDERING_MODE_DEFAULT
;
677 *mode
= IDWriteRenderingParams_GetRenderingMode(params
);
678 if (*mode
!= DWRITE_RENDERING_MODE_DEFAULT
)
681 ppem
= emSize
* ppdip
;
683 if (ppem
>= RECOMMENDED_OUTLINE_AA_THRESHOLD
) {
684 *mode
= DWRITE_RENDERING_MODE_OUTLINE
;
688 ptr
= get_fontface_gasp(This
, &size
);
689 gasp
= opentype_get_gasp_flags(ptr
, size
, ppem
);
690 *mode
= fontface_renderingmode_from_measuringmode(measuring
, ppem
, gasp
);
694 static HRESULT WINAPI
dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace3
*iface
, FLOAT emSize
, FLOAT pixels_per_dip
,
695 DWRITE_MATRIX
const *transform
, DWRITE_FONT_METRICS
*metrics
)
697 DWRITE_FONT_METRICS1 metrics1
;
698 HRESULT hr
= IDWriteFontFace3_GetGdiCompatibleMetrics(iface
, emSize
, pixels_per_dip
, transform
, &metrics1
);
699 memcpy(metrics
, &metrics1
, sizeof(*metrics
));
703 static inline int round_metric(FLOAT metric
)
705 return (int)floorf(metric
+ 0.5f
);
708 static HRESULT WINAPI
dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace3
*iface
, FLOAT emSize
, FLOAT ppdip
,
709 DWRITE_MATRIX
const *m
, BOOL use_gdi_natural
, UINT16
const *glyphs
, UINT32 glyph_count
,
710 DWRITE_GLYPH_METRICS
*metrics
, BOOL is_sideways
)
712 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
713 DWRITE_MEASURING_MODE mode
;
718 TRACE("(%p)->(%.2f %.2f %p %d %p %u %p %d)\n", This
, emSize
, ppdip
, m
, use_gdi_natural
, glyphs
,
719 glyph_count
, metrics
, is_sideways
);
721 if (m
&& memcmp(m
, &identity
, sizeof(*m
)))
722 FIXME("transform is not supported, %s\n", debugstr_matrix(m
));
724 size
= emSize
* ppdip
;
725 scale
= size
/ This
->metrics
.designUnitsPerEm
;
726 mode
= use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
728 for (i
= 0; i
< glyph_count
; i
++) {
729 DWRITE_GLYPH_METRICS
*ret
= metrics
+ i
;
730 DWRITE_GLYPH_METRICS design
;
732 hr
= IDWriteFontFace3_GetDesignGlyphMetrics(iface
, glyphs
+ i
, 1, &design
, is_sideways
);
736 ret
->advanceWidth
= freetype_get_glyph_advance(iface
, size
, glyphs
[i
], mode
);
737 ret
->advanceWidth
= round_metric(ret
->advanceWidth
* This
->metrics
.designUnitsPerEm
/ size
);
739 #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale)
740 SCALE_METRIC(leftSideBearing
);
741 SCALE_METRIC(rightSideBearing
);
742 SCALE_METRIC(topSideBearing
);
743 SCALE_METRIC(advanceHeight
);
744 SCALE_METRIC(bottomSideBearing
);
745 SCALE_METRIC(verticalOriginY
);
752 static void WINAPI
dwritefontface1_GetMetrics(IDWriteFontFace3
*iface
, DWRITE_FONT_METRICS1
*metrics
)
754 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
755 TRACE("(%p)->(%p)\n", This
, metrics
);
756 *metrics
= This
->metrics
;
759 static HRESULT WINAPI
dwritefontface1_GetGdiCompatibleMetrics(IDWriteFontFace3
*iface
, FLOAT em_size
, FLOAT pixels_per_dip
,
760 const DWRITE_MATRIX
*m
, DWRITE_FONT_METRICS1
*metrics
)
762 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
763 const DWRITE_FONT_METRICS1
*design
= &This
->metrics
;
764 UINT16 ascent
, descent
;
767 TRACE("(%p)->(%.2f %.2f %p %p)\n", This
, em_size
, pixels_per_dip
, m
, metrics
);
769 if (em_size
<= 0.0f
|| pixels_per_dip
<= 0.0f
) {
770 memset(metrics
, 0, sizeof(*metrics
));
774 em_size
*= pixels_per_dip
;
775 if (m
&& m
->m22
!= 0.0f
)
776 em_size
*= fabs(m
->m22
);
778 scale
= em_size
/ design
->designUnitsPerEm
;
779 if (!opentype_get_vdmx_size(get_fontface_vdmx(This
), em_size
, &ascent
, &descent
)) {
780 ascent
= round_metric(design
->ascent
* scale
);
781 descent
= round_metric(design
->descent
* scale
);
784 #define SCALE_METRIC(x) metrics->x = round_metric(round_metric((design->x) * scale) / scale)
785 metrics
->designUnitsPerEm
= design
->designUnitsPerEm
;
786 metrics
->ascent
= round_metric(ascent
/ scale
);
787 metrics
->descent
= round_metric(descent
/ scale
);
789 SCALE_METRIC(lineGap
);
790 SCALE_METRIC(capHeight
);
791 SCALE_METRIC(xHeight
);
792 SCALE_METRIC(underlinePosition
);
793 SCALE_METRIC(underlineThickness
);
794 SCALE_METRIC(strikethroughPosition
);
795 SCALE_METRIC(strikethroughThickness
);
796 SCALE_METRIC(glyphBoxLeft
);
797 SCALE_METRIC(glyphBoxTop
);
798 SCALE_METRIC(glyphBoxRight
);
799 SCALE_METRIC(glyphBoxBottom
);
800 SCALE_METRIC(subscriptPositionX
);
801 SCALE_METRIC(subscriptPositionY
);
802 SCALE_METRIC(subscriptSizeX
);
803 SCALE_METRIC(subscriptSizeY
);
804 SCALE_METRIC(superscriptPositionX
);
805 SCALE_METRIC(superscriptPositionY
);
806 SCALE_METRIC(superscriptSizeX
);
807 SCALE_METRIC(superscriptSizeY
);
809 metrics
->hasTypographicMetrics
= design
->hasTypographicMetrics
;
815 static void WINAPI
dwritefontface1_GetCaretMetrics(IDWriteFontFace3
*iface
, DWRITE_CARET_METRICS
*metrics
)
817 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
818 TRACE("(%p)->(%p)\n", This
, metrics
);
819 *metrics
= This
->caret
;
822 static HRESULT WINAPI
dwritefontface1_GetUnicodeRanges(IDWriteFontFace3
*iface
, UINT32 max_count
,
823 DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
825 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
827 TRACE("(%p)->(%u %p %p)\n", This
, max_count
, ranges
, count
);
830 if (max_count
&& !ranges
)
833 return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This
), max_count
, ranges
, count
);
836 static BOOL WINAPI
dwritefontface1_IsMonospacedFont(IDWriteFontFace3
*iface
)
838 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
839 TRACE("(%p)\n", This
);
840 return This
->is_monospaced
;
843 static HRESULT WINAPI
dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace3
*iface
,
844 UINT32 glyph_count
, UINT16
const *glyphs
, INT32
*advances
, BOOL is_sideways
)
846 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
849 TRACE("(%p)->(%u %p %p %d)\n", This
, glyph_count
, glyphs
, advances
, is_sideways
);
852 FIXME("sideways mode not supported\n");
854 for (i
= 0; i
< glyph_count
; i
++)
855 advances
[i
] = freetype_get_glyph_advance(iface
, This
->metrics
.designUnitsPerEm
, glyphs
[i
], DWRITE_MEASURING_MODE_NATURAL
);
860 static HRESULT WINAPI
dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontFace3
*iface
,
861 FLOAT em_size
, FLOAT ppdip
, const DWRITE_MATRIX
*m
, BOOL use_gdi_natural
,
862 BOOL is_sideways
, UINT32 glyph_count
, UINT16
const *glyphs
, INT32
*advances
)
864 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
865 DWRITE_MEASURING_MODE mode
;
868 TRACE("(%p)->(%.2f %.2f %p %d %d %u %p %p)\n", This
, em_size
, ppdip
, m
,
869 use_gdi_natural
, is_sideways
, glyph_count
, glyphs
, advances
);
871 if (em_size
< 0.0f
|| ppdip
<= 0.0f
) {
872 memset(advances
, 0, sizeof(*advances
) * glyph_count
);
877 if (em_size
== 0.0f
) {
878 memset(advances
, 0, sizeof(*advances
) * glyph_count
);
882 if (m
&& memcmp(m
, &identity
, sizeof(*m
)))
883 FIXME("transform is not supported, %s\n", debugstr_matrix(m
));
885 mode
= use_gdi_natural
? DWRITE_MEASURING_MODE_GDI_NATURAL
: DWRITE_MEASURING_MODE_GDI_CLASSIC
;
886 for (i
= 0; i
< glyph_count
; i
++) {
887 advances
[i
] = freetype_get_glyph_advance(iface
, em_size
, glyphs
[i
], mode
);
888 advances
[i
] = round_metric(advances
[i
] * This
->metrics
.designUnitsPerEm
/ em_size
);
894 static HRESULT WINAPI
dwritefontface1_GetKerningPairAdjustments(IDWriteFontFace3
*iface
, UINT32 count
,
895 const UINT16
*indices
, INT32
*adjustments
)
897 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
900 TRACE("(%p)->(%u %p %p)\n", This
, count
, indices
, adjustments
);
902 if (!(indices
|| adjustments
) || !count
)
905 if (!indices
|| count
== 1) {
906 memset(adjustments
, 0, count
*sizeof(INT32
));
910 if (!This
->has_kerning_pairs
) {
911 memset(adjustments
, 0, count
*sizeof(INT32
));
915 for (i
= 0; i
< count
-1; i
++)
916 adjustments
[i
] = freetype_get_kerning_pair_adjustment(iface
, indices
[i
], indices
[i
+1]);
917 adjustments
[count
-1] = 0;
922 static BOOL WINAPI
dwritefontface1_HasKerningPairs(IDWriteFontFace3
*iface
)
924 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
925 TRACE("(%p)\n", This
);
926 return This
->has_kerning_pairs
;
929 static HRESULT WINAPI
dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFace3
*iface
,
930 FLOAT font_emsize
, FLOAT dpiX
, FLOAT dpiY
, const DWRITE_MATRIX
*transform
, BOOL is_sideways
,
931 DWRITE_OUTLINE_THRESHOLD threshold
, DWRITE_MEASURING_MODE measuring_mode
, DWRITE_RENDERING_MODE
*rendering_mode
)
933 DWRITE_GRID_FIT_MODE gridfitmode
;
934 return IDWriteFontFace2_GetRecommendedRenderingMode((IDWriteFontFace2
*)iface
, font_emsize
, dpiX
, dpiY
, transform
, is_sideways
,
935 threshold
, measuring_mode
, NULL
, rendering_mode
, &gridfitmode
);
938 static HRESULT WINAPI
dwritefontface1_GetVerticalGlyphVariants(IDWriteFontFace3
*iface
, UINT32 glyph_count
,
939 const UINT16
*nominal_indices
, UINT16
*vertical_indices
)
941 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
942 FIXME("(%p)->(%u %p %p): stub\n", This
, glyph_count
, nominal_indices
, vertical_indices
);
946 static BOOL WINAPI
dwritefontface1_HasVerticalGlyphVariants(IDWriteFontFace3
*iface
)
948 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
949 FIXME("(%p): stub\n", This
);
953 static BOOL WINAPI
dwritefontface2_IsColorFont(IDWriteFontFace3
*iface
)
955 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
956 TRACE("(%p)\n", This
);
957 return get_fontface_cpal(This
) && get_fontface_colr(This
);
960 static UINT32 WINAPI
dwritefontface2_GetColorPaletteCount(IDWriteFontFace3
*iface
)
962 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
963 TRACE("(%p)\n", This
);
964 return opentype_get_cpal_palettecount(get_fontface_cpal(This
));
967 static UINT32 WINAPI
dwritefontface2_GetPaletteEntryCount(IDWriteFontFace3
*iface
)
969 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
970 TRACE("(%p)\n", This
);
971 return opentype_get_cpal_paletteentrycount(get_fontface_cpal(This
));
974 static HRESULT WINAPI
dwritefontface2_GetPaletteEntries(IDWriteFontFace3
*iface
, UINT32 palette_index
,
975 UINT32 first_entry_index
, UINT32 entry_count
, DWRITE_COLOR_F
*entries
)
977 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
978 TRACE("(%p)->(%u %u %u %p)\n", This
, palette_index
, first_entry_index
, entry_count
, entries
);
979 return opentype_get_cpal_entries(get_fontface_cpal(This
), palette_index
, first_entry_index
, entry_count
, entries
);
982 static HRESULT WINAPI
dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace3
*iface
, FLOAT emSize
,
983 FLOAT dpiX
, FLOAT dpiY
, DWRITE_MATRIX
const *m
, BOOL is_sideways
, DWRITE_OUTLINE_THRESHOLD threshold
,
984 DWRITE_MEASURING_MODE measuringmode
, IDWriteRenderingParams
*params
, DWRITE_RENDERING_MODE
*renderingmode
,
985 DWRITE_GRID_FIT_MODE
*gridfitmode
)
987 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
992 TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This
, emSize
, dpiX
, dpiY
, m
, is_sideways
, threshold
,
993 measuringmode
, params
, renderingmode
, gridfitmode
);
996 FIXME("transform not supported %s\n", debugstr_matrix(m
));
999 FIXME("sideways mode not supported\n");
1001 emSize
*= max(dpiX
, dpiY
) / 96.0f
;
1003 *renderingmode
= DWRITE_RENDERING_MODE_DEFAULT
;
1004 *gridfitmode
= DWRITE_GRID_FIT_MODE_DEFAULT
;
1006 IDWriteRenderingParams2
*params2
;
1009 hr
= IDWriteRenderingParams_QueryInterface(params
, &IID_IDWriteRenderingParams2
, (void**)¶ms2
);
1011 *renderingmode
= IDWriteRenderingParams2_GetRenderingMode(params2
);
1012 *gridfitmode
= IDWriteRenderingParams2_GetGridFitMode(params2
);
1013 IDWriteRenderingParams2_Release(params2
);
1016 *renderingmode
= IDWriteRenderingParams_GetRenderingMode(params
);
1019 emthreshold
= threshold
== DWRITE_OUTLINE_THRESHOLD_ANTIALIASED
? RECOMMENDED_OUTLINE_AA_THRESHOLD
: RECOMMENDED_OUTLINE_A_THRESHOLD
;
1021 ptr
= get_fontface_gasp(This
, &size
);
1022 gasp
= opentype_get_gasp_flags(ptr
, size
, emSize
);
1024 if (*renderingmode
== DWRITE_RENDERING_MODE_DEFAULT
) {
1025 if (emSize
>= emthreshold
)
1026 *renderingmode
= DWRITE_RENDERING_MODE_OUTLINE
;
1028 *renderingmode
= fontface_renderingmode_from_measuringmode(measuringmode
, emSize
, gasp
);
1031 if (*gridfitmode
== DWRITE_GRID_FIT_MODE_DEFAULT
) {
1032 if (emSize
>= emthreshold
)
1033 *gridfitmode
= DWRITE_GRID_FIT_MODE_DISABLED
;
1034 else if (measuringmode
== DWRITE_MEASURING_MODE_GDI_CLASSIC
|| measuringmode
== DWRITE_MEASURING_MODE_GDI_NATURAL
)
1035 *gridfitmode
= DWRITE_GRID_FIT_MODE_ENABLED
;
1037 *gridfitmode
= (gasp
& (GASP_GRIDFIT
|GASP_SYMMETRIC_GRIDFIT
)) ? DWRITE_GRID_FIT_MODE_ENABLED
: DWRITE_GRID_FIT_MODE_DISABLED
;
1043 static HRESULT WINAPI
dwritefontface3_GetFontFaceReference(IDWriteFontFace3
*iface
, IDWriteFontFaceReference
**ref
)
1045 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1046 FIXME("(%p)->(%p): stub\n", This
, ref
);
1050 static void WINAPI
dwritefontface3_GetPanose(IDWriteFontFace3
*iface
, DWRITE_PANOSE
*panose
)
1052 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1053 FIXME("(%p)->(%p): stub\n", This
, panose
);
1056 static DWRITE_FONT_WEIGHT WINAPI
dwritefontface3_GetWeight(IDWriteFontFace3
*iface
)
1058 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1059 FIXME("(%p): stub\n", This
);
1060 return DWRITE_FONT_WEIGHT_NORMAL
;
1063 static DWRITE_FONT_STRETCH WINAPI
dwritefontface3_GetStretch(IDWriteFontFace3
*iface
)
1065 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1066 FIXME("(%p): stub\n", This
);
1067 return DWRITE_FONT_STRETCH_NORMAL
;
1070 static DWRITE_FONT_STYLE WINAPI
dwritefontface3_GetStyle(IDWriteFontFace3
*iface
)
1072 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1073 FIXME("(%p): stub\n", This
);
1074 return DWRITE_FONT_STYLE_NORMAL
;
1077 static HRESULT WINAPI
dwritefontface3_GetFamilyNames(IDWriteFontFace3
*iface
, IDWriteLocalizedStrings
**names
)
1079 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1080 FIXME("(%p)->(%p): stub\n", This
, names
);
1084 static HRESULT WINAPI
dwritefontface3_GetFaceNames(IDWriteFontFace3
*iface
, IDWriteLocalizedStrings
**names
)
1086 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1087 FIXME("(%p)->(%p): stub\n", This
, names
);
1091 static HRESULT WINAPI
dwritefontface3_GetInformationalStrings(IDWriteFontFace3
*iface
, DWRITE_INFORMATIONAL_STRING_ID stringid
,
1092 IDWriteLocalizedStrings
**strings
, BOOL
*exists
)
1094 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1095 FIXME("(%p)->(%u %p %p): stub\n", This
, stringid
, strings
, exists
);
1099 static BOOL WINAPI
dwritefontface3_HasCharacter(IDWriteFontFace3
*iface
, UINT32 ch
)
1101 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1105 TRACE("(%p)->(0x%08x)\n", This
, ch
);
1108 hr
= IDWriteFontFace3_GetGlyphIndices(iface
, &ch
, 1, &index
);
1115 static HRESULT WINAPI
dwritefontface3_GetRecommendedRenderingMode(IDWriteFontFace3
*iface
, FLOAT emsize
, FLOAT dpi_x
, FLOAT dpi_y
,
1116 DWRITE_MATRIX
const *transform
, BOOL is_sideways
, DWRITE_OUTLINE_THRESHOLD threshold
, DWRITE_MEASURING_MODE measuring_mode
,
1117 IDWriteRenderingParams
*params
, DWRITE_RENDERING_MODE1
*rendering_mode
, DWRITE_GRID_FIT_MODE
*gridfit_mode
)
1119 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1120 FIXME("(%p)->(%f %f %f %p %d %u %u %p %p %p): stub\n", This
, emsize
, dpi_x
, dpi_y
, transform
, is_sideways
, threshold
,
1121 measuring_mode
, params
, rendering_mode
, gridfit_mode
);
1125 static BOOL WINAPI
dwritefontface3_IsCharacterLocal(IDWriteFontFace3
*iface
, UINT32 ch
)
1127 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1128 FIXME("(%p)->(0x%x): stub\n", This
, ch
);
1132 static BOOL WINAPI
dwritefontface3_IsGlyphLocal(IDWriteFontFace3
*iface
, UINT16 glyph
)
1134 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1135 FIXME("(%p)->(%u): stub\n", This
, glyph
);
1139 static HRESULT WINAPI
dwritefontface3_AreCharactersLocal(IDWriteFontFace3
*iface
, WCHAR
const *text
,
1140 UINT32 count
, BOOL enqueue_if_not
, BOOL
*are_local
)
1142 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1143 FIXME("(%p)->(%s:%u %d %p): stub\n", This
, debugstr_wn(text
, count
), count
, enqueue_if_not
, are_local
);
1147 static HRESULT WINAPI
dwritefontface3_AreGlyphsLocal(IDWriteFontFace3
*iface
, UINT16
const *glyphs
,
1148 UINT32 count
, BOOL enqueue_if_not
, BOOL
*are_local
)
1150 struct dwrite_fontface
*This
= impl_from_IDWriteFontFace3(iface
);
1151 FIXME("(%p)->(%p %u %d %p): stub\n", This
, glyphs
, count
, enqueue_if_not
, are_local
);
1155 static const IDWriteFontFace3Vtbl dwritefontfacevtbl
= {
1156 dwritefontface_QueryInterface
,
1157 dwritefontface_AddRef
,
1158 dwritefontface_Release
,
1159 dwritefontface_GetType
,
1160 dwritefontface_GetFiles
,
1161 dwritefontface_GetIndex
,
1162 dwritefontface_GetSimulations
,
1163 dwritefontface_IsSymbolFont
,
1164 dwritefontface_GetMetrics
,
1165 dwritefontface_GetGlyphCount
,
1166 dwritefontface_GetDesignGlyphMetrics
,
1167 dwritefontface_GetGlyphIndices
,
1168 dwritefontface_TryGetFontTable
,
1169 dwritefontface_ReleaseFontTable
,
1170 dwritefontface_GetGlyphRunOutline
,
1171 dwritefontface_GetRecommendedRenderingMode
,
1172 dwritefontface_GetGdiCompatibleMetrics
,
1173 dwritefontface_GetGdiCompatibleGlyphMetrics
,
1174 dwritefontface1_GetMetrics
,
1175 dwritefontface1_GetGdiCompatibleMetrics
,
1176 dwritefontface1_GetCaretMetrics
,
1177 dwritefontface1_GetUnicodeRanges
,
1178 dwritefontface1_IsMonospacedFont
,
1179 dwritefontface1_GetDesignGlyphAdvances
,
1180 dwritefontface1_GetGdiCompatibleGlyphAdvances
,
1181 dwritefontface1_GetKerningPairAdjustments
,
1182 dwritefontface1_HasKerningPairs
,
1183 dwritefontface1_GetRecommendedRenderingMode
,
1184 dwritefontface1_GetVerticalGlyphVariants
,
1185 dwritefontface1_HasVerticalGlyphVariants
,
1186 dwritefontface2_IsColorFont
,
1187 dwritefontface2_GetColorPaletteCount
,
1188 dwritefontface2_GetPaletteEntryCount
,
1189 dwritefontface2_GetPaletteEntries
,
1190 dwritefontface2_GetRecommendedRenderingMode
,
1191 dwritefontface3_GetFontFaceReference
,
1192 dwritefontface3_GetPanose
,
1193 dwritefontface3_GetWeight
,
1194 dwritefontface3_GetStretch
,
1195 dwritefontface3_GetStyle
,
1196 dwritefontface3_GetFamilyNames
,
1197 dwritefontface3_GetFaceNames
,
1198 dwritefontface3_GetInformationalStrings
,
1199 dwritefontface3_HasCharacter
,
1200 dwritefontface3_GetRecommendedRenderingMode
,
1201 dwritefontface3_IsCharacterLocal
,
1202 dwritefontface3_IsGlyphLocal
,
1203 dwritefontface3_AreCharactersLocal
,
1204 dwritefontface3_AreGlyphsLocal
1207 static HRESULT
get_fontface_from_font(struct dwrite_font
*font
, IDWriteFontFace3
**fontface
)
1209 struct dwrite_font_data
*data
= font
->data
;
1210 IDWriteFontFace
*face
;
1215 hr
= IDWriteFactory2_CreateFontFace(data
->factory
, data
->face_type
, 1, &data
->file
,
1216 data
->face_index
, font
->data
->simulations
, &face
);
1220 hr
= IDWriteFontFace_QueryInterface(face
, &IID_IDWriteFontFace3
, (void**)fontface
);
1221 IDWriteFontFace_Release(face
);
1226 static HRESULT WINAPI
dwritefont_QueryInterface(IDWriteFont2
*iface
, REFIID riid
, void **obj
)
1228 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1230 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
1232 if (IsEqualIID(riid
, &IID_IDWriteFont2
) ||
1233 IsEqualIID(riid
, &IID_IDWriteFont1
) ||
1234 IsEqualIID(riid
, &IID_IDWriteFont
) ||
1235 IsEqualIID(riid
, &IID_IUnknown
))
1238 IDWriteFont2_AddRef(iface
);
1243 return E_NOINTERFACE
;
1246 static ULONG WINAPI
dwritefont_AddRef(IDWriteFont2
*iface
)
1248 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1249 ULONG ref
= InterlockedIncrement(&This
->ref
);
1250 TRACE("(%p)->(%d)\n", This
, ref
);
1254 static ULONG WINAPI
dwritefont_Release(IDWriteFont2
*iface
)
1256 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1257 ULONG ref
= InterlockedDecrement(&This
->ref
);
1259 TRACE("(%p)->(%d)\n", This
, ref
);
1262 IDWriteFontFamily_Release(This
->family
);
1263 release_font_data(This
->data
);
1270 static HRESULT WINAPI
dwritefont_GetFontFamily(IDWriteFont2
*iface
, IDWriteFontFamily
**family
)
1272 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1273 TRACE("(%p)->(%p)\n", This
, family
);
1275 *family
= This
->family
;
1276 IDWriteFontFamily_AddRef(*family
);
1280 static DWRITE_FONT_WEIGHT WINAPI
dwritefont_GetWeight(IDWriteFont2
*iface
)
1282 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1283 TRACE("(%p)\n", This
);
1284 return This
->data
->weight
;
1287 static DWRITE_FONT_STRETCH WINAPI
dwritefont_GetStretch(IDWriteFont2
*iface
)
1289 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1290 TRACE("(%p)\n", This
);
1291 return This
->data
->stretch
;
1294 static DWRITE_FONT_STYLE WINAPI
dwritefont_GetStyle(IDWriteFont2
*iface
)
1296 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1297 TRACE("(%p)\n", This
);
1301 static BOOL WINAPI
dwritefont_IsSymbolFont(IDWriteFont2
*iface
)
1303 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1304 IDWriteFontFace3
*fontface
;
1307 TRACE("(%p)\n", This
);
1309 hr
= get_fontface_from_font(This
, &fontface
);
1313 return IDWriteFontFace3_IsSymbolFont(fontface
);
1316 static HRESULT WINAPI
dwritefont_GetFaceNames(IDWriteFont2
*iface
, IDWriteLocalizedStrings
**names
)
1318 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1319 TRACE("(%p)->(%p)\n", This
, names
);
1320 return clone_localizedstring(This
->data
->names
, names
);
1323 static HRESULT WINAPI
dwritefont_GetInformationalStrings(IDWriteFont2
*iface
,
1324 DWRITE_INFORMATIONAL_STRING_ID stringid
, IDWriteLocalizedStrings
**strings
, BOOL
*exists
)
1326 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1327 struct dwrite_font_data
*data
= This
->data
;
1330 TRACE("(%p)->(%d %p %p)\n", This
, stringid
, strings
, exists
);
1335 if (stringid
> DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME
|| stringid
== DWRITE_INFORMATIONAL_STRING_NONE
)
1338 if (!data
->info_strings
[stringid
]) {
1339 IDWriteFontFace3
*fontface
;
1340 const void *table_data
;
1345 hr
= get_fontface_from_font(This
, &fontface
);
1349 table_exists
= FALSE
;
1350 hr
= IDWriteFontFace3_TryGetFontTable(fontface
, MS_NAME_TAG
, &table_data
, &size
, &context
, &table_exists
);
1351 if (FAILED(hr
) || !table_exists
)
1352 WARN("no NAME table found.\n");
1355 hr
= opentype_get_font_info_strings(table_data
, stringid
, &data
->info_strings
[stringid
]);
1356 if (FAILED(hr
) || !data
->info_strings
[stringid
])
1358 IDWriteFontFace3_ReleaseFontTable(fontface
, context
);
1362 hr
= clone_localizedstring(data
->info_strings
[stringid
], strings
);
1370 static DWRITE_FONT_SIMULATIONS WINAPI
dwritefont_GetSimulations(IDWriteFont2
*iface
)
1372 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1373 TRACE("(%p)\n", This
);
1374 return This
->data
->simulations
;
1377 static void WINAPI
dwritefont_GetMetrics(IDWriteFont2
*iface
, DWRITE_FONT_METRICS
*metrics
)
1379 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1381 TRACE("(%p)->(%p)\n", This
, metrics
);
1382 memcpy(metrics
, &This
->data
->metrics
, sizeof(*metrics
));
1385 static HRESULT WINAPI
dwritefont_HasCharacter(IDWriteFont2
*iface
, UINT32 value
, BOOL
*exists
)
1387 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1388 IDWriteFontFace3
*fontface
;
1392 TRACE("(%p)->(0x%08x %p)\n", This
, value
, exists
);
1396 hr
= get_fontface_from_font(This
, &fontface
);
1401 hr
= IDWriteFontFace3_GetGlyphIndices(fontface
, &value
, 1, &index
);
1405 *exists
= index
!= 0;
1409 static HRESULT WINAPI
dwritefont_CreateFontFace(IDWriteFont2
*iface
, IDWriteFontFace
**face
)
1411 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1414 TRACE("(%p)->(%p)\n", This
, face
);
1416 hr
= get_fontface_from_font(This
, (IDWriteFontFace3
**)face
);
1418 IDWriteFontFace_AddRef(*face
);
1423 static void WINAPI
dwritefont1_GetMetrics(IDWriteFont2
*iface
, DWRITE_FONT_METRICS1
*metrics
)
1425 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1426 TRACE("(%p)->(%p)\n", This
, metrics
);
1427 *metrics
= This
->data
->metrics
;
1430 static void WINAPI
dwritefont1_GetPanose(IDWriteFont2
*iface
, DWRITE_PANOSE
*panose
)
1432 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1433 TRACE("(%p)->(%p)\n", This
, panose
);
1434 *panose
= This
->data
->panose
;
1437 static HRESULT WINAPI
dwritefont1_GetUnicodeRanges(IDWriteFont2
*iface
, UINT32 max_count
, DWRITE_UNICODE_RANGE
*ranges
, UINT32
*count
)
1439 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1440 IDWriteFontFace3
*fontface
;
1443 TRACE("(%p)->(%u %p %p)\n", This
, max_count
, ranges
, count
);
1445 hr
= get_fontface_from_font(This
, &fontface
);
1449 return IDWriteFontFace3_GetUnicodeRanges(fontface
, max_count
, ranges
, count
);
1452 static BOOL WINAPI
dwritefont1_IsMonospacedFont(IDWriteFont2
*iface
)
1454 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1455 IDWriteFontFace3
*fontface
;
1458 TRACE("(%p)\n", This
);
1460 hr
= get_fontface_from_font(This
, &fontface
);
1464 return IDWriteFontFace3_IsMonospacedFont(fontface
);
1467 static BOOL WINAPI
dwritefont2_IsColorFont(IDWriteFont2
*iface
)
1469 struct dwrite_font
*This
= impl_from_IDWriteFont2(iface
);
1470 IDWriteFontFace3
*fontface
;
1473 TRACE("(%p)\n", This
);
1475 hr
= get_fontface_from_font(This
, &fontface
);
1479 return IDWriteFontFace3_IsColorFont(fontface
);
1482 static const IDWriteFont2Vtbl dwritefontvtbl
= {
1483 dwritefont_QueryInterface
,
1486 dwritefont_GetFontFamily
,
1487 dwritefont_GetWeight
,
1488 dwritefont_GetStretch
,
1489 dwritefont_GetStyle
,
1490 dwritefont_IsSymbolFont
,
1491 dwritefont_GetFaceNames
,
1492 dwritefont_GetInformationalStrings
,
1493 dwritefont_GetSimulations
,
1494 dwritefont_GetMetrics
,
1495 dwritefont_HasCharacter
,
1496 dwritefont_CreateFontFace
,
1497 dwritefont1_GetMetrics
,
1498 dwritefont1_GetPanose
,
1499 dwritefont1_GetUnicodeRanges
,
1500 dwritefont1_IsMonospacedFont
,
1501 dwritefont2_IsColorFont
1504 static HRESULT
create_font(struct dwrite_font_data
*data
, IDWriteFontFamily
*family
, IDWriteFont
**font
)
1506 struct dwrite_font
*This
;
1509 This
= heap_alloc(sizeof(struct dwrite_font
));
1510 if (!This
) return E_OUTOFMEMORY
;
1512 This
->IDWriteFont2_iface
.lpVtbl
= &dwritefontvtbl
;
1514 This
->family
= family
;
1515 IDWriteFontFamily_AddRef(family
);
1516 This
->style
= data
->style
;
1518 InterlockedIncrement(&This
->data
->ref
);
1520 *font
= (IDWriteFont
*)&This
->IDWriteFont2_iface
;
1525 /* IDWriteFontList */
1526 static HRESULT WINAPI
dwritefontlist_QueryInterface(IDWriteFontList
*iface
, REFIID riid
, void **obj
)
1528 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1530 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
1532 if (IsEqualIID(riid
, &IID_IDWriteFontList
) ||
1533 IsEqualIID(riid
, &IID_IUnknown
))
1536 IDWriteFontList_AddRef(iface
);
1541 return E_NOINTERFACE
;
1544 static ULONG WINAPI
dwritefontlist_AddRef(IDWriteFontList
*iface
)
1546 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1547 ULONG ref
= InterlockedIncrement(&This
->ref
);
1548 TRACE("(%p)->(%d)\n", This
, ref
);
1552 static ULONG WINAPI
dwritefontlist_Release(IDWriteFontList
*iface
)
1554 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1555 ULONG ref
= InterlockedDecrement(&This
->ref
);
1557 TRACE("(%p)->(%d)\n", This
, ref
);
1562 for (i
= 0; i
< This
->font_count
; i
++)
1563 release_font_data(This
->fonts
[i
]);
1564 IDWriteFontFamily_Release(This
->family
);
1571 static HRESULT WINAPI
dwritefontlist_GetFontCollection(IDWriteFontList
*iface
, IDWriteFontCollection
**collection
)
1573 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1574 return IDWriteFontFamily_GetFontCollection(This
->family
, collection
);
1577 static UINT32 WINAPI
dwritefontlist_GetFontCount(IDWriteFontList
*iface
)
1579 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1580 TRACE("(%p)\n", This
);
1581 return This
->font_count
;
1584 static HRESULT WINAPI
dwritefontlist_GetFont(IDWriteFontList
*iface
, UINT32 index
, IDWriteFont
**font
)
1586 struct dwrite_fontlist
*This
= impl_from_IDWriteFontList(iface
);
1588 TRACE("(%p)->(%u %p)\n", This
, index
, font
);
1592 if (This
->font_count
== 0)
1595 if (index
>= This
->font_count
)
1596 return E_INVALIDARG
;
1598 return create_font(This
->fonts
[index
], This
->family
, font
);
1601 static const IDWriteFontListVtbl dwritefontlistvtbl
= {
1602 dwritefontlist_QueryInterface
,
1603 dwritefontlist_AddRef
,
1604 dwritefontlist_Release
,
1605 dwritefontlist_GetFontCollection
,
1606 dwritefontlist_GetFontCount
,
1607 dwritefontlist_GetFont
1610 static HRESULT WINAPI
dwritefontfamily_QueryInterface(IDWriteFontFamily
*iface
, REFIID riid
, void **obj
)
1612 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1613 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
1615 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1616 IsEqualIID(riid
, &IID_IDWriteFontList
) ||
1617 IsEqualIID(riid
, &IID_IDWriteFontFamily
))
1620 IDWriteFontFamily_AddRef(iface
);
1625 return E_NOINTERFACE
;
1628 static ULONG WINAPI
dwritefontfamily_AddRef(IDWriteFontFamily
*iface
)
1630 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1631 ULONG ref
= InterlockedIncrement(&This
->ref
);
1632 TRACE("(%p)->(%d)\n", This
, ref
);
1636 static ULONG WINAPI
dwritefontfamily_Release(IDWriteFontFamily
*iface
)
1638 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1639 ULONG ref
= InterlockedDecrement(&This
->ref
);
1641 TRACE("(%p)->(%d)\n", This
, ref
);
1645 IDWriteFontCollection_Release(This
->collection
);
1646 release_fontfamily_data(This
->data
);
1653 static HRESULT WINAPI
dwritefontfamily_GetFontCollection(IDWriteFontFamily
*iface
, IDWriteFontCollection
**collection
)
1655 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1656 TRACE("(%p)->(%p)\n", This
, collection
);
1658 *collection
= This
->collection
;
1659 IDWriteFontCollection_AddRef(This
->collection
);
1663 static UINT32 WINAPI
dwritefontfamily_GetFontCount(IDWriteFontFamily
*iface
)
1665 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1666 TRACE("(%p)\n", This
);
1667 return This
->data
->font_count
;
1670 static HRESULT WINAPI
dwritefontfamily_GetFont(IDWriteFontFamily
*iface
, UINT32 index
, IDWriteFont
**font
)
1672 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1674 TRACE("(%p)->(%u %p)\n", This
, index
, font
);
1678 if (This
->data
->font_count
== 0)
1681 if (index
>= This
->data
->font_count
)
1682 return E_INVALIDARG
;
1684 return create_font(This
->data
->fonts
[index
], iface
, font
);
1687 static HRESULT WINAPI
dwritefontfamily_GetFamilyNames(IDWriteFontFamily
*iface
, IDWriteLocalizedStrings
**names
)
1689 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1690 return clone_localizedstring(This
->data
->familyname
, names
);
1693 static BOOL
is_better_font_match(const struct dwrite_font_propvec
*next
, const struct dwrite_font_propvec
*cur
,
1694 const struct dwrite_font_propvec
*req
)
1696 FLOAT cur_to_req
= get_font_prop_vec_distance(cur
, req
);
1697 FLOAT next_to_req
= get_font_prop_vec_distance(next
, req
);
1698 FLOAT cur_req_prod
, next_req_prod
;
1700 if (next_to_req
< cur_to_req
)
1703 if (next_to_req
> cur_to_req
)
1706 cur_req_prod
= get_font_prop_vec_dotproduct(cur
, req
);
1707 next_req_prod
= get_font_prop_vec_dotproduct(next
, req
);
1709 if (next_req_prod
> cur_req_prod
)
1712 if (next_req_prod
< cur_req_prod
)
1715 if (next
->stretch
> cur
->stretch
)
1717 if (next
->stretch
< cur
->stretch
)
1720 if (next
->style
> cur
->style
)
1722 if (next
->style
< cur
->style
)
1725 if (next
->weight
> cur
->weight
)
1727 if (next
->weight
< cur
->weight
)
1730 /* full match, no reason to prefer new variant */
1734 static HRESULT WINAPI
dwritefontfamily_GetFirstMatchingFont(IDWriteFontFamily
*iface
, DWRITE_FONT_WEIGHT weight
,
1735 DWRITE_FONT_STRETCH stretch
, DWRITE_FONT_STYLE style
, IDWriteFont
**font
)
1737 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1738 struct dwrite_font_propvec req
;
1739 struct dwrite_font_data
*match
;
1742 TRACE("(%p)->(%d %d %d %p)\n", This
, weight
, stretch
, style
, font
);
1744 if (This
->data
->font_count
== 0) {
1746 return DWRITE_E_NOFONT
;
1749 init_font_prop_vec(weight
, stretch
, style
, &req
);
1750 match
= This
->data
->fonts
[0];
1752 for (i
= 1; i
< This
->data
->font_count
; i
++) {
1753 if (is_better_font_match(&This
->data
->fonts
[i
]->propvec
, &match
->propvec
, &req
))
1754 match
= This
->data
->fonts
[i
];
1757 return create_font(match
, iface
, font
);
1760 typedef BOOL (*matching_filter_func
)(const struct dwrite_font_data
*);
1762 static BOOL
is_font_acceptable_for_normal(const struct dwrite_font_data
*font
)
1764 return font
->style
== DWRITE_FONT_STYLE_NORMAL
|| font
->style
== DWRITE_FONT_STYLE_ITALIC
;
1767 static BOOL
is_font_acceptable_for_oblique_italic(const struct dwrite_font_data
*font
)
1769 return font
->style
== DWRITE_FONT_STYLE_OBLIQUE
|| font
->style
== DWRITE_FONT_STYLE_ITALIC
;
1772 static void matchingfonts_sort(struct dwrite_fontlist
*fonts
, const struct dwrite_font_propvec
*req
)
1774 UINT32 b
= fonts
->font_count
- 1, j
, t
;
1779 for (j
= 0; j
< b
; j
++) {
1780 if (is_better_font_match(&fonts
->fonts
[j
+1]->propvec
, &fonts
->fonts
[j
]->propvec
, req
)) {
1781 struct dwrite_font_data
*s
= fonts
->fonts
[j
];
1782 fonts
->fonts
[j
] = fonts
->fonts
[j
+1];
1783 fonts
->fonts
[j
+1] = s
;
1794 static HRESULT WINAPI
dwritefontfamily_GetMatchingFonts(IDWriteFontFamily
*iface
, DWRITE_FONT_WEIGHT weight
,
1795 DWRITE_FONT_STRETCH stretch
, DWRITE_FONT_STYLE style
, IDWriteFontList
**ret
)
1797 struct dwrite_fontfamily
*This
= impl_from_IDWriteFontFamily(iface
);
1798 matching_filter_func func
= NULL
;
1799 struct dwrite_font_propvec req
;
1800 struct dwrite_fontlist
*fonts
;
1803 TRACE("(%p)->(%d %d %d %p)\n", This
, weight
, stretch
, style
, ret
);
1807 fonts
= heap_alloc(sizeof(*fonts
));
1809 return E_OUTOFMEMORY
;
1811 /* Allocate as many as family has, not all of them will be necessary used. */
1812 fonts
->fonts
= heap_alloc(sizeof(*fonts
->fonts
) * This
->data
->font_count
);
1813 if (!fonts
->fonts
) {
1815 return E_OUTOFMEMORY
;
1818 fonts
->IDWriteFontList_iface
.lpVtbl
= &dwritefontlistvtbl
;
1820 fonts
->family
= iface
;
1821 IDWriteFontFamily_AddRef(fonts
->family
);
1822 fonts
->font_count
= 0;
1824 /* Normal style accepts Normal or Italic, Oblique and Italic - both Oblique and Italic styles */
1825 if (style
== DWRITE_FONT_STYLE_NORMAL
) {
1826 if (This
->data
->has_normal_face
|| This
->data
->has_italic_face
)
1827 func
= is_font_acceptable_for_normal
;
1829 else /* requested oblique or italic */ {
1830 if (This
->data
->has_oblique_face
|| This
->data
->has_italic_face
)
1831 func
= is_font_acceptable_for_oblique_italic
;
1834 for (i
= 0; i
< This
->data
->font_count
; i
++) {
1835 if (!func
|| func(This
->data
->fonts
[i
])) {
1836 fonts
->fonts
[fonts
->font_count
] = This
->data
->fonts
[i
];
1837 InterlockedIncrement(&This
->data
->fonts
[i
]->ref
);
1838 fonts
->font_count
++;
1842 /* now potential matches are sorted using same criteria GetFirstMatchingFont uses */
1843 init_font_prop_vec(weight
, stretch
, style
, &req
);
1844 matchingfonts_sort(fonts
, &req
);
1846 *ret
= &fonts
->IDWriteFontList_iface
;
1850 static const IDWriteFontFamilyVtbl fontfamilyvtbl
= {
1851 dwritefontfamily_QueryInterface
,
1852 dwritefontfamily_AddRef
,
1853 dwritefontfamily_Release
,
1854 dwritefontfamily_GetFontCollection
,
1855 dwritefontfamily_GetFontCount
,
1856 dwritefontfamily_GetFont
,
1857 dwritefontfamily_GetFamilyNames
,
1858 dwritefontfamily_GetFirstMatchingFont
,
1859 dwritefontfamily_GetMatchingFonts
1862 static HRESULT
create_fontfamily(struct dwrite_fontfamily_data
*data
, IDWriteFontCollection
*collection
, IDWriteFontFamily
**family
)
1864 struct dwrite_fontfamily
*This
;
1868 This
= heap_alloc(sizeof(struct dwrite_fontfamily
));
1869 if (!This
) return E_OUTOFMEMORY
;
1871 This
->IDWriteFontFamily_iface
.lpVtbl
= &fontfamilyvtbl
;
1873 This
->collection
= collection
;
1874 IDWriteFontCollection_AddRef(collection
);
1876 InterlockedIncrement(&This
->data
->ref
);
1878 *family
= &This
->IDWriteFontFamily_iface
;
1883 BOOL
is_system_collection(IDWriteFontCollection
*collection
)
1886 return IDWriteFontCollection_QueryInterface(collection
, &IID_issystemcollection
, (void**)&obj
) == S_OK
;
1889 static HRESULT WINAPI
dwritefontcollection_QueryInterface(IDWriteFontCollection
*iface
, REFIID riid
, void **obj
)
1891 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1892 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
1894 if (IsEqualIID(riid
, &IID_IUnknown
) ||
1895 IsEqualIID(riid
, &IID_IDWriteFontCollection
))
1898 IDWriteFontCollection_AddRef(iface
);
1904 if (This
->is_system
&& IsEqualIID(riid
, &IID_issystemcollection
))
1907 return E_NOINTERFACE
;
1910 static ULONG WINAPI
dwritefontcollection_AddRef(IDWriteFontCollection
*iface
)
1912 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1913 ULONG ref
= InterlockedIncrement(&This
->ref
);
1914 TRACE("(%p)->(%d)\n", This
, ref
);
1918 static ULONG WINAPI
dwritefontcollection_Release(IDWriteFontCollection
*iface
)
1921 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1922 ULONG ref
= InterlockedDecrement(&This
->ref
);
1923 TRACE("(%p)->(%d)\n", This
, ref
);
1926 for (i
= 0; i
< This
->family_count
; i
++)
1927 release_fontfamily_data(This
->family_data
[i
]);
1928 heap_free(This
->family_data
);
1935 static UINT32 WINAPI
dwritefontcollection_GetFontFamilyCount(IDWriteFontCollection
*iface
)
1937 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1938 TRACE("(%p)\n", This
);
1939 return This
->family_count
;
1942 static HRESULT WINAPI
dwritefontcollection_GetFontFamily(IDWriteFontCollection
*iface
, UINT32 index
, IDWriteFontFamily
**family
)
1944 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1946 TRACE("(%p)->(%u %p)\n", This
, index
, family
);
1948 if (index
>= This
->family_count
) {
1953 return create_fontfamily(This
->family_data
[index
], iface
, family
);
1956 static UINT32
collection_find_family(struct dwrite_fontcollection
*collection
, const WCHAR
*name
)
1960 for (i
= 0; i
< collection
->family_count
; i
++) {
1961 IDWriteLocalizedStrings
*family_name
= collection
->family_data
[i
]->familyname
;
1962 UINT32 j
, count
= IDWriteLocalizedStrings_GetCount(family_name
);
1965 for (j
= 0; j
< count
; j
++) {
1967 hr
= IDWriteLocalizedStrings_GetString(family_name
, j
, buffer
, 255);
1968 if (SUCCEEDED(hr
) && !strcmpiW(buffer
, name
))
1976 static HRESULT WINAPI
dwritefontcollection_FindFamilyName(IDWriteFontCollection
*iface
, const WCHAR
*name
, UINT32
*index
, BOOL
*exists
)
1978 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
1979 TRACE("(%p)->(%s %p %p)\n", This
, debugstr_w(name
), index
, exists
);
1980 *index
= collection_find_family(This
, name
);
1981 *exists
= *index
!= ~0u;
1985 static BOOL
is_same_fontfile(IDWriteFontFile
*left
, IDWriteFontFile
*right
)
1987 UINT32 left_key_size
, right_key_size
;
1988 const void *left_key
, *right_key
;
1994 hr
= IDWriteFontFile_GetReferenceKey(left
, &left_key
, &left_key_size
);
1998 hr
= IDWriteFontFile_GetReferenceKey(right
, &right_key
, &right_key_size
);
2002 if (left_key_size
!= right_key_size
)
2005 return !memcmp(left_key
, right_key
, left_key_size
);
2008 static HRESULT WINAPI
dwritefontcollection_GetFontFromFontFace(IDWriteFontCollection
*iface
, IDWriteFontFace
*face
, IDWriteFont
**font
)
2010 struct dwrite_fontcollection
*This
= impl_from_IDWriteFontCollection(iface
);
2011 struct dwrite_fontfamily_data
*found_family
= NULL
;
2012 struct dwrite_font_data
*found_font
= NULL
;
2013 IDWriteFontFamily
*family
;
2014 UINT32 i
, j
, face_index
;
2015 IDWriteFontFile
*file
;
2018 TRACE("(%p)->(%p %p)\n", This
, face
, font
);
2023 return E_INVALIDARG
;
2026 hr
= IDWriteFontFace_GetFiles(face
, &i
, &file
);
2029 face_index
= IDWriteFontFace_GetIndex(face
);
2031 for (i
= 0; i
< This
->family_count
; i
++) {
2032 struct dwrite_fontfamily_data
*family_data
= This
->family_data
[i
];
2033 for (j
= 0; j
< family_data
->font_count
; j
++) {
2034 struct dwrite_font_data
*font_data
= family_data
->fonts
[j
];
2036 if (face_index
== font_data
->face_index
&& is_same_fontfile(file
, font_data
->file
)) {
2037 found_font
= font_data
;
2038 found_family
= family_data
;
2045 return DWRITE_E_NOFONT
;
2047 hr
= create_fontfamily(found_family
, iface
, &family
);
2051 hr
= create_font(found_font
, family
, font
);
2052 IDWriteFontFamily_Release(family
);
2056 static const IDWriteFontCollectionVtbl fontcollectionvtbl
= {
2057 dwritefontcollection_QueryInterface
,
2058 dwritefontcollection_AddRef
,
2059 dwritefontcollection_Release
,
2060 dwritefontcollection_GetFontFamilyCount
,
2061 dwritefontcollection_GetFontFamily
,
2062 dwritefontcollection_FindFamilyName
,
2063 dwritefontcollection_GetFontFromFontFace
2066 static HRESULT
fontfamily_add_font(struct dwrite_fontfamily_data
*family_data
, struct dwrite_font_data
*font_data
)
2068 if (family_data
->font_count
+ 1 >= family_data
->font_alloc
) {
2069 struct dwrite_font_data
**new_list
;
2072 new_alloc
= family_data
->font_alloc
* 2;
2073 new_list
= heap_realloc(family_data
->fonts
, sizeof(*family_data
->fonts
) * new_alloc
);
2075 return E_OUTOFMEMORY
;
2076 family_data
->fonts
= new_list
;
2077 family_data
->font_alloc
= new_alloc
;
2080 family_data
->fonts
[family_data
->font_count
] = font_data
;
2081 family_data
->font_count
++;
2082 if (font_data
->style
== DWRITE_FONT_STYLE_NORMAL
)
2083 family_data
->has_normal_face
= 1;
2084 else if (font_data
->style
== DWRITE_FONT_STYLE_OBLIQUE
)
2085 family_data
->has_oblique_face
= 1;
2087 family_data
->has_italic_face
= 1;
2091 static HRESULT
fontcollection_add_family(struct dwrite_fontcollection
*collection
, struct dwrite_fontfamily_data
*family
)
2093 if (collection
->family_alloc
< collection
->family_count
+ 1) {
2094 struct dwrite_fontfamily_data
**new_list
;
2097 new_alloc
= collection
->family_alloc
* 2;
2098 new_list
= heap_realloc(collection
->family_data
, sizeof(*new_list
) * new_alloc
);
2100 return E_OUTOFMEMORY
;
2102 collection
->family_alloc
= new_alloc
;
2103 collection
->family_data
= new_list
;
2106 collection
->family_data
[collection
->family_count
] = family
;
2107 collection
->family_count
++;
2112 static HRESULT
init_font_collection(struct dwrite_fontcollection
*collection
, BOOL is_system
)
2114 collection
->IDWriteFontCollection_iface
.lpVtbl
= &fontcollectionvtbl
;
2115 collection
->ref
= 1;
2116 collection
->family_count
= 0;
2117 collection
->family_alloc
= is_system
? 30 : 5;
2118 collection
->is_system
= is_system
;
2120 collection
->family_data
= heap_alloc(sizeof(*collection
->family_data
) * collection
->family_alloc
);
2121 if (!collection
->family_data
)
2122 return E_OUTOFMEMORY
;
2127 HRESULT
get_filestream_from_file(IDWriteFontFile
*file
, IDWriteFontFileStream
**stream
)
2129 IDWriteFontFileLoader
*loader
;
2136 hr
= IDWriteFontFile_GetReferenceKey(file
, &key
, &key_size
);
2140 hr
= IDWriteFontFile_GetLoader(file
, &loader
);
2144 hr
= IDWriteFontFileLoader_CreateStreamFromKey(loader
, key
, key_size
, stream
);
2145 IDWriteFontFileLoader_Release(loader
);
2152 static void fontstrings_get_en_string(IDWriteLocalizedStrings
*strings
, WCHAR
*buffer
, UINT32 size
)
2154 BOOL exists
= FALSE
;
2159 hr
= IDWriteLocalizedStrings_FindLocaleName(strings
, enusW
, &index
, &exists
);
2160 if (FAILED(hr
) || !exists
)
2163 IDWriteLocalizedStrings_GetString(strings
, index
, buffer
, size
);
2166 static int trim_spaces(WCHAR
*in
, WCHAR
*ret
)
2170 while (isspaceW(*in
))
2174 if (!(len
= strlenW(in
)))
2177 while (isspaceW(in
[len
-1]))
2180 memcpy(ret
, in
, len
*sizeof(WCHAR
));
2189 INT len
; /* token length */
2190 INT fulllen
; /* full length including following separators */
2193 static inline BOOL
is_name_separator_char(WCHAR ch
)
2195 return ch
== ' ' || ch
== '.' || ch
== '-' || ch
== '_';
2198 struct name_pattern
{
2199 const WCHAR
*part1
; /* NULL indicates end of list */
2200 const WCHAR
*part2
; /* optional, if not NULL should point to non-empty string */
2203 static BOOL
match_pattern_list(struct list
*tokens
, const struct name_pattern
*patterns
, struct name_token
*match
)
2205 const struct name_pattern
*pattern
;
2206 struct name_token
*token
;
2209 while ((pattern
= &patterns
[i
++])->part1
) {
2210 int len_part1
= strlenW(pattern
->part1
);
2211 int len_part2
= pattern
->part2
? strlenW(pattern
->part2
) : 0;
2213 LIST_FOR_EACH_ENTRY(token
, tokens
, struct name_token
, entry
) {
2214 if (len_part2
== 0) {
2215 /* simple case with single part pattern */
2216 if (token
->len
!= len_part1
)
2219 if (!strncmpiW(token
->ptr
, pattern
->part1
, len_part1
)) {
2220 if (match
) *match
= *token
;
2221 list_remove(&token
->entry
);
2227 struct name_token
*next_token
;
2228 struct list
*next_entry
;
2230 /* pattern parts are stored in reading order, tokens list is reversed */
2231 if (token
->len
< len_part2
)
2234 /* it's possible to have combined string as a token, like ExtraCondensed */
2235 if (token
->len
== len_part1
+ len_part2
) {
2236 if (strncmpiW(token
->ptr
, pattern
->part1
, len_part1
))
2239 if (strncmpiW(&token
->ptr
[len_part1
], pattern
->part2
, len_part2
))
2242 /* combined string match */
2243 if (match
) *match
= *token
;
2244 list_remove(&token
->entry
);
2249 /* now it's only possible to have two tokens matched to respective pattern parts */
2250 if (token
->len
!= len_part2
)
2253 next_entry
= list_next(tokens
, &token
->entry
);
2255 next_token
= LIST_ENTRY(next_entry
, struct name_token
, entry
);
2256 if (next_token
->len
!= len_part1
)
2259 if (strncmpiW(token
->ptr
, pattern
->part2
, len_part2
))
2262 if (strncmpiW(next_token
->ptr
, pattern
->part1
, len_part1
))
2265 /* both parts matched, remove tokens */
2267 match
->ptr
= next_token
->ptr
;
2268 match
->len
= (token
->ptr
- next_token
->ptr
) + token
->len
;
2270 list_remove(&token
->entry
);
2271 list_remove(&next_token
->entry
);
2272 heap_free(next_token
);
2287 static DWRITE_FONT_STYLE
font_extract_style(struct list
*tokens
, DWRITE_FONT_STYLE style
, struct name_token
*match
)
2289 static const WCHAR itaW
[] = {'i','t','a',0};
2290 static const WCHAR italW
[] = {'i','t','a','l',0};
2291 static const WCHAR cursiveW
[] = {'c','u','r','s','i','v','e',0};
2292 static const WCHAR kursivW
[] = {'k','u','r','s','i','v',0};
2294 static const WCHAR inclinedW
[] = {'i','n','c','l','i','n','e','d',0};
2295 static const WCHAR backslantedW
[] = {'b','a','c','k','s','l','a','n','t','e','d',0};
2296 static const WCHAR backslantW
[] = {'b','a','c','k','s','l','a','n','t',0};
2297 static const WCHAR slantedW
[] = {'s','l','a','n','t','e','d',0};
2299 static const struct name_pattern italic_patterns
[] = {
2308 static const struct name_pattern oblique_patterns
[] = {
2317 /* italic patterns first */
2318 if (match_pattern_list(tokens
, italic_patterns
, match
))
2319 return DWRITE_FONT_STYLE_ITALIC
;
2321 /* oblique patterns */
2322 if (match_pattern_list(tokens
, oblique_patterns
, match
))
2323 return DWRITE_FONT_STYLE_OBLIQUE
;
2328 static DWRITE_FONT_STRETCH
font_extract_stretch(struct list
*tokens
, DWRITE_FONT_STRETCH stretch
,
2329 struct name_token
*match
)
2331 static const WCHAR compressedW
[] = {'c','o','m','p','r','e','s','s','e','d',0};
2332 static const WCHAR extendedW
[] = {'e','x','t','e','n','d','e','d',0};
2333 static const WCHAR compactW
[] = {'c','o','m','p','a','c','t',0};
2334 static const WCHAR narrowW
[] = {'n','a','r','r','o','w',0};
2335 static const WCHAR wideW
[] = {'w','i','d','e',0};
2336 static const WCHAR condW
[] = {'c','o','n','d',0};
2338 static const struct name_pattern ultracondensed_patterns
[] = {
2339 { extraW
, compressedW
},
2340 { extW
, compressedW
},
2341 { ultraW
, compressedW
},
2342 { ultraW
, condensedW
},
2347 static const struct name_pattern extracondensed_patterns
[] = {
2349 { extraW
, condensedW
},
2350 { extW
, condensedW
},
2356 static const struct name_pattern semicondensed_patterns
[] = {
2359 { semiW
, condensedW
},
2364 static const struct name_pattern semiexpanded_patterns
[] = {
2366 { semiW
, expandedW
},
2367 { semiW
, extendedW
},
2371 static const struct name_pattern extraexpanded_patterns
[] = {
2372 { extraW
, expandedW
},
2373 { extW
, expandedW
},
2374 { extraW
, extendedW
},
2375 { extW
, extendedW
},
2379 static const struct name_pattern ultraexpanded_patterns
[] = {
2380 { ultraW
, expandedW
},
2381 { ultraW
, extendedW
},
2385 static const struct name_pattern condensed_patterns
[] = {
2391 static const struct name_pattern expanded_patterns
[] = {
2397 if (match_pattern_list(tokens
, ultracondensed_patterns
, match
))
2398 return DWRITE_FONT_STRETCH_ULTRA_CONDENSED
;
2400 if (match_pattern_list(tokens
, extracondensed_patterns
, match
))
2401 return DWRITE_FONT_STRETCH_EXTRA_CONDENSED
;
2403 if (match_pattern_list(tokens
, semicondensed_patterns
, match
))
2404 return DWRITE_FONT_STRETCH_SEMI_CONDENSED
;
2406 if (match_pattern_list(tokens
, semiexpanded_patterns
, match
))
2407 return DWRITE_FONT_STRETCH_SEMI_EXPANDED
;
2409 if (match_pattern_list(tokens
, extraexpanded_patterns
, match
))
2410 return DWRITE_FONT_STRETCH_EXTRA_EXPANDED
;
2412 if (match_pattern_list(tokens
, ultraexpanded_patterns
, match
))
2413 return DWRITE_FONT_STRETCH_ULTRA_EXPANDED
;
2415 if (match_pattern_list(tokens
, condensed_patterns
, match
))
2416 return DWRITE_FONT_STRETCH_CONDENSED
;
2418 if (match_pattern_list(tokens
, expanded_patterns
, match
))
2419 return DWRITE_FONT_STRETCH_EXPANDED
;
2424 static DWRITE_FONT_WEIGHT
font_extract_weight(struct list
*tokens
, DWRITE_FONT_WEIGHT weight
,
2425 struct name_token
*match
)
2427 static const WCHAR heavyW
[] = {'h','e','a','v','y',0};
2428 static const WCHAR nordW
[] = {'n','o','r','d',0};
2430 static const struct name_pattern thin_patterns
[] = {
2437 static const struct name_pattern extralight_patterns
[] = {
2444 static const struct name_pattern semilight_patterns
[] = {
2449 static const struct name_pattern demibold_patterns
[] = {
2455 static const struct name_pattern extrabold_patterns
[] = {
2462 static const struct name_pattern extrablack_patterns
[] = {
2469 static const struct name_pattern bold_patterns
[] = {
2474 static const struct name_pattern thin2_patterns
[] = {
2479 static const struct name_pattern light_patterns
[] = {
2484 static const struct name_pattern medium_patterns
[] = {
2489 static const struct name_pattern black_patterns
[] = {
2496 static const struct name_pattern demibold2_patterns
[] = {
2501 static const struct name_pattern extrabold2_patterns
[] = {
2506 /* FIXME: allow optional 'face' suffix, separated or not. It's removed together with
2507 matching pattern. */
2509 if (match_pattern_list(tokens
, thin_patterns
, match
))
2510 return DWRITE_FONT_WEIGHT_THIN
;
2512 if (match_pattern_list(tokens
, extralight_patterns
, match
))
2513 return DWRITE_FONT_WEIGHT_EXTRA_LIGHT
;
2515 if (match_pattern_list(tokens
, semilight_patterns
, match
))
2516 return DWRITE_FONT_WEIGHT_SEMI_LIGHT
;
2518 if (match_pattern_list(tokens
, demibold_patterns
, match
))
2519 return DWRITE_FONT_WEIGHT_DEMI_BOLD
;
2521 if (match_pattern_list(tokens
, extrabold_patterns
, match
))
2522 return DWRITE_FONT_WEIGHT_EXTRA_BOLD
;
2524 if (match_pattern_list(tokens
, extrablack_patterns
, match
))
2525 return DWRITE_FONT_WEIGHT_EXTRA_BLACK
;
2527 if (match_pattern_list(tokens
, bold_patterns
, match
))
2528 return DWRITE_FONT_WEIGHT_BOLD
;
2530 if (match_pattern_list(tokens
, thin2_patterns
, match
))
2531 return DWRITE_FONT_WEIGHT_THIN
;
2533 if (match_pattern_list(tokens
, light_patterns
, match
))
2534 return DWRITE_FONT_WEIGHT_LIGHT
;
2536 if (match_pattern_list(tokens
, medium_patterns
, match
))
2537 return DWRITE_FONT_WEIGHT_MEDIUM
;
2539 if (match_pattern_list(tokens
, black_patterns
, match
))
2540 return DWRITE_FONT_WEIGHT_BLACK
;
2542 if (match_pattern_list(tokens
, black_patterns
, match
))
2543 return DWRITE_FONT_WEIGHT_BLACK
;
2545 if (match_pattern_list(tokens
, demibold2_patterns
, match
))
2546 return DWRITE_FONT_WEIGHT_DEMI_BOLD
;
2548 if (match_pattern_list(tokens
, extrabold2_patterns
, match
))
2549 return DWRITE_FONT_WEIGHT_EXTRA_BOLD
;
2551 /* FIXME: use abbreviated names to extract weight */
2556 struct knownweight_entry
{
2558 DWRITE_FONT_WEIGHT weight
;
2561 static int compare_knownweights(const void *a
, const void* b
)
2563 DWRITE_FONT_WEIGHT target
= *(DWRITE_FONT_WEIGHT
*)a
;
2564 const struct knownweight_entry
*entry
= (struct knownweight_entry
*)b
;
2567 if (target
> entry
->weight
)
2569 else if (target
< entry
->weight
)
2575 static BOOL
is_known_weight_value(DWRITE_FONT_WEIGHT weight
, WCHAR
*nameW
)
2577 static const WCHAR extralightW
[] = {'E','x','t','r','a',' ','L','i','g','h','t',0};
2578 static const WCHAR semilightW
[] = {'S','e','m','i',' ','L','i','g','h','t',0};
2579 static const WCHAR extrablackW
[] = {'E','x','t','r','a',' ','B','l','a','c','k',0};
2580 static const WCHAR extraboldW
[] = {'E','x','t','r','a',' ','B','o','l','d',0};
2581 static const WCHAR demiboldW
[] = {'D','e','m','i',' ','B','o','l','d',0};
2582 const struct knownweight_entry
*ptr
;
2584 static const struct knownweight_entry knownweights
[] = {
2585 { thinW
, DWRITE_FONT_WEIGHT_THIN
},
2586 { extralightW
, DWRITE_FONT_WEIGHT_EXTRA_LIGHT
},
2587 { lightW
, DWRITE_FONT_WEIGHT_LIGHT
},
2588 { semilightW
, DWRITE_FONT_WEIGHT_SEMI_LIGHT
},
2589 { mediumW
, DWRITE_FONT_WEIGHT_MEDIUM
},
2590 { demiboldW
, DWRITE_FONT_WEIGHT_DEMI_BOLD
},
2591 { boldW
, DWRITE_FONT_WEIGHT_BOLD
},
2592 { extraboldW
, DWRITE_FONT_WEIGHT_EXTRA_BOLD
},
2593 { blackW
, DWRITE_FONT_WEIGHT_BLACK
},
2594 { extrablackW
, DWRITE_FONT_WEIGHT_EXTRA_BLACK
}
2597 ptr
= bsearch(&weight
, knownweights
, sizeof(knownweights
)/sizeof(knownweights
[0]), sizeof(knownweights
[0]),
2598 compare_knownweights
);
2604 strcpyW(nameW
, ptr
->nameW
);
2608 static inline void font_name_token_to_str(const struct name_token
*name
, WCHAR
*strW
)
2610 memcpy(strW
, name
->ptr
, name
->len
* sizeof(WCHAR
));
2611 strW
[name
->len
] = 0;
2614 /* Modifies facenameW string, and returns pointer to regular term that was removed */
2615 static const WCHAR
*facename_remove_regular_term(WCHAR
*facenameW
, INT len
)
2617 static const WCHAR bookW
[] = {'B','o','o','k',0};
2618 static const WCHAR normalW
[] = {'N','o','r','m','a','l',0};
2619 static const WCHAR regularW
[] = {'R','e','g','u','l','a','r',0};
2620 static const WCHAR romanW
[] = {'R','o','m','a','n',0};
2621 static const WCHAR uprightW
[] = {'U','p','r','i','g','h','t',0};
2623 static const WCHAR
*regular_patterns
[] = {
2632 const WCHAR
*regular_ptr
= NULL
, *ptr
;
2636 len
= strlenW(facenameW
);
2638 /* remove rightmost regular variant from face name */
2639 while (!regular_ptr
&& (ptr
= regular_patterns
[i
++])) {
2640 int pattern_len
= strlenW(ptr
);
2643 if (pattern_len
> len
)
2646 src
= facenameW
+ len
- pattern_len
;
2647 while (src
>= facenameW
) {
2648 if (!strncmpiW(src
, ptr
, pattern_len
)) {
2649 memmove(src
, src
+ pattern_len
, (len
- pattern_len
- (src
- facenameW
) + 1)*sizeof(WCHAR
));
2650 len
= strlenW(facenameW
);
2662 static void fontname_tokenize(struct list
*tokens
, const WCHAR
*nameW
)
2670 struct name_token
*token
= heap_alloc(sizeof(*token
));
2675 while (*ptr
&& !is_name_separator_char(*ptr
)) {
2681 /* skip separators */
2682 while (is_name_separator_char(*ptr
)) {
2687 list_add_head(tokens
, &token
->entry
);
2691 static void fontname_tokens_to_str(struct list
*tokens
, WCHAR
*nameW
)
2693 struct name_token
*token
, *token2
;
2694 LIST_FOR_EACH_ENTRY_SAFE_REV(token
, token2
, tokens
, struct name_token
, entry
) {
2697 list_remove(&token
->entry
);
2699 /* don't include last separator */
2700 len
= list_empty(tokens
) ? token
->len
: token
->fulllen
;
2701 memcpy(nameW
, token
->ptr
, len
* sizeof(WCHAR
));
2709 static BOOL
font_apply_differentiation_rules(struct dwrite_font_data
*font
, WCHAR
*familyW
, WCHAR
*faceW
)
2711 struct name_token stretch_name
, weight_name
, style_name
;
2712 WCHAR familynameW
[255], facenameW
[255], finalW
[255];
2713 WCHAR weightW
[32], stretchW
[32], styleW
[32];
2714 const WCHAR
*regular_ptr
= NULL
;
2715 DWRITE_FONT_STRETCH stretch
;
2716 DWRITE_FONT_WEIGHT weight
;
2720 /* remove leading and trailing spaces from family and face name */
2721 trim_spaces(familyW
, familynameW
);
2722 len
= trim_spaces(faceW
, facenameW
);
2724 /* remove rightmost regular variant from face name */
2725 regular_ptr
= facename_remove_regular_term(facenameW
, len
);
2727 /* append face name to family name, FIXME check if face name is a substring of family name */
2729 strcatW(familynameW
, spaceW
);
2730 strcatW(familynameW
, facenameW
);
2733 /* tokenize with " .-_" */
2734 fontname_tokenize(&tokens
, familynameW
);
2736 /* extract and resolve style */
2737 font
->style
= font_extract_style(&tokens
, font
->style
, &style_name
);
2739 /* extract stretch */
2740 stretch
= font_extract_stretch(&tokens
, font
->stretch
, &stretch_name
);
2742 /* extract weight */
2743 weight
= font_extract_weight(&tokens
, font
->weight
, &weight_name
);
2745 /* resolve weight */
2746 if (weight
!= font
->weight
) {
2747 if (!(weight
< DWRITE_FONT_WEIGHT_NORMAL
&& font
->weight
< DWRITE_FONT_WEIGHT_NORMAL
) &&
2748 !(weight
> DWRITE_FONT_WEIGHT_MEDIUM
&& font
->weight
> DWRITE_FONT_WEIGHT_MEDIUM
) &&
2749 !((weight
== DWRITE_FONT_WEIGHT_NORMAL
&& font
->weight
== DWRITE_FONT_WEIGHT_MEDIUM
) ||
2750 (weight
== DWRITE_FONT_WEIGHT_MEDIUM
&& font
->weight
== DWRITE_FONT_WEIGHT_NORMAL
)) &&
2751 !(abs(weight
- font
->weight
) <= 150 &&
2752 font
->weight
!= DWRITE_FONT_WEIGHT_NORMAL
&&
2753 font
->weight
!= DWRITE_FONT_WEIGHT_MEDIUM
&&
2754 font
->weight
!= DWRITE_FONT_WEIGHT_BOLD
)) {
2756 font
->weight
= weight
;
2760 /* Resolve stretch - extracted stretch can't be normal, it will override specified stretch if
2761 it's leaning in opposite direction from normal comparing to specified stretch or if specified
2762 stretch itself is normal (extracted stretch is never normal). */
2763 if (stretch
!= font
->stretch
) {
2764 if ((font
->stretch
== DWRITE_FONT_STRETCH_NORMAL
) ||
2765 (font
->stretch
< DWRITE_FONT_STRETCH_NORMAL
&& stretch
> DWRITE_FONT_STRETCH_NORMAL
) ||
2766 (font
->stretch
> DWRITE_FONT_STRETCH_NORMAL
&& stretch
< DWRITE_FONT_STRETCH_NORMAL
)) {
2768 font
->stretch
= stretch
;
2772 /* FIXME: cleanup face name from possible 2-3 digit prefixes */
2774 /* get final combined string from what's left in token list, list is released */
2775 fontname_tokens_to_str(&tokens
, finalW
);
2777 if (!strcmpW(familyW
, finalW
))
2780 /* construct face name */
2781 strcpyW(familyW
, finalW
);
2783 /* resolved weight name */
2784 if (weight_name
.ptr
)
2785 font_name_token_to_str(&weight_name
, weightW
);
2786 /* ignore normal weight */
2787 else if (font
->weight
== DWRITE_FONT_WEIGHT_NORMAL
)
2789 /* for known weight values use appropriate names */
2790 else if (is_known_weight_value(font
->weight
, weightW
)) {
2792 /* use Wnnn format as a fallback in case weight is not one of known values */
2794 static const WCHAR fmtW
[] = {'W','%','d',0};
2795 sprintfW(weightW
, fmtW
, font
->weight
);
2798 /* resolved stretch name */
2799 if (stretch_name
.ptr
)
2800 font_name_token_to_str(&stretch_name
, stretchW
);
2801 /* ignore normal stretch */
2802 else if (font
->stretch
== DWRITE_FONT_STRETCH_NORMAL
)
2804 /* use predefined stretch names */
2806 static const WCHAR ultracondensedW
[] = {'U','l','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2807 static const WCHAR extracondensedW
[] = {'E','x','t','r','a',' ','C','o','n','d','e','n','s','e','d',0};
2808 static const WCHAR semicondensedW
[] = {'S','e','m','i',' ','C','o','n','d','e','n','s','e','d',0};
2809 static const WCHAR semiexpandedW
[] = {'S','e','m','i',' ','E','x','p','a','n','d','e','d',0};
2810 static const WCHAR extraexpandedW
[] = {'E','x','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2811 static const WCHAR ultraexpandedW
[] = {'U','l','t','r','a',' ','E','x','p','a','n','d','e','d',0};
2813 static const WCHAR
*stretchnamesW
[] = {
2818 NULL
, /* DWRITE_FONT_STRETCH_NORMAL */
2824 strcpyW(stretchW
, stretchnamesW
[font
->stretch
]);
2827 /* resolved style name */
2829 font_name_token_to_str(&style_name
, styleW
);
2830 else if (font
->style
== DWRITE_FONT_STYLE_NORMAL
)
2832 /* use predefined names */
2834 if (font
->style
== DWRITE_FONT_STYLE_ITALIC
)
2835 strcpyW(styleW
, italicW
);
2837 strcpyW(styleW
, obliqueW
);
2840 /* use Regular match if it was found initially */
2841 if (!*weightW
&& !*stretchW
&& !*styleW
)
2842 strcpyW(faceW
, regular_ptr
? regular_ptr
: regularW
);
2846 strcpyW(faceW
, stretchW
);
2849 strcatW(faceW
, spaceW
);
2850 strcatW(faceW
, weightW
);
2854 strcatW(faceW
, spaceW
);
2855 strcatW(faceW
, styleW
);
2859 TRACE("resolved family %s, face %s\n", debugstr_w(familyW
), debugstr_w(faceW
));
2863 static HRESULT
init_font_data(IDWriteFactory2
*factory
, IDWriteFontFile
*file
, DWRITE_FONT_FACE_TYPE face_type
, UINT32 face_index
,
2864 IDWriteLocalizedStrings
**family_name
, struct dwrite_font_data
**ret
)
2866 struct dwrite_font_props props
;
2867 struct dwrite_font_data
*data
;
2868 IDWriteFontFileStream
*stream
;
2869 WCHAR familyW
[255], faceW
[255];
2873 data
= heap_alloc_zero(sizeof(*data
));
2875 return E_OUTOFMEMORY
;
2877 hr
= get_filestream_from_file(file
, &stream
);
2884 data
->factory
= factory
;
2886 data
->face_index
= face_index
;
2887 data
->face_type
= face_type
;
2888 data
->simulations
= DWRITE_FONT_SIMULATIONS_NONE
;
2889 data
->bold_sim_tested
= 0;
2890 data
->oblique_sim_tested
= 0;
2891 IDWriteFontFile_AddRef(file
);
2892 IDWriteFactory2_AddRef(factory
);
2894 opentype_get_font_properties(stream
, face_type
, face_index
, &props
);
2895 opentype_get_font_metrics(stream
, face_type
, face_index
, &data
->metrics
, NULL
);
2896 opentype_get_font_facename(stream
, face_type
, face_index
, &data
->names
);
2898 /* get family name from font file */
2899 hr
= opentype_get_font_familyname(stream
, face_type
, face_index
, family_name
);
2900 IDWriteFontFileStream_Release(stream
);
2902 WARN("unable to get family name from font\n");
2903 release_font_data(data
);
2907 data
->style
= props
.style
;
2908 data
->stretch
= props
.stretch
;
2909 data
->weight
= props
.weight
;
2910 data
->panose
= props
.panose
;
2912 fontstrings_get_en_string(*family_name
, familyW
, sizeof(familyW
)/sizeof(WCHAR
));
2913 fontstrings_get_en_string(data
->names
, faceW
, sizeof(faceW
)/sizeof(WCHAR
));
2914 if (font_apply_differentiation_rules(data
, familyW
, faceW
)) {
2915 set_en_localizedstring(*family_name
, familyW
);
2916 set_en_localizedstring(data
->names
, faceW
);
2919 init_font_prop_vec(data
->weight
, data
->stretch
, data
->style
, &data
->propvec
);
2925 static HRESULT
init_font_data_from_font(const struct dwrite_font_data
*src
, DWRITE_FONT_SIMULATIONS sim
, const WCHAR
*facenameW
,
2926 struct dwrite_font_data
**ret
)
2928 struct dwrite_font_data
*data
;
2931 data
= heap_alloc_zero(sizeof(*data
));
2933 return E_OUTOFMEMORY
;
2937 data
->simulations
|= sim
;
2938 if (sim
== DWRITE_FONT_SIMULATIONS_BOLD
)
2939 data
->weight
= DWRITE_FONT_WEIGHT_BOLD
;
2940 else if (sim
== DWRITE_FONT_SIMULATIONS_OBLIQUE
)
2941 data
->style
= DWRITE_FONT_STYLE_OBLIQUE
;
2942 memset(data
->info_strings
, 0, sizeof(data
->info_strings
));
2944 IDWriteFactory2_AddRef(data
->factory
);
2945 IDWriteFontFile_AddRef(data
->file
);
2947 create_localizedstrings(&data
->names
);
2948 add_localizedstring(data
->names
, enusW
, facenameW
);
2950 init_font_prop_vec(data
->weight
, data
->stretch
, data
->style
, &data
->propvec
);
2956 static HRESULT
init_fontfamily_data(IDWriteLocalizedStrings
*familyname
, struct dwrite_fontfamily_data
**ret
)
2958 struct dwrite_fontfamily_data
*data
;
2960 data
= heap_alloc(sizeof(*data
));
2962 return E_OUTOFMEMORY
;
2965 data
->font_count
= 0;
2966 data
->font_alloc
= 2;
2967 data
->has_normal_face
= 0;
2968 data
->has_oblique_face
= 0;
2969 data
->has_italic_face
= 0;
2971 data
->fonts
= heap_alloc(sizeof(*data
->fonts
)*data
->font_alloc
);
2974 return E_OUTOFMEMORY
;
2977 data
->familyname
= familyname
;
2978 IDWriteLocalizedStrings_AddRef(familyname
);
2984 static void fontfamily_add_bold_simulated_face(struct dwrite_fontfamily_data
*family
)
2986 UINT32 i
, j
, heaviest
;
2988 for (i
= 0; i
< family
->font_count
; i
++) {
2989 DWRITE_FONT_WEIGHT weight
= family
->fonts
[i
]->weight
;
2992 if (family
->fonts
[i
]->bold_sim_tested
)
2995 family
->fonts
[i
]->bold_sim_tested
= 1;
2996 for (j
= i
; j
< family
->font_count
; j
++) {
2997 if (family
->fonts
[j
]->bold_sim_tested
)
3000 if ((family
->fonts
[i
]->style
== family
->fonts
[j
]->style
) &&
3001 (family
->fonts
[i
]->stretch
== family
->fonts
[j
]->stretch
)) {
3002 if (family
->fonts
[j
]->weight
> weight
) {
3003 weight
= family
->fonts
[j
]->weight
;
3006 family
->fonts
[j
]->bold_sim_tested
= 1;
3010 if (weight
>= DWRITE_FONT_WEIGHT_SEMI_LIGHT
&& weight
<= 550) {
3011 static const struct name_pattern weightsim_patterns
[] = {
3026 WCHAR facenameW
[255], initialW
[255];
3027 struct dwrite_font_data
*boldface
;
3030 /* add Bold simulation based on heaviest face data */
3032 /* Simulated face name should only contain Bold as weight term,
3033 so remove existing regular and weight terms. */
3034 fontstrings_get_en_string(family
->fonts
[heaviest
]->names
, initialW
, sizeof(initialW
)/sizeof(WCHAR
));
3035 facename_remove_regular_term(initialW
, -1);
3037 /* remove current weight pattern */
3038 fontname_tokenize(&tokens
, initialW
);
3039 match_pattern_list(&tokens
, weightsim_patterns
, NULL
);
3040 fontname_tokens_to_str(&tokens
, facenameW
);
3042 /* Bold suffix for new name */
3044 strcatW(facenameW
, spaceW
);
3045 strcatW(facenameW
, boldW
);
3047 if (init_font_data_from_font(family
->fonts
[heaviest
], DWRITE_FONT_SIMULATIONS_BOLD
, facenameW
, &boldface
) == S_OK
) {
3048 boldface
->bold_sim_tested
= 1;
3049 fontfamily_add_font(family
, boldface
);
3055 static void fontfamily_add_oblique_simulated_face(struct dwrite_fontfamily_data
*family
)
3059 for (i
= 0; i
< family
->font_count
; i
++) {
3060 UINT32 regular
= ~0u, oblique
= ~0u;
3061 struct dwrite_font_data
*obliqueface
;
3062 WCHAR facenameW
[255];
3064 if (family
->fonts
[i
]->oblique_sim_tested
)
3067 family
->fonts
[i
]->oblique_sim_tested
= 1;
3068 if (family
->fonts
[i
]->style
== DWRITE_FONT_STYLE_NORMAL
)
3070 else if (family
->fonts
[i
]->style
== DWRITE_FONT_STYLE_OBLIQUE
)
3073 /* find regular style with same weight/stretch values */
3074 for (j
= i
; j
< family
->font_count
; j
++) {
3075 if (family
->fonts
[j
]->oblique_sim_tested
)
3078 if ((family
->fonts
[i
]->weight
== family
->fonts
[j
]->weight
) &&
3079 (family
->fonts
[i
]->stretch
== family
->fonts
[j
]->stretch
)) {
3081 family
->fonts
[j
]->oblique_sim_tested
= 1;
3082 if (regular
== ~0 && family
->fonts
[j
]->style
== DWRITE_FONT_STYLE_NORMAL
)
3085 if (oblique
== ~0 && family
->fonts
[j
]->style
== DWRITE_FONT_STYLE_OBLIQUE
)
3089 if (regular
!= ~0u && oblique
!= ~0u)
3093 /* no regular variant for this weight/stretch pair, nothing to base simulated face on */
3097 /* regular face exists, and corresponding oblique is present as well, nothing to do */
3101 /* add oblique simulation based on this regular face */
3103 /* remove regular term if any, append 'Oblique' */
3104 fontstrings_get_en_string(family
->fonts
[regular
]->names
, facenameW
, sizeof(facenameW
)/sizeof(WCHAR
));
3105 facename_remove_regular_term(facenameW
, -1);
3108 strcatW(facenameW
, spaceW
);
3109 strcatW(facenameW
, obliqueW
);
3111 if (init_font_data_from_font(family
->fonts
[regular
], DWRITE_FONT_SIMULATIONS_OBLIQUE
, facenameW
, &obliqueface
) == S_OK
) {
3112 obliqueface
->oblique_sim_tested
= 1;
3113 fontfamily_add_font(family
, obliqueface
);
3118 static BOOL
fontcollection_add_replacement(struct dwrite_fontcollection
*collection
, const WCHAR
*target_name
,
3119 const WCHAR
*replacement_name
)
3121 UINT32 i
= collection_find_family(collection
, replacement_name
);
3122 struct dwrite_fontfamily_data
*target
;
3123 IDWriteLocalizedStrings
*strings
;
3126 /* replacement does not exist */
3130 hr
= create_localizedstrings(&strings
);
3134 /* add a new family with target name, reuse font data from replacement */
3135 add_localizedstring(strings
, enusW
, target_name
);
3136 hr
= init_fontfamily_data(strings
, &target
);
3138 struct dwrite_fontfamily_data
*replacement
= collection
->family_data
[i
];
3141 for (i
= 0; i
< replacement
->font_count
; i
++)
3142 fontfamily_add_font(target
, replacement
->fonts
[i
]);
3144 fontcollection_add_family(collection
, target
);
3145 fontstrings_get_en_string(replacement
->familyname
, nameW
, sizeof(nameW
)/sizeof(WCHAR
));
3146 TRACE("replacement %s -> %s\n", debugstr_w(target_name
), debugstr_w(nameW
));
3148 IDWriteLocalizedStrings_Release(strings
);
3152 /* Add family mappings from HKCU\Software\Wine\Fonts\Replacements. This only affects
3153 system font collections. */
3154 static void fontcollection_add_replacements(struct dwrite_fontcollection
*collection
)
3156 DWORD max_namelen
, max_datalen
, i
= 0, type
, datalen
, namelen
;
3161 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Fonts\\Replacements", &hkey
))
3164 if (RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_namelen
, &max_datalen
, NULL
, NULL
)) {
3169 max_namelen
++; /* returned value doesn't include room for '\0' */
3170 name
= heap_alloc(max_namelen
* sizeof(WCHAR
));
3171 data
= heap_alloc(max_datalen
);
3173 datalen
= max_datalen
;
3174 namelen
= max_namelen
;
3175 while (RegEnumValueW(hkey
, i
++, name
, &namelen
, NULL
, &type
, data
, &datalen
) == ERROR_SUCCESS
) {
3176 if (collection_find_family(collection
, name
) == ~0u) {
3177 if (type
== REG_MULTI_SZ
) {
3178 WCHAR
*replacement
= data
;
3179 while (*replacement
) {
3180 if (fontcollection_add_replacement(collection
, name
, replacement
))
3182 replacement
+= strlenW(replacement
) + 1;
3185 else if (type
== REG_SZ
)
3186 fontcollection_add_replacement(collection
, name
, data
);
3189 TRACE("%s is available, won't be replaced.\n", debugstr_w(name
));
3191 datalen
= max_datalen
;
3192 namelen
= max_namelen
;
3200 HRESULT
create_font_collection(IDWriteFactory2
* factory
, IDWriteFontFileEnumerator
*enumerator
, BOOL is_system
, IDWriteFontCollection
**ret
)
3202 struct fontfile_enum
{
3204 IDWriteFontFile
*file
;
3206 struct fontfile_enum
*fileenum
, *fileenum2
;
3207 struct dwrite_fontcollection
*collection
;
3208 struct list scannedfiles
;
3209 BOOL current
= FALSE
;
3215 collection
= heap_alloc(sizeof(struct dwrite_fontcollection
));
3216 if (!collection
) return E_OUTOFMEMORY
;
3218 hr
= init_font_collection(collection
, is_system
);
3220 heap_free(collection
);
3224 *ret
= &collection
->IDWriteFontCollection_iface
;
3226 TRACE("building font collection:\n");
3228 list_init(&scannedfiles
);
3229 while (hr
== S_OK
) {
3230 DWRITE_FONT_FACE_TYPE face_type
;
3231 DWRITE_FONT_FILE_TYPE file_type
;
3232 BOOL supported
, same
= FALSE
;
3233 IDWriteFontFile
*file
;
3237 hr
= IDWriteFontFileEnumerator_MoveNext(enumerator
, ¤t
);
3238 if (FAILED(hr
) || !current
)
3241 hr
= IDWriteFontFileEnumerator_GetCurrentFontFile(enumerator
, &file
);
3245 /* check if we've scanned this file already */
3246 LIST_FOR_EACH_ENTRY(fileenum
, &scannedfiles
, struct fontfile_enum
, entry
) {
3247 if ((same
= is_same_fontfile(fileenum
->file
, file
)))
3252 IDWriteFontFile_Release(file
);
3256 /* failed font files are skipped */
3257 hr
= IDWriteFontFile_Analyze(file
, &supported
, &file_type
, &face_type
, &face_count
);
3258 if (FAILED(hr
) || !supported
|| face_count
== 0) {
3259 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file
, hr
, supported
, face_count
);
3260 IDWriteFontFile_Release(file
);
3265 /* add to scanned list */
3266 fileenum
= heap_alloc(sizeof(*fileenum
));
3267 fileenum
->file
= file
;
3268 list_add_tail(&scannedfiles
, &fileenum
->entry
);
3270 for (i
= 0; i
< face_count
; i
++) {
3271 IDWriteLocalizedStrings
*family_name
= NULL
;
3272 struct dwrite_font_data
*font_data
;
3276 /* alloc and init new font data structure */
3277 hr
= init_font_data(factory
, file
, face_type
, i
, &family_name
, &font_data
);
3279 /* move to next one */
3284 fontstrings_get_en_string(family_name
, familyW
, sizeof(familyW
)/sizeof(WCHAR
));
3286 index
= collection_find_family(collection
, familyW
);
3288 hr
= fontfamily_add_font(collection
->family_data
[index
], font_data
);
3290 struct dwrite_fontfamily_data
*family_data
;
3292 /* create and init new family */
3293 hr
= init_fontfamily_data(family_name
, &family_data
);
3295 /* add font to family, family - to collection */
3296 hr
= fontfamily_add_font(family_data
, font_data
);
3298 hr
= fontcollection_add_family(collection
, family_data
);
3301 release_fontfamily_data(family_data
);
3305 IDWriteLocalizedStrings_Release(family_name
);
3312 LIST_FOR_EACH_ENTRY_SAFE(fileenum
, fileenum2
, &scannedfiles
, struct fontfile_enum
, entry
) {
3313 IDWriteFontFile_Release(fileenum
->file
);
3314 list_remove(&fileenum
->entry
);
3315 heap_free(fileenum
);
3318 for (i
= 0; i
< collection
->family_count
; i
++) {
3319 fontfamily_add_bold_simulated_face(collection
->family_data
[i
]);
3320 fontfamily_add_oblique_simulated_face(collection
->family_data
[i
]);
3324 fontcollection_add_replacements(collection
);
3329 struct system_fontfile_enumerator
3331 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface
;
3334 IDWriteFactory2
*factory
;
3339 static inline struct system_fontfile_enumerator
*impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator
* iface
)
3341 return CONTAINING_RECORD(iface
, struct system_fontfile_enumerator
, IDWriteFontFileEnumerator_iface
);
3344 static HRESULT WINAPI
systemfontfileenumerator_QueryInterface(IDWriteFontFileEnumerator
*iface
, REFIID riid
, void **obj
)
3348 if (IsEqualIID(riid
, &IID_IDWriteFontFileEnumerator
) || IsEqualIID(riid
, &IID_IUnknown
)) {
3349 IDWriteFontFileEnumerator_AddRef(iface
);
3354 return E_NOINTERFACE
;
3357 static ULONG WINAPI
systemfontfileenumerator_AddRef(IDWriteFontFileEnumerator
*iface
)
3359 struct system_fontfile_enumerator
*enumerator
= impl_from_IDWriteFontFileEnumerator(iface
);
3360 return InterlockedIncrement(&enumerator
->ref
);
3363 static ULONG WINAPI
systemfontfileenumerator_Release(IDWriteFontFileEnumerator
*iface
)
3365 struct system_fontfile_enumerator
*enumerator
= impl_from_IDWriteFontFileEnumerator(iface
);
3366 ULONG ref
= InterlockedDecrement(&enumerator
->ref
);
3369 IDWriteFactory2_Release(enumerator
->factory
);
3370 RegCloseKey(enumerator
->hkey
);
3371 heap_free(enumerator
);
3377 static HRESULT
create_local_file_reference(IDWriteFactory2
*factory
, const WCHAR
*filename
, IDWriteFontFile
**file
)
3381 /* Fonts installed in 'Fonts' system dir don't get full path in registry font files cache */
3382 if (!strchrW(filename
, '\\')) {
3383 static const WCHAR fontsW
[] = {'\\','f','o','n','t','s','\\',0};
3384 WCHAR fullpathW
[MAX_PATH
];
3386 GetWindowsDirectoryW(fullpathW
, sizeof(fullpathW
)/sizeof(WCHAR
));
3387 strcatW(fullpathW
, fontsW
);
3388 strcatW(fullpathW
, filename
);
3390 hr
= IDWriteFactory2_CreateFontFileReference(factory
, fullpathW
, NULL
, file
);
3393 hr
= IDWriteFactory2_CreateFontFileReference(factory
, filename
, NULL
, file
);
3398 static HRESULT WINAPI
systemfontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator
*iface
, IDWriteFontFile
**file
)
3400 struct system_fontfile_enumerator
*enumerator
= impl_from_IDWriteFontFileEnumerator(iface
);
3401 DWORD ret
, type
, val_count
, count
;
3402 WCHAR
*value
, *filename
;
3407 if (enumerator
->index
< 0)
3410 ret
= RegQueryInfoKeyW(enumerator
->hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &val_count
, &count
, NULL
, NULL
);
3411 if (ret
!= ERROR_SUCCESS
)
3415 value
= heap_alloc( val_count
* sizeof(value
[0]) );
3416 filename
= heap_alloc(count
);
3417 if (!value
|| !filename
) {
3419 heap_free(filename
);
3420 return E_OUTOFMEMORY
;
3423 ret
= RegEnumValueW(enumerator
->hkey
, enumerator
->index
, value
, &val_count
, NULL
, &type
, (BYTE
*)filename
, &count
);
3426 heap_free(filename
);
3430 hr
= create_local_file_reference(enumerator
->factory
, filename
, file
);
3433 heap_free(filename
);
3437 static HRESULT WINAPI
systemfontfileenumerator_MoveNext(IDWriteFontFileEnumerator
*iface
, BOOL
*current
)
3439 struct system_fontfile_enumerator
*enumerator
= impl_from_IDWriteFontFileEnumerator(iface
);
3440 DWORD ret
, max_val_count
;
3444 enumerator
->index
++;
3446 ret
= RegQueryInfoKeyW(enumerator
->hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &max_val_count
, NULL
, NULL
, NULL
);
3447 if (ret
!= ERROR_SUCCESS
)
3451 if (!(value
= heap_alloc( max_val_count
* sizeof(value
[0]) )))
3452 return E_OUTOFMEMORY
;
3454 /* iterate until we find next string value */
3456 DWORD type
= 0, count
, val_count
;
3457 val_count
= max_val_count
;
3458 if (RegEnumValueW(enumerator
->hkey
, enumerator
->index
, value
, &val_count
, NULL
, &type
, NULL
, &count
))
3460 if (type
== REG_SZ
) {
3464 enumerator
->index
++;
3467 TRACE("index = %d, current = %d\n", enumerator
->index
, *current
);
3472 static const struct IDWriteFontFileEnumeratorVtbl systemfontfileenumeratorvtbl
=
3474 systemfontfileenumerator_QueryInterface
,
3475 systemfontfileenumerator_AddRef
,
3476 systemfontfileenumerator_Release
,
3477 systemfontfileenumerator_MoveNext
,
3478 systemfontfileenumerator_GetCurrentFontFile
3481 static HRESULT
create_system_fontfile_enumerator(IDWriteFactory2
*factory
, IDWriteFontFileEnumerator
**ret
)
3483 struct system_fontfile_enumerator
*enumerator
;
3484 static const WCHAR fontslistW
[] = {
3485 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
3486 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3487 'F','o','n','t','s',0
3492 enumerator
= heap_alloc(sizeof(*enumerator
));
3494 return E_OUTOFMEMORY
;
3496 enumerator
->IDWriteFontFileEnumerator_iface
.lpVtbl
= &systemfontfileenumeratorvtbl
;
3497 enumerator
->ref
= 1;
3498 enumerator
->factory
= factory
;
3499 enumerator
->index
= -1;
3500 IDWriteFactory2_AddRef(factory
);
3502 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, fontslistW
, 0, GENERIC_READ
, &enumerator
->hkey
)) {
3503 ERR("failed to open fonts list key\n");
3504 IDWriteFactory2_Release(factory
);
3505 heap_free(enumerator
);
3509 *ret
= &enumerator
->IDWriteFontFileEnumerator_iface
;
3514 HRESULT
get_system_fontcollection(IDWriteFactory2
*factory
, IDWriteFontCollection
**collection
)
3516 IDWriteFontFileEnumerator
*enumerator
;
3521 hr
= create_system_fontfile_enumerator(factory
, &enumerator
);
3525 TRACE("building system font collection for factory %p\n", factory
);
3526 hr
= create_font_collection(factory
, enumerator
, TRUE
, collection
);
3527 IDWriteFontFileEnumerator_Release(enumerator
);
3531 static HRESULT
eudc_collection_add_family(IDWriteFactory2
*factory
, struct dwrite_fontcollection
*collection
,
3532 const WCHAR
*keynameW
, const WCHAR
*pathW
)
3534 static const WCHAR defaultfontW
[] = {'S','y','s','t','e','m','D','e','f','a','u','l','t','E','U','D','C','F','o','n','t',0};
3535 static const WCHAR emptyW
[] = {0};
3536 IDWriteLocalizedStrings
*names
;
3537 DWRITE_FONT_FACE_TYPE face_type
;
3538 DWRITE_FONT_FILE_TYPE file_type
;
3540 UINT32 face_count
, i
;
3541 IDWriteFontFile
*file
;
3543 struct dwrite_fontfamily_data
*family_data
;
3545 /* create font file from this path */
3546 hr
= create_local_file_reference(factory
, pathW
, &file
);
3550 /* failed font files are skipped */
3551 hr
= IDWriteFontFile_Analyze(file
, &supported
, &file_type
, &face_type
, &face_count
);
3552 if (FAILED(hr
) || !supported
|| face_count
== 0) {
3553 TRACE("unsupported font (%p, 0x%08x, %d, %u)\n", file
, hr
, supported
, face_count
);
3554 IDWriteFontFile_Release(file
);
3558 /* create and init new family */
3560 /* Family names are added for non-specific locale, represented with empty string.
3561 Default family appears with empty family name. */
3562 create_localizedstrings(&names
);
3563 if (!strcmpiW(keynameW
, defaultfontW
))
3564 add_localizedstring(names
, emptyW
, emptyW
);
3566 add_localizedstring(names
, emptyW
, keynameW
);
3568 hr
= init_fontfamily_data(names
, &family_data
);
3569 IDWriteLocalizedStrings_Release(names
);
3571 IDWriteFontFile_Release(file
);
3575 /* fill with faces */
3576 for (i
= 0; i
< face_count
; i
++) {
3577 struct dwrite_font_data
*font_data
;
3579 /* alloc and init new font data structure */
3580 hr
= init_font_data(factory
, file
, face_type
, i
, &names
, &font_data
);
3584 IDWriteLocalizedStrings_Release(names
);
3586 /* add font to family */
3587 hr
= fontfamily_add_font(family_data
, font_data
);
3589 release_font_data(font_data
);
3592 /* add family to collection */
3593 hr
= fontcollection_add_family(collection
, family_data
);
3595 release_fontfamily_data(family_data
);
3596 IDWriteFontFile_Release(file
);
3601 HRESULT
get_eudc_fontcollection(IDWriteFactory2
*factory
, IDWriteFontCollection
**ret
)
3603 static const WCHAR eudckeyfmtW
[] = {'E','U','D','C','\\','%','u',0};
3604 struct dwrite_fontcollection
*collection
;
3605 static const WCHAR emptyW
[] = {0};
3606 WCHAR eudckeypathW
[16];
3614 TRACE("building EUDC font collection for factory %p, ACP %u\n", factory
, GetACP());
3618 collection
= heap_alloc(sizeof(struct dwrite_fontcollection
));
3619 if (!collection
) return E_OUTOFMEMORY
;
3621 hr
= init_font_collection(collection
, FALSE
);
3623 heap_free(collection
);
3627 *ret
= &collection
->IDWriteFontCollection_iface
;
3629 /* return empty collection if EUDC fonts are not configured */
3630 sprintfW(eudckeypathW
, eudckeyfmtW
, GetACP());
3631 if (RegOpenKeyExW(HKEY_CURRENT_USER
, eudckeypathW
, 0, GENERIC_READ
, &eudckey
))
3634 retval
= ERROR_SUCCESS
;
3636 while (retval
!= ERROR_NO_MORE_ITEMS
) {
3637 WCHAR keynameW
[64], pathW
[MAX_PATH
];
3638 DWORD type
, path_len
, name_len
;
3640 path_len
= sizeof(pathW
)/sizeof(*pathW
);
3641 name_len
= sizeof(keynameW
)/sizeof(*keynameW
);
3642 retval
= RegEnumValueW(eudckey
, index
++, keynameW
, &name_len
, NULL
, &type
, (BYTE
*)pathW
, &path_len
);
3643 if (retval
|| type
!= REG_SZ
)
3646 hr
= eudc_collection_add_family(factory
, collection
, keynameW
, pathW
);
3648 WARN("failed to add family %s, path %s\n", debugstr_w(keynameW
), debugstr_w(pathW
));
3650 RegCloseKey(eudckey
);
3652 /* try to add global default if not defined for specific codepage */
3654 hr
= IDWriteFontCollection_FindFamilyName(&collection
->IDWriteFontCollection_iface
, emptyW
,
3656 if (FAILED(hr
) || !exists
) {
3657 const WCHAR globaldefaultW
[] = {'E','U','D','C','.','T','T','E',0};
3658 hr
= eudc_collection_add_family(factory
, collection
, emptyW
, globaldefaultW
);
3660 WARN("failed to add global default EUDC font, 0x%08x\n", hr
);
3663 /* EUDC collection offers simulated faces too */
3664 for (i
= 0; i
< collection
->family_count
; i
++) {
3665 fontfamily_add_bold_simulated_face(collection
->family_data
[i
]);
3666 fontfamily_add_oblique_simulated_face(collection
->family_data
[i
]);
3672 static HRESULT WINAPI
dwritefontfile_QueryInterface(IDWriteFontFile
*iface
, REFIID riid
, void **obj
)
3674 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3676 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3678 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteFontFile
))
3681 IDWriteFontFile_AddRef(iface
);
3686 return E_NOINTERFACE
;
3689 static ULONG WINAPI
dwritefontfile_AddRef(IDWriteFontFile
*iface
)
3691 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3692 ULONG ref
= InterlockedIncrement(&This
->ref
);
3693 TRACE("(%p)->(%d)\n", This
, ref
);
3697 static ULONG WINAPI
dwritefontfile_Release(IDWriteFontFile
*iface
)
3699 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3700 ULONG ref
= InterlockedDecrement(&This
->ref
);
3702 TRACE("(%p)->(%d)\n", This
, ref
);
3706 IDWriteFontFileLoader_Release(This
->loader
);
3707 if (This
->stream
) IDWriteFontFileStream_Release(This
->stream
);
3708 heap_free(This
->reference_key
);
3715 static HRESULT WINAPI
dwritefontfile_GetReferenceKey(IDWriteFontFile
*iface
, const void **fontFileReferenceKey
, UINT32
*fontFileReferenceKeySize
)
3717 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3718 TRACE("(%p)->(%p, %p)\n", This
, fontFileReferenceKey
, fontFileReferenceKeySize
);
3719 *fontFileReferenceKey
= This
->reference_key
;
3720 *fontFileReferenceKeySize
= This
->key_size
;
3725 static HRESULT WINAPI
dwritefontfile_GetLoader(IDWriteFontFile
*iface
, IDWriteFontFileLoader
**fontFileLoader
)
3727 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3728 TRACE("(%p)->(%p)\n", This
, fontFileLoader
);
3729 *fontFileLoader
= This
->loader
;
3730 IDWriteFontFileLoader_AddRef(This
->loader
);
3735 static HRESULT WINAPI
dwritefontfile_Analyze(IDWriteFontFile
*iface
, BOOL
*isSupportedFontType
, DWRITE_FONT_FILE_TYPE
*fontFileType
,
3736 DWRITE_FONT_FACE_TYPE
*fontFaceType
, UINT32
*numberOfFaces
)
3738 struct dwrite_fontfile
*This
= impl_from_IDWriteFontFile(iface
);
3739 IDWriteFontFileStream
*stream
;
3742 TRACE("(%p)->(%p, %p, %p, %p)\n", This
, isSupportedFontType
, fontFileType
, fontFaceType
, numberOfFaces
);
3744 *isSupportedFontType
= FALSE
;
3745 *fontFileType
= DWRITE_FONT_FILE_TYPE_UNKNOWN
;
3747 *fontFaceType
= DWRITE_FONT_FACE_TYPE_UNKNOWN
;
3750 hr
= IDWriteFontFileLoader_CreateStreamFromKey(This
->loader
, This
->reference_key
, This
->key_size
, &stream
);
3754 hr
= opentype_analyze_font(stream
, numberOfFaces
, fontFileType
, fontFaceType
, isSupportedFontType
);
3756 /* TODO: Further Analysis */
3757 IDWriteFontFileStream_Release(stream
);
3761 static const IDWriteFontFileVtbl dwritefontfilevtbl
= {
3762 dwritefontfile_QueryInterface
,
3763 dwritefontfile_AddRef
,
3764 dwritefontfile_Release
,
3765 dwritefontfile_GetReferenceKey
,
3766 dwritefontfile_GetLoader
,
3767 dwritefontfile_Analyze
,
3770 HRESULT
create_font_file(IDWriteFontFileLoader
*loader
, const void *reference_key
, UINT32 key_size
, IDWriteFontFile
**font_file
)
3772 struct dwrite_fontfile
*This
;
3774 This
= heap_alloc(sizeof(struct dwrite_fontfile
));
3775 if (!This
) return E_OUTOFMEMORY
;
3777 This
->IDWriteFontFile_iface
.lpVtbl
= &dwritefontfilevtbl
;
3779 IDWriteFontFileLoader_AddRef(loader
);
3780 This
->loader
= loader
;
3781 This
->stream
= NULL
;
3782 This
->reference_key
= heap_alloc(key_size
);
3783 memcpy(This
->reference_key
, reference_key
, key_size
);
3784 This
->key_size
= key_size
;
3786 *font_file
= &This
->IDWriteFontFile_iface
;
3791 static HRESULT
get_stream_from_file(IDWriteFontFile
*file
, IDWriteFontFileStream
**stream
)
3793 IDWriteFontFileLoader
*loader
;
3799 hr
= IDWriteFontFile_GetLoader(file
, &loader
);
3803 hr
= IDWriteFontFile_GetReferenceKey(file
, &key
, &key_size
);
3805 IDWriteFontFileLoader_Release(loader
);
3809 hr
= IDWriteFontFileLoader_CreateStreamFromKey(loader
, key
, key_size
, stream
);
3810 IDWriteFontFileLoader_Release(loader
);
3815 HRESULT
create_fontface(DWRITE_FONT_FACE_TYPE facetype
, UINT32 files_number
, IDWriteFontFile
* const* font_files
, UINT32 index
,
3816 DWRITE_FONT_SIMULATIONS simulations
, IDWriteFontFace3
**ret
)
3818 struct dwrite_fontface
*fontface
;
3824 fontface
= heap_alloc(sizeof(struct dwrite_fontface
));
3826 return E_OUTOFMEMORY
;
3828 fontface
->files
= heap_alloc_zero(sizeof(*fontface
->files
) * files_number
);
3829 fontface
->streams
= heap_alloc_zero(sizeof(*fontface
->streams
) * files_number
);
3831 if (!fontface
->files
|| !fontface
->streams
) {
3832 heap_free(fontface
->files
);
3833 heap_free(fontface
->streams
);
3834 heap_free(fontface
);
3835 return E_OUTOFMEMORY
;
3838 fontface
->IDWriteFontFace3_iface
.lpVtbl
= &dwritefontfacevtbl
;
3840 fontface
->type
= facetype
;
3841 fontface
->file_count
= files_number
;
3842 memset(&fontface
->cmap
, 0, sizeof(fontface
->cmap
));
3843 memset(&fontface
->vdmx
, 0, sizeof(fontface
->vdmx
));
3844 memset(&fontface
->gasp
, 0, sizeof(fontface
->gasp
));
3845 memset(&fontface
->cpal
, 0, sizeof(fontface
->cpal
));
3846 memset(&fontface
->colr
, 0, sizeof(fontface
->colr
));
3847 fontface
->cmap
.exists
= TRUE
;
3848 fontface
->vdmx
.exists
= TRUE
;
3849 fontface
->gasp
.exists
= TRUE
;
3850 fontface
->cpal
.exists
= TRUE
;
3851 fontface
->colr
.exists
= TRUE
;
3852 fontface
->index
= index
;
3853 fontface
->simulations
= simulations
;
3854 memset(fontface
->glyphs
, 0, sizeof(fontface
->glyphs
));
3856 for (i
= 0; i
< fontface
->file_count
; i
++) {
3857 hr
= get_stream_from_file(font_files
[i
], &fontface
->streams
[i
]);
3859 IDWriteFontFace3_Release(&fontface
->IDWriteFontFace3_iface
);
3863 fontface
->files
[i
] = font_files
[i
];
3864 IDWriteFontFile_AddRef(font_files
[i
]);
3867 opentype_get_font_metrics(fontface
->streams
[0], facetype
, index
, &fontface
->metrics
, &fontface
->caret
);
3868 if (simulations
& DWRITE_FONT_SIMULATIONS_OBLIQUE
) {
3869 /* TODO: test what happens if caret is already slanted */
3870 if (fontface
->caret
.slopeRise
== 1) {
3871 fontface
->caret
.slopeRise
= fontface
->metrics
.designUnitsPerEm
;
3872 fontface
->caret
.slopeRun
= fontface
->caret
.slopeRise
/ 3;
3875 fontface
->charmap
= freetype_get_charmap_index(&fontface
->IDWriteFontFace3_iface
, &fontface
->is_symbol
);
3876 fontface
->has_kerning_pairs
= freetype_has_kerning_pairs(&fontface
->IDWriteFontFace3_iface
);
3877 fontface
->is_monospaced
= freetype_is_monospaced(&fontface
->IDWriteFontFace3_iface
);
3879 *ret
= &fontface
->IDWriteFontFace3_iface
;
3883 /* IDWriteLocalFontFileLoader and its required IDWriteFontFileStream */
3890 struct local_cached_stream
3893 IDWriteFontFileStream
*stream
;
3894 struct local_refkey
*key
;
3898 struct dwrite_localfontfilestream
3900 IDWriteFontFileStream IDWriteFontFileStream_iface
;
3903 struct local_cached_stream
*entry
;
3904 const void *file_ptr
;
3908 struct dwrite_localfontfileloader
{
3909 IDWriteLocalFontFileLoader IDWriteLocalFontFileLoader_iface
;
3912 struct list streams
;
3915 static inline struct dwrite_localfontfileloader
*impl_from_IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoader
*iface
)
3917 return CONTAINING_RECORD(iface
, struct dwrite_localfontfileloader
, IDWriteLocalFontFileLoader_iface
);
3920 static inline struct dwrite_localfontfilestream
*impl_from_IDWriteFontFileStream(IDWriteFontFileStream
*iface
)
3922 return CONTAINING_RECORD(iface
, struct dwrite_localfontfilestream
, IDWriteFontFileStream_iface
);
3925 static HRESULT WINAPI
localfontfilestream_QueryInterface(IDWriteFontFileStream
*iface
, REFIID riid
, void **obj
)
3927 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3928 TRACE_(dwrite_file
)("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
3929 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteFontFileStream
))
3932 IDWriteFontFileStream_AddRef(iface
);
3937 return E_NOINTERFACE
;
3940 static ULONG WINAPI
localfontfilestream_AddRef(IDWriteFontFileStream
*iface
)
3942 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3943 ULONG ref
= InterlockedIncrement(&This
->ref
);
3944 TRACE_(dwrite_file
)("(%p)->(%d)\n", This
, ref
);
3948 static inline void release_cached_stream(struct local_cached_stream
*stream
)
3950 list_remove(&stream
->entry
);
3951 heap_free(stream
->key
);
3955 static ULONG WINAPI
localfontfilestream_Release(IDWriteFontFileStream
*iface
)
3957 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3958 ULONG ref
= InterlockedDecrement(&This
->ref
);
3960 TRACE_(dwrite_file
)("(%p)->(%d)\n", This
, ref
);
3963 UnmapViewOfFile(This
->file_ptr
);
3964 release_cached_stream(This
->entry
);
3971 static HRESULT WINAPI
localfontfilestream_ReadFileFragment(IDWriteFontFileStream
*iface
, void const **fragment_start
, UINT64 offset
, UINT64 fragment_size
, void **fragment_context
)
3973 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3975 TRACE_(dwrite_file
)("(%p)->(%p, %s, %s, %p)\n",This
, fragment_start
,
3976 wine_dbgstr_longlong(offset
), wine_dbgstr_longlong(fragment_size
), fragment_context
);
3978 *fragment_context
= NULL
;
3980 if ((offset
>= This
->size
- 1) || (fragment_size
> This
->size
- offset
)) {
3981 *fragment_start
= NULL
;
3985 *fragment_start
= (char*)This
->file_ptr
+ offset
;
3989 static void WINAPI
localfontfilestream_ReleaseFileFragment(IDWriteFontFileStream
*iface
, void *fragment_context
)
3991 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3992 TRACE_(dwrite_file
)("(%p)->(%p)\n", This
, fragment_context
);
3995 static HRESULT WINAPI
localfontfilestream_GetFileSize(IDWriteFontFileStream
*iface
, UINT64
*size
)
3997 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
3998 TRACE_(dwrite_file
)("(%p)->(%p)\n", This
, size
);
4003 static HRESULT WINAPI
localfontfilestream_GetLastWriteTime(IDWriteFontFileStream
*iface
, UINT64
*last_writetime
)
4005 struct dwrite_localfontfilestream
*This
= impl_from_IDWriteFontFileStream(iface
);
4008 TRACE_(dwrite_file
)("(%p)->(%p)\n", This
, last_writetime
);
4010 li
.u
.LowPart
= This
->entry
->key
->writetime
.dwLowDateTime
;
4011 li
.u
.HighPart
= This
->entry
->key
->writetime
.dwHighDateTime
;
4012 *last_writetime
= li
.QuadPart
;
4017 static const IDWriteFontFileStreamVtbl localfontfilestreamvtbl
=
4019 localfontfilestream_QueryInterface
,
4020 localfontfilestream_AddRef
,
4021 localfontfilestream_Release
,
4022 localfontfilestream_ReadFileFragment
,
4023 localfontfilestream_ReleaseFileFragment
,
4024 localfontfilestream_GetFileSize
,
4025 localfontfilestream_GetLastWriteTime
4028 static HRESULT
create_localfontfilestream(const void *file_ptr
, UINT64 size
, struct local_cached_stream
*entry
, IDWriteFontFileStream
**ret
)
4030 struct dwrite_localfontfilestream
*This
;
4034 This
= heap_alloc(sizeof(struct dwrite_localfontfilestream
));
4036 return E_OUTOFMEMORY
;
4038 This
->IDWriteFontFileStream_iface
.lpVtbl
= &localfontfilestreamvtbl
;
4041 This
->file_ptr
= file_ptr
;
4043 This
->entry
= entry
;
4045 *ret
= &This
->IDWriteFontFileStream_iface
;
4049 static HRESULT WINAPI
localfontfileloader_QueryInterface(IDWriteLocalFontFileLoader
*iface
, REFIID riid
, void **obj
)
4051 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4053 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), obj
);
4055 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IDWriteFontFileLoader
) || IsEqualIID(riid
, &IID_IDWriteLocalFontFileLoader
))
4058 IDWriteLocalFontFileLoader_AddRef(iface
);
4063 return E_NOINTERFACE
;
4066 static ULONG WINAPI
localfontfileloader_AddRef(IDWriteLocalFontFileLoader
*iface
)
4068 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4069 ULONG ref
= InterlockedIncrement(&This
->ref
);
4070 TRACE("(%p)->(%d)\n", This
, ref
);
4074 static ULONG WINAPI
localfontfileloader_Release(IDWriteLocalFontFileLoader
*iface
)
4076 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4077 ULONG ref
= InterlockedDecrement(&This
->ref
);
4079 TRACE("(%p)->(%d)\n", This
, ref
);
4082 struct local_cached_stream
*stream
, *stream2
;
4084 /* This will detach all entries from cache. Entries are released together with streams,
4085 so stream controls cache entry lifetime. */
4086 LIST_FOR_EACH_ENTRY_SAFE(stream
, stream2
, &This
->streams
, struct local_cached_stream
, entry
)
4087 list_init(&stream
->entry
);
4095 static HRESULT WINAPI
localfontfileloader_CreateStreamFromKey(IDWriteLocalFontFileLoader
*iface
, const void *key
, UINT32 key_size
, IDWriteFontFileStream
**ret
)
4097 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4098 const struct local_refkey
*refkey
= key
;
4099 struct local_cached_stream
*stream
;
4100 IDWriteFontFileStream
*filestream
;
4101 HANDLE file
, mapping
;
4106 TRACE("(%p)->(%p, %i, %p)\n", This
, key
, key_size
, ret
);
4107 TRACE("name: %s\n", debugstr_w(refkey
->name
));
4109 /* search cache first */
4110 LIST_FOR_EACH_ENTRY(stream
, &This
->streams
, struct local_cached_stream
, entry
) {
4111 if (key_size
== stream
->key_size
&& !memcmp(stream
->key
, key
, key_size
)) {
4112 *ret
= stream
->stream
;
4113 IDWriteFontFileStream_AddRef(*ret
);
4120 file
= CreateFileW(refkey
->name
, GENERIC_READ
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
4121 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
4122 if (file
== INVALID_HANDLE_VALUE
)
4125 GetFileSizeEx(file
, &size
);
4126 mapping
= CreateFileMappingW(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4131 file_ptr
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4132 CloseHandle(mapping
);
4134 stream
= heap_alloc(sizeof(*stream
));
4136 UnmapViewOfFile(file_ptr
);
4137 return E_OUTOFMEMORY
;
4140 stream
->key
= heap_alloc(key_size
);
4142 UnmapViewOfFile(file_ptr
);
4144 return E_OUTOFMEMORY
;
4147 stream
->key_size
= key_size
;
4148 memcpy(stream
->key
, key
, key_size
);
4150 hr
= create_localfontfilestream(file_ptr
, size
.QuadPart
, stream
, &filestream
);
4152 UnmapViewOfFile(file_ptr
);
4153 heap_free(stream
->key
);
4158 stream
->stream
= filestream
;
4159 list_add_head(&This
->streams
, &stream
->entry
);
4161 *ret
= stream
->stream
;
4166 static HRESULT WINAPI
localfontfileloader_GetFilePathLengthFromKey(IDWriteLocalFontFileLoader
*iface
, void const *key
, UINT32 key_size
, UINT32
*length
)
4168 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4169 const struct local_refkey
*refkey
= key
;
4171 TRACE("(%p)->(%p, %i, %p)\n", This
, key
, key_size
, length
);
4173 *length
= strlenW(refkey
->name
);
4177 static HRESULT WINAPI
localfontfileloader_GetFilePathFromKey(IDWriteLocalFontFileLoader
*iface
, void const *key
, UINT32 key_size
, WCHAR
*path
, UINT32 length
)
4179 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4180 const struct local_refkey
*refkey
= key
;
4182 TRACE("(%p)->(%p, %i, %p, %i)\n", This
, key
, key_size
, path
, length
);
4184 if (length
< strlenW(refkey
->name
))
4185 return E_INVALIDARG
;
4187 strcpyW(path
, refkey
->name
);
4191 static HRESULT WINAPI
localfontfileloader_GetLastWriteTimeFromKey(IDWriteLocalFontFileLoader
*iface
, void const *key
, UINT32 key_size
, FILETIME
*writetime
)
4193 struct dwrite_localfontfileloader
*This
= impl_from_IDWriteLocalFontFileLoader(iface
);
4194 const struct local_refkey
*refkey
= key
;
4196 TRACE("(%p)->(%p, %i, %p)\n", This
, key
, key_size
, writetime
);
4198 *writetime
= refkey
->writetime
;
4202 static const struct IDWriteLocalFontFileLoaderVtbl localfontfileloadervtbl
= {
4203 localfontfileloader_QueryInterface
,
4204 localfontfileloader_AddRef
,
4205 localfontfileloader_Release
,
4206 localfontfileloader_CreateStreamFromKey
,
4207 localfontfileloader_GetFilePathLengthFromKey
,
4208 localfontfileloader_GetFilePathFromKey
,
4209 localfontfileloader_GetLastWriteTimeFromKey
4212 HRESULT
create_localfontfileloader(IDWriteLocalFontFileLoader
**ret
)
4214 struct dwrite_localfontfileloader
*This
;
4218 This
= heap_alloc(sizeof(struct dwrite_localfontfileloader
));
4220 return E_OUTOFMEMORY
;
4222 This
->IDWriteLocalFontFileLoader_iface
.lpVtbl
= &localfontfileloadervtbl
;
4224 list_init(&This
->streams
);
4226 *ret
= &This
->IDWriteLocalFontFileLoader_iface
;
4230 HRESULT
get_local_refkey(const WCHAR
*path
, const FILETIME
*writetime
, void **key
, UINT32
*size
)
4232 struct local_refkey
*refkey
;
4234 *size
= FIELD_OFFSET(struct local_refkey
, name
) + (strlenW(path
)+1)*sizeof(WCHAR
);
4237 refkey
= heap_alloc(*size
);
4239 return E_OUTOFMEMORY
;
4242 refkey
->writetime
= *writetime
;
4244 WIN32_FILE_ATTRIBUTE_DATA info
;
4246 if (GetFileAttributesExW(path
, GetFileExInfoStandard
, &info
))
4247 refkey
->writetime
= info
.ftLastWriteTime
;
4249 memset(&refkey
->writetime
, 0, sizeof(refkey
->writetime
));
4251 strcpyW(refkey
->name
, path
);
4258 /* IDWriteGlyphRunAnalysis */
4259 static HRESULT WINAPI
glyphrunanalysis_QueryInterface(IDWriteGlyphRunAnalysis
*iface
, REFIID riid
, void **ppv
)
4261 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4263 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
4265 if (IsEqualIID(riid
, &IID_IDWriteGlyphRunAnalysis
) ||
4266 IsEqualIID(riid
, &IID_IUnknown
))
4269 IDWriteGlyphRunAnalysis_AddRef(iface
);
4274 return E_NOINTERFACE
;
4277 static ULONG WINAPI
glyphrunanalysis_AddRef(IDWriteGlyphRunAnalysis
*iface
)
4279 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4280 ULONG ref
= InterlockedIncrement(&This
->ref
);
4281 TRACE("(%p)->(%u)\n", This
, ref
);
4285 static ULONG WINAPI
glyphrunanalysis_Release(IDWriteGlyphRunAnalysis
*iface
)
4287 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4288 ULONG ref
= InterlockedDecrement(&This
->ref
);
4290 TRACE("(%p)->(%u)\n", This
, ref
);
4293 if (This
->run
.fontFace
)
4294 IDWriteFontFace_Release(This
->run
.fontFace
);
4295 heap_free(This
->glyphs
);
4296 heap_free(This
->advances
);
4297 heap_free(This
->advanceoffsets
);
4298 heap_free(This
->ascenderoffsets
);
4299 heap_free(This
->bitmap
);
4306 static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis
*analysis
, RECT
*bounds
)
4308 struct dwrite_glyphbitmap glyph_bitmap
;
4309 IDWriteFontFace3
*fontface3
;
4310 D2D_POINT_2F origin
;
4315 if (analysis
->flags
& RUNANALYSIS_BOUNDS_READY
) {
4316 *bounds
= analysis
->bounds
;
4320 if (analysis
->run
.isSideways
)
4321 FIXME("sideways runs are not supported.\n");
4323 hr
= IDWriteFontFace_QueryInterface(analysis
->run
.fontFace
, &IID_IDWriteFontFace3
, (void**)&fontface3
);
4325 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr
);
4327 /* Start with empty bounds at (0,0) origin, returned bounds are not translated back to (0,0), e.g. for
4328 RTL run negative left bound is returned, same goes for vertical direction - top bound will be negative
4329 for any non-zero glyph ascender */
4330 origin
.x
= origin
.y
= 0.0f
;
4331 is_rtl
= analysis
->run
.bidiLevel
& 1;
4333 memset(&glyph_bitmap
, 0, sizeof(glyph_bitmap
));
4334 glyph_bitmap
.fontface
= fontface3
;
4335 glyph_bitmap
.emsize
= analysis
->run
.fontEmSize
* analysis
->ppdip
;
4336 glyph_bitmap
.nohint
= analysis
->rendering_mode
== DWRITE_RENDERING_MODE_NATURAL
||
4337 analysis
->rendering_mode
== DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
;
4338 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4339 glyph_bitmap
.m
= &analysis
->m
;
4341 for (i
= 0; i
< analysis
->run
.glyphCount
; i
++) {
4342 const D2D_POINT_2F
*advanceoffset
= analysis
->advanceoffsets
? analysis
->advanceoffsets
+ i
: NULL
;
4343 const D2D_POINT_2F
*ascenderoffset
= analysis
->ascenderoffsets
? analysis
->ascenderoffsets
+ i
: NULL
;
4344 const D2D_POINT_2F
*advance
= analysis
->advances
+ i
;
4345 RECT
*bbox
= &glyph_bitmap
.bbox
;
4347 glyph_bitmap
.index
= analysis
->run
.glyphIndices
[i
];
4348 freetype_get_glyph_bbox(&glyph_bitmap
);
4351 OffsetRect(bbox
, origin
.x
+ advance
->x
, origin
.y
+ advance
->y
);
4353 OffsetRect(bbox
, origin
.x
, origin
.y
);
4356 OffsetRect(bbox
, advanceoffset
->x
+ ascenderoffset
->x
, advanceoffset
->y
+ ascenderoffset
->y
);
4358 UnionRect(&analysis
->bounds
, &analysis
->bounds
, bbox
);
4359 origin
.x
+= advance
->x
;
4360 origin
.y
+= advance
->y
;
4363 IDWriteFontFace3_Release(fontface3
);
4365 /* translate to given run origin */
4366 OffsetRect(&analysis
->bounds
, analysis
->origin
.x
, analysis
->origin
.y
);
4367 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4368 OffsetRect(&analysis
->bounds
, analysis
->m
.dx
, analysis
->m
.dy
);
4370 analysis
->flags
|= RUNANALYSIS_BOUNDS_READY
;
4371 *bounds
= analysis
->bounds
;
4374 static HRESULT WINAPI
glyphrunanalysis_GetAlphaTextureBounds(IDWriteGlyphRunAnalysis
*iface
, DWRITE_TEXTURE_TYPE type
, RECT
*bounds
)
4376 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4378 TRACE("(%p)->(%d %p)\n", This
, type
, bounds
);
4380 if ((UINT32
)type
> DWRITE_TEXTURE_CLEARTYPE_3x1
) {
4381 memset(bounds
, 0, sizeof(*bounds
));
4382 return E_INVALIDARG
;
4385 if ((type
== DWRITE_TEXTURE_ALIASED_1x1
&& This
->rendering_mode
!= DWRITE_RENDERING_MODE_ALIASED
) ||
4386 (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
&& This
->rendering_mode
== DWRITE_RENDERING_MODE_ALIASED
)) {
4387 memset(bounds
, 0, sizeof(*bounds
));
4391 glyphrunanalysis_get_texturebounds(This
, bounds
);
4395 static inline int get_dib_stride( int width
, int bpp
)
4397 return ((width
* bpp
+ 31) >> 3) & ~3;
4400 static inline BYTE
*get_pixel_ptr(BYTE
*ptr
, DWRITE_TEXTURE_TYPE type
, const RECT
*runbounds
, const RECT
*bounds
)
4402 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
)
4403 return ptr
+ (runbounds
->top
- bounds
->top
) * (bounds
->right
- bounds
->left
) * 3 +
4404 (runbounds
->left
- bounds
->left
) * 3;
4406 return ptr
+ (runbounds
->top
- bounds
->top
) * (bounds
->right
- bounds
->left
) +
4407 runbounds
->left
- bounds
->left
;
4410 static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis
*analysis
, DWRITE_TEXTURE_TYPE type
)
4412 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
4413 struct dwrite_glyphbitmap glyph_bitmap
;
4414 IDWriteFontFace3
*fontface2
;
4415 D2D_POINT_2F origin
;
4421 hr
= IDWriteFontFace_QueryInterface(analysis
->run
.fontFace
, &IID_IDWriteFontFace3
, (void**)&fontface2
);
4423 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr
);
4427 size
= (analysis
->bounds
.right
- analysis
->bounds
.left
)*(analysis
->bounds
.bottom
- analysis
->bounds
.top
);
4428 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
)
4430 analysis
->bitmap
= heap_alloc_zero(size
);
4432 origin
.x
= origin
.y
= 0.0f
;
4433 is_rtl
= analysis
->run
.bidiLevel
& 1;
4435 memset(&glyph_bitmap
, 0, sizeof(glyph_bitmap
));
4436 glyph_bitmap
.fontface
= fontface2
;
4437 glyph_bitmap
.emsize
= analysis
->run
.fontEmSize
* analysis
->ppdip
;
4438 glyph_bitmap
.nohint
= analysis
->rendering_mode
== DWRITE_RENDERING_MODE_NATURAL
||
4439 analysis
->rendering_mode
== DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
;
4440 glyph_bitmap
.type
= type
;
4441 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4442 glyph_bitmap
.m
= &analysis
->m
;
4443 bbox
= &glyph_bitmap
.bbox
;
4445 for (i
= 0; i
< analysis
->run
.glyphCount
; i
++) {
4446 const D2D_POINT_2F
*advanceoffset
= analysis
->advanceoffsets
? analysis
->advanceoffsets
+ i
: NULL
;
4447 const D2D_POINT_2F
*ascenderoffset
= analysis
->ascenderoffsets
? analysis
->ascenderoffsets
+ i
: NULL
;
4448 const D2D_POINT_2F
*advance
= analysis
->advances
+ i
;
4449 int x
, y
, width
, height
;
4453 glyph_bitmap
.index
= analysis
->run
.glyphIndices
[i
];
4454 freetype_get_glyph_bbox(&glyph_bitmap
);
4456 if (IsRectEmpty(bbox
)) {
4457 origin
.x
+= advance
->x
;
4458 origin
.y
+= advance
->y
;
4462 width
= bbox
->right
- bbox
->left
;
4463 height
= bbox
->bottom
- bbox
->top
;
4465 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
)
4466 glyph_bitmap
.pitch
= (width
+ 3) / 4 * 4;
4468 glyph_bitmap
.pitch
= ((width
+ 31) >> 5) << 2;
4470 glyph_bitmap
.buf
= src
= heap_alloc_zero(height
* glyph_bitmap
.pitch
);
4471 is_1bpp
= freetype_get_glyph_bitmap(&glyph_bitmap
);
4474 OffsetRect(bbox
, origin
.x
+ advance
->x
, origin
.y
+ advance
->y
);
4476 OffsetRect(bbox
, origin
.x
, origin
.y
);
4479 OffsetRect(bbox
, advanceoffset
->x
+ ascenderoffset
->x
, advanceoffset
->y
+ ascenderoffset
->y
);
4481 OffsetRect(bbox
, analysis
->origin
.x
, analysis
->origin
.y
);
4482 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4483 OffsetRect(bbox
, analysis
->m
.dx
, analysis
->m
.dy
);
4485 /* blit to analysis bitmap */
4486 dst
= get_pixel_ptr(analysis
->bitmap
, type
, bbox
, &analysis
->bounds
);
4489 /* convert 1bpp to 8bpp/24bpp */
4490 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
) {
4491 for (y
= 0; y
< height
; y
++) {
4492 for (x
= 0; x
< width
; x
++)
4493 if (src
[x
/ 8] & masks
[x
% 8])
4494 dst
[3*x
] = dst
[3*x
+1] = dst
[3*x
+2] = DWRITE_ALPHA_MAX
;
4495 src
+= glyph_bitmap
.pitch
;
4496 dst
+= (analysis
->bounds
.right
- analysis
->bounds
.left
) * 3;
4500 for (y
= 0; y
< height
; y
++) {
4501 for (x
= 0; x
< width
; x
++)
4502 if (src
[x
/ 8] & masks
[x
% 8])
4503 dst
[x
] = DWRITE_ALPHA_MAX
;
4504 src
+= get_dib_stride(width
, 1);
4505 dst
+= analysis
->bounds
.right
- analysis
->bounds
.left
;
4510 /* at this point it's DWRITE_TEXTURE_CLEARTYPE_3x1 with 8bpp src bitmap */
4511 for (y
= 0; y
< height
; y
++) {
4512 for (x
= 0; x
< width
; x
++)
4513 dst
[3*x
] = dst
[3*x
+1] = dst
[3*x
+2] = src
[x
] | dst
[3*x
];
4514 src
+= glyph_bitmap
.pitch
;
4515 dst
+= (analysis
->bounds
.right
- analysis
->bounds
.left
) * 3;
4519 heap_free(glyph_bitmap
.buf
);
4521 origin
.x
+= advance
->x
;
4522 origin
.y
+= advance
->y
;
4525 IDWriteFontFace3_Release(fontface2
);
4527 analysis
->flags
|= RUNANALYSIS_BITMAP_READY
;
4529 /* we don't need this anymore */
4530 heap_free(analysis
->glyphs
);
4531 heap_free(analysis
->advances
);
4532 heap_free(analysis
->advanceoffsets
);
4533 heap_free(analysis
->ascenderoffsets
);
4534 IDWriteFontFace_Release(analysis
->run
.fontFace
);
4536 analysis
->glyphs
= NULL
;
4537 analysis
->advances
= NULL
;
4538 analysis
->advanceoffsets
= NULL
;
4539 analysis
->ascenderoffsets
= NULL
;
4540 analysis
->run
.glyphIndices
= NULL
;
4541 analysis
->run
.fontFace
= NULL
;
4544 static HRESULT WINAPI
glyphrunanalysis_CreateAlphaTexture(IDWriteGlyphRunAnalysis
*iface
, DWRITE_TEXTURE_TYPE type
,
4545 RECT
const *bounds
, BYTE
*bitmap
, UINT32 size
)
4547 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4551 TRACE("(%p)->(%d %s %p %u)\n", This
, type
, wine_dbgstr_rect(bounds
), bitmap
, size
);
4553 if (!bounds
|| !bitmap
|| (UINT32
)type
> DWRITE_TEXTURE_CLEARTYPE_3x1
)
4554 return E_INVALIDARG
;
4556 /* make sure buffer is large enough for requested texture type */
4557 required
= (bounds
->right
- bounds
->left
) * (bounds
->bottom
- bounds
->top
);
4558 if (type
== DWRITE_TEXTURE_CLEARTYPE_3x1
)
4561 if (size
< required
)
4562 return E_NOT_SUFFICIENT_BUFFER
;
4564 /* validate requested texture type with rendering mode */
4565 switch (This
->rendering_mode
)
4567 case DWRITE_RENDERING_MODE_ALIASED
:
4568 if (type
!= DWRITE_TEXTURE_ALIASED_1x1
)
4569 return DWRITE_E_UNSUPPORTEDOPERATION
;
4571 case DWRITE_RENDERING_MODE_GDI_CLASSIC
:
4572 case DWRITE_RENDERING_MODE_GDI_NATURAL
:
4573 case DWRITE_RENDERING_MODE_NATURAL
:
4574 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
:
4575 if (type
!= DWRITE_TEXTURE_CLEARTYPE_3x1
)
4576 return DWRITE_E_UNSUPPORTEDOPERATION
;
4582 memset(bitmap
, 0, size
);
4583 glyphrunanalysis_get_texturebounds(This
, &runbounds
);
4584 if (IntersectRect(&runbounds
, &runbounds
, bounds
)) {
4585 int pixel_size
= type
== DWRITE_TEXTURE_CLEARTYPE_3x1
? 3 : 1;
4586 int src_width
= (This
->bounds
.right
- This
->bounds
.left
) * pixel_size
;
4587 int dst_width
= (bounds
->right
- bounds
->left
) * pixel_size
;
4588 int draw_width
= (runbounds
.right
- runbounds
.left
) * pixel_size
;
4592 if (!(This
->flags
& RUNANALYSIS_BITMAP_READY
))
4593 glyphrunanalysis_render(This
, type
);
4595 src
= get_pixel_ptr(This
->bitmap
, type
, &runbounds
, &This
->bounds
);
4596 dst
= get_pixel_ptr(bitmap
, type
, &runbounds
, bounds
);
4598 for (y
= 0; y
< runbounds
.bottom
- runbounds
.top
; y
++) {
4599 memcpy(dst
, src
, draw_width
);
4608 static HRESULT WINAPI
glyphrunanalysis_GetAlphaBlendParams(IDWriteGlyphRunAnalysis
*iface
, IDWriteRenderingParams
*params
,
4609 FLOAT
*gamma
, FLOAT
*contrast
, FLOAT
*cleartypelevel
)
4611 struct dwrite_glyphrunanalysis
*This
= impl_from_IDWriteGlyphRunAnalysis(iface
);
4613 TRACE("(%p)->(%p %p %p %p)\n", This
, params
, gamma
, contrast
, cleartypelevel
);
4616 return E_INVALIDARG
;
4618 switch (This
->rendering_mode
)
4620 case DWRITE_RENDERING_MODE_GDI_CLASSIC
:
4621 case DWRITE_RENDERING_MODE_GDI_NATURAL
:
4624 SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST
, 0, &value
, 0);
4625 *gamma
= (FLOAT
)value
/ 1000.0f
;
4627 *cleartypelevel
= 1.0f
;
4630 case DWRITE_RENDERING_MODE_ALIASED
:
4631 case DWRITE_RENDERING_MODE_NATURAL
:
4632 case DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
:
4633 *gamma
= IDWriteRenderingParams_GetGamma(params
);
4634 *contrast
= IDWriteRenderingParams_GetEnhancedContrast(params
);
4635 *cleartypelevel
= IDWriteRenderingParams_GetClearTypeLevel(params
);
4644 static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl
= {
4645 glyphrunanalysis_QueryInterface
,
4646 glyphrunanalysis_AddRef
,
4647 glyphrunanalysis_Release
,
4648 glyphrunanalysis_GetAlphaTextureBounds
,
4649 glyphrunanalysis_CreateAlphaTexture
,
4650 glyphrunanalysis_GetAlphaBlendParams
4653 static inline void init_2d_vec(D2D_POINT_2F
*vec
, FLOAT length
, BOOL is_vertical
)
4665 static inline void transform_2d_vec(D2D_POINT_2F
*vec
, const DWRITE_MATRIX
*m
)
4668 ret
.x
= vec
->x
* m
->m11
+ vec
->y
* m
->m21
;
4669 ret
.y
= vec
->x
* m
->m12
+ vec
->y
* m
->m22
;
4673 HRESULT
create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode
, DWRITE_MEASURING_MODE measuring_mode
, DWRITE_GLYPH_RUN
const *run
,
4674 FLOAT ppdip
, const DWRITE_MATRIX
*transform
, DWRITE_GRID_FIT_MODE gridfit_mode
, DWRITE_TEXT_ANTIALIAS_MODE aa_mode
,
4675 FLOAT originX
, FLOAT originY
, IDWriteGlyphRunAnalysis
**ret
)
4677 struct dwrite_glyphrunanalysis
*analysis
;
4683 /* check for valid rendering mode */
4684 if ((UINT32
)rendering_mode
>= DWRITE_RENDERING_MODE_OUTLINE
|| rendering_mode
== DWRITE_RENDERING_MODE_DEFAULT
)
4685 return E_INVALIDARG
;
4687 analysis
= heap_alloc(sizeof(*analysis
));
4689 return E_OUTOFMEMORY
;
4691 analysis
->IDWriteGlyphRunAnalysis_iface
.lpVtbl
= &glyphrunanalysisvtbl
;
4693 analysis
->rendering_mode
= rendering_mode
;
4694 analysis
->flags
= 0;
4695 analysis
->bitmap
= NULL
;
4696 analysis
->ppdip
= ppdip
;
4697 analysis
->origin
.x
= originX
* ppdip
;
4698 analysis
->origin
.y
= originY
* ppdip
;
4699 SetRectEmpty(&analysis
->bounds
);
4700 analysis
->run
= *run
;
4701 IDWriteFontFace_AddRef(analysis
->run
.fontFace
);
4702 analysis
->glyphs
= heap_alloc(run
->glyphCount
*sizeof(*run
->glyphIndices
));
4703 analysis
->advances
= heap_alloc(run
->glyphCount
*sizeof(*analysis
->advances
));
4704 if (run
->glyphOffsets
) {
4705 analysis
->advanceoffsets
= heap_alloc(run
->glyphCount
*sizeof(*analysis
->advanceoffsets
));
4706 analysis
->ascenderoffsets
= heap_alloc(run
->glyphCount
*sizeof(*analysis
->ascenderoffsets
));
4709 analysis
->advanceoffsets
= NULL
;
4710 analysis
->ascenderoffsets
= NULL
;
4713 if (!analysis
->glyphs
|| !analysis
->advances
|| ((!analysis
->advanceoffsets
|| !analysis
->ascenderoffsets
) && run
->glyphOffsets
)) {
4714 heap_free(analysis
->glyphs
);
4715 heap_free(analysis
->advances
);
4716 heap_free(analysis
->advanceoffsets
);
4717 heap_free(analysis
->ascenderoffsets
);
4719 analysis
->glyphs
= NULL
;
4720 analysis
->advances
= NULL
;
4721 analysis
->advanceoffsets
= NULL
;
4722 analysis
->ascenderoffsets
= NULL
;
4724 IDWriteGlyphRunAnalysis_Release(&analysis
->IDWriteGlyphRunAnalysis_iface
);
4725 return E_OUTOFMEMORY
;
4728 /* check if transform is usable */
4729 if (transform
&& memcmp(transform
, &identity
, sizeof(*transform
))) {
4730 analysis
->m
= *transform
;
4731 analysis
->flags
|= RUNANALYSIS_USE_TRANSFORM
;
4734 memset(&analysis
->m
, 0, sizeof(analysis
->m
));
4736 analysis
->run
.glyphIndices
= analysis
->glyphs
;
4737 analysis
->run
.glyphAdvances
= NULL
;
4738 analysis
->run
.glyphOffsets
= NULL
;
4740 rtl_factor
= run
->bidiLevel
& 1 ? -1.0f
: 1.0f
;
4742 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4743 transform_2d_vec(&analysis
->origin
, &analysis
->m
);
4745 memcpy(analysis
->glyphs
, run
->glyphIndices
, run
->glyphCount
*sizeof(*run
->glyphIndices
));
4747 if (run
->glyphAdvances
) {
4748 for (i
= 0; i
< run
->glyphCount
; i
++) {
4749 init_2d_vec(analysis
->advances
+ i
, rtl_factor
* run
->glyphAdvances
[i
] * ppdip
, run
->isSideways
);
4750 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4751 transform_2d_vec(analysis
->advances
+ i
, &analysis
->m
);
4755 DWRITE_FONT_METRICS metrics
;
4756 IDWriteFontFace1
*fontface1
;
4758 IDWriteFontFace_GetMetrics(run
->fontFace
, &metrics
);
4759 IDWriteFontFace_QueryInterface(run
->fontFace
, &IID_IDWriteFontFace1
, (void**)&fontface1
);
4761 for (i
= 0; i
< run
->glyphCount
; i
++) {
4765 switch (measuring_mode
)
4767 case DWRITE_MEASURING_MODE_NATURAL
:
4768 hr
= IDWriteFontFace1_GetDesignGlyphAdvances(fontface1
, 1, run
->glyphIndices
+ i
, &a
, run
->isSideways
);
4771 init_2d_vec(analysis
->advances
+ i
, rtl_factor
* get_scaled_advance_width(a
, run
->fontEmSize
, &metrics
) * ppdip
,
4774 case DWRITE_MEASURING_MODE_GDI_CLASSIC
:
4775 case DWRITE_MEASURING_MODE_GDI_NATURAL
:
4776 hr
= IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1
, run
->fontEmSize
, ppdip
, transform
,
4777 measuring_mode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->isSideways
, 1, run
->glyphIndices
+ i
, &a
);
4779 init_2d_vec(analysis
->advances
+ i
, 0.0f
, FALSE
);
4781 init_2d_vec(analysis
->advances
+ i
, rtl_factor
* floorf(a
* run
->fontEmSize
* ppdip
/ metrics
.designUnitsPerEm
+ 0.5f
),
4788 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
)
4789 transform_2d_vec(analysis
->advances
+ i
, &analysis
->m
);
4792 IDWriteFontFace1_Release(fontface1
);
4795 if (run
->glyphOffsets
) {
4796 for (i
= 0; i
< run
->glyphCount
; i
++) {
4797 init_2d_vec(analysis
->advanceoffsets
+ i
, rtl_factor
* run
->glyphOffsets
[i
].advanceOffset
* ppdip
, run
->isSideways
);
4798 /* Positive ascender offset moves glyph up. Keep it orthogonal to advance direction. */
4799 init_2d_vec(analysis
->ascenderoffsets
+ i
, -run
->glyphOffsets
[i
].ascenderOffset
* ppdip
, !run
->isSideways
);
4800 if (analysis
->flags
& RUNANALYSIS_USE_TRANSFORM
) {
4801 transform_2d_vec(analysis
->advanceoffsets
+ i
, &analysis
->m
);
4802 transform_2d_vec(analysis
->ascenderoffsets
+ i
, &analysis
->m
);
4807 *ret
= &analysis
->IDWriteGlyphRunAnalysis_iface
;
4811 /* IDWriteColorGlyphRunEnumerator */
4812 static HRESULT WINAPI
colorglyphenum_QueryInterface(IDWriteColorGlyphRunEnumerator
*iface
, REFIID riid
, void **ppv
)
4814 struct dwrite_colorglyphenum
*This
= impl_from_IDWriteColorGlyphRunEnumerator(iface
);
4816 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
4818 if (IsEqualIID(riid
, &IID_IDWriteColorGlyphRunEnumerator
) ||
4819 IsEqualIID(riid
, &IID_IUnknown
))
4822 IDWriteColorGlyphRunEnumerator_AddRef(iface
);
4827 return E_NOINTERFACE
;
4830 static ULONG WINAPI
colorglyphenum_AddRef(IDWriteColorGlyphRunEnumerator
*iface
)
4832 struct dwrite_colorglyphenum
*This
= impl_from_IDWriteColorGlyphRunEnumerator(iface
);
4833 ULONG ref
= InterlockedIncrement(&This
->ref
);
4834 TRACE("(%p)->(%u)\n", This
, ref
);
4838 static ULONG WINAPI
colorglyphenum_Release(IDWriteColorGlyphRunEnumerator
*iface
)
4840 struct dwrite_colorglyphenum
*This
= impl_from_IDWriteColorGlyphRunEnumerator(iface
);
4841 ULONG ref
= InterlockedDecrement(&This
->ref
);
4843 TRACE("(%p)->(%u)\n", This
, ref
);
4846 heap_free(This
->advances
);
4847 heap_free(This
->color_advances
);
4848 heap_free(This
->offsets
);
4849 heap_free(This
->color_offsets
);
4850 heap_free(This
->glyphindices
);
4851 heap_free(This
->glyphs
);
4852 if (This
->colr
.context
)
4853 IDWriteFontFace3_ReleaseFontTable(This
->fontface
, This
->colr
.context
);
4854 IDWriteFontFace3_Release(This
->fontface
);
4861 static FLOAT
get_glyph_origin(const struct dwrite_colorglyphenum
*glyphenum
, UINT32 g
)
4863 BOOL is_rtl
= glyphenum
->run
.bidiLevel
& 1;
4864 FLOAT origin
= 0.0f
;
4870 origin
+= is_rtl
? -glyphenum
->advances
[g
] : glyphenum
->advances
[g
];
4874 static BOOL
colorglyphenum_build_color_run(struct dwrite_colorglyphenum
*glyphenum
)
4876 DWRITE_COLOR_GLYPH_RUN
*colorrun
= &glyphenum
->colorrun
;
4877 FLOAT advance_adj
= 0.0f
;
4878 BOOL got_palette_index
;
4881 /* start with regular glyphs */
4882 if (glyphenum
->current_layer
== 0 && glyphenum
->has_regular_glyphs
) {
4883 UINT32 first_glyph
= 0;
4885 for (g
= 0; g
< glyphenum
->run
.glyphCount
; g
++) {
4886 if (glyphenum
->glyphs
[g
].num_layers
== 0) {
4887 glyphenum
->glyphindices
[g
] = glyphenum
->glyphs
[g
].glyph
;
4888 first_glyph
= min(first_glyph
, g
);
4891 glyphenum
->glyphindices
[g
] = 1;
4892 glyphenum
->color_advances
[g
] = glyphenum
->advances
[g
];
4893 if (glyphenum
->color_offsets
)
4894 glyphenum
->color_offsets
[g
] = glyphenum
->offsets
[g
];
4897 colorrun
->baselineOriginX
= glyphenum
->origin_x
+ get_glyph_origin(glyphenum
, first_glyph
);
4898 colorrun
->baselineOriginY
= glyphenum
->origin_y
;
4899 colorrun
->glyphRun
.glyphCount
= glyphenum
->run
.glyphCount
;
4900 colorrun
->paletteIndex
= 0xffff;
4901 memset(&colorrun
->runColor
, 0, sizeof(colorrun
->runColor
));
4902 glyphenum
->has_regular_glyphs
= FALSE
;
4906 colorrun
->glyphRun
.glyphCount
= 0;
4907 got_palette_index
= FALSE
;
4911 for (g
= 0; g
< glyphenum
->run
.glyphCount
; g
++) {
4913 glyphenum
->glyphindices
[g
] = 1;
4915 /* all glyph layers were returned */
4916 if (glyphenum
->glyphs
[g
].layer
== glyphenum
->glyphs
[g
].num_layers
) {
4917 advance_adj
+= glyphenum
->advances
[g
];
4921 if (glyphenum
->current_layer
== glyphenum
->glyphs
[g
].layer
&& (!got_palette_index
|| colorrun
->paletteIndex
== glyphenum
->glyphs
[g
].palette_index
)) {
4922 UINT32 index
= colorrun
->glyphRun
.glyphCount
;
4923 if (!got_palette_index
) {
4924 colorrun
->paletteIndex
= glyphenum
->glyphs
[g
].palette_index
;
4925 /* use foreground color or request one from the font */
4926 memset(&colorrun
->runColor
, 0, sizeof(colorrun
->runColor
));
4927 if (colorrun
->paletteIndex
!= 0xffff) {
4928 HRESULT hr
= IDWriteFontFace3_GetPaletteEntries(glyphenum
->fontface
, glyphenum
->palette
, colorrun
->paletteIndex
,
4929 1, &colorrun
->runColor
);
4931 WARN("failed to get palette entry, fontface %p, palette %u, index %u, 0x%08x\n", glyphenum
->fontface
,
4932 glyphenum
->palette
, colorrun
->paletteIndex
, hr
);
4934 /* found a glyph position new color run starts from, origin is "original origin + distance to this glyph" */
4935 colorrun
->baselineOriginX
= glyphenum
->origin_x
+ get_glyph_origin(glyphenum
, g
);
4936 colorrun
->baselineOriginY
= glyphenum
->origin_y
;
4937 glyphenum
->color_advances
[index
] = glyphenum
->advances
[g
];
4938 got_palette_index
= TRUE
;
4941 glyphenum
->glyphindices
[index
] = glyphenum
->glyphs
[g
].glyph
;
4942 /* offsets are relative to glyph origin, nothing to fix up */
4943 if (glyphenum
->color_offsets
)
4944 glyphenum
->color_offsets
[index
] = glyphenum
->offsets
[g
];
4945 opentype_colr_next_glyph(glyphenum
->colr
.data
, glyphenum
->glyphs
+ g
);
4947 glyphenum
->color_advances
[index
-1] += advance_adj
;
4948 colorrun
->glyphRun
.glyphCount
++;
4952 advance_adj
+= glyphenum
->advances
[g
];
4955 /* reset last advance */
4956 if (colorrun
->glyphRun
.glyphCount
)
4957 glyphenum
->color_advances
[colorrun
->glyphRun
.glyphCount
-1] = 0.0f
;
4959 return colorrun
->glyphRun
.glyphCount
> 0;
4962 static HRESULT WINAPI
colorglyphenum_MoveNext(IDWriteColorGlyphRunEnumerator
*iface
, BOOL
*has_run
)
4964 struct dwrite_colorglyphenum
*This
= impl_from_IDWriteColorGlyphRunEnumerator(iface
);
4966 TRACE("(%p)->(%p)\n", This
, has_run
);
4970 This
->colorrun
.glyphRun
.glyphCount
= 0;
4971 while (This
->current_layer
< This
->max_layer_num
) {
4972 if (colorglyphenum_build_color_run(This
))
4975 This
->current_layer
++;
4978 *has_run
= This
->colorrun
.glyphRun
.glyphCount
> 0;
4983 static HRESULT WINAPI
colorglyphenum_GetCurrentRun(IDWriteColorGlyphRunEnumerator
*iface
, DWRITE_COLOR_GLYPH_RUN
const **run
)
4985 struct dwrite_colorglyphenum
*This
= impl_from_IDWriteColorGlyphRunEnumerator(iface
);
4987 TRACE("(%p)->(%p)\n", This
, run
);
4989 if (This
->colorrun
.glyphRun
.glyphCount
== 0) {
4991 return E_NOT_VALID_STATE
;
4994 *run
= &This
->colorrun
;
4998 static const IDWriteColorGlyphRunEnumeratorVtbl colorglyphenumvtbl
= {
4999 colorglyphenum_QueryInterface
,
5000 colorglyphenum_AddRef
,
5001 colorglyphenum_Release
,
5002 colorglyphenum_MoveNext
,
5003 colorglyphenum_GetCurrentRun
5006 HRESULT
create_colorglyphenum(FLOAT originX
, FLOAT originY
, const DWRITE_GLYPH_RUN
*run
, const DWRITE_GLYPH_RUN_DESCRIPTION
*rundescr
,
5007 DWRITE_MEASURING_MODE measuring_mode
, const DWRITE_MATRIX
*transform
, UINT32 palette
, IDWriteColorGlyphRunEnumerator
**ret
)
5009 struct dwrite_colorglyphenum
*colorglyphenum
;
5010 BOOL colorfont
, has_colored_glyph
;
5011 IDWriteFontFace3
*fontface3
;
5017 hr
= IDWriteFontFace_QueryInterface(run
->fontFace
, &IID_IDWriteFontFace3
, (void**)&fontface3
);
5019 WARN("failed to get IDWriteFontFace3, 0x%08x\n", hr
);
5023 colorfont
= IDWriteFontFace3_IsColorFont(fontface3
) && IDWriteFontFace3_GetColorPaletteCount(fontface3
) > palette
;
5025 hr
= DWRITE_E_NOCOLOR
;
5029 colorglyphenum
= heap_alloc_zero(sizeof(*colorglyphenum
));
5030 if (!colorglyphenum
) {
5035 colorglyphenum
->IDWriteColorGlyphRunEnumerator_iface
.lpVtbl
= &colorglyphenumvtbl
;
5036 colorglyphenum
->ref
= 1;
5037 colorglyphenum
->origin_x
= originX
;
5038 colorglyphenum
->origin_y
= originY
;
5039 colorglyphenum
->fontface
= fontface3
;
5040 colorglyphenum
->glyphs
= NULL
;
5041 colorglyphenum
->run
= *run
;
5042 colorglyphenum
->run
.glyphIndices
= NULL
;
5043 colorglyphenum
->run
.glyphAdvances
= NULL
;
5044 colorglyphenum
->run
.glyphOffsets
= NULL
;
5045 colorglyphenum
->palette
= palette
;
5046 memset(&colorglyphenum
->colr
, 0, sizeof(colorglyphenum
->colr
));
5047 colorglyphenum
->colr
.exists
= TRUE
;
5048 get_fontface_table(fontface3
, MS_COLR_TAG
, &colorglyphenum
->colr
);
5049 colorglyphenum
->current_layer
= 0;
5050 colorglyphenum
->max_layer_num
= 0;
5052 colorglyphenum
->glyphs
= heap_alloc_zero(run
->glyphCount
* sizeof(*colorglyphenum
->glyphs
));
5054 has_colored_glyph
= FALSE
;
5055 colorglyphenum
->has_regular_glyphs
= FALSE
;
5056 for (i
= 0; i
< run
->glyphCount
; i
++) {
5057 if (opentype_get_colr_glyph(colorglyphenum
->colr
.data
, run
->glyphIndices
[i
], colorglyphenum
->glyphs
+ i
) == S_OK
) {
5058 colorglyphenum
->max_layer_num
= max(colorglyphenum
->max_layer_num
, colorglyphenum
->glyphs
[i
].num_layers
);
5059 has_colored_glyph
= TRUE
;
5061 if (colorglyphenum
->glyphs
[i
].num_layers
== 0)
5062 colorglyphenum
->has_regular_glyphs
= TRUE
;
5065 /* It's acceptable to have a subset of glyphs mapped to color layers, for regular runs client
5066 is supposed to proceed normally, like if font had no color info at all. */
5067 if (!has_colored_glyph
) {
5068 IDWriteColorGlyphRunEnumerator_Release(&colorglyphenum
->IDWriteColorGlyphRunEnumerator_iface
);
5069 return DWRITE_E_NOCOLOR
;
5072 colorglyphenum
->advances
= heap_alloc(run
->glyphCount
* sizeof(FLOAT
));
5073 colorglyphenum
->color_advances
= heap_alloc(run
->glyphCount
* sizeof(FLOAT
));
5074 colorglyphenum
->glyphindices
= heap_alloc(run
->glyphCount
* sizeof(UINT16
));
5075 if (run
->glyphOffsets
) {
5076 colorglyphenum
->offsets
= heap_alloc(run
->glyphCount
* sizeof(*colorglyphenum
->offsets
));
5077 colorglyphenum
->color_offsets
= heap_alloc(run
->glyphCount
* sizeof(*colorglyphenum
->color_offsets
));
5078 memcpy(colorglyphenum
->offsets
, run
->glyphOffsets
, run
->glyphCount
* sizeof(*run
->glyphOffsets
));
5081 colorglyphenum
->colorrun
.glyphRun
.glyphIndices
= colorglyphenum
->glyphindices
;
5082 colorglyphenum
->colorrun
.glyphRun
.glyphAdvances
= colorglyphenum
->color_advances
;
5083 colorglyphenum
->colorrun
.glyphRun
.glyphOffsets
= colorglyphenum
->color_offsets
;
5084 colorglyphenum
->colorrun
.glyphRunDescription
= NULL
; /* FIXME */
5086 if (run
->glyphAdvances
)
5087 memcpy(colorglyphenum
->advances
, run
->glyphAdvances
, run
->glyphCount
* sizeof(FLOAT
));
5089 DWRITE_FONT_METRICS metrics
;
5091 IDWriteFontFace_GetMetrics(run
->fontFace
, &metrics
);
5092 for (i
= 0; i
< run
->glyphCount
; i
++) {
5096 switch (measuring_mode
)
5098 case DWRITE_MEASURING_MODE_NATURAL
:
5099 hr
= IDWriteFontFace3_GetDesignGlyphAdvances(fontface3
, 1, run
->glyphIndices
+ i
, &a
, run
->isSideways
);
5102 colorglyphenum
->advances
[i
] = get_scaled_advance_width(a
, run
->fontEmSize
, &metrics
);
5104 case DWRITE_MEASURING_MODE_GDI_CLASSIC
:
5105 case DWRITE_MEASURING_MODE_GDI_NATURAL
:
5106 hr
= IDWriteFontFace3_GetGdiCompatibleGlyphAdvances(fontface3
, run
->fontEmSize
, 1.0f
, transform
,
5107 measuring_mode
== DWRITE_MEASURING_MODE_GDI_NATURAL
, run
->isSideways
, 1, run
->glyphIndices
+ i
, &a
);
5109 colorglyphenum
->advances
[i
] = 0.0f
;
5111 colorglyphenum
->advances
[i
] = floorf(a
* run
->fontEmSize
/ metrics
.designUnitsPerEm
+ 0.5f
);
5119 *ret
= &colorglyphenum
->IDWriteColorGlyphRunEnumerator_iface
;
5123 IDWriteFontFace3_Release(fontface3
);